[CalendarServer-changes] [4134] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Fri May 1 12:30:58 PDT 2009


Revision: 4134
          http://trac.macosforge.org/projects/calendarserver/changeset/4134
Author:   exarkun at twistedmatrix.com
Date:     2009-05-01 12:30:58 -0700 (Fri, 01 May 2009)
Log Message:
-----------
Merge exarkun/update-twisted-3816-3

Change the run script to point to the dav-take-two-3081-4 branch, drop the patches
which this obviates the need for, and make other adjustments to the codebase so that
the implementation works with the new branch and the tests pass.

Modified Paths:
--------------
    CalendarServer/trunk/lib-patches/Twisted/twisted.python.util.patch
    CalendarServer/trunk/run
    CalendarServer/trunk/twistedcaldav/notify.py
    CalendarServer/trunk/twistedcaldav/test/test_index.py
    CalendarServer/trunk/twistedcaldav/test/test_upgrade.py
    CalendarServer/trunk/twistedcaldav/test/util.py

Added Paths:
-----------
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.digest.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.resource.patch

Removed Paths:
-------------
    CalendarServer/trunk/lib-patches/Twisted/twisted.application.app.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.conch.test.test_keys.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.internet._sslverify.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.internet.defer.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.mail.imap4.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.mail.pop3client.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.persisted.sob.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.plugins.__init__.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.python.filepath.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.runner.procmon.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.spread.pb.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.test.test_plugin.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.test.test_tcp.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web.test.test_webclient.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.basic.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.digest.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.interfaces.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.wrapper.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.__init__.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.auth.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.davxml.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.__init__.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.base.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.extensions.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.parser.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.rfc2518.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.rfc3744.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.rfc4331.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.fileop.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.http.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.idav.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.__init__.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.copymove.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.delete.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.prop_common.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.propfind.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.put.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.put_common.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_acl_principal_prop_set.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_expand.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_principal_match.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.resource.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.static.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.stream.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.data.quota_100.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_copy.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_pipeline.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_prop.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_quota.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_static.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_stream.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_xml.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.tworequest_client.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.util.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.util.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.xattrprops.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.http.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.log.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.server.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.static.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.test.test_http.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch
    CalendarServer/trunk/lib-patches/Twisted/twisted.words.protocols.jabber.sasl_mechanisms.patch

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.application.app.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.application.app.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.application.app.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,13 +0,0 @@
-Index: twisted/application/app.py
-===================================================================
---- twisted/application/app.py	(revision 19773)
-+++ twisted/application/app.py	(working copy)
-@@ -18,7 +18,7 @@
- def runWithProfiler(reactor, config):
-     """Run reactor under standard profiler."""
-     try:
--        import profile
-+        import cProfile as profile
-     except ImportError, e:
-         s = "Failed to import module profile: %s" % e
-         s += """

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.conch.test.test_keys.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.conch.test.test_keys.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.conch.test.test_keys.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,16 +0,0 @@
-Index: twisted/conch/test/test_keys.py
-===================================================================
---- twisted/conch/test/test_keys.py	(revision 19773)
-+++ twisted/conch/test/test_keys.py	(working copy)
-@@ -4,10 +4,10 @@
- 
- try:
-     import Crypto
-+    from twisted.conch.ssh import keys
- except ImportError:
-     Crypto = None
- 
--from twisted.conch.ssh import keys
- from twisted.trial import unittest
- 
- publicRSA_openssh = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEArzJx8OYOnJmzf4tfBEvLi8DVPrJ3/c9k2I/Az64fxjHf9imyRJbixtQhlH9lfNjUIx+4LmrJH5QNRsFporcHDKOTwTTYLh5KmRpslkYHRivcJSkbh/C+BR3utDS555mV comment"

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.internet._sslverify.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.internet._sslverify.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.internet._sslverify.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,35 +0,0 @@
-Index: twisted/internet/_sslverify.py
-===================================================================
---- twisted/internet/_sslverify.py	(revision 19773)
-+++ twisted/internet/_sslverify.py	(working copy)
-@@ -1,7 +1,11 @@
- # -*- test-case-name: twisted.test.test_sslverify -*-
- # Copyright 2005 Divmod, Inc.  See LICENSE file for details
- 
--import itertools, md5
-+import itertools
-+try:
-+    from hashlib import md5
-+except ImportError:
-+    from md5 import new as md5
- from OpenSSL import SSL, crypto
- 
- from twisted.python import reflect, util
-@@ -666,7 +670,7 @@
-         MD5 hex digest of signature on an empty certificate request with this
-         key.
-         """
--        return md5.md5(self._emptyReq).hexdigest()
-+        return md5(self._emptyReq).hexdigest()
- 
- 
-     def inspect(self):
-@@ -942,7 +946,7 @@
-             ctx.set_options(self._OP_ALL)
- 
-         if self.enableSessions:
--            sessionName = md5.md5("%s-%d" % (reflect.qual(self.__class__), _sessionCounter())).hexdigest()
-+            sessionName = md5("%s-%d" % (reflect.qual(self.__class__), _sessionCounter())).hexdigest()
-             ctx.set_session_id(sessionName)
- 
-         return ctx

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.internet.defer.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.internet.defer.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.internet.defer.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,12 +0,0 @@
-Index: twisted/internet/defer.py
-===================================================================
---- twisted/internet/defer.py	(revision 19773)
-+++ twisted/internet/defer.py	(working copy)
-@@ -998,6 +998,6 @@
- __all__ = ["Deferred", "DeferredList", "succeed", "fail", "FAILURE", "SUCCESS",
-            "AlreadyCalledError", "TimeoutError", "gatherResults",
-            "maybeDeferred",
--           "waitForDeferred", "deferredGenerator", "inlineCallbacks",
-+           "waitForDeferred", "deferredGenerator", "returnValue", "inlineCallbacks",
-            "DeferredLock", "DeferredSemaphore", "DeferredQueue",
-           ]

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.mail.imap4.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.mail.imap4.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.mail.imap4.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,65 +0,0 @@
-Index: twisted/mail/imap4.py
-===================================================================
---- twisted/mail/imap4.py	(revision 19773)
-+++ twisted/mail/imap4.py	(working copy)
-@@ -363,16 +363,11 @@
-         for L in self.lines:
-             names = parseNestedParens(L)
-             N = len(names)
-+            # This section is patched as described in http://twistedmatrix.com/trac/ticket/1105
-             if (N >= 1 and names[0] in self._1_RESPONSES or
-+                N >= 2 and names[1] in self._2_RESPONSES or
-                 N >= 2 and names[0] == 'OK' and isinstance(names[1], types.ListType) and names[1][0] in self._OK_RESPONSES):
-                 send.append(L)
--            elif N >= 3 and names[1] in self._2_RESPONSES:
--                if isinstance(names[2], list) and len(names[2]) >= 1 and names[2][0] == 'FLAGS' and 'FLAGS' not in self.args:
--                    unuse.append(L)
--                else:
--                    send.append(L)
--            elif N >= 2 and names[1] in self._2_RESPONSES:
--                send.append(L)
-             else:
-                 unuse.append(L)
-         d, self.defer = self.defer, None
-@@ -2245,10 +2240,12 @@
-                     for f in fetched.get('FLAGS', []):
-                         sum.append(f)
-                     flags.setdefault(mId, []).extend(sum)
-+            elif L.find('BYE LOGOUT') != -1:
-+                pass
-             else:
-                 log.msg('Unhandled unsolicited response: ' + repr(L))
--        if flags:
--            self.flagsChanged(flags)
-+        #if flags:
-+        #    self.flagsChanged(flags)
-         if recent is not None or exists is not None:
-             self.newMessages(exists, recent)
- 
-@@ -3336,6 +3333,8 @@
-                             if len(data) < 2:
-                                 raise IllegalServerResponse("Not enough arguments", data)
-                             flags.setdefault(id, {})[data[0]] = data[1]
-+                            if data[0] == 'FLAGS':
-+                                self.flagsChanged({id: data[1]})
-                             del data[:2]
-                 else:
-                     print '(2)Ignoring ', parts
-@@ -3431,7 +3430,16 @@
-                     except ValueError:
-                         raise IllegalServerResponse, line
-                     else:
--                        info[id] = parseNestedParens(parts[2])
-+                        data = parseNestedParens(parts[2])[0]
-+                        # This section is patched as described in http://twistedmatrix.com/trac/ticket/1105
-+                        # XXX this will fail if 'FLAGS' is a retrieved part
-+                        for i in range(len(data) -1):
-+                            if data[i] == 'FLAGS':
-+                                self.flagsChanged({id: data[i+1]})
-+                                del data[i:i+2]
-+                                break
-+                        if data:
-+                            info.setdefault(id, []).append(data)
-         return info
- 
-     def _fetch(self, messages, useUID=0, **terms):

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.mail.pop3client.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.mail.pop3client.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.mail.pop3client.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,28 +0,0 @@
-Index: twisted/mail/pop3client.py
-===================================================================
---- twisted/mail/pop3client.py	(revision 19773)
-+++ twisted/mail/pop3client.py	(working copy)
-@@ -11,8 +11,13 @@
- API Stability: Unstable
- """
- 
--import re, md5
-+import re
- 
-+try:
-+    from hashlib import md5
-+except ImportError:
-+    from md5 import new as md5
-+
- from twisted.python import log
- from twisted.internet import defer
- from twisted.protocols import basic
-@@ -486,7 +491,7 @@
-     def _apop(self, username, password, challenge):
-         # Internal helper.  Computes and sends an APOP response.  Returns
-         # a Deferred that fires when the server responds to the response.
--        digest = md5.new(challenge + password).hexdigest()
-+        digest = md5(challenge + password).hexdigest()
-         return self.apop(username, digest)
- 
-     def apop(self, username, digest):

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.persisted.sob.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.persisted.sob.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.persisted.sob.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,32 +0,0 @@
-Index: twisted/persisted/sob.py
-===================================================================
---- twisted/persisted/sob.py	(revision 19773)
-+++ twisted/persisted/sob.py	(working copy)
-@@ -10,8 +10,12 @@
- Maintainer: U{Moshe Zadka<mailto:moshez at twistedmatrix.com>}
- """
- 
--import os, md5, sys
-+import os, sys
- try:
-+    from hashlib import md5
-+except ImportError:
-+    from md5 import new as md5
-+try:
-     import cPickle as pickle
- except ImportError:
-     import pickle
-@@ -32,11 +36,11 @@
-     leftover = len(data) % cipher.block_size
-     if leftover:
-         data += ' '*(cipher.block_size - leftover)
--    return cipher.new(md5.new(passphrase).digest()[:16]).encrypt(data)
-+    return cipher.new(md5(passphrase).digest()[:16]).encrypt(data)
- 
- def _decrypt(passphrase, data):
-     from Crypto.Cipher import AES
--    return AES.new(md5.new(passphrase).digest()[:16]).decrypt(data)
-+    return AES.new(md5(passphrase).digest()[:16]).decrypt(data)
- 
- 
- class IPersistable(Interface):

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.plugins.__init__.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.plugins.__init__.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.plugins.__init__.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,12 +0,0 @@
-Index: twisted/plugins/__init__.py
-===================================================================
---- twisted/plugins/__init__.py	(revision 19773)
-+++ twisted/plugins/__init__.py	(working copy)
-@@ -12,6 +12,6 @@
- """
- 
- import os, sys
--__path__ = [os.path.abspath(os.path.join(x, 'twisted', 'plugins')) for x in sys.path]
-+__path__ = [os.path.abspath(os.path.join(x, 'twisted', 'plugins')) for x in sys.path if not x.startswith('/System')]
- 
- __all__ = []                    # nothing to see here, move along, move along

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.python.filepath.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.python.filepath.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.python.filepath.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,28 +0,0 @@
-Index: twisted/python/filepath.py
-===================================================================
---- twisted/python/filepath.py	(revision 19773)
-+++ twisted/python/filepath.py	(working copy)
-@@ -9,9 +9,13 @@
- import os
- import errno
- import random
--import sha
- import base64
- 
-+try:
-+    from hashlib import sha1
-+except ImportError:
-+    from sha import new as sha1
-+
- from os.path import isabs, exists, normpath, abspath, splitext
- from os.path import basename, dirname
- from os.path import join as joinpath
-@@ -109,7 +113,7 @@
-     """
-     Create a pseudorandom, 16-character string for use in secure filenames.
-     """
--    return armor(sha.new(randomBytes(64)).digest())[:16]
-+    return armor(sha1(randomBytes(64)).digest())[:16]
- 
- class _PathHelper:
-     """

Modified: CalendarServer/trunk/lib-patches/Twisted/twisted.python.util.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.python.util.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.python.util.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,180 +1,36 @@
 Index: twisted/python/util.py
 ===================================================================
---- twisted/python/util.py	(revision 19773)
+--- twisted/python/util.py	(revision 26741)
 +++ twisted/python/util.py	(working copy)
-@@ -561,83 +561,107 @@
+@@ -569,9 +569,30 @@
      L2.sort()
      return [e[2] for e in L2]
  
+-if pwd is None or grp is None or setgroups is None or getgroups is None:
 +
-+# The python implementation of initgroups below, which iterates all groups,
-+# doesn't scale, so use the libc version if available:
-+
- try:
--    import pwd, grp
--    from os import setgroups, getgroups
--    
--    def _setgroups_until_success(l):
--        while(1):
--            # NASTY NASTY HACK (but glibc does it so it must be okay):
--            # In case sysconfig didn't give the right answer, find the limit
--            # on max groups by just looping, trying to set fewer and fewer
--            # groups each time until it succeeds.
-+    from ctypes import *
-+    import ctypes.util
++try:
++    from ctypes import c_int, c_char_p
++    from ctypes.cdll import LoadLibrary
++    from ctypes.util import find_library
 +    hasCtypes = True
 +except ImportError:
 +    hasCtypes = False
 +
 +if sys.platform == "darwin" and hasCtypes:
 +    import pwd
-+
-+    libc = cdll.LoadLibrary(ctypes.util.find_library("libc"))
-+
-+    def initgroups(uid, primaryGid):
++    libc = LoadLibrary(find_library("libc"))
+     def initgroups(uid, primaryGid):
+         """
++        Call initgroups with ctypes.
++        """
 +        c_gid = c_int(primaryGid)
 +        username = pwd.getpwuid(uid)[0]
 +        c_username = c_char_p(username)
 +        return libc.initgroups(c_username, c_gid)
 +
-+else:
-+    # Original twisted implementation
-+    try:
-+        import pwd, grp
-+        from os import setgroups, getgroups
-+        
-+        def _setgroups_until_success(l):
-+            while(1):
-+                # NASTY NASTY HACK (but glibc does it so it must be okay):
-+                # In case sysconfig didn't give the right answer, find the limit
-+                # on max groups by just looping, trying to set fewer and fewer
-+                # groups each time until it succeeds.
-+                try:
-+                    setgroups(l)
-+                except ValueError:
-+                    # This exception comes from python itself restricting
-+                    # number of groups allowed.
-+                    if len(l) > 1:
-+                        del l[-1]
-+                    else:
-+                        raise
-+                except OSError, e:
-+                    if e.errno == errno.EINVAL and len(l) > 1:
-+                        # This comes from the OS saying too many groups
-+                        del l[-1]
-+                    else:
-+                        raise
-+                else:
-+                    # Success, yay!
-+                    return
-+                
-+        def initgroups(uid, primaryGid):
-+            """Initializes the group access list.
-+
-+            This is done by reading the group database /etc/group and using all
-+            groups of which C{uid} is a member.  The additional group
-+            C{primaryGid} is also added to the list.
-+
-+            If the given user is a member of more than C{NGROUPS}, arbitrary
-+            groups will be silently discarded to bring the number below that
-+            limit.
-+            """       
-             try:
--                setgroups(l)
--            except ValueError:
--                # This exception comes from python itself restricting
--                # number of groups allowed.
--                if len(l) > 1:
--                    del l[-1]
--                else:
--                    raise
-+                # Try to get the maximum number of groups
-+                max_groups = os.sysconf("SC_NGROUPS_MAX")
-+            except:
-+                # No predefined limit
-+                max_groups = 0
-+            
-+            username = pwd.getpwuid(uid)[0]
-+            l = []
-+            if primaryGid is not None:
-+                l.append(primaryGid)
-+            for groupname, password, gid, userlist in grp.getgrall():
-+                if username in userlist:
-+                    l.append(gid)
-+                    if len(l) == max_groups:
-+                        break # No more groups, ignore any more
-+            try:
-+                _setgroups_until_success(l)
-             except OSError, e:
--                if e.errno == errno.EINVAL and len(l) > 1:
--                    # This comes from the OS saying too many groups
--                    del l[-1]
-+                # We might be able to remove this code now that we
-+                # don't try to setgid/setuid even when not asked to.
-+                if e.errno == errno.EPERM:
-+                    for g in getgroups():
-+                        if g not in l:
-+                            raise
-                 else:
-                     raise
--            else:
--                # Success, yay!
--                return
--            
--    def initgroups(uid, primaryGid):
--        """Initializes the group access list.
-+                                        
++elif pwd is None or grp is None or setgroups is None or getgroups is None:
++    def initgroups(uid, primaryGid):
++        """
+         Do nothing.
  
--        This is done by reading the group database /etc/group and using all
--        groups of which C{uid} is a member.  The additional group
--        C{primaryGid} is also added to the list.
-+    except:
-+        def initgroups(uid, primaryGid):
-+            """Do nothing.
- 
--        If the given user is a member of more than C{NGROUPS}, arbitrary
--        groups will be silently discarded to bring the number below that
--        limit.
--        """       
--        try:
--            # Try to get the maximum number of groups
--            max_groups = os.sysconf("SC_NGROUPS_MAX")
--        except:
--            # No predefined limit
--            max_groups = 0
--        
--        username = pwd.getpwuid(uid)[0]
--        l = []
--        if primaryGid is not None:
--            l.append(primaryGid)
--        for groupname, password, gid, userlist in grp.getgrall():
--            if username in userlist:
--                l.append(gid)
--                if len(l) == max_groups:
--                    break # No more groups, ignore any more
--        try:
--            _setgroups_until_success(l)
--        except OSError, e:
--            # We might be able to remove this code now that we
--            # don't try to setgid/setuid even when not asked to.
--            if e.errno == errno.EPERM:
--                for g in getgroups():
--                    if g not in l:
--                        raise
--            else:
--                raise
--                                    
-+            Underlying platform support require to manipulate groups is missing.
-+            """
- 
--except:
--    def initgroups(uid, primaryGid):
--        """Do nothing.
- 
--        Underlying platform support require to manipulate groups is missing.
--        """
--
--
- def switchUID(uid, gid, euid=False):
-     if euid:
-         setuid = os.seteuid
+         Underlying platform support require to manipulate groups is missing.

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.runner.procmon.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.runner.procmon.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.runner.procmon.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,39 +0,0 @@
-Index: twisted/runner/procmon.py
-===================================================================
---- twisted/runner/procmon.py	(revision 19773)
-+++ twisted/runner/procmon.py	(working copy)
-@@ -59,6 +59,9 @@
- 
-     disconnecting = 0
- 
-+    def loseConnection(self):
-+        pass
-+
- transport = DummyTransport() 
- 
- class LineLogger(basic.LineReceiver):
-@@ -130,10 +133,10 @@
-         self.consistency = reactor.callLater(self.consistencyDelay,
-                                              self._checkConsistency)
- 
--    def addProcess(self, name, args, uid=None, gid=None):
-+    def addProcess(self, name, args, uid=None, gid=None, env={}):
-         if self.processes.has_key(name):
-             raise KeyError("remove %s first" % name)
--        self.processes[name] = args, uid, gid
-+        self.processes[name] = args, uid, gid, env
-         if self.active:
-             self.startProcess(name)
- 
-@@ -175,9 +178,9 @@
-         p = self.protocols[name] = LoggingProtocol()
-         p.service = self
-         p.name = name
--        args, uid, gid = self.processes[name]
-+        args, uid, gid, env = self.processes[name]
-         self.timeStarted[name] = time.time()
--        reactor.spawnProcess(p, args[0], args, uid=uid, gid=gid)
-+        reactor.spawnProcess(p, args[0], args, uid=uid, gid=gid, env=env)
- 
-     def _forceStopProcess(self, proc):
-         try:

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.spread.pb.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.spread.pb.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.spread.pb.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,53 +0,0 @@
-Index: twisted/spread/pb.py
-===================================================================
---- twisted/spread/pb.py	(revision 19773)
-+++ twisted/spread/pb.py	(working copy)
-@@ -64,7 +64,11 @@
- except ImportError:
-     import StringIO
- 
--import md5
-+try:
-+    from hashlib import md5
-+except ImportError:
-+    from md5 import new as md5
-+
- import random
- import new
- import types
-@@ -1003,10 +1007,10 @@
- 
-     This is useful for challenge/response authentication.
-     """
--    m = md5.new()
-+    m = md5()
-     m.update(password)
-     hashedPassword = m.digest()
--    m = md5.new()
-+    m = md5()
-     m.update(hashedPassword)
-     m.update(challenge)
-     doubleHashedPassword = m.digest()
-@@ -1017,7 +1021,7 @@
-     crap = ''
-     for x in range(random.randrange(15,25)):
-         crap = crap + chr(random.randint(65,90))
--    crap = md5.new(crap).digest()
-+    crap = md5(crap).digest()
-     return crap
- 
- 
-@@ -1226,11 +1230,11 @@
- 
-     # IUsernameHashedPassword:
-     def checkPassword(self, password):
--        return self.checkMD5Password(md5.md5(password).digest())
-+        return self.checkMD5Password(md5(password).digest())
- 
-     # IUsernameMD5Password
-     def checkMD5Password(self, md5Password):
--        md = md5.new()
-+        md = md5()
-         md.update(md5Password)
-         md.update(self.challenge)
-         correct = md.digest()

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.test.test_plugin.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.test.test_plugin.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.test.test_plugin.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,11 +0,0 @@
-Index: twisted/test/test_plugin.py
-===================================================================
---- twisted/test/test_plugin.py	(revision 19773)
-+++ twisted/test/test_plugin.py	(working copy)
-@@ -518,3 +518,6 @@
-         self.assertEqual(len(self.flushLoggedErrors()), 0)
-         self.assertIn('one', self.getAllPlugins())
-         self.assertEqual(len(self.flushLoggedErrors()), 1)
-+
-+    
-+    test_newPluginsOnReadOnlyPath.skip = "Seems not to work on OS X 10.4 buildbot machine."

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.test.test_tcp.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.test.test_tcp.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.test.test_tcp.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,13 +0,0 @@
-Index: twisted/test/test_tcp.py
-===================================================================
---- twisted/test/test_tcp.py	(revision 19773)
-+++ twisted/test/test_tcp.py	(working copy)
-@@ -1294,6 +1294,8 @@
-             self.client.transport.loseConnection()
-             log.flushErrors(RuntimeError)
-         return d.addCallback(check)
-+
-+    testReadNotificationRaises.todo = "self.f.protocol is None"
-     
-     def testWriteNotificationRaises(self):
-         self.client.writeConnectionLost = self.aBug

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web.test.test_webclient.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web.test.test_webclient.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web.test.test_webclient.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,13 +0,0 @@
-Index: twisted/web/test/test_webclient.py
-===================================================================
---- twisted/web/test/test_webclient.py	(revision 19773)
-+++ twisted/web/test/test_webclient.py	(working copy)
-@@ -206,6 +206,8 @@
-         d.addBoth(self._cleanupDownloadPageError3)
-         return d
- 
-+    testDownloadPageError3.skip = "Seems not to work on OS X."
-+
-     def _cleanupDownloadPageError3(self, ignored):
-         os.chmod("unwritable", 0700)
-         os.unlink("unwritable")

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.basic.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.basic.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.basic.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,29 +0,0 @@
-Index: twisted/web2/auth/basic.py
-===================================================================
---- twisted/web2/auth/basic.py	(revision 19773)
-+++ twisted/web2/auth/basic.py	(working copy)
-@@ -1,6 +1,7 @@
- # -*- test-case-name: twisted.web2.test.test_httpauth -*-
- 
- from twisted.cred import credentials, error
-+from twisted.internet.defer import succeed
- from twisted.web2.auth.interfaces import ICredentialFactory
- 
- from zope.interface import implements
-@@ -18,7 +19,7 @@
-         self.realm = realm
- 
-     def getChallenge(self, peer):
--        return {'realm': self.realm}
-+        return succeed({'realm': self.realm})
- 
-     def decode(self, response, request):
-         try:
-@@ -28,6 +29,6 @@
- 
-         creds = creds.split(':', 1)
-         if len(creds) == 2:
--            return credentials.UsernamePassword(*creds)
-+            return succeed(credentials.UsernamePassword(*creds))
-         else:
-             raise error.LoginFailed('Invalid credentials')

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.digest.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.digest.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.digest.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,135 +0,0 @@
-Index: twisted/web2/auth/digest.py
-===================================================================
---- twisted/web2/auth/digest.py	(revision 19773)
-+++ twisted/web2/auth/digest.py	(working copy)
-@@ -8,19 +8,28 @@
- import time
- 
- from twisted.cred import credentials, error
-+from twisted.internet.defer import succeed
- from zope.interface import implements, Interface
- 
- from twisted.web2.auth.interfaces import ICredentialFactory
-+from twisted.web2.http_headers import tokenize
-+from twisted.web2.http_headers import Token
-+from twisted.web2.http_headers import split
-+from twisted.web2.http_headers import parseKeyValue
- 
--import md5, sha
-+try:
-+    from hashlib import md5, sha1
-+except ImportError:
-+    from md5 import new as md5
-+    from sha import new as sha1
- import random, sys
- 
- # The digest math
- 
- algorithms = {
--    'md5': md5.new,
--    'md5-sess': md5.new,
--    'sha': sha.new,
-+    'md5': md5,
-+    'md5-sess': md5,
-+    'sha': sha1,
- }
- 
- # DigestCalcHA1
-@@ -153,7 +162,18 @@
-             calcHA1(algo, self.username, self.realm, password, nonce, cnonce),
-             algo, nonce, nc, cnonce, qop, self.method, uri, None
-         )
-+        
-+        if expected == response:
-+            return True
- 
-+        # IE7 sends cnonce and nc values, but auth fails if they are used.
-+        # So try again without them...
-+        # They can be omitted for backwards compatibility [RFC 2069].
-+        expected = calcResponse(
-+            calcHA1(algo, self.username, self.realm, password, nonce, cnonce),
-+            algo, nonce, None, None, qop, self.method, uri, None
-+        )
-+
-         return expected == response
- 
-     def checkHash(self, digestHash):
-@@ -228,9 +248,9 @@
-         # Now, what we do is encode the nonce, client ip and a timestamp
-         # in the opaque value with a suitable digest
-         key = "%s,%s,%s" % (nonce, clientip, str(int(self._getTime())))
--        digest = md5.new(key + self.privateKey).hexdigest()
-+        digest = md5(key + self.privateKey).hexdigest()
-         ekey = key.encode('base64')
--        return "%s-%s" % (digest, ekey.strip('\n'))
-+        return "%s-%s" % (digest, ekey.replace('\n', ''))
- 
-     def verifyOpaque(self, opaque, nonce, clientip):
-         """
-@@ -274,7 +294,7 @@
-                 'Invalid response, incompatible opaque/nonce too old')
- 
-         # Verify the digest
--        digest = md5.new(key + self.privateKey).hexdigest()
-+        digest = md5(key + self.privateKey).hexdigest()
-         if digest != opaqueParts[0]:
-             raise error.LoginFailed('Invalid response, invalid opaque value')
- 
-@@ -293,11 +313,12 @@
-         c = self.generateNonce()
-         o = self.generateOpaque(c, peer.host)
- 
--        return {'nonce': c,
--                'opaque': o,
--                'qop': 'auth',
--                'algorithm': self.algorithm,
--                'realm': self.realm}
-+        return succeed({'nonce': c,
-+            'opaque': o,
-+            'qop': 'auth',
-+            'algorithm': self.algorithm,
-+            'realm': self.realm,
-+        })
- 
-     def decode(self, response, request):
-         """
-@@ -315,18 +336,18 @@
-         @raise: L{error.LoginFailed} if the response does not contain a
-             username, a nonce, an opaque, or if the opaque is invalid.
-         """
--        def unq(s):
--            if s[0] == s[-1] == '"':
--                return s[1:-1]
--            return s
-         response = ' '.join(response.splitlines())
--        parts = response.split(',')
--
--        auth = {}
--
--        for (k, v) in [p.split('=', 1) for p in parts]:
--            auth[k.strip()] = unq(v.strip())
--
-+        
-+        try:
-+            parts = split(tokenize((response,), foldCase=False), Token(","))
-+    
-+            auth = {}
-+    
-+            for (k, v) in [parseKeyValue(p) for p in parts]:
-+                auth[k.strip()] = v.strip()
-+        except ValueError:
-+            raise error.LoginFailed('Invalid response.')
-+            
-         username = auth.get('username')
-         if not username:
-             raise error.LoginFailed('Invalid response, no username given.')
-@@ -342,7 +363,7 @@
-                              auth.get('nonce'),
-                              request.remoteAddr.host):
- 
--            return DigestedCredentials(username,
-+            return succeed(DigestedCredentials(username,
-                                        request.method,
-                                        self.realm,
--                                       auth)
-+                                       auth))

Copied: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.digest.patch (from rev 4133, CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.digest.patch)
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.digest.patch	                        (rev 0)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.digest.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -0,0 +1,22 @@
+Index: twisted/web2/auth/digest.py
+===================================================================
+--- twisted/web2/auth/digest.py	(revision 26741)
++++ twisted/web2/auth/digest.py	(working copy)
+@@ -158,6 +158,17 @@
+             algo, nonce, nc, cnonce, qop, self.method, uri, None
+         )
+ 
++        if expected == response:
++            return True
++
++        # IE7 sends cnonce and nc values, but auth fails if they are used.
++        # So try again without them...
++        # They can be omitted for backwards compatibility [RFC 2069].
++        expected = calcResponse(
++            calcHA1(algo, self.username, self.realm, password, nonce, cnonce),
++            algo, nonce, None, None, qop, self.method, uri, None
++        )
++
+         return expected == response
+ 
+     def checkHash(self, digestHash):

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.interfaces.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.interfaces.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.interfaces.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,22 +0,0 @@
-Index: twisted/web2/auth/interfaces.py
-===================================================================
---- twisted/web2/auth/interfaces.py	(revision 19773)
-+++ twisted/web2/auth/interfaces.py	(working copy)
-@@ -18,7 +18,7 @@
-         @param peer: The client's address
- 
-         @rtype: C{dict}
--        @return: dictionary of challenge arguments
-+        @return: deferred returning dictionary of challenge arguments
-         """
- 
-     def decode(response, request):
-@@ -32,7 +32,7 @@
-         @type request: L{twisted.web2.server.Request}
-         @param request: the request being processed
- 
--        @return: ICredentials
-+        @return: deferred returning ICredentials
-         """
- 
- 

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.wrapper.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.wrapper.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.auth.wrapper.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,205 +0,0 @@
-Index: twisted/web2/auth/wrapper.py
-===================================================================
---- twisted/web2/auth/wrapper.py	(revision 19773)
-+++ twisted/web2/auth/wrapper.py	(working copy)
-@@ -5,32 +5,45 @@
- """
- from zope.interface import implements, directlyProvides
- from twisted.cred import error, credentials
--from twisted.python import failure
- from twisted.web2 import responsecode
- from twisted.web2 import http
- from twisted.web2 import iweb
- from twisted.web2.auth.interfaces import IAuthenticatedRequest
-+from twisted.internet.defer import inlineCallbacks, returnValue
- 
- class UnauthorizedResponse(http.StatusResponse):
-     """A specialized response class for generating www-authenticate headers
-     from the given L{CredentialFactory} instances
-     """
- 
--    def __init__(self, factories, remoteAddr=None):
-+    @staticmethod
-+    def makeResponse(factories, remoteAddr=None):
-+        
-+        response = UnauthorizedResponse()
-+        d = response.generateHeaders(factories, remoteAddr)
-+        d.addCallback(lambda _:response)
-+        return d
-+
-+    def __init__(self):
-+
-+        super(UnauthorizedResponse, self).__init__(
-+            responsecode.UNAUTHORIZED,
-+            "You are not authorized to access this resource."
-+    )
-+
-+    @inlineCallbacks
-+    def generateHeaders(self, factories, remoteAddr=None):
-         """
-         @param factories: A L{dict} of {'scheme': ICredentialFactory}
- 
-         @param remoteAddr: An L{IAddress} for the connecting client.
-         """
- 
--        super(UnauthorizedResponse, self).__init__(
--            responsecode.UNAUTHORIZED,
--            "You are not authorized to access this resource.")
--
-         authHeaders = []
-         for factory in factories.itervalues():
--            authHeaders.append((factory.scheme,
--                                factory.getChallenge(remoteAddr)))
-+            scheme = factory.scheme
-+            challenge = (yield factory.getChallenge(remoteAddr))
-+            authHeaders.append((scheme, challenge,))
- 
-         self.headers.setHeader('www-authenticate', authHeaders)
- 
-@@ -71,8 +84,6 @@
- 
-     def _loginSucceeded(self, avatar, request):
-         """
--        Callback for successful login.
--
-         @param avatar: A tuple of the form (interface, avatar) as
-             returned by your realm.
- 
-@@ -85,6 +96,7 @@
- 
-         directlyProvides(request, IAuthenticatedRequest)
- 
-+        @inlineCallbacks
-         def _addAuthenticateHeaders(request, response):
-             """
-             A response filter that adds www-authenticate headers
-@@ -93,14 +105,16 @@
-             """
-             if response.code == responsecode.UNAUTHORIZED:
-                 if not response.headers.hasHeader('www-authenticate'):
--                    newResp = UnauthorizedResponse(self.credentialFactories,
--                                                   request.remoteAddr)
-+                    newResp = (yield UnauthorizedResponse.makeResponse(
-+                        self.credentialFactories,
-+                        request.remoteAddr
-+                    ))
- 
-                     response.headers.setHeader(
-                         'www-authenticate',
-                         newResp.headers.getHeader('www-authenticate'))
- 
--            return response
-+            returnValue(response)
- 
-         _addAuthenticateHeaders.handleErrors = True
- 
-@@ -108,27 +122,22 @@
- 
-         return self.wrappedResource
- 
--    def _loginFailed(self, result, request):
-+    @inlineCallbacks
-+    def _loginFailed(self, request):
-         """
--        Errback for failed login.
--
--        @param result: L{Failure} returned by portal.login
--
-         @param request: L{IRequest} that encapsulates this auth
-             attempt.
- 
--        @return: A L{Failure} containing an L{HTTPError} containing the
--            L{UnauthorizedResponse} if C{result} is an L{UnauthorizedLogin}
--            or L{UnhandledCredentials} error
-+        @raise: always rais HTTPError
-         """
--        result.trap(error.UnauthorizedLogin, error.UnhandledCredentials)
- 
--        return failure.Failure(
--            http.HTTPError(
--                UnauthorizedResponse(
--                self.credentialFactories,
--                request.remoteAddr)))
-+        response = (yield UnauthorizedResponse.makeResponse(
-+            self.credentialFactories,
-+            request.remoteAddr
-+        ))
-+        raise http.HTTPError(response)
- 
-+    @inlineCallbacks
-     def login(self, factory, response, request):
-         """
-         @param factory: An L{ICredentialFactory} that understands the given
-@@ -142,50 +151,48 @@
-             or a failure containing an L{UnauthorizedResponse}
-         """
-         try:
--            creds = factory.decode(response, request)
-+            creds = (yield factory.decode(response, request))
-         except error.LoginFailed:
--            raise http.HTTPError(UnauthorizedResponse(
--                                    self.credentialFactories,
--                                    request.remoteAddr))
-+            yield self._loginFailed(request)
- 
-+        try:
-+            avatar = (yield self.portal.login(creds, None, *self.interfaces))
-+        except (error.UnauthorizedLogin, error.UnhandledCredentials):
-+            yield self._loginFailed(request)
-+        resource = self._loginSucceeded(avatar, request)
-+        returnValue(resource)
- 
--        return self.portal.login(creds, None, *self.interfaces
--                                ).addCallbacks(self._loginSucceeded,
--                                               self._loginFailed,
--                                               (request,), None,
--                                               (request,), None)
--
-+    @inlineCallbacks
-     def authenticate(self, request):
-         """
--        Attempt to authenticate the givin request
-+        Attempt to authenticate the giving request
- 
-         @param request: An L{IRequest} to be authenticated.
-         """
-         authHeader = request.headers.getHeader('authorization')
- 
-         if authHeader is None:
--            return self.portal.login(credentials.Anonymous(),
--                                     None,
--                                     *self.interfaces
--                                     ).addCallbacks(self._loginSucceeded,
--                                                    self._loginFailed,
--                                                    (request,), None,
--                                                    (request,), None)
-+            try:
-+                avatar = (yield self.portal.login(credentials.Anonymous(), None, *self.interfaces))
-+            except:
-+                yield self._loginFailed(request)
-+            resource = self._loginSucceeded(avatar, request)
-+            returnValue(resource)
- 
-         elif authHeader[0] not in self.credentialFactories:
--            raise http.HTTPError(UnauthorizedResponse(
--                                    self.credentialFactories,
--                                    request.remoteAddr))
-+            yield self._loginFailed(request)
-         else:
--            return self.login(self.credentialFactories[authHeader[0]],
--                              authHeader[1], request)
-+            result = (yield self.login(self.credentialFactories[authHeader[0]], authHeader[1], request))
-+            returnValue(result)
- 
-     def locateChild(self, request, seg):
-         """
-         Authenticate the request then return the C{self.wrappedResource}
-         and the unmodified segments.
-         """
--        return self.authenticate(request), seg
-+        d = self.authenticate(request)
-+        d.addCallback(lambda result:(result, seg,))
-+        return d
- 
-     def renderHTTP(self, request):
-         """

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.__init__.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.__init__.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.__init__.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,12 +0,0 @@
-Index: twisted/web2/dav/__init__.py
-===================================================================
---- twisted/web2/dav/__init__.py	(revision 19773)
-+++ twisted/web2/dav/__init__.py	(working copy)
-@@ -45,6 +45,7 @@
-     "noneprops",
-     "resource",
-     "static",
-+    "stream",
-     "util",
-     "xattrprops",
- ]

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.auth.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.auth.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.auth.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,83 +0,0 @@
-Index: twisted/web2/dav/auth.py
-===================================================================
---- twisted/web2/dav/auth.py	(revision 19773)
-+++ twisted/web2/dav/auth.py	(working copy)
-@@ -5,7 +5,13 @@
- from twisted.web2.dav import davxml
- from twisted.web2.dav.davxml import twisted_private_namespace
- 
--__all__ = ["PrincipalCredentials", "AuthenticationWrapper"]
-+__all__ = [
-+    "IPrincipal",
-+    "DavRealm",
-+    "IPrincipalCredentials",
-+    "PrincipalCredentials",
-+    "AuthenticationWrapper",
-+]
- 
- class AuthenticationWrapper(WrapperResource):
-     def __init__(self, resource, portal, credentialFactories, loginInterfaces):
-@@ -40,7 +46,7 @@
- 
-     def requestAvatar(self, avatarId, mind, *interfaces):
-         if IPrincipal in interfaces:
--            return IPrincipal, davxml.Principal(davxml.HRef(avatarId))
-+            return IPrincipal, davxml.Principal(davxml.HRef(avatarId[0])), davxml.Principal(davxml.HRef(avatarId[1]))
-         
-         raise NotImplementedError("Only IPrincipal interface is supported")
- 
-@@ -52,33 +58,44 @@
- class PrincipalCredentials(object):
-     implements(IPrincipalCredentials)
- 
--    def __init__(self, principal, principalURI, credentials):
--        self.principal = principal
--        self.principalURI = principalURI
-+    def __init__(self, authnPrincipal, authzPrincipal, credentials):
-+        """
-+        Initialize with both authentication and authorization values. Note that in most cases theses will be the same
-+        since HTTP auth makes no distinction between the two - but we may be layering some addition auth on top of this
-+        (.e.g.. proxy auth, cookies, forms etc) that make result in authentication and authorization being different.
-+
-+        @param authnPrincipal: L{IDAVPrincipalResource} for the authenticated principal.
-+        @param authnURI: C{str} containing the URI of the authenticated principal.
-+        @param authzPrincipal: L{IDAVPrincipalResource} for the authorized principal.
-+        @param authzURI: C{str} containing the URI of the authorized principal.
-+        @param credentials: L{ICredentials} for the authentication credentials.
-+        """
-+        self.authnPrincipal = authnPrincipal
-+        self.authzPrincipal = authzPrincipal
-         self.credentials = credentials
- 
-     def checkPassword(self, password):
-         return self.credentials.checkPassword(password)
- 
- 
--class TwistedPropertyChecker:
-+class TwistedPropertyChecker(object):
-     implements(checkers.ICredentialsChecker)
- 
-     credentialInterfaces = (IPrincipalCredentials,)
- 
--    def _cbPasswordMatch(self, matched, principalURI):
-+    def _cbPasswordMatch(self, matched, principalURIs):
-         if matched:
--            return principalURI
-+            # We return both URIs
-+            return principalURIs
-         else:
--            raise error.UnauthorizedLogin(
--                "Bad credentials for: %s" % (principalURI,))
-+            raise error.UnauthorizedLogin("Bad credentials for: %s" % (principalURIs[0],))
- 
-     def requestAvatarId(self, credentials):
-         pcreds = IPrincipalCredentials(credentials)
--        pswd = str(pcreds.principal.readDeadProperty(TwistedPasswordProperty))
-+        pswd = str(pcreds.authnPrincipal.readDeadProperty(TwistedPasswordProperty))
- 
-         d = defer.maybeDeferred(credentials.checkPassword, pswd)
--        d.addCallback(self._cbPasswordMatch, pcreds.principalURI)
-+        d.addCallback(self._cbPasswordMatch, (pcreds.authnPrincipal.principalURL(), pcreds.authzPrincipal.principalURL()))
-         return d
- 
- ##

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.davxml.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.davxml.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.davxml.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,30 +0,0 @@
-Index: twisted/web2/dav/davxml.py
-===================================================================
---- twisted/web2/dav/davxml.py	(revision 19773)
-+++ twisted/web2/dav/davxml.py	(working copy)
-@@ -45,6 +45,8 @@
- from twisted.web2.dav.element.rfc2518 import *
- from twisted.web2.dav.element.rfc3253 import *
- from twisted.web2.dav.element.rfc3744 import *
-+from twisted.web2.dav.element.rfc4331 import *
-+from twisted.web2.dav.element.extensions import *
- 
- #
- # Register all XML elements with the parser
-@@ -56,11 +58,15 @@
- import twisted.web2.dav.element.rfc2518
- import twisted.web2.dav.element.rfc3253
- import twisted.web2.dav.element.rfc3744
-+import twisted.web2.dav.element.rfc4331
-+import twisted.web2.dav.element.extensions
- 
- __all__ = (
-     registerElements(twisted.web2.dav.element.base   ) +
-     registerElements(twisted.web2.dav.element.parser ) +
-     registerElements(twisted.web2.dav.element.rfc2518) +
-     registerElements(twisted.web2.dav.element.rfc3253) +
--    registerElements(twisted.web2.dav.element.rfc3744)
-+    registerElements(twisted.web2.dav.element.rfc3744) +
-+    registerElements(twisted.web2.dav.element.rfc4331) +
-+    registerElements(twisted.web2.dav.element.extensions)
- )

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.__init__.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.__init__.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.__init__.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,11 +0,0 @@
-Index: twisted/web2/dav/element/__init__.py
-===================================================================
---- twisted/web2/dav/element/__init__.py	(revision 19773)
-+++ twisted/web2/dav/element/__init__.py	(working copy)
-@@ -35,4 +35,6 @@
-     "rfc2518",
-     "rfc3253",
-     "rfc3744",
-+    "rfc4331",
-+    "extensions",
- ]

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.base.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.base.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.base.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,267 +0,0 @@
-Index: twisted/web2/dav/element/base.py
-===================================================================
---- twisted/web2/dav/element/base.py	(revision 19773)
-+++ twisted/web2/dav/element/base.py	(working copy)
-@@ -45,7 +45,7 @@
- ]
- 
- import string
--import StringIO
-+import cStringIO as StringIO
- import xml.dom.minidom
- 
- import datetime
-@@ -90,6 +90,35 @@
-             raise NotImplementedError("WebDAVElement subclass %s is not implemented."
-                                       % (self.__class__.__name__,))
- 
-+        my_children = []
-+
-+        allowPCDATA = self.allowed_children.has_key(PCDATAElement)
-+
-+        for child in children:
-+            if child is None:
-+                continue
-+
-+            if isinstance(child, (str, unicode)):
-+                child = PCDATAElement(child)
-+
-+            if isinstance(child, PCDATAElement) and not allowPCDATA:
-+                continue
-+
-+            my_children.append(child)
-+
-+        self.children = tuple(my_children)
-+
-+        self.attributes = attributes
-+
-+    def validate(self):
-+
-+        children = self.children
-+        attributes = self.attributes
-+
-+        if self.allowed_children is None:
-+            raise NotImplementedError("WebDAVElement subclass %s is not implemented."
-+                                      % (self.__class__.__name__,))
-+
-         #
-         # Validate that children are of acceptable types
-         #
-@@ -102,13 +131,10 @@
-         my_children = []
- 
-         for child in children:
--            if child is None:
--                continue
- 
--            if isinstance(child, (str, unicode)):
--                child = PCDATAElement(child)
--
-             assert isinstance(child, (WebDAVElement, PCDATAElement)), "Not an element: %r" % (child,)
-+            
-+            child.validate()
- 
-             for allowed, (min, max) in allowed_children.items():
-                 if type(allowed) == type and isinstance(child, allowed):
-@@ -145,24 +171,26 @@
- 
-         if self.allowed_attributes:
-             for name in attributes:
--                if name in self.allowed_attributes:
--                    my_attributes[name] = attributes[name]
--                else:
--                    log.msg("Attribute %s is unexpected and therefore ignored in %s element"
--                            % (name, self.sname()))
-+                if name not in self.allowed_attributes:
-+                    log.msg("Attribute %s is unexpected in %s element" % (name, self.sname()))
-+                my_attributes[name] = attributes[name]
-     
-             for name, required in self.allowed_attributes.items():
-                 if required and name not in my_attributes:
-                     raise ValueError("Attribute %s is required in %s element"
-                                      % (name, self.sname()))
- 
--        elif not isinstance(self, WebDAVUnknownElement):
--            if attributes:
--                log.msg("Attributes %s are unexpected and therefore ignored in %s element"
-+        else:
-+            if not isinstance(self, WebDAVUnknownElement) and attributes:
-+                log.msg("Attributes %s are unexpected in %s element"
-                         % (attributes.keys(), self.sname()))
-+            my_attributes.update(attributes)
- 
-         self.attributes = my_attributes
- 
-+    def emptyCopy(self):
-+        return self.__class__()
-+
-     def __str__(self):
-         return self.sname()
- 
-@@ -190,14 +218,93 @@
-         return child in self.children
- 
-     def writeXML(self, output):
--        document = xml.dom.minidom.Document()
--        self.addToDOM(document, None)
--        PrintXML(document, stream=output)
-+        # FIXME: Now have a 'fast' write implementation as well as previous PyXML-based one.
-+        # For now the fast one is the default and we will test to see if its good enough.
-+        
-+        usePyXML = False
-+        if usePyXML:
-+            document = xml.dom.minidom.Document()
-+            self.addToDOM(document, None)
-+            PrintXML(document, stream=output)
-+        else:
-+            output.write("<?xml version='1.0' encoding='UTF-8'?>\r\n")
-+            self.writeToStream(output, "", 0, True)
-+            output.write("\r\n")
-+    
-+    def writeToStream(self, output, ns, level, pretty):
-+        """
-+        Fast XML output.
- 
-+        @param output: C{stream} to write to.
-+        @param ns: C{str} containing the namespace of the enclosing element.
-+        @param level: C{int} containing the element nesting level (starts at 0).
-+        @param pretty: C{bool} whether to use 'pretty' formatted output or not.
-+        """
-+        
-+        # Do pretty indent
-+        if pretty and level:
-+            output.write("  " * level)
-+        
-+        # Check for empty element (one with either no children or a single PCDATA that is itself empty)
-+        if (len(self.children) == 0 or
-+            (len(self.children) == 1 and isinstance(self.children[0], PCDATAElement) and len(str(self.children[0])) == 0)):
-+
-+            # Write out any attributes or the namespace if difference from enclosing element.
-+            if self.attributes or (ns != self.namespace):
-+                output.write("<%s" % (self.name,))
-+                for name, value in self.attributes.iteritems():
-+                    self.writeAttributeToStream(output, name, value)
-+                if ns != self.namespace:
-+                    output.write(" xmlns='%s'" % (self.namespace,))
-+                output.write("/>")
-+            else:
-+                output.write("<%s/>" % (self.name,))
-+        else:
-+            # Write out any attributes or the namespace if difference from enclosing element.
-+            if self.attributes or (ns != self.namespace):
-+                output.write("<%s" % (self.name,))
-+                for name, value in self.attributes.iteritems():
-+                    self.writeAttributeToStream(output, name, value)
-+                if ns != self.namespace:
-+                    output.write(" xmlns='%s'" % (self.namespace,))
-+                    ns = self.namespace
-+                output.write(">")
-+            else:
-+                output.write("<%s>" % (self.name,))
-+                
-+            # Determine nature of children when doing pretty print: we do
-+            # not want to insert CRLFs or any other whitespace in PCDATA.
-+            hasPCDATA = False
-+            for child in self.children:
-+                if isinstance(child, PCDATAElement):
-+                    hasPCDATA = True
-+                    break
-+            
-+            # Write out the children.
-+            if pretty and not hasPCDATA:
-+                output.write("\r\n")
-+            for child in self.children:
-+                child.writeToStream(output, ns, level+1, pretty)
-+                
-+            # Close the element.
-+            if pretty and not hasPCDATA and level:
-+                output.write("  " * level)
-+            output.write("</%s>" % (self.name,))
-+
-+        if pretty and level:
-+            output.write("\r\n")
-+
-+    def writeAttributeToStream(self, output, name, value):
-+        
-+        # Quote any single quotes. We do not need to be any smarter than this.
-+        value = value.replace("'", "&apos;")
-+
-+        output.write(" %s='%s'" % (name, value,))  
-+      
-     def toxml(self):
-         output = StringIO.StringIO()
-         self.writeXML(output)
--        return output.getvalue()
-+        return str(output.getvalue())
- 
-     def element(self, document):
-         element = document.createElementNS(self.namespace, self.name)
-@@ -285,6 +392,9 @@
- 
-         self.data = data
- 
-+    def validate(self):
-+        pass
-+
-     def __str__(self):
-         return str(self.data)
- 
-@@ -324,6 +434,22 @@
-             log.err("Invalid PCDATA: %r" % (self.data,))
-             raise
- 
-+    def writeToStream(self, output, ns, level, pretty):
-+        # Do escaping/CDATA behavior
-+        if "\r" in self.data or "\n" in self.data:
-+            # Do CDATA
-+            cdata = "<![CDATA[%s]]>" % (self.data.replace("]]>", "]]&gt;"),)
-+        else:
-+            cdata = self.data
-+            if "&" in cdata:
-+                cdata = cdata.replace("&", "&amp;")
-+            if "<" in cdata:
-+                cdata = cdata.replace("<", "&lt;")
-+            if ">" in cdata:
-+                cdata = cdata.replace(">", "&gt;")
-+
-+        output.write(cdata)
-+
- class WebDAVOneShotElement (WebDAVElement):
-     """
-     Element with exactly one WebDAVEmptyElement child and no attributes.
-@@ -364,6 +490,18 @@
-         PCDATAElement: (0, None),
-     }
- 
-+    def qname(self):
-+        return (self.namespace, self.name)
-+
-+    def sname(self):
-+        return "{%s}%s" % (self.namespace, self.name)
-+
-+    def emptyCopy(self):
-+        copied = self.__class__()
-+        copied.name = self.name
-+        copied.namespace = self.namespace
-+        return copied
-+
- class WebDAVEmptyElement (WebDAVElement):
-     """
-     WebDAV element with no contents.
-@@ -388,6 +526,7 @@
-     """
-     WebDAV element containing PCDATA.
-     """
-+    @classmethod
-     def fromString(clazz, string):
-         if string is None:
-             return clazz()
-@@ -396,8 +535,6 @@
-         else:
-             return clazz(PCDATAElement(str(string)))
- 
--    fromString = classmethod(fromString)
--
-     allowed_children = { PCDATAElement: (0, None) }
- 
-     def __str__(self):

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.extensions.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.extensions.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.extensions.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,44 +0,0 @@
-Index: twisted/web2/dav/element/extensions.py
-===================================================================
---- twisted/web2/dav/element/extensions.py	(revision 0)
-+++ twisted/web2/dav/element/extensions.py	(revision 0)
-@@ -0,0 +1,39 @@
-+##
-+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
-+#
-+# Permission is hereby granted, free of charge, to any person obtaining a copy
-+# of this software and associated documentation files (the "Software"), to deal
-+# in the Software without restriction, including without limitation the rights
-+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+# copies of the Software, and to permit persons to whom the Software is
-+# furnished to do so, subject to the following conditions:
-+# 
-+# The above copyright notice and this permission notice shall be included in all
-+# copies or substantial portions of the Software.
-+# 
-+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+# SOFTWARE.
-+#
-+##
-+
-+from twisted.web2.dav.element.base import *
-+
-+##
-+# draft-sanchez-webdav-current-principal
-+##
-+
-+class CurrentUserPrincipal(WebDAVElement):
-+    """
-+    Current principal information
-+    """
-+
-+    name = "current-user-principal"
-+    allowed_children = {
-+        (dav_namespace, "href" )                : (0, 1),
-+        (dav_namespace, "unauthenticated" )     : (0, 1),
-+    }

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.parser.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.parser.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.parser.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,81 +0,0 @@
-Index: twisted/web2/dav/element/parser.py
-===================================================================
---- twisted/web2/dav/element/parser.py	(revision 19773)
-+++ twisted/web2/dav/element/parser.py	(working copy)
-@@ -37,7 +37,7 @@
-     "WebDAVDocument",
- ]
- 
--import StringIO
-+import cStringIO as StringIO
- import xml.dom.minidom
- import xml.sax
- 
-@@ -106,6 +106,12 @@
-             "children"   : [],
-         }]
- 
-+        # Keep a cache of the subclasses we create for unknown XML
-+        # elements, so that we don't create multiple classes for the
-+        # same element; it's fairly typical for elements to appear
-+        # multiple times in a document.
-+        self.unknownElementClasses = {}
-+
-     def endDocument(self):
-         top = self.stack[-1]
- 
-@@ -115,6 +121,7 @@
-         assert len(top["children"]) is 1, "Must have exactly one root element, got %d" % len(top["children"])
- 
-         self.dom = WebDAVDocument(top["children"][0])
-+        del(self.unknownElementClasses)
- 
-     def startElementNS(self, name, qname, attributes):
-         attributes_dict = {}
-@@ -125,13 +132,17 @@
- 
-         tag_namespace, tag_name = name
- 
--        if (name not in elements_by_tag_name):
--            class UnknownElement (WebDAVUnknownElement):
--                namespace = tag_namespace
--                name      = tag_name
--            element_class = UnknownElement
-+        if name in elements_by_tag_name:
-+            element_class = elements_by_tag_name[name]
-+        elif name in self.unknownElementClasses:
-+            element_class = self.unknownElementClasses[name]
-         else:
--            element_class = elements_by_tag_name[name]
-+            def element_class(*args, **kwargs):
-+                element = WebDAVUnknownElement(*args, **kwargs)
-+                element.namespace = tag_namespace
-+                element.name      = tag_name
-+                return element
-+            self.unknownElementClasses[name] = element_class
- 
-         self.stack.append({
-             "name"       : name,
-@@ -158,7 +169,12 @@
-         self.stack[-1]["children"].append(element)
- 
-     def characters(self, content):
--        self.stack[-1]["children"].append(PCDATAElement(content))
-+        # Coalesce adjacent PCDATAElements
-+        pcdata = PCDATAElement(content)
-+        if len(self.stack[-1]["children"]) and isinstance(self.stack[-1]["children"][-1], PCDATAElement):
-+            self.stack[-1]["children"][-1] = self.stack[-1]["children"][-1] + pcdata
-+        else:
-+            self.stack[-1]["children"].append(pcdata)
- 
-     def ignorableWhitespace(self, whitespace):
-         self.characters(self, whitespace)
-@@ -194,6 +210,8 @@
-             except xml.sax.SAXParseException, e:
-                 raise ValueError(e)
- 
-+            #handler.dom.root_element.validate()
-+
-             return handler.dom
- 
-         return parse

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.rfc2518.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.rfc2518.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.rfc2518.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,37 +0,0 @@
-Index: twisted/web2/dav/element/rfc2518.py
-===================================================================
---- twisted/web2/dav/element/rfc2518.py	(revision 19773)
-+++ twisted/web2/dav/element/rfc2518.py	(working copy)
-@@ -59,8 +59,8 @@
-     """
-     name = "depth"
- 
--    def __init__(self, *children, **attributes):
--        super(Depth, self).__init__(*children, **attributes)
-+    def validate(self):
-+        super(Depth, self).validate()
- 
-         depth = str(self)
-         if depth not in ("0", "1", "infinity"):
-@@ -382,8 +382,8 @@
-         PCDATAElement: (0, 1),
-     }
- 
--    def __init__(self, *children, **attributes):
--        super(KeepAlive, self).__init__(*children, **attributes)
-+    def validate(self):
-+        super(KeepAlive, self).validate()
- 
-         type = None
- 
-@@ -450,8 +450,8 @@
-         (dav_namespace, "prop"    ): (0, 1),
-     }
- 
--    def __init__(self, *children, **attributes):
--        super(PropertyFind, self).__init__(*children, **attributes)
-+    def validate(self):
-+        super(PropertyFind, self).validate()
- 
-         if len(self.children) != 1:
-             raise ValueError(

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.rfc3744.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.rfc3744.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.rfc3744.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,102 +0,0 @@
-Index: twisted/web2/dav/element/rfc3744.py
-===================================================================
---- twisted/web2/dav/element/rfc3744.py	(revision 19773)
-+++ twisted/web2/dav/element/rfc3744.py	(working copy)
-@@ -131,8 +131,8 @@
-         (dav_namespace, "self"           ): (0, 1),
-     }
- 
--    def __init__(self, *children, **attributes):
--        super(Principal, self).__init__(*children, **attributes)
-+    def validate(self):
-+        super(Principal, self).validate()
- 
-         if len(self.children) > 1:
-             raise ValueError(
-@@ -385,9 +385,14 @@
-         self.inherited  = None
-         self.protected  = False
- 
-+        my_children = []
-+
-         for child in self.children:
-             namespace, name = child.qname()
- 
-+            if isinstance(child, PCDATAElement):
-+                continue
-+
-             if (namespace == dav_namespace):
-                 if name in ("principal", "invert"):
-                     if self.principal is not None:
-@@ -417,6 +422,10 @@
-                 elif name == "protected":
-                     self.protected = True
- 
-+            my_children.append(child)
-+
-+        self.children = tuple(my_children)
-+
-         if self.principal is None:
-             raise ValueError(
-                 "One of DAV:principal or DAV:invert is required in %s, got: %s"
-@@ -456,7 +465,7 @@
-     """
-     name = "self"
- 
--class Invert (WebDAVEmptyElement):
-+class Invert (WebDAVElement):
-     """
-     Principal which matches a user if the user does not match the principal
-     contained by this principal. (RFC 3744, section 5.5.1)
-@@ -551,8 +560,8 @@
-         (dav_namespace, "property"       ): (0, None),
-     }
- 
--    def __init__(self, *children, **attributes):
--        super(RequiredPrincipal, self).__init__(*children, **attributes)
-+    def validate(self):
-+        super(RequiredPrincipal, self).validate()
- 
-         type = None
- 
-@@ -628,8 +637,8 @@
- 
-     allowed_children = { WebDAVElement: (0, None) }
- 
--    def __init__(self, *children, **attributes):
--        super(ACLPrincipalPropSet, self).__init__(*children, **attributes)
-+    def validate(self):
-+        super(ACLPrincipalPropSet, self).validate()
- 
-         prop = False
-         
-@@ -656,8 +665,8 @@
-         (dav_namespace, "prop"              ): (0, 1),
-     }
- 
--    def __init__(self, *children, **attributes):
--        super(PrincipalMatch, self).__init__(*children, **attributes)
-+    def validate(self):
-+        super(PrincipalMatch, self).validate()
- 
-         # This element can be empty when uses in supported-report-set
-         if not len(self.children):
-@@ -705,6 +714,7 @@
-         (dav_namespace, "prop"                             ): (0, 1),
-         (dav_namespace, "apply-to-principal-collection-set"): (0, 1),
-     }
-+    allowed_attributes = { "test": False }
- 
- class PropertySearch (WebDAVElement):
-     """
-@@ -745,4 +755,10 @@
-         (dav_namespace, "description"): (1, 1),
-     }
- 
-+class NumberOfMatchesWithinLimits (WebDAVEmptyElement):
-+    """
-+    Error which indicates too many results
-+    """
-+    name = "number-of-matches-within-limits"
-+
- # For DAV:description element (RFC 3744, section 9.5) see Description class above.

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.rfc4331.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.rfc4331.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.rfc4331.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,60 +0,0 @@
-Index: twisted/web2/dav/element/rfc4331.py
-===================================================================
---- twisted/web2/dav/element/rfc4331.py	(revision 0)
-+++ twisted/web2/dav/element/rfc4331.py	(revision 0)
-@@ -0,0 +1,55 @@
-+##
-+# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
-+#
-+# Permission is hereby granted, free of charge, to any person obtaining a copy
-+# of this software and associated documentation files (the "Software"), to deal
-+# in the Software without restriction, including without limitation the rights
-+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+# copies of the Software, and to permit persons to whom the Software is
-+# furnished to do so, subject to the following conditions:
-+# 
-+# The above copyright notice and this permission notice shall be included in all
-+# copies or substantial portions of the Software.
-+# 
-+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+# SOFTWARE.
-+#
-+# DRI: Cyrus Daboo, cdaboo at apple.com
-+##
-+
-+"""
-+RFC 4331 (Quota and Size Properties for WebDAV Collections) XML Elements
-+
-+This module provides XML element definitions for use with WebDAV.
-+
-+See RFC 4331: http://www.ietf.org/rfc/rfc4331.txt
-+"""
-+
-+from twisted.web2.dav.element.base import WebDAVTextElement
-+
-+##
-+# Section 3 & 4 (Quota Properties)
-+##
-+
-+class QuotaAvailableBytes (WebDAVTextElement):
-+    """
-+    Property which contains the the number of bytes available under the
-+    current quota to store data in a collection (RFC 4331, section 3)
-+    """
-+    name = "quota-available-bytes"
-+    hidden = True
-+    protected = True
-+
-+class QuotaUsedBytes (WebDAVTextElement):
-+    """
-+    Property which contains the the number of bytes used under the
-+    current quota to store data in a collection (RFC 4331, section 4)
-+    """
-+    name = "quota-used-bytes"
-+    hidden = True
-+    protected = True

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.fileop.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.fileop.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.fileop.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,31 +0,0 @@
-Index: twisted/web2/dav/fileop.py
-===================================================================
---- twisted/web2/dav/fileop.py	(revision 19773)
-+++ twisted/web2/dav/fileop.py	(working copy)
-@@ -35,6 +35,7 @@
-     "move",
-     "put",
-     "mkcollection",
-+    "rmdir",
- ]
- 
- import os
-@@ -287,7 +288,7 @@
-                     response = waitForDeferred(copy(FilePath(source_path), FilePath(destination_path), destination_uri, depth))
-                     yield response
-                     response = response.getResult()
--                    checkResponse(response, "copy", responsecode.NO_CONTENT)
-+                    checkResponse(response, "copy", responsecode.CREATED, responsecode.NO_CONTENT)
- 
-             for subdir in subdirs:
-                 source_path, destination_path = paths(dir, subdir)
-@@ -509,7 +510,5 @@
-     os.rmdir(dirname)
- 
- def checkResponse(response, method, *codes):
--    assert (
--        response in codes,
--        "%s() should have raised, but returned one of %r instead" % (method, codes)
--    )
-+    assert  response in codes, \
-+        "%s() returned %r, but should have returned one of %r instead" % (method, response, codes)

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.http.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.http.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.http.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,41 +0,0 @@
-Index: twisted/web2/dav/http.py
-===================================================================
---- twisted/web2/dav/http.py	(revision 19773)
-+++ twisted/web2/dav/http.py	(working copy)
-@@ -28,10 +28,13 @@
- 
- __all__ = [
-     "ErrorResponse",
-+    "NeedPrivilegesResponse",
-     "MultiStatusResponse",
-     "ResponseQueue",
-     "PropertyStatusResponseQueue",
-     "statusForFailure",
-+    "errorForFailure",
-+    "messageForFailure",
- ]
- 
- import errno
-@@ -69,10 +72,9 @@
-         """
-         if type(error) is tuple:
-             xml_namespace, xml_name = error
--            class EmptyError (davxml.WebDAVEmptyElement):
--                namespace = xml_namespace
--                name      = xml_name
--            error = EmptyError()
-+            error = davxml.WebDAVUnknownElement()
-+            error.namespace = xml_namespace
-+            error.name = xml_name
- 
-         output = davxml.Error(error).toxml()
- 
-@@ -227,7 +229,7 @@
- 
-         if len(property.children) > 0:
-             # Re-instantiate as empty element.
--            property = property.__class__()
-+            property = property.emptyCopy()
- 
-         if code > 400: # Error codes only
-             log.err("Error during %s for %s: %s" % (self.method, property, message))

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.idav.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.idav.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.idav.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,157 +0,0 @@
-Index: twisted/web2/dav/idav.py
-===================================================================
---- twisted/web2/dav/idav.py	(revision 19773)
-+++ twisted/web2/dav/idav.py	(working copy)
-@@ -26,7 +26,7 @@
- web2.dav interfaces.
- """
- 
--__all__ = [ "IDAVResource", "IDAVPrincipalResource" ]
-+__all__ = [ "IDAVResource", "IDAVPrincipalResource", "IDAVPrincipalCollectionResource", ]
- 
- from twisted.web2.iweb import IResource
- 
-@@ -41,7 +41,7 @@
-             otherwise.
-         """
- 
--    def findChildren(depth, request, callback, privileges):
-+    def findChildren(depth, request, callback, privileges, inherited_aces):
-         """
-         Returns an iterable of child resources for the given depth.
-         Because resources do not know their request URIs, chidren are returned
-@@ -52,6 +52,8 @@
-         @param callback: C{callable} that will be called for each child found
-         @param privileges: the list of L{Privilege}s to test for.  This should 
-             default to None.
-+        @param inherited_aces: a list of L{Privilege}s for aces being inherited from
-+            the parent collection used to bypass inheritance lookup.
-         @return: An L{Deferred} that fires when all the children have been found
-         """
- 
-@@ -125,15 +127,10 @@
-             L{responsecode.UNAUTHORIZED}) if not authorized.
-         """
- 
--    def principalCollections(request):
-+    def principalCollections():
-         """
--        Provides the DAV:HRef's of collection resources which contain principal
--        resources which may be used in access control entries on this resource.
--        (RFC 3744, section 5.8)
--        @param request: the request being processed.
--        @return: a deferred sequence of L{davxml.HRef}s referring to
--            collection resources which implement the
--            C{DAV:principal-property-search} C{REPORT}.
-+        @return: an interable of L{IDAVPrincipalCollectionResource}s which
-+            contain principals used in ACLs for this resource.
-         """
- 
-     def setAccessControlList(acl):
-@@ -180,6 +177,80 @@
-             the specified principal.
-         """
- 
-+    ##
-+    # Quota
-+    ##
-+    
-+    def quota(request):
-+        """
-+        Get current available & used quota values for this resource's quota root
-+        collection.
-+
-+        @return: a C{tuple} containing two C{int}'s the first is 
-+            quota-available-bytes, the second is quota-used-bytes, or
-+            C{None} if quota is not defined on the resource.
-+        """
-+    
-+    def hasQuota(request):
-+        """
-+        Check whether this resource is undre quota control by checking each parent to see if
-+        it has a quota root.
-+        
-+        @return: C{True} if under quota control, C{False} if not.
-+        """
-+        
-+    def hasQuotaRoot(request):
-+        """
-+        Determine whether the resource has a quota root.
-+
-+        @return: a C{True} if this resource has quota root, C{False} otherwise.
-+        """
-+    
-+
-+    def quotaRoot(request):
-+        """
-+        Get the quota root (max. allowed bytes) value for this collection.
-+
-+        @return: a C{int} containing the maximum allowed bytes if this collection
-+            is quota-controlled, or C{None} if not quota controlled.
-+        """
-+    
-+    def setQuotaRoot(request, maxsize):
-+        """
-+        Set the quota root (max. allowed bytes) value for this collection.
-+
-+        @param maxsize: a C{int} containing the maximum allowed bytes for the contents
-+            of this collection.
-+        """
-+    
-+    def quotaSize(request):
-+        """
-+        Get the size of this resource (if its a collection get total for all children as well).
-+        TODO: Take into account size of dead-properties.
-+
-+        @return: a L{Deferred} with a C{int} result containing the size of the resource.
-+        """
-+        
-+    def currentQuotaUse(request):
-+        """
-+        Get the cached quota use value, or if not present (or invalid) determine
-+        quota use by brute force.
-+
-+        @return: an L{Deferred} with a C{int} result containing the current used byte count if
-+            this collection is quota-controlled, or C{None} if not quota controlled.
-+        """
-+        
-+    def updateQuotaUse(request, adjust):
-+        """
-+        Adjust current quota use on this all all parent collections that also
-+        have quota roots.
-+
-+        @param adjust: a C{int} containing the number of bytes added (positive) or
-+        removed (negative) that should be used to adjust the cached total.
-+        @return: an L{Deferred} with a C{int} result containing the current used byte if this collection
-+            is quota-controlled, or C{None} if not quota controlled.
-+        """
-+
- class IDAVPrincipalResource (IDAVResource):
-     """
-     WebDAV principal resource.  (RFC 3744, section 2)
-@@ -203,12 +274,23 @@
-         """
-         Provides the principal URLs of principals that are direct members of
-         this (group) principal.  (RFC 3744, section 4.3)
--        @return: a iterable of principal URLs.
-+        @return: a deferred returning an iterable of principal URLs.
-         """
- 
-     def groupMemberships():
-         """
-         Provides the URLs of the group principals in which the principal is
-         directly a member.  (RFC 3744, section 4.4)
--        @return: a iterable of group principal URLs.
-+        @return: a deferred containing an iterable of group principal URLs.
-         """
-+
-+class IDAVPrincipalCollectionResource (IDAVResource):
-+    """
-+    WebDAV principal collection resource.  (RFC 3744, section 5.8)
-+    """
-+    def principalCollectionURL():
-+        """
-+        Provides a URL for this resource which may be used to identify this
-+        resource in ACL requests.  (RFC 3744, section 5.8)
-+        @return: a URL.
-+        """

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.__init__.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.__init__.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.__init__.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,12 +0,0 @@
-Index: twisted/web2/dav/method/__init__.py
-===================================================================
---- twisted/web2/dav/method/__init__.py	(revision 19773)
-+++ twisted/web2/dav/method/__init__.py	(working copy)
-@@ -40,6 +40,7 @@
-     "proppatch",
-     "prop_common",
-     "put",
-+    "put_common",
-     "report",
-     "report_acl_principal_prop_set",
-     "report_expand",

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.copymove.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.copymove.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.copymove.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,76 +0,0 @@
-Index: twisted/web2/dav/method/copymove.py
-===================================================================
---- twisted/web2/dav/method/copymove.py	(revision 19773)
-+++ twisted/web2/dav/method/copymove.py	(working copy)
-@@ -34,11 +34,12 @@
- from twisted.python import log
- from twisted.internet.defer import waitForDeferred, deferredGenerator
- from twisted.web2 import responsecode
-+from twisted.web2.dav.fileop import move
- from twisted.web2.http import HTTPError, StatusResponse
- from twisted.web2.filter.location import addLocation
- from twisted.web2.dav import davxml
- from twisted.web2.dav.idav import IDAVResource
--from twisted.web2.dav.fileop import copy, move
-+from twisted.web2.dav.method import put_common
- from twisted.web2.dav.util import parentForURL
- 
- # FIXME: This is circular
-@@ -81,7 +82,15 @@
-         # May need to add a location header
-         addLocation(request, destination_uri)
- 
--    x = waitForDeferred(copy(self.fp, destination.fp, destination_uri, depth))
-+    #x = waitForDeferred(copy(self.fp, destination.fp, destination_uri, depth))
-+    x = waitForDeferred(put_common.storeResource(request,
-+                                                 source=self,
-+                                                 source_uri=request.uri,
-+                                                 destination=destination,
-+                                                 destination_uri=destination_uri,
-+                                                 deletesource=False,
-+                                                 depth=depth
-+                                                 ))
-     yield x
-     yield x.getResult()
- 
-@@ -100,7 +109,8 @@
-     #
-     # Check authentication and access controls
-     #
--    parent = waitForDeferred(request.locateResource(parentForURL(request.uri)))
-+    parentURL = parentForURL(request.uri)
-+    parent = waitForDeferred(request.locateResource(parentURL))
-     yield parent
-     parent = parent.getResult()
- 
-@@ -117,7 +127,8 @@
-         yield x
-         x.getResult()
-     else:
--        destparent = waitForDeferred(request.locateResource(parentForURL(destination_uri)))
-+        destparentURL = parentForURL(destination_uri)
-+        destparent = waitForDeferred(request.locateResource(destparentURL))
-         yield destparent
-         destparent = destparent.getResult()
- 
-@@ -144,7 +155,19 @@
-         log.err(msg)
-         raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, msg))
- 
--    x = waitForDeferred(move(self.fp, request.uri, destination.fp, destination_uri, depth))
-+    # Lets optimise a move within the same directory to a new resource as a simple move
-+    # rather than using the full transaction based storeResource api. This allows simple
-+    # "rename" operations to work quickly.
-+    if (not destination.exists()) and destparent == parent:
-+        x = waitForDeferred(move(self.fp, request.uri, destination.fp, destination_uri, depth))
-+    else:
-+        x = waitForDeferred(put_common.storeResource(request,
-+                                                     source=self,
-+                                                     source_uri=request.uri,
-+                                                     destination=destination,
-+                                                     destination_uri=destination_uri,
-+                                                     deletesource=True,
-+                                                     depth=depth))
-     yield x
-     yield x.getResult()
- 

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.delete.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.delete.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.delete.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,34 +0,0 @@
-Index: twisted/web2/dav/method/delete.py
-===================================================================
---- twisted/web2/dav/method/delete.py	(revision 19773)
-+++ twisted/web2/dav/method/delete.py	(working copy)
-@@ -58,8 +58,28 @@
-     yield x
-     x.getResult()
- 
-+    # Do quota checks before we start deleting things
-+    myquota = waitForDeferred(self.quota(request))
-+    yield myquota
-+    myquota = myquota.getResult()
-+    if myquota is not None:
-+        old_size = waitForDeferred(self.quotaSize(request))
-+        yield old_size
-+        old_size = old_size.getResult()
-+    else:
-+        old_size = 0
-+
-+    # Do delete
-     x = waitForDeferred(delete(request.uri, self.fp, depth))
-     yield x
--    yield x.getResult()
-+    result = x.getResult()
- 
-+    # Adjust quota
-+    if myquota is not None:
-+        d = waitForDeferred(self.quotaSizeAdjust(request, -old_size))
-+        yield d
-+        d.getResult()
-+    
-+    yield result
-+
- http_DELETE = deferredGenerator(http_DELETE)

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.prop_common.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.prop_common.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.prop_common.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,36 +0,0 @@
-Index: twisted/web2/dav/method/prop_common.py
-===================================================================
---- twisted/web2/dav/method/prop_common.py	(revision 19773)
-+++ twisted/web2/dav/method/prop_common.py	(working copy)
-@@ -23,19 +23,21 @@
-         properties_by_status = waitForDeferred(propertiesForResource(request, propertyreq, resource))
-         yield properties_by_status
-         properties_by_status = properties_by_status.getResult()
--        
-+
-+        propstats = []
-+
-         for status in properties_by_status:
-             properties = properties_by_status[status]
-             if properties:
--                responses.append(
--                    davxml.PropertyStatusResponse(
--                        href,
--                        davxml.PropertyStatus(
--                            davxml.PropertyContainer(*properties),
--                            davxml.Status.fromResponseCode(status)
--                        )
--                    )
--                )
-+                xml_status = davxml.Status.fromResponseCode(status)
-+                xml_container = davxml.PropertyContainer(*properties)
-+                xml_propstat = davxml.PropertyStatus(xml_container, xml_status)
-+
-+                propstats.append(xml_propstat)
-+
-+        if propstats:
-+            responses.append(davxml.PropertyStatusResponse(href, *propstats))
-+
-     else:
-         responses.append(
-             davxml.StatusResponse(

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.propfind.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.propfind.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.propfind.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,28 +0,0 @@
-Index: twisted/web2/dav/method/propfind.py
-===================================================================
---- twisted/web2/dav/method/propfind.py	(revision 19773)
-+++ twisted/web2/dav/method/propfind.py	(working copy)
-@@ -27,7 +27,10 @@
- WebDAV PROPFIND method
- """
- 
--__all__ = ["http_PROPFIND"]
-+__all__ = [
-+    "http_PROPFIND",
-+    "propertyName",
-+]
- 
- from twisted.python import log
- from twisted.python.failure import Failure
-@@ -200,7 +203,7 @@
- 
- def propertyName(name):
-     property_namespace, property_name = name
--    class PropertyName (davxml.WebDAVEmptyElement):
--        namespace = property_namespace
--        name = property_name
--    return PropertyName()
-+    pname = davxml.WebDAVUnknownElement()
-+    pname.namespace = property_namespace
-+    pname.name = property_name
-+    return pname

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.put.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.put.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.put.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,20 +0,0 @@
-Index: twisted/web2/dav/method/put.py
-===================================================================
---- twisted/web2/dav/method/put.py	(revision 19773)
-+++ twisted/web2/dav/method/put.py	(working copy)
-@@ -34,7 +34,7 @@
- from twisted.web2 import responsecode
- from twisted.web2.http import HTTPError, StatusResponse
- from twisted.web2.dav import davxml
--from twisted.web2.dav.fileop import put
-+from twisted.web2.dav.method import put_common
- from twisted.web2.dav.util import parentForURL
- 
- def preconditions_PUT(self, request):
-@@ -107,4 +107,5 @@
-     # to return a MULTI_STATUS response, which is WebDAV-specific (and PUT is
-     # not).
-     #
--    return put(request.stream, self.fp)
-+    #return put(request.stream, self.fp)
-+    return put_common.storeResource(request, destination=self, destination_uri=request.uri)

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.put_common.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.put_common.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.put_common.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,270 +0,0 @@
-Index: twisted/web2/dav/method/put_common.py
-===================================================================
---- twisted/web2/dav/method/put_common.py	(revision 0)
-+++ twisted/web2/dav/method/put_common.py	(revision 0)
-@@ -0,0 +1,265 @@
-+##
-+# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
-+#
-+# Licensed under the Apache License, Version 2.0 (the "License");
-+# you may not use this file except in compliance with the License.
-+# You may obtain a copy of the License at
-+#
-+# http://www.apache.org/licenses/LICENSE-2.0
-+#
-+# Unless required by applicable law or agreed to in writing, software
-+# distributed under the License is distributed on an "AS IS" BASIS,
-+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+# See the License for the specific language governing permissions and
-+# limitations under the License.
-+#
-+# DRI: Cyrus Daboo, cdaboo at apple.com
-+##
-+
-+"""
-+PUT/COPY/MOVE common behavior.
-+"""
-+
-+__version__ = "0.0"
-+
-+__all__ = ["storeCalendarObjectResource"]
-+
-+from twisted.internet.defer import deferredGenerator, maybeDeferred, waitForDeferred
-+from twisted.python import failure, log
-+from twisted.python.filepath import FilePath
-+from twisted.web2 import responsecode
-+from twisted.web2.dav import davxml
-+from twisted.web2.dav.element.base import dav_namespace
-+from twisted.web2.dav.fileop import copy, delete, put
-+from twisted.web2.dav.http import ErrorResponse
-+from twisted.web2.dav.resource import TwistedGETContentMD5
-+from twisted.web2.dav.stream import MD5StreamWrapper
-+from twisted.web2.http import HTTPError
-+from twisted.web2.http_headers import generateContentType
-+from twisted.web2.iweb import IResponse
-+from twisted.web2.stream import MemoryStream
-+
-+def storeResource(
-+    request,
-+    source=None, source_uri=None, data=None,
-+    destination=None, destination_uri=None,
-+    deletesource=False,
-+    depth="0"
-+):
-+    """
-+    Function that does common PUT/COPY/MOVE behaviour.
-+    
-+    @param request:           the L{twisted.web2.server.Request} for the current HTTP request.
-+    @param source:            the L{DAVFile} for the source resource to copy from, or None if source data
-+                              is to be read from the request.
-+    @param source_uri:        the URI for the source resource.
-+    @param data:              a C{str} to copy data from instead of the request stream.
-+    @param destination:       the L{DAVFile} for the destination resource to copy into.
-+    @param destination_uri:   the URI for the destination resource.
-+    @param deletesource:      True if the source resource is to be deleted on successful completion, False otherwise.
-+    @param depth:             a C{str} containing the COPY/MOVE Depth header value.
-+    @return:                  status response.
-+    """
-+    
-+    try:
-+        assert request is not None and destination is not None and destination_uri is not None
-+        assert (source is None) or (source is not None and source_uri is not None)
-+        assert not deletesource or (deletesource and source is not None)
-+    except AssertionError:
-+        log.err("Invalid arguments to storeResource():")
-+        log.err("request=%s\n" % (request,))
-+        log.err("source=%s\n" % (source,))
-+        log.err("source_uri=%s\n" % (source_uri,))
-+        log.err("data=%s\n" % (data,))
-+        log.err("destination=%s\n" % (destination,))
-+        log.err("destination_uri=%s\n" % (destination_uri,))
-+        log.err("deletesource=%s\n" % (deletesource,))
-+        log.err("depth=%s\n" % (depth,))
-+        raise
-+
-+    class RollbackState(object):
-+        """
-+        This class encapsulates the state needed to rollback the entire PUT/COPY/MOVE
-+        transaction, leaving the server state the same as it was before the request was
-+        processed. The DoRollback method will actually execute the rollback operations.
-+        """
-+        
-+        def __init__(self):
-+            self.active = True
-+            self.source_copy = None
-+            self.destination_copy = None
-+            self.destination_created = False
-+            self.source_deleted = False
-+        
-+        def Rollback(self):
-+            """
-+            Rollback the server state. Do not allow this to raise another exception. If
-+            rollback fails then we are going to be left in an awkward state that will need
-+            to be cleaned up eventually.
-+            """
-+            if self.active:
-+                self.active = False
-+                log.err("Rollback: rollback")
-+                try:
-+                    if self.source_copy and self.source_deleted:
-+                        self.source_copy.moveTo(source.fp)
-+                        log.err("Rollback: source restored %s to %s" % (self.source_copy.path, source.fp.path))
-+                        self.source_copy = None
-+                        self.source_deleted = False
-+                    if self.destination_copy:
-+                        destination.fp.remove()
-+                        log.err("Rollback: destination restored %s to %s" % (self.destination_copy.path, destination.fp.path))
-+                        self.destination_copy.moveTo(destination.fp)
-+                        self.destination_copy = None
-+                    elif self.destination_created:
-+                        destination.fp.remove()
-+                        log.err("Rollback: destination removed %s" % (destination.fp.path,))
-+                        self.destination_created = False
-+                except:
-+                    log.err("Rollback: exception caught and not handled: %s" % failure.Failure())
-+
-+        def Commit(self):
-+            """
-+            Commit the resource changes by wiping the rollback state.
-+            """
-+            if self.active:
-+                log.err("Rollback: commit")
-+                self.active = False
-+                if self.source_copy:
-+                    self.source_copy.remove()
-+                    log.err("Rollback: removed source backup %s" % (self.source_copy.path,))
-+                    self.source_copy = None
-+                if self.destination_copy:
-+                    self.destination_copy.remove()
-+                    log.err("Rollback: removed destination backup %s" % (self.destination_copy.path,))
-+                    self.destination_copy = None
-+                self.destination_created = False
-+                self.source_deleted = False
-+    
-+    rollback = RollbackState()
-+
-+    try:
-+        """
-+        Handle validation operations here.
-+        """
-+
-+        """
-+        Handle rollback setup here.
-+        """
-+
-+        # Do quota checks on destination and source before we start messing with adding other files
-+        destquota = waitForDeferred(destination.quota(request))
-+        yield destquota
-+        destquota = destquota.getResult()
-+        if destquota is not None and destination.exists():
-+            old_dest_size = waitForDeferred(destination.quotaSize(request))
-+            yield old_dest_size
-+            old_dest_size = old_dest_size.getResult()
-+        else:
-+            old_dest_size = 0
-+            
-+        if source is not None:
-+            sourcequota = waitForDeferred(source.quota(request))
-+            yield sourcequota
-+            sourcequota = sourcequota.getResult()
-+            if sourcequota is not None and source.exists():
-+                old_source_size = waitForDeferred(source.quotaSize(request))
-+                yield old_source_size
-+                old_source_size = old_source_size.getResult()
-+            else:
-+                old_source_size = 0
-+        else:
-+            sourcequota = None
-+            old_source_size = 0
-+
-+        # We may need to restore the original resource data if the PUT/COPY/MOVE fails,
-+        # so rename the original file in case we need to rollback.
-+        overwrite = destination.exists()
-+        if overwrite:
-+            rollback.destination_copy = FilePath(destination.fp.path)
-+            rollback.destination_copy.path += ".rollback"
-+            destination.fp.copyTo(rollback.destination_copy)
-+        else:
-+            rollback.destination_created = True
-+
-+        if deletesource:
-+            rollback.source_copy = FilePath(source.fp.path)
-+            rollback.source_copy.path += ".rollback"
-+            source.fp.copyTo(rollback.source_copy)
-+    
-+        """
-+        Handle actual store operations here.
-+        """
-+
-+        # Do put or copy based on whether source exists
-+        if source is not None:
-+            response = maybeDeferred(copy, source.fp, destination.fp, destination_uri, depth)
-+        else:
-+            datastream = request.stream
-+            if data is not None:
-+                datastream = MemoryStream(data)
-+            md5 = MD5StreamWrapper(datastream)
-+            response = maybeDeferred(put, md5, destination.fp)
-+
-+        response = waitForDeferred(response)
-+        yield response
-+        response = response.getResult()
-+
-+        # Update the MD5 value on the resource
-+        if source is not None:
-+            # Copy MD5 value from source to destination
-+            if source.hasDeadProperty(TwistedGETContentMD5):
-+                md5 = source.readDeadProperty(TwistedGETContentMD5)
-+                destination.writeDeadProperty(md5)
-+        else:
-+            # Finish MD5 calc and write dead property
-+            md5.close()
-+            md5 = md5.getMD5()
-+            destination.writeDeadProperty(TwistedGETContentMD5.fromString(md5))
-+
-+        # Update the content-type value on the resource if it is not been copied or moved
-+        if source is None:
-+            content_type = request.headers.getHeader("content-type")
-+            if content_type is not None:
-+                destination.writeDeadProperty(davxml.GETContentType.fromString(generateContentType(content_type)))
-+
-+        response = IResponse(response)
-+        
-+        # Do quota check on destination
-+        if destquota is not None:
-+            # Get size of new/old resources
-+            new_dest_size = waitForDeferred(destination.quotaSize(request))
-+            yield new_dest_size
-+            new_dest_size = new_dest_size.getResult()
-+            diff_size = new_dest_size - old_dest_size
-+            if diff_size >= destquota[0]:
-+                log.err("Over quota: available %d, need %d" % (destquota[0], diff_size))
-+                raise HTTPError(ErrorResponse(responsecode.INSUFFICIENT_STORAGE_SPACE, (dav_namespace, "quota-not-exceeded")))
-+            d = waitForDeferred(destination.quotaSizeAdjust(request, diff_size))
-+            yield d
-+            d.getResult()
-+
-+        if deletesource:
-+            # Delete the source resource
-+            if sourcequota is not None:
-+                delete_size = 0 - old_source_size
-+                d = waitForDeferred(source.quotaSizeAdjust(request, delete_size))
-+                yield d
-+                d.getResult()
-+
-+            delete(source_uri, source.fp, depth)
-+            rollback.source_deleted = True
-+
-+        # Can now commit changes and forget the rollback details
-+        rollback.Commit()
-+
-+        yield response
-+        return
-+        
-+    except:
-+        # Roll back changes to original server state. Note this may do nothing
-+        # if the rollback has already ocurred or changes already committed.
-+        rollback.Rollback()
-+        raise
-+
-+storeResource = deferredGenerator(storeResource)

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,33 +0,0 @@
-Index: twisted/web2/dav/method/report.py
-===================================================================
---- twisted/web2/dav/method/report.py	(revision 19773)
-+++ twisted/web2/dav/method/report.py	(working copy)
-@@ -27,7 +27,11 @@
- WebDAV REPORT method
- """
- 
--__all__ = ["http_REPORT"]
-+__all__ = [
-+    "max_number_of_matches",
-+    "NumberOfMatchesWithinLimits",
-+    "http_REPORT",
-+]
- 
- import string
- 
-@@ -43,7 +47,14 @@
- max_number_of_matches = 500
- 
- class NumberOfMatchesWithinLimits(Exception):
--    pass
-+    
-+    def __init__(self, limit):
-+        
-+        super(NumberOfMatchesWithinLimits, self).__init__()
-+        self.limit = limit
-+        
-+    def maxLimit(self):
-+        return self.limit
- 
- def http_REPORT(self, request):
-     """

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_acl_principal_prop_set.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_acl_principal_prop_set.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_acl_principal_prop_set.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,22 +0,0 @@
-Index: twisted/web2/dav/method/report_acl_principal_prop_set.py
-===================================================================
---- twisted/web2/dav/method/report_acl_principal_prop_set.py	(revision 19773)
-+++ twisted/web2/dav/method/report_acl_principal_prop_set.py	(working copy)
-@@ -103,7 +103,7 @@
-             # Check size of results is within limit
-             matchcount += 1
-             if matchcount > max_number_of_matches:
--                raise NumberOfMatchesWithinLimits
-+                raise NumberOfMatchesWithinLimits(max_number_of_matches)
- 
-             resource = waitForDeferred(request.locateResource(str(principal)))
-             yield resource
-@@ -144,7 +144,7 @@
-         log.err("Too many matching components")
-         raise HTTPError(ErrorResponse(
-             responsecode.FORBIDDEN,
--            (dav_namespace, "number-of-matches-within-limits")
-+            davxml.NumberOfMatchesWithinLimits()
-         ))
- 
-     yield MultiStatusResponse(responses)

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_expand.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_expand.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_expand.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,214 +0,0 @@
-Index: twisted/web2/dav/method/report_expand.py
-===================================================================
---- twisted/web2/dav/method/report_expand.py	(revision 19773)
-+++ twisted/web2/dav/method/report_expand.py	(working copy)
-@@ -1,6 +1,6 @@
- # -*- test-case-name: twisted.web2.dav.test.test_report_expand -*-
- ##
--# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
-+# Copyright (c) 2005-2008 Apple Computer, Inc. All rights reserved.
- #
- # Permission is hereby granted, free of charge, to any person obtaining a copy
- # of this software and associated documentation files (the "Software"), to deal
-@@ -19,8 +19,6 @@
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- # SOFTWARE.
--#
--# DRI: Wilfredo Sanchez, wsanchez at apple.com
- ##
- 
- """
-@@ -29,86 +27,143 @@
- 
- __all__ = ["report_DAV__expand_property"]
- 
-+from twisted.internet.defer import inlineCallbacks, returnValue
- from twisted.python import log
- from twisted.python.failure import Failure
--from twisted.internet.defer import deferredGenerator, waitForDeferred
- from twisted.web2 import responsecode
- from twisted.web2.dav import davxml
--from twisted.web2.dav.http import statusForFailure
- from twisted.web2.dav.davxml import dav_namespace
-+from twisted.web2.dav.http import statusForFailure, MultiStatusResponse
-+from twisted.web2.dav.method import prop_common
-+from twisted.web2.dav.method.propfind import propertyName
-+from twisted.web2.dav.resource import AccessDeniedError
-+from twisted.web2.dav.util import parentForURL
-+from twisted.web2.http import HTTPError, StatusResponse
- 
-+ at inlineCallbacks
- def report_DAV__expand_property(self, request, expand_property):
-     """
-     Generate an expand-property REPORT. (RFC 3253, section 3.8)
-+    
-+    TODO: for simplicity we will only support one level of expansion.
-     """
--    # FIXME: Handle depth header
--
-+    # Verify root element
-     if not isinstance(expand_property, davxml.ExpandProperty):
-         raise ValueError("%s expected as root element, not %s."
-                          % (davxml.ExpandProperty.sname(), expand_property.sname()))
- 
-+    # Only handle Depth: 0
-+    depth = request.headers.getHeader("depth", "0")
-+    if depth != "0":
-+        log.err("Non-zero depth is not allowed: %s" % (depth,))
-+        raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, "Depth %s not allowed" % (depth,)))
-+    
-     #
--    # Expand DAV:allprop
-+    # Get top level properties to expand and make sure we only have one level
-     #
-     properties = {}
- 
-     for property in expand_property.children:
--        namespace = property.getAttribute("namespace")
--        name      = property.getAttribute("name")
-+        namespace = property.attributes.get("namespace", dav_namespace)
-+        name      = property.attributes.get("name", "")
-+        
-+        # Make sure children have no children
-+        props_to_find = []
-+        for child in property.children:
-+            if child.children:
-+                log.err("expand-property REPORT only supports single level expansion")
-+                raise HTTPError(StatusResponse(
-+                    responsecode.NOT_IMPLEMENTED,
-+                    "expand-property REPORT only supports single level expansion"
-+                ))
-+            child_namespace = child.attributes.get("namespace", dav_namespace)
-+            child_name      = child.attributes.get("name", "")
-+            props_to_find.append((child_namespace, child_name))
- 
--        if not namespace: namespace = dav_namespace
-+        properties[(namespace, name)] = props_to_find
- 
--        if (namespace, name) == (dav_namespace, "allprop"):
--            all_properties = waitForDeferred(self.listAllProp(request))
--            yield all_properties
--            all_properties = all_properties.getResult()
--
--            for all_property in all_properties:
--                properties[all_property.qname()] = property
--        else:
--            properties[(namespace, name)] = property
--
-     #
--    # Look up the requested properties
-+    # Generate the expanded responses status for each top-level property
-     #
-     properties_by_status = {
-         responsecode.OK        : [],
-         responsecode.NOT_FOUND : [],
-     }
-+    
-+    filteredaces = None
-+    lastParent = None
- 
--    for property in properties:
--        my_properties = waitForDeferred(self.listProperties(request))
--        yield my_properties
--        my_properties = my_properties.getResult()
-+    for qname in properties.iterkeys():
-+        try:
-+            prop = (yield self.readProperty(qname, request))
-+            
-+            # Form the PROPFIND-style DAV:prop element we need later
-+            props_to_return = davxml.PropertyContainer(*properties[qname])
- 
--        if property in my_properties:
--            try:
--                value = waitForDeferred(self.readProperty(property, request))
--                yield value
--                value = value.getResult()
-+            # Now dereference any HRefs
-+            responses = []
-+            for href in prop.children:
-+                if isinstance(href, davxml.HRef):
-+                    
-+                    # Locate the Href resource and its parent
-+                    resource_uri = str(href)
-+                    child = (yield request.locateResource(resource_uri))
-+    
-+                    if not child or not child.exists():
-+                        responses.append(davxml.StatusResponse(href, davxml.Status.fromResponseCode(responsecode.NOT_FOUND)))
-+                        continue
-+                    parent = (yield request.locateResource(parentForURL(resource_uri)))
-+    
-+                    # Check privileges on parent - must have at least DAV:read
-+                    try:
-+                        yield parent.checkPrivileges(request, (davxml.Read(),))
-+                    except AccessDeniedError:
-+                        responses.append(davxml.StatusResponse(href, davxml.Status.fromResponseCode(responsecode.FORBIDDEN)))
-+                        continue
-+                    
-+                    # Cache the last parent's inherited aces for checkPrivileges optimization
-+                    if lastParent != parent:
-+                        lastParent = parent
-+                
-+                        # Do some optimisation of access control calculation by determining any inherited ACLs outside of
-+                        # the child resource loop and supply those to the checkPrivileges on each child.
-+                        filteredaces = (yield parent.inheritedACEsforChildren(request))
- 
--                if isinstance(value, davxml.HRef):
--                    raise NotImplementedError()
--                else:
--                    raise NotImplementedError()
--            except:
--                f = Failure()
-+                    # Check privileges - must have at least DAV:read
-+                    try:
-+                        yield child.checkPrivileges(request, (davxml.Read(),), inherited_aces=filteredaces)
-+                    except AccessDeniedError:
-+                        responses.append(davxml.StatusResponse(href, davxml.Status.fromResponseCode(responsecode.FORBIDDEN)))
-+                        continue
-+            
-+                    # Now retrieve all the requested properties on the HRef resource
-+                    yield prop_common.responseForHref(
-+                        request,
-+                        responses,
-+                        href,
-+                        child,
-+                        prop_common.propertyListForResource,
-+                        props_to_return,
-+                    )
-+            
-+            prop.children = responses
-+            properties_by_status[responsecode.OK].append(prop)
-+        except:
-+            f = Failure()
- 
--                log.err("Error reading property %r for resource %s: %s"
--                        % (property, self, f.value))
-+            log.err("Error reading property %r for resource %s: %s" % (qname, request.uri, f.value))
- 
--                status = statusForFailure(f, "getting property: %s" % (property,))
--                if status not in properties_by_status:
--                    properties_by_status[status] = []
-+            status = statusForFailure(f, "getting property: %s" % (qname,))
-+            if status not in properties_by_status: properties_by_status[status] = []
-+            properties_by_status[status].append(propertyName(qname))
- 
--                raise NotImplementedError()
-+    # Build the overall response
-+    propstats = [
-+        davxml.PropertyStatus(
-+            davxml.PropertyContainer(*properties_by_status[status]),
-+            davxml.Status.fromResponseCode(status)
-+        )
-+        for status in properties_by_status if properties_by_status[status]
-+    ]
- 
--                #properties_by_status[status].append(
--                #    ____propertyName(property)
--                #)
--        else:
--            properties_by_status[responsecode.NOT_FOUND].append(property)
--
--    raise NotImplementedError()
--
--report_DAV__expand_property = deferredGenerator(report_DAV__expand_property)
-+    returnValue(MultiStatusResponse((davxml.PropertyStatusResponse(davxml.HRef(request.uri), *propstats),)))

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_principal_match.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_principal_match.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_principal_match.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,150 +0,0 @@
-Index: twisted/web2/dav/method/report_principal_match.py
-===================================================================
---- twisted/web2/dav/method/report_principal_match.py	(revision 19773)
-+++ twisted/web2/dav/method/report_principal_match.py	(working copy)
-@@ -89,40 +89,64 @@
-         responses = []
-         matchcount = 0
- 
--        selfPrincipal = self.currentPrincipal(request).children[0]
-+        selfPrincipalURL = self.currentPrincipal(request).children[0]
- 
--        # Do some optimisation of access control calculation by determining any inherited ACLs outside of
--        # the child resource loop and supply those to the checkPrivileges on each child.
--        filteredaces = waitForDeferred(self.inheritedACEsforChildren(request))
--        yield filteredaces
--        filteredaces = filteredaces.getResult()
--    
--        children = []
--        d = waitForDeferred(self.findChildren("infinity", request, lambda x, y: children.append((x,y)),
--                                              privileges=(davxml.Read(),), inherited_aces=filteredaces))
--        yield d
--        d.getResult()
--
-         if lookForPrincipals:
- 
--            for child, uri in children:
--                if isPrincipalResource(child) and child.principalMatch(selfPrincipal):
--                    # Check size of results is within limit
--                    matchcount += 1
--                    if matchcount > max_number_of_matches:
--                        raise NumberOfMatchesWithinLimits
-+            # Find the set of principals that represent "self".
-+            
-+            # First add "self"
-+            principal = waitForDeferred(request.locateResource(str(selfPrincipalURL)))
-+            yield principal
-+            principal = principal.getResult()
-+            selfItems = [principal,]
-+            
-+            # Get group memberships for "self" and add each of those
-+            d = waitForDeferred(principal.groupMemberships())
-+            yield d
-+            memberships = d.getResult()
-+            selfItems.extend(memberships)
-+            
-+            # Now add each principal found to the response provided the principal resource is a child of
-+            # the current resource.
-+            for principal in selfItems:
-+                # Get all the URIs that point to the principal resource
-+                # FIXME: making the assumption that the principalURL() is the URL of the resource we found
-+                principal_uris = [principal.principalURL()]
-+                principal_uris.extend(principal.alternateURIs())
-+                
-+                # Compare each one to the request URI and return at most one that matches
-+                for uri in principal_uris:
-+                    if uri.startswith(request.uri):
-+                        # Check size of results is within limit
-+                        matchcount += 1
-+                        if matchcount > max_number_of_matches:
-+                            raise NumberOfMatchesWithinLimits(max_number_of_matches)
-+        
-+                        d = waitForDeferred(prop_common.responseForHref(
-+                            request,
-+                            responses,
-+                            davxml.HRef.fromString(uri),
-+                            principal,
-+                            propertiesForResource,
-+                            propElement
-+                        ))
-+                        yield d
-+                        d.getResult()
-+                        break
-+        else:
-+            # Do some optimisation of access control calculation by determining any inherited ACLs outside of
-+            # the child resource loop and supply those to the checkPrivileges on each child.
-+            filteredaces = waitForDeferred(self.inheritedACEsforChildren(request))
-+            yield filteredaces
-+            filteredaces = filteredaces.getResult()
-+        
-+            children = []
-+            d = waitForDeferred(self.findChildren("infinity", request, lambda x, y: children.append((x,y)),
-+                                                  privileges=(davxml.Read(),), inherited_aces=filteredaces))
-+            yield d
-+            d.getResult()
- 
--                    d = waitForDeferred(prop_common.responseForHref(
--                        request,
--                        responses,
--                        davxml.HRef.fromString(uri),
--                        child,
--                        propertiesForResource,
--                        propElement
--                    ))
--                    yield d
--                    d.getResult()
--        else:
-             for child, uri in children:
-                 # Try to read the requested property from this resource
-                 try:
-@@ -137,22 +161,26 @@
-                         yield principal
-                         principal = principal.getResult()
- 
--                        if principal and isPrincipalResource(principal) and principal.principalMatch(selfPrincipal):
--                            # Check size of results is within limit
--                            matchcount += 1
--                            if matchcount > max_number_of_matches:
--                                raise NumberOfMatchesWithinLimits
--
--                            d = waitForDeferred(prop_common.responseForHref(
--                                request,
--                                responses,
--                                davxml.HRef.fromString(uri),
--                                child,
--                                propertiesForResource,
--                                propElement
--                            ))
-+                        if principal and isPrincipalResource(principal):
-+                            d = waitForDeferred(principal.principalMatch(selfPrincipalURL))
-                             yield d
--                            d.getResult()
-+                            matched = d.getResult()
-+                            if matched:
-+                                # Check size of results is within limit
-+                                matchcount += 1
-+                                if matchcount > max_number_of_matches:
-+                                    raise NumberOfMatchesWithinLimits(max_number_of_matches)
-+    
-+                                d = waitForDeferred(prop_common.responseForHref(
-+                                    request,
-+                                    responses,
-+                                    davxml.HRef.fromString(uri),
-+                                    child,
-+                                    propertiesForResource,
-+                                    propElement
-+                                ))
-+                                yield d
-+                                d.getResult()
-                 except HTTPError:
-                     # Just ignore a failure to access the property. We treat this like a property that does not exist
-                     # or does not match the principal.
-@@ -162,7 +190,7 @@
-         log.err("Too many matching components in principal-match report")
-         raise HTTPError(ErrorResponse(
-             responsecode.FORBIDDEN,
--            (dav_namespace, "number-of-matches-within-limits")
-+            davxml.NumberOfMatchesWithinLimits()
-         ))
- 
-     yield MultiStatusResponse(responses)

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,22 +0,0 @@
-Index: twisted/web2/dav/method/report_principal_property_search.py
-===================================================================
---- twisted/web2/dav/method/report_principal_property_search.py	(revision 19773)
-+++ twisted/web2/dav/method/report_principal_property_search.py	(working copy)
-@@ -166,7 +166,7 @@
-                         # Check size of results is within limit
-                         matchcount += 1
-                         if matchcount > max_number_of_matches:
--                            raise NumberOfMatchesWithinLimits
-+                            raise NumberOfMatchesWithinLimits(max_number_of_matches)
-     
-                         d = waitForDeferred(prop_common.responseForHref(
-                             request,
-@@ -183,7 +183,7 @@
-         log.err("Too many matching components in prinicpal-property-search report")
-         raise HTTPError(ErrorResponse(
-             responsecode.FORBIDDEN,
--            (dav_namespace, "number-of-matches-within-limits")
-+            davxml.NumberOfMatchesWithinLimits()
-         ))
- 
-     yield MultiStatusResponse(responses)

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.resource.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.resource.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.resource.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,1238 +0,0 @@
-Index: twisted/web2/dav/resource.py
-===================================================================
---- twisted/web2/dav/resource.py	(revision 19773)
-+++ twisted/web2/dav/resource.py	(working copy)
-@@ -31,20 +31,31 @@
-     "DAVResource",
-     "DAVLeafResource",
-     "DAVPrincipalResource",
-+    "DAVPrincipalCollectionResource",
-     "AccessDeniedError",
-     "isPrincipalResource",
-     "TwistedACLInheritable",
-+    "TwistedGETContentMD5",
-+    "TwistedQuotaRootProperty",
-     "allACL",
-     "readonlyACL",
-     "davPrivilegeSet",
-     "unauthenticatedPrincipal",
- ]
- 
- import urllib
-+import __builtin__
-+if not hasattr(__builtin__, "set"):
-+    import sets.Set as set
-+if not hasattr(__builtin__, "frozenset"):
-+    import sets.ImmutableSet as frozenset
- 
- from zope.interface import implements
- from twisted.python import log
--from twisted.internet.defer import Deferred, maybeDeferred, succeed
-+from twisted.python.failure import Failure
-+from twisted.cred.error import LoginFailed, UnauthorizedLogin
-+from twisted.internet.defer import Deferred, maybeDeferred, succeed,\
-+    inlineCallbacks, returnValue
- from twisted.internet.defer import waitForDeferred, deferredGenerator
- from twisted.internet import reactor
- from twisted.web2 import responsecode
-@@ -52,12 +62,13 @@
- from twisted.web2.http_headers import generateContentType
- from twisted.web2.iweb import IResponse
- from twisted.web2.resource import LeafResource
-+from twisted.web2.server import NoURLForResourceError
- from twisted.web2.static import MetaDataMixin, StaticRenderMixin
- from twisted.web2.auth.wrapper import UnauthorizedResponse
- from twisted.web2.dav import davxml
- from twisted.web2.dav.davxml import dav_namespace, lookupElement
- from twisted.web2.dav.davxml import twisted_dav_namespace, twisted_private_namespace
--from twisted.web2.dav.idav import IDAVResource, IDAVPrincipalResource
-+from twisted.web2.dav.idav import IDAVResource, IDAVPrincipalResource, IDAVPrincipalCollectionResource
- from twisted.web2.dav.http import NeedPrivilegesResponse
- from twisted.web2.dav.noneprops import NonePropertyStore
- from twisted.web2.dav.util import unimplemented, parentForURL, joinURL
-@@ -126,10 +137,13 @@
-        #(dav_namespace, "group"                     ), # RFC 3744, section 5.2
-         (dav_namespace, "supported-privilege-set"   ), # RFC 3744, section 5.3
-         (dav_namespace, "current-user-privilege-set"), # RFC 3744, section 5.4
-+        (dav_namespace, "current-user-principal"    ), # draft-sanchez-webdav-current-principal
-         (dav_namespace, "acl"                       ), # RFC 3744, section 5.5
-         (dav_namespace, "acl-restrictions"          ), # RFC 3744, section 5.6
-         (dav_namespace, "inherited-acl-set"         ), # RFC 3744, section 5.7
-         (dav_namespace, "principal-collection-set"  ), # RFC 3744, section 5.8
-+        (dav_namespace, "quota-available-bytes"     ), # RFC 4331, section 3
-+        (dav_namespace, "quota-used-bytes"          ), # RFC 4331, section 4
- 
-         (twisted_dav_namespace, "resource-class"),
-     )
-@@ -166,6 +180,14 @@
-         if qname[0] == twisted_private_namespace:
-             return succeed(False)
- 
-+        # Need to special case the dynamic live properties
-+        namespace, name = qname
-+        if namespace == dav_namespace:
-+            if name in ("quota-available-bytes", "quota-used-bytes"):
-+                d = self.hasQuota(request)
-+                d.addCallback(lambda result: result)
-+                return d
-+        
-         return succeed(qname in self.liveProperties or self.deadProperties().contains(qname))
- 
-     def readProperty(self, property, request):
-@@ -201,7 +223,6 @@
-                     mimeType = self.contentType()
-                     if mimeType is None:
-                         return None
--                    mimeType.params = None # WebDAV getcontenttype property does not include parameters
-                     return davxml.GETContentType(generateContentType(mimeType))
- 
-                 if name == "getcontentlength":
-@@ -239,8 +260,10 @@
-                     )
- 
-                 if name == "supported-report-set":
--                    supported = [davxml.SupportedReport(report,) for report in self.supportedReports()]
--                    return davxml.SupportedReportSet(*supported)
-+                    return davxml.SupportedReportSet(*[
-+                        davxml.SupportedReport(report,)
-+                        for report in self.supportedReports()
-+                    ])
- 
-                 if name == "supported-privilege-set":
-                     return self.supportedPrivileges(request)
-@@ -252,9 +275,10 @@
-                     return davxml.InheritedACLSet(*self.inheritedACLSet())
- 
-                 if name == "principal-collection-set":
--                    d = self.principalCollections(request)
--                    d.addCallback(lambda collections: davxml.PrincipalCollectionSet(*collections))
--                    return d
-+                    return davxml.PrincipalCollectionSet(*[
-+                        davxml.HRef(principalCollection.principalCollectionURL())
-+                        for principalCollection in self.principalCollections()
-+                    ])
- 
-                 def ifAllowed(privileges, callback):
-                     def onError(failure):
-@@ -286,7 +310,36 @@
-                         d.addCallback(gotACL)
-                         return d
-                     return ifAllowed((davxml.ReadACL(),), callback)
-+                
-+                if name == "current-user-principal":
-+                    return davxml.CurrentUserPrincipal(self.currentPrincipal(request).children[0])
- 
-+                if name == "quota-available-bytes":
-+                    def callback(qvalue):
-+                        if qvalue is None:
-+                            raise HTTPError(StatusResponse(
-+                                responsecode.NOT_FOUND,
-+                                "Property %s does not exist." % (sname,)
-+                            ))
-+                        else:
-+                            return davxml.QuotaAvailableBytes(str(qvalue[0]))
-+                    d = self.quota(request)
-+                    d.addCallback(callback)
-+                    return d
-+
-+                if name == "quota-used-bytes":
-+                    def callback(qvalue):
-+                        if qvalue is None:
-+                            raise HTTPError(StatusResponse(
-+                                responsecode.NOT_FOUND,
-+                                "Property %s does not exist." % (sname,)
-+                            ))
-+                        else:
-+                            return davxml.QuotaUsedBytes(str(qvalue[1]))
-+                    d = self.quota(request)
-+                    d.addCallback(callback)
-+                    return d
-+
-             elif namespace == twisted_dav_namespace:
-                 if name == "resource-class":
-                     class ResourceClass (davxml.WebDAVTextElement):
-@@ -309,10 +362,7 @@
-         """
-         See L{IDAVResource.writeProperty}.
-         """
--        assert (
--            isinstance(property, davxml.WebDAVElement),
--            "Not a property: %r" % (property,)
--        )
-+        assert isinstance(property, davxml.WebDAVElement), "Not a property: %r" % (property,)
- 
-         def defer():
-             if property.protected:
-@@ -363,15 +413,28 @@
-         """
-         See L{IDAVResource.listProperties}.
-         """
--        # FIXME: A set would be better here, that that's a python 2.4+ feature.
--        qnames = list(self.liveProperties)
-+        qnames = set(self.liveProperties)
- 
-+        # Add dynamic live properties that exist
-+        dynamicLiveProperties = (
-+            (dav_namespace, "quota-available-bytes"     ),
-+            (dav_namespace, "quota-used-bytes"          ),
-+        )
-+        for dqname in dynamicLiveProperties:
-+            has = waitForDeferred(self.hasProperty(dqname, request))
-+            yield has
-+            has = has.getResult()
-+            if not has:
-+                qnames.remove(dqname)
-+
-         for qname in self.deadProperties().list():
-             if (qname not in qnames) and (qname[0] != twisted_private_namespace):
--                qnames.append(qname)
-+                qnames.add(qname)
- 
--        return succeed(qnames)
-+        yield qnames
- 
-+    listProperties = deferredGenerator(listProperties)
-+
-     def listAllprop(self, request):
-         """
-         Some DAV properties should not be returned to a C{DAV:allprop} query.
-@@ -465,8 +528,22 @@
-             return super(DAVPropertyMixIn, self).displayName()
- 
- class DAVResource (DAVPropertyMixIn, StaticRenderMixin):
-+    """
-+    WebDAV resource.
-+    """
-     implements(IDAVResource)
- 
-+    def __init__(self, principalCollections=None):
-+        """
-+        @param principalCollections: an iterable of L{IDAVPrincipalCollectionResource}s
-+            which contain principals to be used in ACLs for this resource.
-+        """
-+        if principalCollections is not None:
-+            self._principalCollections = frozenset([
-+                IDAVPrincipalCollectionResource(principalCollection)
-+                for principalCollection in principalCollections
-+            ])
-+
-     ##
-     # DAV
-     ##
-@@ -553,69 +630,65 @@
-     def supportedReports(self):
-         """
-         See L{IDAVResource.supportedReports}.
--        This implementation lists the three main ACL reports.
-+        This implementation lists the three main ACL reports and expand-property.
-         """
-         result = []
-         result.append(davxml.Report(davxml.ACLPrincipalPropSet(),))
-         result.append(davxml.Report(davxml.PrincipalMatch(),))
-         result.append(davxml.Report(davxml.PrincipalPropertySearch(),))
-+        result.append(davxml.Report(davxml.ExpandProperty(),))
-         return result
- 
-     ##
-     # Authentication
-     ##
- 
-+    @inlineCallbacks
-     def authorize(self, request, privileges, recurse=False):
-         """
-         See L{IDAVResource.authorize}.
-         """
--        def onError(failure):
--            log.err("Invalid authentication details: %s" % (request,))
--            raise HTTPError(UnauthorizedResponse(
-+
-+        try:
-+            yield self.authenticate(request)
-+        except (UnauthorizedLogin, LoginFailed), e:
-+            log.msg("Authentication failed: %s" % (e,))
-+            response = (yield UnauthorizedResponse.makeResponse(
-                 request.credentialFactories,
-                 request.remoteAddr
-             ))
-+            raise HTTPError(response)
- 
--        def onAuth(result):
--            def onErrors(failure):
--                failure.trap(AccessDeniedError)
--                
--                # If we were unauthorized to start with (no Authorization header from client) then
--                # we should return an unauthorized response instead to force the client to login if it can
--                if request.user == davxml.Principal(davxml.Unauthenticated()):
--                    response = UnauthorizedResponse(request.credentialFactories,
--                                                    request.remoteAddr)
--                else:
--                    response = NeedPrivilegesResponse(request.uri,
--                                                      failure.value.errors)
--                #
--                # We're not adding the headers here because this response
--                # class is supposed to be a FORBIDDEN status code and
--                # "Authorization will not help" according to RFC2616
--                #
--                raise HTTPError(response)
-+        try:
-+            yield self.checkPrivileges(request, privileges, recurse)
-+        except AccessDeniedError, e:
-+            # If we were unauthenticated to start with (no Authorization header from client) then
-+            # we should return an unauthorized response instead to force the client to login if it can
-+            if request.authnUser == davxml.Principal(davxml.Unauthenticated()):
-+                response = (yield UnauthorizedResponse.makeResponse(
-+                    request.credentialFactories,
-+                    request.remoteAddr
-+                ))
-+            else:
-+                response = NeedPrivilegesResponse(request.uri, e.errors)
-+            #
-+            # We're not adding the headers here because this response
-+            # class is supposed to be a FORBIDDEN status code and
-+            # "Authorization will not help" according to RFC2616
-+            #
-+            raise HTTPError(response)
- 
--            d = self.checkPrivileges(request, privileges, recurse)
--            d.addErrback(onErrors)
--            return d
--
--        d = maybeDeferred(self.authenticate, request)
--        d.addCallbacks(onAuth, onError)
--
--        return d
--
-+    @inlineCallbacks
-     def authenticate(self, request):
--        def loginSuccess(result):
--            request.user = result[1]
--            return request.user
- 
-         if not (
-             hasattr(request, 'portal') and 
-             hasattr(request, 'credentialFactories') and
-             hasattr(request, 'loginInterfaces')
-         ):
--            request.user = davxml.Principal(davxml.Unauthenticated())
--            return request.user
-+            request.authnUser = davxml.Principal(davxml.Unauthenticated())
-+            request.authzUser = davxml.Principal(davxml.Unauthenticated())
-+            returnValue((request.authnUser, request.authzUser,))
- 
-         authHeader = request.headers.getHeader('authorization')
- 
-@@ -623,31 +696,32 @@
-             if authHeader[0] not in request.credentialFactories:
-                 log.err("Client authentication scheme %s is not provided by server %s"
-                         % (authHeader[0], request.credentialFactories.keys()))
--                raise HTTPError(responsecode.FORBIDDEN)
-+
-+                response = (yield UnauthorizedResponse.makeResponse(
-+                    request.credentialFactories,
-+                    request.remoteAddr
-+                ))
-+                raise HTTPError(response)
-             else:
-                 factory = request.credentialFactories[authHeader[0]]
- 
--                creds = factory.decode(authHeader[1], request)
-+                creds = (yield factory.decode(authHeader[1], request))
- 
-                 # Try to match principals in each principal collection on the resource
--                def gotDetails(details):
--                    principal = IDAVPrincipalResource(details[0])
--                    principalURI = details[1]
--                    return PrincipalCredentials(principal, principalURI, creds)
-+                authnPrincipal, authzPrincipal = (yield self.principalsForAuthID(request, creds.username))
-+                authnPrincipal = IDAVPrincipalResource(authnPrincipal)
-+                authzPrincipal = IDAVPrincipalResource(authzPrincipal)
- 
--                def login(pcreds):
--                    d = request.portal.login(pcreds, None, *request.loginInterfaces)
--                    d.addCallback(loginSuccess)
-+                pcreds = PrincipalCredentials(authnPrincipal, authzPrincipal, creds)
- 
--                    return d
--
--                d = self.findPrincipalForAuthID(request, creds.username)
--                d.addCallback(gotDetails).addCallback(login)
--
--                return d
-+                result = (yield request.portal.login(pcreds, None, *request.loginInterfaces))
-+                request.authnUser = result[1]
-+                request.authzUser = result[2]
-+                returnValue((request.authnUser, request.authzUser,))
-         else:
--            request.user = davxml.Principal(davxml.Unauthenticated())
--            return request.user
-+            request.authnUser = davxml.Principal(davxml.Unauthenticated())
-+            request.authzUser = davxml.Principal(davxml.Unauthenticated())
-+            returnValue((request.authnUser, request.authzUser,))
- 
-     ##
-     # ACL
-@@ -656,49 +730,23 @@
-     def currentPrincipal(self, request):
-         """
-         @param request: the request being processed.
--        @return: the current principal, as derived from the given request.
-+        @return: the current authorized principal, as derived from the given request.
-         """
--        if hasattr(request, "user"):
--            return request.user
-+        if hasattr(request, "authzUser"):
-+            return request.authzUser
-         else:
-             return unauthenticatedPrincipal
- 
--    def principalCollections(self, request):
-+    def principalCollections(self):
-         """
-         See L{IDAVResource.accessControlList}.
--
--        This implementation tries to read the L{davxml.PrincipalCollectionSet}
--        from the dead property store of this resource and uses that. If not
--        present on this resource, it tries to get it from the parent, unless it
--        is the root or has no parent.
-         """
--        try:
--            principalCollections = self.readDeadProperty(davxml.PrincipalCollectionSet).childrenOfType(davxml.HRef)
--        except HTTPError, e:
--            if e.response.code != responsecode.NOT_FOUND:
--                raise
-+        if hasattr(self, "_principalCollections"):
-+            return self._principalCollections
-+        else:
-+            return ()
- 
--            principalCollections = []
--
--            # Try the parent
--            myURL = request.urlForResource(self)
--            if myURL != "/":
--                parentURL = parentForURL(myURL)
--
--                parent = waitForDeferred(request.locateResource(parentURL))
--                yield parent
--                parent = parent.getResult()
--
--                if parent:
--                    principalCollections = waitForDeferred(parent.principalCollections(request))
--                    yield principalCollections
--                    principalCollections = principalCollections.getResult()
--
--        yield principalCollections
--
--    principalCollections = deferredGenerator(principalCollections)
--
--    def defaultAccessControlList(self):
-+    def defaultRootAccessControlList(self):
-         """
-         @return: the L{davxml.ACL} element containing the default access control
-             list for this resource.
-@@ -710,6 +758,17 @@
-         #
-         return readonlyACL
- 
-+    def defaultAccessControlList(self):
-+        """
-+        @return: the L{davxml.ACL} element containing the default access control
-+            list for this resource.
-+        """
-+        #
-+        # The default behaviour is no ACL; we should inherrit from the parent
-+        # collection.
-+        #
-+        return davxml.ACL()
-+
-     def setAccessControlList(self, acl):
-         """
-         See L{IDAVResource.setAccessControlList}.
-@@ -748,13 +807,16 @@
-         # 10. Verify that new acl is not in conflict with itself
-         # 11. Update acl on the resource
- 
--        old_acl = waitForDeferred(self.accessControlList(request))
-+        # Get the current access control list, preserving any private properties on the ACEs as
-+        # we will need to keep those when we change the ACL.
-+        old_acl = waitForDeferred(self.accessControlList(request, expanding=True))
-         yield old_acl
-         old_acl = old_acl.getResult()
- 
-         # Check disabled
-         if old_acl is None:
-             yield None
-+            return
- 
-         # Need to get list of supported privileges
-         supported = []
-@@ -773,10 +835,7 @@
-         yield supportedPrivs
-         supportedPrivs = supportedPrivs.getResult()
-         for item in supportedPrivs.children:
--            assert (
--                isinstance(item, davxml.SupportedPrivilege),
--                "Not a SupportedPrivilege: %r" % (item,)
--            )
-+            assert isinstance(item, davxml.SupportedPrivilege), "Not a SupportedPrivilege: %r" % (item,)
-             addSupportedPrivilege(item)
- 
-         # Steps 1 - 6
-@@ -910,8 +969,7 @@
-         supportedPrivs = supportedPrivs.getResult()
- 
-         # Other principals types don't make sense as actors.
--        assert (
--            principal.children[0].name in ("unauthenticated", "href"),
-+        assert principal.children[0].name in ("unauthenticated", "href"), (
-             "Principal is not an actor: %r" % (principal,)
-         )
- 
-@@ -1019,15 +1077,16 @@
-         def getMyURL():
-             url = request.urlForResource(self)
- 
--            assert url is not None, "urlForResource(self) returned None for resource %s" % (self,)
-+            assert url is not None, (
-+                "urlForResource(self) returned None for resource %s" % (self,)
-+            )
- 
-             return url
- 
-         try:
-             acl = self.readDeadProperty(davxml.ACL)
-         except HTTPError, e:
--            assert (
--                e.response.code == responsecode.NOT_FOUND,
-+            assert e.response.code == responsecode.NOT_FOUND, (
-                 "Expected %s response from readDeadProperty() exception, not %s"
-                 % (responsecode.NOT_FOUND, e.response.code)
-             )
-@@ -1038,9 +1097,9 @@
- 
-             if myURL == "/":
-                 # If we get to the root without any ACLs, then use the default.
-+                acl = self.defaultRootAccessControlList()
-+            else:
-                 acl = self.defaultAccessControlList()
--            else:
--                acl = davxml.ACL()
- 
-         # Dynamically update privileges for those ace's that are inherited.
-         if inheritance:
-@@ -1076,7 +1135,7 @@
-                                 # Adjust ACE for inherit on this resource
-                                 children = list(ace.children)
-                                 children.remove(TwistedACLInheritable())
--                                children.append(davxml.Inherited(davxml.HRef.fromString(parentURL)))
-+                                children.append(davxml.Inherited(davxml.HRef(parentURL)))
-                                 aces.append(davxml.ACE(*children))
-             else:
-                 aces.extend(inherited_aces)
-@@ -1105,8 +1164,7 @@
-         the child resource loop and supply those to the checkPrivileges on each child.
- 
-         @param request: the L{IRequest} for the request in progress.
--        @return:        a C{list} of L{Ace}s that child resources of this one will
--            inherit and which will match the currently authenticated principal.
-+        @return:        a C{list} of L{Ace}s that child resources of this one will inherit.
-         """
-         
-         # Get the parent ACLs with inheritance and preserve the <inheritable> element.
-@@ -1128,21 +1186,9 @@
-                 # Adjust ACE for inherit on this resource
-                 children = list(ace.children)
-                 children.remove(TwistedACLInheritable())
--                children.append(davxml.Inherited(davxml.HRef.fromString(request.urlForResource(self))))
-+                children.append(davxml.Inherited(davxml.HRef(request.urlForResource(self))))
-                 aces.append(davxml.ACE(*children))
--                
--        # Filter out those that do not have a principal match with the current principal
--        principal = self.currentPrincipal(request)
--        filteredaces = []
--        for ace in aces:
--            if self.matchPrincipal(principal, ace.principal, request):
--                if ace.invert:
--                    continue
--            else:
--                if not ace.invert:
--                    continue
--            filteredaces.append(ace)
--        yield filteredaces
-+        yield aces
- 
-     inheritedACEsforChildren = deferredGenerator(inheritedACEsforChildren)
- 
-@@ -1152,49 +1198,69 @@
- 
-         This implementation returns an empty set.
-         """
--
-         return []
- 
--    def findPrincipalForAuthID(self, request, authid):
-+    def principalsForAuthID(self, request, authid):
-         """
-+        Return authentication and authorization prinicipal identifiers for the
-+        authentication identifer passed in. In this implementation authn and authz
-+        principals are the same.
-+
-         @param request: the L{IRequest} for the request in progress.
-         @param authid: a string containing the
-             authentication/authorization identifier for the principal
-             to lookup.
--        @return: a deferred tuple of C{(principal, principalURI)}
--            where: C{principal} is the L{Principal} that is found;
--            C{principalURI} is the C{str} URI of the principal. 
-+        @return: a deferred tuple of two tuples. Each tuple is
-+            C{(principal, principalURI)} where: C{principal} is the L{Principal}
-+            that is found; {principalURI} is the C{str} URI of the principal.
-+            The first tuple corresponds to authentication identifiers,
-+            the second to authorization identifiers.
-             It will errback with an HTTPError(responsecode.FORBIDDEN) if
-             the principal isn't found.
-         """
--        # Try to match principals in each principal collection on the resource
--        collections = waitForDeferred(self.principalCollections(request))
--        yield collections
--        collections = collections.getResult()
-+        authnPrincipal = self.findPrincipalForAuthID(authid)
- 
--        for collection in collections:
--            principalURI = joinURL(str(collection), authid)
-+        if authnPrincipal is None:
-+            log.msg("Could not find the principal resource for user id: %s" % (authid,))
-+            raise HTTPError(responsecode.FORBIDDEN)
- 
--            principal = waitForDeferred(request.locateResource(principalURI))
--            yield principal
--            principal = principal.getResult()
-+        d = self.authorizationPrincipal(request, authid, authnPrincipal)
-+        d.addCallback(lambda authzPrincipal: (authnPrincipal, authzPrincipal))
-+        return d
- 
--            if isPrincipalResource(principal):
--                yield (principal, principalURI)
--                return
--        else:
--            principalCollections = waitForDeferred(self.principalCollections(request))
--            yield principalCollections
--            principalCollections = principalCollections.getResult()
-+    def findPrincipalForAuthID(self, authid):
-+        """
-+        Return authentication and authoirization prinicipal identifiers for the
-+        authentication identifer passed in. In this implementation authn and authz
-+        principals are the same.
- 
--            if len(principalCollections) == 0:
--                log.msg("DAV:principal-collection-set property cannot be found on the resource being authorized: %s" % self)
--            else:
--                log.msg("Could not find principal matching user id: %s" % authid)
--            raise HTTPError(responsecode.FORBIDDEN)
-+        @param authid: a string containing the
-+            authentication/authorization identifier for the principal
-+            to lookup.
-+        @return: a tuple of C{(principal, principalURI)} where: C{principal} is the L{Principal}
-+            that is found; {principalURI} is the C{str} URI of the principal.
-+            If not found return None.
-+        """
-+        for collection in self.principalCollections():
-+            principal = collection.principalForUser(authid)
-+            if principal is not None:
-+                return principal
-+        return None
- 
--    findPrincipalForAuthID = deferredGenerator(findPrincipalForAuthID)
--
-+    def authorizationPrincipal(self, request, authid, authnPrincipal):
-+        """
-+        Determine the authorization principal for the given request and authentication principal.
-+        This implementation simply uses aht authentication principalk as the authoization principal.
-+        
-+        @param request: the L{IRequest} for the request in progress.
-+        @param authid: a string containing the uthentication/authorization identifier
-+            for the principal to lookup.
-+        @param authnPrincipal: the L{IDAVPrincipal} for the authenticated principal
-+         @return: a deferred result C{tuple} of (L{IDAVPrincipal}, C{str}) containing the authorization principal
-+            resource and URI respectively.
-+        """
-+        return succeed(authnPrincipal)
-+        
-     def samePrincipal(self, principal1, principal2):
-         """
-         Check whether the two prinicpals are exactly the same in terms of
-@@ -1219,7 +1285,6 @@
-             return False
-                 
-     def matchPrincipal(self, principal1, principal2, request):
--
-         """
-         Check whether the principal1 is a principal in the set defined by
-         principal2.
-@@ -1244,6 +1309,9 @@
-             if isinstance(principal1, davxml.Unauthenticated):
-                 yield False
-                 return
-+            elif isinstance(principal1, davxml.All):
-+                yield False
-+                return
-             else:
-                 yield True
-                 return
-@@ -1260,10 +1328,7 @@
-             yield False
-             return
- 
--        assert (
--            isinstance(principal1, davxml.HRef),
--            "Not an HRef: %r" % (principal1,)
--        )
-+        assert isinstance(principal1, davxml.HRef), "Not an HRef: %r" % (principal1,)
- 
-         principal2 = waitForDeferred(self.resolvePrincipal(principal2, request))
-         yield principal2
-@@ -1271,7 +1336,6 @@
- 
-         assert principal2 is not None, "principal2 is None"
- 
--
-         # Compare two HRefs and do group membership test as well
-         if principal1 == principal2:
-             yield True
-@@ -1289,6 +1353,7 @@
- 
-     matchPrincipal = deferredGenerator(matchPrincipal)
- 
-+    @deferredGenerator
-     def principalIsGroupMember(self, principal1, principal2, request):
-         """
-         Check whether one principal is a group member of another.
-@@ -1299,18 +1364,21 @@
-         @return: L{Deferred} with result C{True} if principal1 is a member of principal2, C{False} otherwise
-         """
-         
--        def testGroup(group):
--            # Get principal resource for principal2
--            if group and isinstance(group, DAVPrincipalResource):
--                members = group.groupMembers()
--                if principal1 in members:
--                    return True
--                
--            return False
-+        d = waitForDeferred(request.locateResource(principal2))
-+        yield d
-+        group = d.getResult()
- 
--        d = request.locateResource(principal2)
--        d.addCallback(testGroup)
--        return d
-+        # Get principal resource for principal2
-+        if group and isinstance(group, DAVPrincipalResource):
-+            d = waitForDeferred(group.expandedGroupMembers())
-+            yield d
-+            members = d.getResult()
-+            for member in members:
-+                if member.principalURL() == principal1:
-+                    yield True
-+                    return
-+            
-+        yield False
-         
-     def validPrincipal(self, ace_principal, request):
-         """
-@@ -1351,11 +1419,16 @@
-         @return C{True} if C{href_principal} is valid, C{False} otherwise.
- 
-         This implementation tests for a href element that corresponds to
--        a principal resource.
-+        a principal resource and matches the principal-URL.
-         """
--        # Must have the principal resource type
-+
-+        # Must have the principal resource type and must match the principal-URL
-+        
-+        def _matchPrincipalURL(resource):
-+            return isPrincipalResource(resource) and resource.principalURL() == str(href_principal)
-+
-         d = request.locateResource(str(href_principal))
--        d.addCallback(isPrincipalResource)
-+        d.addCallback(_matchPrincipalURL)
-         return d
- 
-     def resolvePrincipal(self, principal, request):
-@@ -1404,8 +1477,7 @@
-             try:
-                 principal = principal.getResult()
-             except HTTPError, e:
--                assert (
--                    e.response.code == responsecode.NOT_FOUND,
-+                assert e.response.code == responsecode.NOT_FOUND, (
-                     "Expected %s response from readProperty() exception, not %s"
-                     % (responsecode.NOT_FOUND, e.response.code)
-                 )
-@@ -1432,15 +1504,15 @@
-                 log.err("DAV:self ACE is set on non-principal resource %r" % (self,))
-                 yield None
-                 return
--            principal = davxml.HRef.fromString(self.principalURL())
-+            principal = davxml.HRef(self.principalURL())
- 
-         if isinstance(principal, davxml.HRef):
-             yield principal
-+            return
-         else:
-             yield None
- 
--        assert (
--            isinstance(principal, (davxml.All, davxml.Authenticated, davxml.Unauthenticated)),
-+        assert isinstance(principal, (davxml.All, davxml.Authenticated, davxml.Unauthenticated)), (
-             "Not a meta-principal: %r" % (principal,)
-         )
- 
-@@ -1517,6 +1589,280 @@
-         return None
- 
-     ##
-+    # Quota
-+    ##
-+    
-+    """
-+    The basic policy here is to define a private 'quota-root' property on a collection.
-+    That property will contain the maximum allowed bytes for the collections and all
-+    its contents.
-+    
-+    In order to determine the quota property values on a resource, the server must look
-+    for the private property on that resource and any of its parents. If found on a parent,
-+    then that parent should be queried for quota information. If not found, no quota
-+    exists for the resource.
-+    
-+    To determine tha actual quota in use we will cache the used byte count on the quota-root
-+    collection in another private property. It is the servers responsibility to
-+    keep that property up to date by adjusting it after every PUT, DELETE, COPY,
-+    MOVE, MKCOL, PROPPATCH, ACL, POST or any other method that may affect the size of
-+    stored data. If the private property is not present, the server will fall back to
-+    getting the size by iterating over all resources (this is done in static.py).
-+    
-+    """
-+
-+    def quota(self, request):
-+        """
-+        Get current available & used quota values for this resource's quota root
-+        collection.
-+
-+        @return: an L{Defered} with result C{tuple} containing two C{int}'s the first is 
-+            quota-available-bytes, the second is quota-used-bytes, or
-+            C{None} if quota is not defined on the resource.
-+        """
-+        
-+        # See if already cached
-+        if not hasattr(request, "quota"):
-+            request.quota = {}
-+        if request.quota.has_key(self):
-+            yield request.quota[self]
-+            return
-+
-+        # Check this resource first
-+        if self.isCollection():
-+            qroot = self.quotaRoot(request)
-+            if qroot is not None:
-+                used = waitForDeferred(self.currentQuotaUse(request))
-+                yield used
-+                used = used.getResult()
-+                available = qroot - used
-+                if available < 0:
-+                    available = 0
-+                request.quota[self] = (available, used)
-+                yield request.quota[self]
-+                return
-+        
-+        # Check the next parent
-+        url = request.urlForResource(self)
-+        if url != "/":
-+            parent = waitForDeferred(request.locateResource(parentForURL(url)))
-+            yield parent
-+            parent = parent.getResult()
-+            d = waitForDeferred(parent.quota(request))
-+            yield d
-+            request.quota[self] = d.getResult()
-+        else:
-+            request.quota[self] = None
-+
-+        yield request.quota[self]
-+        return
-+    
-+    quota = deferredGenerator(quota)
-+
-+    def hasQuota(self, request):
-+        """
-+        Check whether this resource is undre quota control by checking each parent to see if
-+        it has a quota root.
-+        
-+        @return: C{True} if under quota control, C{False} if not.
-+        """
-+        
-+        # Check this one first
-+        if self.hasQuotaRoot(request):
-+            yield True
-+            return
-+        
-+        # Look at each parent
-+        try:
-+            url = request.urlForResource(self)
-+            if url != "/":
-+                parent = waitForDeferred(request.locateResource(parentForURL(url)))
-+                yield parent
-+                parent = parent.getResult()
-+                d = waitForDeferred(parent.hasQuota(request))
-+                yield d
-+                yield d.getResult()
-+            else:
-+                yield False
-+        except NoURLForResourceError:
-+            yield False
-+    
-+    hasQuota = deferredGenerator(hasQuota)
-+        
-+    def hasQuotaRoot(self, request):
-+        """
-+        @return: a C{True} if this resource has quota root, C{False} otherwise.
-+        """
-+        return self.hasDeadProperty(TwistedQuotaRootProperty)
-+    
-+    def quotaRoot(self, request):
-+        """
-+        @return: a C{int} containing the maximum allowed bytes if this collection
-+            is quota-controlled, or C{None} if not quota controlled.
-+        """
-+        if self.hasDeadProperty(TwistedQuotaRootProperty):
-+            return int(str(self.readDeadProperty(TwistedQuotaRootProperty)))
-+        else:
-+            return None
-+    
-+    def quotaRootParent(self, request):
-+        """
-+        Return the next quota root above this resource.
-+        
-+        @return: L{DAVResource} or C{None}
-+        """
-+
-+        # Check the next parent
-+        url = request.urlForResource(self)
-+        while (url != "/"):
-+            url = parentForURL(url)
-+            parent = waitForDeferred(request.locateResource(url))
-+            yield parent
-+            parent = parent.getResult()
-+            if parent.hasQuotaRoot(request):
-+                yield parent
-+                return
-+
-+        yield None
-+    
-+    quotaRootParent = deferredGenerator(quotaRootParent)
-+        
-+    def setQuotaRoot(self, request, maxsize):
-+        """
-+        @param maxsize: a C{int} containing the maximum allowed bytes for the contents
-+            of this collection, or C{None} tp remove quota restriction.
-+        """
-+        assert self.isCollection(), "Only collections can have a quota root"
-+        assert maxsize is None or isinstance(maxsize, int), "maxsize must be an int or None"
-+        
-+        if maxsize is not None:
-+            self.writeDeadProperty(TwistedQuotaRootProperty(str(maxsize)))
-+        else:
-+            # Remove both the root and the cached used value
-+            self.removeDeadProperty(TwistedQuotaRootProperty)
-+            self.removeDeadProperty(TwistedQuotaUsedProperty)
-+    
-+    def quotaSize(self, request):
-+        """
-+        Get the size of this resource (if its a collection get total for all children as well).
-+        TODO: Take into account size of dead-properties.
-+
-+        @return: a C{int} containing the size of the resource.
-+        """
-+        unimplemented(self)
-+
-+    def checkQuota(self, request, available):
-+        """
-+        Check to see whether all quota roots have sufficient available bytes.
-+        We currently do not use hierarchical quota checks - i.e. only the most
-+        immediate quota root parent is checked for quota.
-+        
-+        @param available: a C{int} containing the additional quota required.
-+        @return: C{True} if there is sufficient quota remaining on all quota roots,
-+            C{False} otherwise.
-+        """
-+        
-+        quotaroot = self
-+        while(quotaroot is not None):
-+            # Check quota on this root (if it has one)
-+            quota = quotaroot.quotaRoot(request)
-+            if quota is not None:
-+                if available > quota[0]:
-+                    yield False
-+                    return
-+
-+            # Check the next parent with a quota root
-+            quotaroot = waitForDeferred(quotaroot.quotaRootParent(request))
-+            yield quotaroot
-+            quotaroot = quotaroot.getResult()
-+
-+        yield True
-+
-+    checkQuota = deferredGenerator(checkQuota)
-+
-+    def quotaSizeAdjust(self, request, adjust):
-+        """
-+        Update the quota used value on all quota root parents of this resource.
-+
-+        @param adjust: a C{int} containing the number of bytes added (positive) or
-+            removed (negative) that should be used to adjust the cached total.
-+        """
-+        
-+        # Check this resource first
-+        if self.isCollection():
-+            if self.hasQuotaRoot(request):
-+                d = waitForDeferred(self.updateQuotaUse(request, adjust))
-+                yield d
-+                d.getResult()
-+                yield None
-+                return
-+        
-+        # Check the next parent
-+        url = request.urlForResource(self)
-+        if url != "/":
-+            parent = waitForDeferred(request.locateResource(parentForURL(url)))
-+            yield parent
-+            parent = parent.getResult()
-+            d = waitForDeferred(parent.quotaSizeAdjust(request, adjust))
-+            yield d
-+            d.getResult()
-+
-+        yield None
-+
-+    quotaSizeAdjust = deferredGenerator(quotaSizeAdjust)
-+
-+    def currentQuotaUse(self, request):
-+        """
-+        Get the cached quota use value, or if not present (or invalid) determine
-+        quota use by brute force.
-+
-+        @return: an L{Deferred} with a C{int} result containing the current used byte if this collection
-+            is quota-controlled, or C{None} if not quota controlled.
-+        """
-+        assert self.isCollection(), "Only collections can have a quota root"
-+        assert self.hasQuotaRoot(request), "Quota use only on quota root collection"
-+        
-+        # Try to get the cached value property
-+        if self.hasDeadProperty(TwistedQuotaUsedProperty):
-+            return succeed(int(str(self.readDeadProperty(TwistedQuotaUsedProperty))))
-+        else:
-+            # Do brute force size determination and cache the result in the private property
-+            def _defer(result):
-+                self.writeDeadProperty(TwistedQuotaUsedProperty(str(result)))
-+                return result
-+            d = self.quotaSize(request)
-+            d.addCallback(_defer)
-+            return d
-+
-+    def updateQuotaUse(self, request, adjust):
-+        """
-+        Update the quota used value on this resource.
-+
-+        @param adjust: a C{int} containing the number of bytes added (positive) or
-+        removed (negative) that should be used to adjust the cached total.
-+        @return: an L{Deferred} with a C{int} result containing the current used byte if this collection
-+            is quota-controlled, or C{None} if not quota controlled.
-+        """
-+        assert self.isCollection(), "Only collections can have a quota root"
-+        
-+        # Get current value
-+        def _defer(size):
-+            size += adjust
-+            
-+            # Sanity check the resulting size
-+            if size >= 0:
-+                self.writeDeadProperty(TwistedQuotaUsedProperty(str(size)))
-+            else:
-+                # Remove the dead property and re-read to do brute force quota calc
-+                log.msg("Attempt to set quota used to a negative value: %s (adjustment: %s)" % (size, adjust,))
-+                self.removeDeadProperty(TwistedQuotaUsedProperty)
-+                return self.currentQuotaUse(request)
-+
-+        d = self.currentQuotaUse(request)
-+        d.addCallback(_defer)
-+        return d
-+        
-+    ##
-     # HTTP
-     ##
- 
-@@ -1525,15 +1871,11 @@
-         #litmus = request.headers.getRawHeaders("x-litmus")
-         #if litmus: log.msg("*** Litmus test: %s ***" % (litmus,))
- 
--        # FIXME: Learn how to use twisted logging facility, wsanchez
--        protocol = "HTTP/%s.%s" % request.clientproto
--        log.msg("%s %s %s" % (request.method, urllib.unquote(request.uri), protocol))
--
-         #
-         # If this is a collection and the URI doesn't end in "/", redirect.
-         #
--        if self.isCollection() and request.uri[-1:] != "/":
--            return RedirectResponse(request.uri + "/")
-+        if self.isCollection() and request.path[-1:] != "/":
-+            return RedirectResponse(request.unparseURL(path=urllib.quote(request.path, safe=':/')+'/'))
- 
-         def setHeaders(response):
-             response = IResponse(response)
-@@ -1567,7 +1909,7 @@
-     def findChildren(self, depth, request, callback, privileges=None, inherited_aces=None):
-         return succeed(None)
- 
--class DAVPrincipalResource (DAVLeafResource):
-+class DAVPrincipalResource (DAVResource):
-     """
-     Resource representing a WebDAV principal.  (RFC 3744, section 2)
-     """
-@@ -1577,7 +1919,7 @@
-     # WebDAV
-     ##
- 
--    liveProperties = DAVLeafResource.liveProperties + (
-+    liveProperties = DAVResource.liveProperties + (
-         (dav_namespace, "alternate-URI-set"),
-         (dav_namespace, "principal-URL"    ),
-         (dav_namespace, "group-member-set" ),
-@@ -1585,14 +1927,11 @@
-     )
- 
-     def davComplianceClasses(self):
--        return ("1",)
-+        return ("1", "access-control",)
- 
-     def isCollection(self):
-         return False
- 
--    def findChildren(self, depth, request, callback, privileges=None, inherited_aces=None):
--        return succeed(None)
--
-     def readProperty(self, property, request):
-         def defer():
-             if type(property) is tuple:
-@@ -1610,10 +1949,20 @@
-                     return davxml.PrincipalURL(davxml.HRef(self.principalURL()))
- 
-                 if name == "group-member-set":
--                    return davxml.GroupMemberSet(*[davxml.HRef(p) for p in self.groupMembers()])
-+                    def callback(members):
-+                        return davxml.GroupMemberSet(*[davxml.HRef(p.principalURL()) for p in members])
-+                    
-+                    d = self.groupMembers()
-+                    d.addCallback(callback)
-+                    return d
- 
-                 if name == "group-membership":
--                    return davxml.GroupMembership(*[davxml.HRef(g) for g in self.groupMemberships()])
-+                    def callback(memberships):
-+                        return davxml.GroupMembership(*[davxml.HRef(g.principalURL()) for g in memberships])
-+                    
-+                    d = self.groupMemberships()
-+                    d.addCallback(callback)
-+                    return d
- 
-                 if name == "resourcetype":
-                     if self.isCollection():
-@@ -1655,7 +2004,7 @@
-         principals.  Subclasses should override this method to provide member
-         URLs for this resource if appropriate.
-         """
--        return ()
-+        return succeed(())
- 
-     def groupMemberships(self):
-         """
-@@ -1666,6 +2015,7 @@
-         """
-         unimplemented(self)
- 
-+    @deferredGenerator
-     def principalMatch(self, href):
-         """
-         Check whether the supplied principal matches this principal or is a
-@@ -1675,10 +2025,33 @@
-         """
-         uri = str(href)
-         if self.principalURL() == uri:
--            return True
-+            yield True
-+            return
-         else:
--            return uri in self.groupMembers()
-+            d = waitForDeferred(self.expandedGroupMembers())
-+            yield d
-+            members = d.getResult()
-+            member_uris = [member.principalURL() for member in members]
-+            yield uri in member_uris
- 
-+class DAVPrincipalCollectionResource (DAVResource):
-+    """
-+    WebDAV principal collection resource.  (RFC 3744, section 5.8)
-+    """
-+    implements(IDAVPrincipalCollectionResource)
-+
-+    def __init__(self, url, principalCollections=()):
-+        """
-+        @param url: This resource's URL.
-+        """
-+        DAVResource.__init__(self, principalCollections=principalCollections)
-+
-+        assert url.endswith("/"), "Collection URL must end in '/'"
-+        self._url = url
-+
-+    def principalCollectionURL(self):
-+        return self._url
-+
- class AccessDeniedError(Exception):
-     def __init__(self, errors):
-         """ 
-@@ -1718,6 +2091,37 @@
- davxml.registerElement(TwistedACLInheritable)
- davxml.ACE.allowed_children[(twisted_dav_namespace, "inheritable")] = (0, 1)
- 
-+class TwistedGETContentMD5 (davxml.WebDAVTextElement):
-+    """
-+    MD5 hash of the resource content.
-+    """
-+    namespace = twisted_dav_namespace
-+    name = "getcontentmd5"
-+
-+davxml.registerElement(TwistedGETContentMD5)
-+
-+"""
-+When set on a collection, this property indicates that the collection has a quota limit for
-+the size of all resources stored in the collection (and any associate meta-data such as properties).
-+The value is a number - the maximum size in bytes allowed.
-+"""
-+class TwistedQuotaRootProperty (davxml.WebDAVTextElement):
-+    namespace = twisted_private_namespace
-+    name = "quota-root"
-+
-+davxml.registerElement(TwistedQuotaRootProperty)
-+
-+"""
-+When set on a collection, this property contains the cached running total of the size of all
-+resources stored in the collection (and any associate meta-data such as properties).
-+The value is a number - the size in bytes used.
-+"""
-+class TwistedQuotaUsedProperty (davxml.WebDAVTextElement):
-+    namespace = twisted_private_namespace
-+    name = "quota-used"
-+
-+davxml.registerElement(TwistedQuotaUsedProperty)
-+
- allACL = davxml.ACL(
-     davxml.ACE(
-         davxml.Principal(davxml.All()),

Copied: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.resource.patch (from rev 4133, CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.resource.patch)
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.resource.patch	                        (rev 0)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.resource.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -0,0 +1,13 @@
+Index: twisted/web2/dav/resource.py
+===================================================================
+--- twisted/web2/dav/resource.py	(revision 26741)
++++ twisted/web2/dav/resource.py	(working copy)
+@@ -1888,7 +1888,7 @@
+         # If this is a collection and the URI doesn't end in "/", redirect.
+         #
+         if self.isCollection() and request.path[-1:] != "/":
+-            return RedirectResponse(request.unparseURL(path=request.path+'/'))
++            return RedirectResponse(request.unparseURL(path=urllib.quote(request.path, safe=':/')+'/'))
+ 
+         def setHeaders(response):
+             response = IResponse(response)

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.static.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.static.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.static.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,161 +0,0 @@
-Index: twisted/web2/dav/static.py
-===================================================================
---- twisted/web2/dav/static.py	(revision 19773)
-+++ twisted/web2/dav/static.py	(working copy)
-@@ -28,16 +28,17 @@
- 
- __all__ = ["DAVFile"]
- 
--import os
--
-+from twisted.internet.defer import succeed, deferredGenerator, waitForDeferred
-+from twisted.python.filepath import InsecurePath
- from twisted.python import log
--from twisted.internet.defer import succeed, deferredGenerator, waitForDeferred
--from twisted.web2.static import File
-+from twisted.web2 import http_headers
- from twisted.web2 import responsecode, dirlist
--from twisted.web2.http import RedirectResponse
- from twisted.web2.dav import davxml
- from twisted.web2.dav.resource import DAVResource, davPrivilegeSet
-+from twisted.web2.dav.resource import TwistedGETContentMD5
- from twisted.web2.dav.util import bindMethods
-+from twisted.web2.http import HTTPError, StatusResponse, RedirectResponse
-+from twisted.web2.static import File
- 
- try:
-     from twisted.web2.dav.xattrprops import xattrPropertyStore as DeadPropertyStore
-@@ -52,9 +53,11 @@
- 
-     Extends twisted.web2.static.File to handle WebDAV methods.
-     """
--    def __init__(self, path,
--                 defaultType="text/plain",
--                 indexNames=None):
-+    def __init__(
-+        self, path,
-+        defaultType="text/plain", indexNames=None,
-+        principalCollections=()
-+    ):
-         """
-         @param path: the path of the file backing this resource.
-         @param defaultType: the default mime type (as a string) for this
-@@ -62,11 +65,14 @@
-         @param indexNames: a sequence of index file names.
-         @param acl: an L{IDAVAccessControlList} with the .
-         """
--        super(DAVFile, self).__init__(path,
--                                      defaultType = defaultType,
--                                      ignoredExts = (),
--                                      processors  = None,
--                                      indexNames  = indexNames)
-+        File.__init__(
-+            self, path,
-+            defaultType = defaultType,
-+            ignoredExts = (),
-+            processors = None,
-+            indexNames = indexNames,
-+        )
-+        DAVResource.__init__(self, principalCollections=principalCollections)
- 
-     def __repr__(self):
-         return "<%s: %s>" % (self.__class__.__name__, self.fp.path)
-@@ -75,6 +81,13 @@
-     # WebDAV
-     ##
- 
-+    def etag(self):
-+        if not self.fp.exists(): return None
-+        if self.hasDeadProperty(TwistedGETContentMD5):
-+            return http_headers.ETag(str(self.readDeadProperty(TwistedGETContentMD5)))
-+        else:
-+            return super(DAVFile, self).etag()
-+
-     def davComplianceClasses(self):
-         return ("1", "access-control") # Add "2" when we have locking
- 
-@@ -87,7 +100,6 @@
-         """
-         See L{IDAVResource.isCollection}.
-         """
--        for child in self.listChildren(): return True
-         return self.fp.isdir()
- 
-     ##
-@@ -98,6 +110,50 @@
-         return succeed(davPrivilegeSet)
- 
-     ##
-+    # Quota
-+    ##
-+
-+    def quotaSize(self, request):
-+        """
-+        Get the size of this resource.
-+        TODO: Take into account size of dead-properties. Does stat
-+            include xattrs size?
-+
-+        @return: an L{Deferred} with a C{int} result containing the size of the resource.
-+        """
-+        if self.isCollection():
-+            def walktree(top):
-+                """
-+                Recursively descend the directory tree rooted at top,
-+                calling the callback function for each regular file
-+                
-+                @param top: L{FilePath} for the directory to walk.
-+                """
-+            
-+                total = 0
-+                for f in top.listdir():
-+                    child = top.child(f)
-+                    if child.isdir():
-+                        # It's a directory, recurse into it
-+                        result = waitForDeferred(walktree(child))
-+                        yield result
-+                        total += result.getResult()
-+                    elif child.isfile():
-+                        # It's a file, call the callback function
-+                        total += child.getsize()
-+                    else:
-+                        # Unknown file type, print a message
-+                        pass
-+            
-+                yield total
-+            
-+            walktree = deferredGenerator(walktree)
-+    
-+            return walktree(self.fp)
-+        else:
-+            return succeed(self.fp.getsize())
-+
-+    ##
-     # Workarounds for issues with File
-     ##
- 
-@@ -112,8 +168,12 @@
-         See L{IResource}C{.locateChild}.
-         """
-         # If getChild() finds a child resource, return it
--        child = self.getChild(segments[0])
--        if child is not None: return (child, segments[1:])
-+        try:
-+            child = self.getChild(segments[0])
-+            if child is not None:
-+                return (child, segments[1:])
-+        except InsecurePath:
-+            raise HTTPError(StatusResponse(responsecode.FORBIDDEN, "Invalid URL path"))
-         
-         # If we're not backed by a directory, we have no children.
-         # But check for existance first; we might be a collection resource
-@@ -132,7 +192,9 @@
-         return (self.createSimilarFile(self.fp.child(path).path), segments[1:])
- 
-     def createSimilarFile(self, path):
--        return self.__class__(path, defaultType=self.defaultType, indexNames=self.indexNames[:])
-+        return self.__class__(
-+            path, defaultType=self.defaultType, indexNames=self.indexNames[:],
-+            principalCollections=self.principalCollections())
- 
- #
- # Attach method handlers to DAVFile

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.stream.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.stream.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.stream.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,84 +0,0 @@
-Index: twisted/web2/dav/stream.py
-===================================================================
---- twisted/web2/dav/stream.py	(revision 0)
-+++ twisted/web2/dav/stream.py	(revision 0)
-@@ -0,0 +1,79 @@
-+##
-+# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
-+#
-+# Permission is hereby granted, free of charge, to any person obtaining a copy
-+# of this software and associated documentation files (the "Software"), to deal
-+# in the Software without restriction, including without limitation the rights
-+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+# copies of the Software, and to permit persons to whom the Software is
-+# furnished to do so, subject to the following conditions:
-+# 
-+# The above copyright notice and this permission notice shall be included in all
-+# copies or substantial portions of the Software.
-+# 
-+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+# SOFTWARE.
-+#
-+# DRI: Cyrus Daboo, cdaboo at apple.com
-+##
-+
-+"""
-+Class that implements a stream that calculates the MD5 hash of the data
-+as the data is read.
-+"""
-+
-+__all__ = ["MD5StreamWrapper"]
-+
-+from twisted.internet.defer import Deferred
-+from twisted.web2.stream import SimpleStream
-+
-+try:
-+    from hashlib import md5
-+except ImportError:
-+    from md5 import new as md5
-+
-+class MD5StreamWrapper(SimpleStream):
-+ 
-+    def __init__(self, wrap):
-+        
-+        assert wrap is not None, "Must have a stream to wrap."
-+
-+        self.stream = wrap
-+
-+        # Init MD5
-+        self.md5 = md5()
-+    
-+    def read(self):
-+        assert self.md5 is not None, "Cannot call read after close."
-+
-+        # Read from wrapped stream first
-+        b = self.stream.read()
-+        
-+        if isinstance(b, Deferred):
-+            def _gotData(data):
-+                if data is not None:
-+                    self.md5.update(data)
-+                return data
-+            b.addCallback(_gotData)
-+        else:
-+            # Update current MD5 state
-+            if b is not None:
-+                self.md5.update(str(b))
-+    
-+        return b
-+    
-+    def close(self):
-+        # Close out the MD5 hash
-+        self.md5value = self.md5.hexdigest()
-+        self.md5 = None
-+
-+        SimpleStream.close(self)
-+    
-+    def getMD5(self):
-+        assert hasattr(self, "md5value"), "Stream has to be closed first"
-+        return self.md5value

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.data.quota_100.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.data.quota_100.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.data.quota_100.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,15 +0,0 @@
-Index: twisted/web2/dav/test/data/quota_100.txt
-===================================================================
---- twisted/web2/dav/test/data/quota_100.txt	(revision 0)
-+++ twisted/web2/dav/test/data/quota_100.txt	(revision 0)
-@@ -0,0 +1,10 @@
-+123456789
-+123456789
-+123456789
-+123456789
-+123456789
-+123456789
-+123456789
-+123456789
-+123456789
-+123456789

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,108 +0,0 @@
-Index: twisted/web2/dav/test/test_acl.py
-===================================================================
---- twisted/web2/dav/test/test_acl.py	(revision 19773)
-+++ twisted/web2/dav/test/test_acl.py	(working copy)
-@@ -30,6 +30,7 @@
- from twisted.web2.auth import basic
- from twisted.web2.stream import MemoryStream
- from twisted.web2.dav import davxml
-+from twisted.web2.dav.resource import DAVPrincipalCollectionResource
- from twisted.web2.dav.util import davXMLFromStream
- from twisted.web2.dav.auth import TwistedPasswordProperty, IPrincipal, DavRealm, TwistedPropertyChecker, AuthenticationWrapper
- 
-@@ -38,6 +39,25 @@
- from twisted.web2.dav.test.util import Site, serialize
- from twisted.web2.dav.test.test_resource import TestResource, TestDAVPrincipalResource
- 
-+class TestPrincipalsCollection(DAVPrincipalCollectionResource, TestResource):
-+    def __init__(self, url, children):
-+        DAVPrincipalCollectionResource.__init__(self, url)
-+        TestResource.__init__(self, url, children, principalCollections=(self,))
-+    
-+    def principalForUser(self, user):
-+        return self.principalForShortName('users', user)
-+
-+    def principalForAuthID(self, creds):
-+        return self.principalForShortName('users', creds.username)
-+
-+    def principalForShortName(self, type, shortName):
-+        typeResource = self.children.get(type, None)
-+        user = None
-+        if typeResource:
-+            user = typeResource.children.get(shortName, None)
-+
-+        return user
-+
- class ACL(twisted.web2.dav.test.util.TestCase):
-     """
-     RFC 3744 (WebDAV ACL) tests.
-@@ -46,8 +66,18 @@
-         if not hasattr(self, "docroot"):
-             self.docroot = self.mktemp()
-             os.mkdir(self.docroot)
--            rootresource = self.resource_class(self.docroot)
- 
-+            userResource = TestDAVPrincipalResource("/principals/users/user01")
-+            userResource.writeDeadProperty(TwistedPasswordProperty("user01"))
-+
-+            principalCollection = TestPrincipalsCollection(
-+                "/principals/", 
-+                children={"users": TestPrincipalsCollection(
-+                        "/principals/users/",
-+                        children={"user01": userResource})})
-+
-+            rootResource = self.resource_class(self.docroot, principalCollections=(principalCollection,))
-+
-             portal = Portal(DavRealm())
-             portal.registerChecker(TwistedPropertyChecker())
- 
-@@ -56,26 +86,14 @@
-             loginInterfaces = (IPrincipal,)
- 
-             self.site = Site(AuthenticationWrapper(
--                rootresource, 
-+                rootResource, 
-                 portal,
-                 credentialFactories,
-                 loginInterfaces
-             ))
- 
--            rootresource.setAccessControlList(self.grant(davxml.All()))
-+            rootResource.setAccessControlList(self.grant(davxml.All()))
- 
--            userresource = TestDAVPrincipalResource("/principals/user01")
--            userresource.writeDeadProperty(TwistedPasswordProperty.fromString("user01"))
--
--            rootresource.putChild(
--                "principals",
--                TestResource("/principals", {"user01": userresource})
--            )
--
--            rootresource.writeDeadProperty(
--                davxml.PrincipalCollectionSet(davxml.HRef("/principals/"))
--            )
--
-         for name, acl in (
-             ("none"       , self.grant()),
-             ("read"       , self.grant(davxml.Read())),
-@@ -361,9 +379,7 @@
-                 if method == "GET":
-                     ok = responsecode.OK
-                 elif method == "REPORT":
--                    # BAD_REQUEST in the allowed case, because we're not actually
--                    # including the required XML in the request body.
--                    ok = responsecode.BAD_REQUEST
-+                    ok = responsecode.MULTI_STATUS
-                 else:
-                     raise AssertionError("We shouldn't be here.  (method = %r)" % (method,))
- 
-@@ -377,6 +393,9 @@
-                     path = os.path.join(self.docroot, name)
- 
-                     request = SimpleRequest(self.site, method, "/" + name)
-+                    if method == "REPORT":
-+                        request.stream = MemoryStream(davxml.PrincipalPropertySearch().toxml())
-+
-                     _add_auth_header(request)
- 
-                     def test(response, code=code, path=path):

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_copy.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_copy.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_copy.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,24 +0,0 @@
-Index: twisted/web2/dav/test/test_copy.py
-===================================================================
---- twisted/web2/dav/test/test_copy.py	(revision 19773)
-+++ twisted/web2/dav/test/test_copy.py	(working copy)
-@@ -22,9 +22,9 @@
- # DRI: Wilfredo Sanchez, wsanchez at apple.com
- ##
- 
-+from hashlib import md5
- import os
- import urllib
--import md5
- 
- import twisted.web2.dav.test.util
- from twisted.web2 import responsecode
-@@ -161,7 +161,7 @@
-             yield (request, do_test)
- 
- def sumFile(path):
--    m = md5.new()
-+    m = md5()
- 
-     if os.path.isfile(path):
-         f = file(path)

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_pipeline.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_pipeline.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_pipeline.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,74 +0,0 @@
-Index: twisted/web2/dav/test/test_pipeline.py
-===================================================================
---- twisted/web2/dav/test/test_pipeline.py	(revision 0)
-+++ twisted/web2/dav/test/test_pipeline.py	(revision 0)
-@@ -0,0 +1,69 @@
-+##
-+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
-+#
-+# Permission is hereby granted, free of charge, to any person obtaining a copy
-+# of this software and associated documentation files (the "Software"), to deal
-+# in the Software without restriction, including without limitation the rights
-+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+# copies of the Software, and to permit persons to whom the Software is
-+# furnished to do so, subject to the following conditions:
-+# 
-+# The above copyright notice and this permission notice shall be included in all
-+# copies or substantial portions of the Software.
-+# 
-+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+# SOFTWARE.
-+#
-+# DRI: Wilfredo Sanchez, wsanchez at apple.com
-+##
-+from twisted.internet import utils
-+from twisted.web2.test import test_server
-+from twisted.web2 import resource
-+from twisted.web2 import http
-+from twisted.web2.test import test_http
-+import sys
-+
-+from twisted.internet.defer import waitForDeferred, deferredGenerator
-+
-+from twisted.python import util
-+
-+class Pipeline(test_server.BaseCase):
-+    """
-+    Pipelined request
-+    """
-+    class TestResource(resource.LeafResource):
-+        def render(self, req):
-+            return http.Response(stream="Host:%s, Path:%s"%(req.host, req.path))
-+            
-+    def setUp(self):
-+        self.root = self.TestResource()
-+
-+    def chanrequest(self, root, uri, length, headers, method, version, prepath, content):
-+        self.cr = super(Pipeline, self).chanrequest(root, uri, length, headers, method, version, prepath, content)
-+        return self.cr
-+
-+    def test_root(self):
-+        
-+        def _testStreamRead(x):
-+            self.assertTrue(self.cr.request.stream.length == 0)
-+
-+        return self.assertResponse(
-+            (self.root, 'http://host/path', {"content-type":"text/plain",}, "PUT", None, '', "This is some text."),
-+            (405, {}, None)).addCallback(_testStreamRead)
-+
-+class SSLPipeline(test_http.SSLServerTest):
-+
-+    @deferredGenerator
-+    def testAdvancedWorkingness(self):
-+        args = ('-u', util.sibpath(__file__, "tworequest_client.py"), "basic",
-+                str(self.port), self.type)
-+        d = waitForDeferred(utils.getProcessOutputAndValue(sys.executable, args=args))
-+        yield d; out,err,code = d.getResult()
-+
-+        self.assertEquals(code, 0, "Error output:\n%s" % (err,))
-+        self.assertEquals(out, "HTTP/1.1 403 Forbidden\r\nContent-Length: 0\r\n\r\nHTTP/1.1 403 Forbidden\r\nContent-Length: 0\r\n\r\n")

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_prop.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_prop.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_prop.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,69 +0,0 @@
-Index: twisted/web2/dav/test/test_prop.py
-===================================================================
---- twisted/web2/dav/test/test_prop.py	(revision 19773)
-+++ twisted/web2/dav/test/test_prop.py	(working copy)
-@@ -21,6 +21,8 @@
- #
- # DRI: Wilfredo Sanchez, wsanchez at apple.com
- ##
-+from twisted.web2.dav.element.rfc4331 import QuotaUsedBytes
-+from twisted.web2.dav.element.rfc4331 import QuotaAvailableBytes
- 
- import random
- 
-@@ -37,8 +39,13 @@
- from twisted.web2.dav.test.util import serialize
- import twisted.web2.dav.test.util
- 
--live_properties = [lookupElement(qname)() for qname in DAVResource.liveProperties if qname[0] == dav_namespace]
-+# Remove dynamic live properties that exist
-+dynamicLiveProperties = (
-+    (dav_namespace, "quota-available-bytes"     ),
-+    (dav_namespace, "quota-used-bytes"          ),
-+)
- 
-+
- #
- # See whether dead properties are available
- #
-@@ -49,6 +56,10 @@
-     """
-     PROPFIND, PROPPATCH requests
-     """
-+
-+    def liveProperties(self):
-+        return [lookupElement(qname)() for qname in self.resource_class.liveProperties if (qname[0] == dav_namespace) and qname not in dynamicLiveProperties]
-+
-     def test_PROPFIND_basic(self):
-         """
-         PROPFIND request
-@@ -85,7 +96,7 @@
-                             self.fail("PROPFIND failed (status %s) to locate live properties: %s"
-                                       % (status.code, properties))
- 
--                        properties_to_find = [p.qname() for p in live_properties]
-+                        properties_to_find = [p.qname() for p in self.liveProperties()]
- 
-                         for property in properties:
-                             qname = property.qname()
-@@ -102,7 +113,7 @@
-             else:
-                 self.fail("No response for URI /")
- 
--        query = davxml.PropertyFind(davxml.PropertyContainer(*live_properties))
-+        query = davxml.PropertyFind(davxml.PropertyContainer(*self.liveProperties()))
- 
-         request = SimpleRequest(self.site, "PROPFIND", "/")
- 
-@@ -146,9 +157,9 @@
-                               % (status.code, properties))
- 
-                 if which.name == "allprop":
--                    properties_to_find = [p.qname() for p in live_properties if not p.hidden]
-+                    properties_to_find = [p.qname() for p in self.liveProperties() if not p.hidden]
-                 else:
--                    properties_to_find = [p.qname() for p in live_properties]
-+                    properties_to_find = [p.qname() for p in self.liveProperties()]
- 
-                 for property in properties:
-                     qname = property.qname()

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_quota.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_quota.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_quota.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,206 +0,0 @@
-Index: twisted/web2/dav/test/test_quota.py
-===================================================================
---- twisted/web2/dav/test/test_quota.py	(revision 0)
-+++ twisted/web2/dav/test/test_quota.py	(revision 0)
-@@ -0,0 +1,201 @@
-+##
-+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
-+#
-+# Permission is hereby granted, free of charge, to any person obtaining a copy
-+# of this software and associated documentation files (the "Software"), to deal
-+# in the Software without restriction, including without limitation the rights
-+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+# copies of the Software, and to permit persons to whom the Software is
-+# furnished to do so, subject to the following conditions:
-+# 
-+# The above copyright notice and this permission notice shall be included in all
-+# copies or substantial portions of the Software.
-+# 
-+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+# SOFTWARE.
-+#
-+# DRI: Wilfredo Sanchez, wsanchez at apple.com
-+##
-+
-+from twisted.web2 import responsecode
-+from twisted.web2.iweb import IResponse
-+from twisted.web2.stream import FileStream
-+
-+import twisted.web2.dav.test.util
-+from twisted.web2.test.test_server import SimpleRequest
-+from twisted.web2.dav.test.util import Site
-+from twisted.web2.dav import davxml
-+import os
-+
-+class QuotaBase(twisted.web2.dav.test.util.TestCase):
-+
-+    def setUp(self):
-+        
-+        #super(Quota, self).setUp()
-+        self.docroot = self.mktemp()
-+        os.mkdir(self.docroot)
-+        rootresource = self.resource_class(self.docroot)
-+        rootresource.setAccessControlList(self.grantInherit(davxml.All()))
-+        self.site = Site(rootresource)
-+        self.site.resource.setQuotaRoot(None, 100000)
-+
-+    def checkQuota(self, value):
-+        def _defer(quota):
-+            self.assertEqual(quota, value)
-+            
-+        d = self.site.resource.currentQuotaUse(None)
-+        d.addCallback(_defer)
-+        return d
-+        
-+class QuotaEmpty(QuotaBase):
-+
-+    def test_Empty_Quota(self):
-+        
-+        return self.checkQuota(0)
-+
-+class QuotaPUT(QuotaBase):
-+
-+    def test_Quota_PUT(self):
-+        """
-+        Quota change on PUT
-+        """
-+        dst_uri = "/dst"
-+
-+        def checkResult(response):
-+            response = IResponse(response)
-+
-+            if response.code != responsecode.CREATED:
-+                self.fail("Incorrect response code for PUT (%s != %s)"
-+                          % (response.code, responsecode.CREATED))
-+                
-+            return self.checkQuota(100)
-+
-+        request = SimpleRequest(self.site, "PUT", dst_uri)
-+        request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb"))        
-+        return self.send(request, checkResult)
-+
-+class QuotaDELETE(QuotaBase):
-+
-+    def test_Quota_DELETE(self):
-+        """
-+        Quota change on DELETE
-+        """
-+        dst_uri = "/dst"
-+
-+        def checkPUTResult(response):
-+            response = IResponse(response)
-+
-+            if response.code != responsecode.CREATED:
-+                self.fail("Incorrect response code for PUT (%s != %s)"
-+                          % (response.code, responsecode.CREATED))
-+            
-+            def doDelete(_ignore):
-+                def checkDELETEResult(response):
-+                    response = IResponse(response)
-+        
-+                    if response.code != responsecode.NO_CONTENT:
-+                        self.fail("Incorrect response code for PUT (%s != %s)"
-+                                  % (response.code, responsecode.NO_CONTENT))
-+
-+                    return self.checkQuota(0)
-+                    
-+                request = SimpleRequest(self.site, "DELETE", dst_uri)
-+                return self.send(request, checkDELETEResult)
-+                
-+            d = self.checkQuota(100)
-+            d.addCallback(doDelete)
-+            return d
-+
-+        request = SimpleRequest(self.site, "PUT", dst_uri)
-+        request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb"))        
-+        return self.send(request, checkPUTResult)
-+
-+class OverQuotaPUT(QuotaBase):
-+
-+    def test_Quota_PUT(self):
-+        """
-+        Quota change on PUT
-+        """
-+        dst_uri = "/dst"
-+
-+        self.site.resource.setQuotaRoot(None, 90)
-+
-+        def checkResult(response):
-+            response = IResponse(response)
-+
-+            if response.code != responsecode.INSUFFICIENT_STORAGE_SPACE:
-+                self.fail("Incorrect response code for PUT (%s != %s)"
-+                          % (response.code, responsecode.INSUFFICIENT_STORAGE_SPACE))
-+                
-+            return self.checkQuota(0)
-+
-+        request = SimpleRequest(self.site, "PUT", dst_uri)
-+        request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb"))        
-+        return self.send(request, checkResult)
-+
-+class QuotaOKAdjustment(QuotaBase):
-+
-+    def test_Quota_OK_Adjustment(self):
-+        """
-+        Quota adjustment OK
-+        """
-+        dst_uri = "/dst"
-+
-+        def checkPUTResult(response):
-+            response = IResponse(response)
-+
-+            if response.code != responsecode.CREATED:
-+                self.fail("Incorrect response code for PUT (%s != %s)"
-+                          % (response.code, responsecode.CREATED))
-+            
-+            def doOKAdjustment(_ignore):
-+                def checkAdjustmentResult(_ignore):
-+                    return self.checkQuota(10)
-+                
-+                d = self.site.resource.quotaSizeAdjust(None, -90)
-+                d.addCallback(checkAdjustmentResult)
-+                return d
-+                
-+            d = self.checkQuota(100)
-+            d.addCallback(doOKAdjustment)
-+            return d
-+
-+        request = SimpleRequest(self.site, "PUT", dst_uri)
-+        request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb"))        
-+        return self.send(request, checkPUTResult)
-+
-+class QuotaBadAdjustment(QuotaBase):
-+
-+    def test_Quota_Bad_Adjustment(self):
-+        """
-+        Quota adjustment too much
-+        """
-+        dst_uri = "/dst"
-+
-+        def checkPUTResult(response):
-+            response = IResponse(response)
-+
-+            if response.code != responsecode.CREATED:
-+                self.fail("Incorrect response code for PUT (%s != %s)"
-+                          % (response.code, responsecode.CREATED))
-+            
-+            def doBadAdjustment(_ignore):
-+                def checkAdjustmentResult(_ignore):
-+                    return self.checkQuota(100)
-+                
-+                d = self.site.resource.quotaSizeAdjust(None, -200)
-+                d.addCallback(checkAdjustmentResult)
-+                return d
-+                
-+            d = self.checkQuota(100)
-+            d.addCallback(doBadAdjustment)
-+            return d
-+
-+        request = SimpleRequest(self.site, "PUT", dst_uri)
-+        request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb"))        
-+        return self.send(request, checkPUTResult)

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,102 +0,0 @@
-Index: twisted/web2/dav/test/test_resource.py
-===================================================================
---- twisted/web2/dav/test/test_resource.py	(revision 19773)
-+++ twisted/web2/dav/test/test_resource.py	(working copy)
-@@ -192,13 +192,10 @@
- class AccessTests(TestCase):
-     def setUp(self):
-         gooduser = TestDAVPrincipalResource('/users/gooduser')
-+        gooduser.writeDeadProperty(TwistedPasswordProperty('goodpass'))
- 
--        gooduser.writeDeadProperty(
--            TwistedPasswordProperty.fromString('goodpass'))
--
-         baduser = TestDAVPrincipalResource('/users/baduser')
--        baduser.writeDeadProperty(
--            TwistedPasswordProperty.fromString('badpass'))
-+        baduser.writeDeadProperty(TwistedPasswordProperty('badpass'))
- 
-         protected = TestResource('/protected')
-         protected.setAccessControlList(davxml.ACL(
-@@ -282,7 +279,8 @@
-         # Has auth; should allow
- 
-         request = SimpleRequest(site, "GET", "/")
--        request.user = davxml.Principal(davxml.HRef("/users/d00d"))
-+        request.authnUser = davxml.Principal(davxml.HRef("/users/d00d"))
-+        request.authzUser = davxml.Principal(davxml.HRef("/users/d00d"))
-         d = request.locateResource('/')
-         d.addCallback(_checkPrivileges)
-         d.addCallback(expectOK)
-@@ -301,6 +299,8 @@
-                       
-         return self.checkSecurity(request)
- 
-+    test_authorize.todo = "Needs refactoring"
-+
-     def test_badUsernameOrPassword(self):
-         request = SimpleRequest(self.site, 'GET', '/protected')
- 
-@@ -316,6 +316,8 @@
- 
-         return d
- 
-+    test_badUsernameOrPassword.todo = "Needs refactoring."
-+
-     def test_lacksPrivileges(self):
-         request = SimpleRequest(self.site, 'GET', '/protected')
- 
-@@ -348,12 +350,12 @@
-             davxml.Grant(davxml.Privilege(davxml.All())),
-             davxml.Protected()))
- 
--    def __init__(self, uri=None, children=None):
-+    def __init__(self, uri=None, children=None, principalCollections=()):
-         """
-         @param uri: A string respresenting the URI of the given resource
-         @param children: a dictionary of names to Resources
-         """
--
-+        DAVResource.__init__(self, principalCollections=principalCollections)
-         self.children = children
-         self.uri = uri
- 
-@@ -380,8 +382,8 @@
-         return succeed(davPrivilegeSet)
- 
-     def currentPrincipal(self, request):
--        if hasattr(request, "user"):
--            return request.user
-+        if hasattr(request, "authzUser"):
-+            return request.authzUser
-         else:
-             return davxml.Principal(davxml.Unauthenticated())
- 
-@@ -399,18 +401,21 @@
- 
-     def accessControlList(self, request, **kwargs):
-         return succeed(self.acl)
--    
- 
- class AuthAllResource (TestResource):
--    """Give Authenticated principals all privileges deny everything else
-     """
-+    Give Authenticated principals all privileges and deny everyone else.
-+    """
-     acl = davxml.ACL(
-         davxml.ACE(
-             davxml.Principal(davxml.Authenticated()),
-             davxml.Grant(davxml.Privilege(davxml.All())),
--            davxml.Protected()))
--
-+            davxml.Protected()
-+        )
-+    )
-     
- class TestDAVPrincipalResource(DAVPrincipalResource, TestResource):
--    """Get deadProperties from TestResource
--    """
-+    # Get dead properties from TestResource
-+
-+    def principalURL(self):
-+        return self.uri

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_static.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_static.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_static.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,10 +0,0 @@
-Index: twisted/web2/dav/test/test_static.py
-===================================================================
---- twisted/web2/dav/test/test_static.py	(revision 19773)
-+++ twisted/web2/dav/test/test_static.py	(working copy)
-@@ -60,3 +60,5 @@
-         d.addCallback(assertListing)
- 
-         return d
-+
-+    test_renderPrivileges.todo = "We changed the rules here; test needs an update"

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_stream.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_stream.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_stream.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,56 +0,0 @@
-Index: twisted/web2/dav/test/test_stream.py
-===================================================================
---- twisted/web2/dav/test/test_stream.py	(revision 0)
-+++ twisted/web2/dav/test/test_stream.py	(revision 0)
-@@ -0,0 +1,51 @@
-+##
-+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
-+#
-+# Permission is hereby granted, free of charge, to any person obtaining a copy
-+# of this software and associated documentation files (the "Software"), to deal
-+# in the Software without restriction, including without limitation the rights
-+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+# copies of the Software, and to permit persons to whom the Software is
-+# furnished to do so, subject to the following conditions:
-+# 
-+# The above copyright notice and this permission notice shall be included in all
-+# copies or substantial portions of the Software.
-+# 
-+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+# SOFTWARE.
-+##
-+
-+from twisted.trial import unittest
-+from twisted.web2.stream import MemoryStream
-+from twisted.web2.dav.stream import MD5StreamWrapper
-+import md5
-+
-+class Stream(unittest.TestCase):
-+    """
-+    MD5StreamWrapper tests.
-+    """
-+    def test_simple(self):
-+        """
-+        Simple test
-+        """
-+        
-+        data = """I am sorry Dave, I can't do that.
-+--HAL 9000
-+"""
-+
-+        datastream = MemoryStream(data)
-+        stream = MD5StreamWrapper(datastream)
-+        
-+        while stream.read() is not None:
-+            pass
-+        stream.close()
-+
-+        m = md5.new()
-+        m.update(data)
-+        
-+        self.assertEqual(m.hexdigest(), stream.getMD5())

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_xml.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_xml.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.test_xml.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,88 +0,0 @@
-Index: twisted/web2/dav/test/test_xml.py
-===================================================================
---- twisted/web2/dav/test/test_xml.py	(revision 0)
-+++ twisted/web2/dav/test/test_xml.py	(revision 0)
-@@ -0,0 +1,83 @@
-+##
-+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
-+#
-+# Permission is hereby granted, free of charge, to any person obtaining a copy
-+# of this software and associated documentation files (the "Software"), to deal
-+# in the Software without restriction, including without limitation the rights
-+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+# copies of the Software, and to permit persons to whom the Software is
-+# furnished to do so, subject to the following conditions:
-+# 
-+# The above copyright notice and this permission notice shall be included in all
-+# copies or substantial portions of the Software.
-+# 
-+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+# SOFTWARE.
-+##
-+
-+from twisted.trial import unittest
-+from twisted.web2.dav import davxml
-+
-+class XML(unittest.TestCase):
-+    """
-+    XML tests.
-+    """
-+    def test_parse(self):
-+        """
-+        Simple parsing
-+        """
-+        doc = davxml.WebDAVDocument.fromString(
-+            """<?xml version="1.0" encoding="utf-8" ?>"""
-+            """<D:multistatus xmlns:D="DAV:">"""
-+            """  <D:response>"""
-+            """    <D:href>http://webdav.sb.aol.com/webdav/secret</D:href>"""
-+            """    <D:status>HTTP/1.1 403 Forbidden</D:status>"""
-+            """  </D:response>"""
-+            """</D:multistatus>"""
-+        )
-+        self.assertEquals(
-+            doc,
-+            davxml.WebDAVDocument(
-+                davxml.MultiStatus(
-+                    davxml.Response(
-+                        davxml.HRef("http://webdav.sb.aol.com/webdav/secret"),
-+                        davxml.Status("HTTP/1.1 403 Forbidden"),
-+                    )
-+                )
-+            )
-+        )
-+
-+    def test_serialize_unserialize(self):
-+        """
-+        Serialization and unserialization results in equivalent document.
-+        """
-+        doc = davxml.WebDAVDocument(
-+            davxml.MultiStatus(
-+                davxml.Response(
-+                    davxml.HRef("http://webdav.sb.aol.com/webdav/secret"),
-+                    davxml.Status("HTTP/1.1 403 Forbidden"),
-+                )
-+            )
-+        )
-+        self.assertEquals(doc, davxml.WebDAVDocument.fromString(doc.toxml()))
-+
-+    def test_unknownElement(self):
-+        """
-+        Serialization and unserialization of unknown element.
-+        """
-+        doc = davxml.WebDAVDocument.fromString(
-+            """<?xml version="1.0" encoding="utf-8" ?>"""
-+            """<T:foo xmlns:T="http://twistedmatrix.com/"/>"""
-+        )
-+
-+        foo = davxml.WebDAVUnknownElement()
-+        foo.namespace = "http://twistedmatrix.com/"
-+        foo.name = "foo"
-+
-+        self.assertEquals(doc, davxml.WebDAVDocument(foo))
-+        self.assertEquals(doc, davxml.WebDAVDocument.fromString(doc.toxml()))

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.tworequest_client.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.tworequest_client.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.tworequest_client.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,52 +0,0 @@
-Index: twisted/web2/dav/test/tworequest_client.py
-===================================================================
---- twisted/web2/dav/test/tworequest_client.py	(revision 0)
-+++ twisted/web2/dav/test/tworequest_client.py	(revision 0)
-@@ -0,0 +1,47 @@
-+import socket, sys
-+
-+test_type = sys.argv[1]
-+port = int(sys.argv[2])
-+socket_type = sys.argv[3]
-+
-+s = socket.socket(socket.AF_INET)
-+s.connect(("127.0.0.1", port))
-+s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 40000)
-+
-+if socket_type == 'ssl':
-+    s2 = socket.ssl(s)
-+    send=s2.write
-+    recv=s2.read
-+else:
-+    send=s.send
-+    recv=s.recv
-+    
-+print >> sys.stderr, ">> Making %s request to port %d" % (socket_type, port)
-+
-+send("PUT /forbidden HTTP/1.1\r\n")
-+send("Host: localhost\r\n")
-+
-+print >> sys.stderr, ">> Sending lots of data"
-+send("Content-Length: 100\r\n\r\n")
-+send("X"*100)
-+
-+send("PUT /forbidden HTTP/1.1\r\n")
-+send("Host: localhost\r\n")
-+
-+print >> sys.stderr, ">> Sending lots of data"
-+send("Content-Length: 100\r\n\r\n")
-+send("X"*100)
-+
-+#import time
-+#time.sleep(5)
-+print >> sys.stderr, ">> Getting data"
-+data=''
-+while len(data) < 299999:
-+    try:
-+        x=recv(10000)
-+    except:
-+        break
-+    if x == '':
-+        break
-+    data+=x
-+sys.stdout.write(data)

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.util.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.util.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.test.util.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,20 +0,0 @@
-Index: twisted/web2/dav/test/util.py
-===================================================================
---- twisted/web2/dav/test/util.py	(revision 19773)
-+++ twisted/web2/dav/test/util.py	(working copy)
-@@ -184,10 +184,11 @@
-         d.addCallback(lambda resource: resource.renderHTTP(request))
-         d.addCallback(request._cbFinishRender)
- 
--        if type(callback) is tuple:
--            d.addCallbacks(*callback)
--        else:
--            d.addCallback(callback)
-+        if callback:
-+            if type(callback) is tuple:
-+                d.addCallbacks(*callback)
-+            else:
-+                d.addCallback(callback)
- 
-         return d
- 

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.util.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.util.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.util.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,23 +0,0 @@
-Index: twisted/web2/dav/util.py
-===================================================================
---- twisted/web2/dav/util.py	(revision 19773)
-+++ twisted/web2/dav/util.py	(working copy)
-@@ -37,6 +37,7 @@
-     "normalizeURL",
-     "joinURL",
-     "parentForURL",
-+    "unimplemented",
-     "bindMethods",
- ]
- 
-@@ -76,7 +77,9 @@
- 
-     def parse(xml):
-         try:
--            return davxml.WebDAVDocument.fromString(xml)
-+            doc = davxml.WebDAVDocument.fromString(xml)
-+            doc.root_element.validate()
-+            return doc
-         except ValueError:
-             log.err("Bad XML:\n%s" % (xml,))
-             raise

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.xattrprops.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.xattrprops.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.xattrprops.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,169 +0,0 @@
-Index: twisted/web2/dav/xattrprops.py
-===================================================================
---- twisted/web2/dav/xattrprops.py	(revision 19773)
-+++ twisted/web2/dav/xattrprops.py	(working copy)
-@@ -33,15 +33,24 @@
- 
- import urllib
- import sys
-+import zlib
-+from time import sleep
-+from random import random
-+from errno import EAGAIN
-+from zlib import compress, decompress
-+from cPickle import loads as unpickle, PicklingError, UnpicklingError
- 
- import xattr
- 
- if getattr(xattr, 'xattr', None) is None:
-     raise ImportError("wrong xattr package imported")
- 
-+from twisted.python import log
-+from twisted.python.failure import Failure
- from twisted.web2 import responsecode
- from twisted.web2.http import HTTPError, StatusResponse
- from twisted.web2.dav import davxml
-+from twisted.web2.dav.http import statusForFailure
- 
- class xattrPropertyStore (object):
-     """
-@@ -66,16 +75,8 @@
-         deadPropertyXattrPrefix = "user."
- 
-     def _encode(clazz, name):
--        #
--        # FIXME: The xattr API in Mac OS 10.4.2 breaks if you have "/" in an
--        # attribute name (radar://4202440). We'll quote the strings to get rid
--        # of "/" characters for now.
--        #
--        result = list("{%s}%s" % name)
--        for i in range(len(result)):
--            c = result[i]
--            if c in "%/": result[i] = "%%%02X" % (ord(c),)
--        r = clazz.deadPropertyXattrPrefix + ''.join(result)
-+        result = urllib.quote("{%s}%s" % name, safe='{}:')
-+        r = clazz.deadPropertyXattrPrefix + result
-         return r
- 
-     def _decode(clazz, name):
-@@ -97,19 +98,83 @@
- 
-     def get(self, qname):
-         try:
--            value = self.attrs[self._encode(qname)]
-+            data = self.attrs[self._encode(qname)]
-         except KeyError:
-             raise HTTPError(StatusResponse(
-                 responsecode.NOT_FOUND,
-                 "No such property: {%s}%s" % qname
-             ))
-+        except Exception, e:
-+            raise HTTPError(StatusResponse(
-+                statusForFailure(Failure()),
-+                "Unable to read property: {%s}%s" % qname
-+            ))
- 
--        doc = davxml.WebDAVDocument.fromString(value)
-+        #
-+        # Serialize XML data to an xattr.  The storage format has
-+        # changed over time:
-+        #
-+        #  1- Started with XML
-+        #  2- Started compressing the XML due to limits on xattr size
-+        #  3- Switched to pickle which is faster, still compressing
-+        #  4- Back to compressed XML for interoperability, size
-+        #
-+        # We only write the current format, but we also read the old
-+        # ones for compatibility.
-+        #
-+        legacy = False
- 
--        return doc.root_element
-+        try:
-+            data = decompress(data)
-+        except zlib.error:
-+            legacy = True
- 
-+        try:
-+            doc = davxml.WebDAVDocument.fromString(data)
-+            result = doc.root_element
-+        except ValueError:
-+            legacy = True
-+
-+            try:
-+                result = unpickle(data)
-+            except UnpicklingError:
-+                msg = ("Invalid property value stored on server: {%s}%s %s"
-+                       % (qname[0], qname[1], data))
-+                log.err(msg)
-+                raise HTTPError(StatusResponse(responsecode.INTERNAL_SERVER_ERROR, msg))
-+
-+        if legacy:
-+            # Try to upgrade the property to the current format
-+            try:
-+                log.msg("Upgrading property %r on resource %r"
-+                        % (qname, self.resource.fp.path))
-+                self.set(result)
-+            except Exception, e:
-+                #
-+                # Hrm, that failed.  No need to re-raise here, since
-+                # we can do what we were asked to do, but let's
-+                # complain about it.
-+                #
-+                log.err("Error while upgrading property %r on resource %r: %s"
-+                        % (qname, self.resource.fp.path, e))
-+
-+        return result
-+
-     def set(self, property):
--        self.attrs[self._encode(property.qname())] = property.toxml()
-+        for n in range(20):
-+            data = compress(property.toxml())
-+            try:
-+                self.attrs[self._encode(property.qname())] = data
-+            except Exception, e:
-+                if e.errno == EAGAIN and n < 19:
-+                    sleep(random() / 10) # OMG Brutal Hax
-+                else:
-+                    raise HTTPError(StatusResponse(
-+                        statusForFailure(Failure()),
-+                        "Unable to write property: %s" % (property.sname(),)
-+                    ))
-+            else:
-+                break
- 
-         # Update the resource because we've modified it
-         self.resource.fp.restat()
-@@ -121,15 +186,31 @@
-             # RFC 2518 Section 12.13.1 says that removal of
-             # non-existing property is not an error.
-             pass
-+        except Exception, e:
-+            raise HTTPError(StatusResponse(
-+                statusForFailure(Failure()),
-+                "Unable to delete property: {%s}%s" % qname
-+            ))
- 
-     def contains(self, qname):
-         try:
-             return self._encode(qname) in self.attrs
-         except TypeError:
-             return False
-+        except Exception, e:
-+            raise HTTPError(StatusResponse(
-+                statusForFailure(Failure()),
-+                "Unable to read properties"
-+            ))
- 
-     def list(self):
-         prefix     = self.deadPropertyXattrPrefix
-         prefix_len = len(prefix)
- 
--        return [ self._decode(name) for name in self.attrs if name.startswith(prefix) ]
-+        try:
-+            return [ self._decode(name) for name in self.attrs if name.startswith(prefix) ]
-+        except Exception, e:
-+            raise HTTPError(StatusResponse(
-+                statusForFailure(Failure()),
-+                "Unable to list properties"
-+            ))

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.http.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.http.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.http.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,57 +0,0 @@
-Index: twisted/web2/http.py
-===================================================================
---- twisted/web2/http.py	(revision 19773)
-+++ twisted/web2/http.py	(working copy)
-@@ -26,7 +26,7 @@
- from twisted.web2 import http_headers
- from twisted.web2 import iweb
- from twisted.web2 import stream
--from twisted.web2.stream import IByteStream
-+from twisted.web2.stream import IByteStream, readAndDiscard
- 
- defaultPortForScheme = {'http': 80, 'https':443, 'ftp':21}
- 
-@@ -66,9 +66,9 @@
-             object.
-         @type codeOrResponse: C{int} or L{http.Response}
-         """
--        Exception.__init__(self)
--        self.response = iweb.IResponse(codeOrResponse)
--        self.args = str(self.response)
-+        response = iweb.IResponse(codeOrResponse)
-+        Exception.__init__(self, str(response))
-+        self.response = response
- 
-     def __repr__(self):
-         return "<%s %s>" % (self.__class__.__name__, self.response)
-@@ -408,9 +408,22 @@
-     def _sendContinue(self):
-         self.chanRequest.writeIntermediateResponse(responsecode.CONTINUE)
- 
--    def _finished(self, x):
-+    def _reallyFinished(self, x):
-         """We are finished writing data."""
-         self.chanRequest.finish()
-+        
-+    def _finished(self, x):
-+        """
-+        We are finished writing data.
-+        But we need to check that we have also finished reading all data as we
-+        might have sent a, for example, 401 response before we read any data.
-+        To make sure that the stream/producer sequencing works properly we need
-+        to discard the remaining data in the request.  
-+        """
-+        if self.stream.length != 0:
-+            return readAndDiscard(self.stream).addCallback(self._reallyFinished).addErrback(self._error)
-+        else:
-+            self._reallyFinished(x)
- 
-     def _error(self, reason):
-         if reason.check(error.ConnectionLost):
-@@ -471,5 +484,5 @@
- else:
-     components.registerAdapter(compat.OldResourceAdapter, resource.IResource, iweb.IOldNevowResource)
- 
--__all__ = ['HTTPError', 'NotModifiedResponse', 'Request', 'Response', 'checkIfRange', 'checkPreconditions', 'defaultPortForScheme', 'parseVersion', 'splitHostPort']
-+__all__ = ['HTTPError', 'NotModifiedResponse', 'Request', 'Response', 'StatusResponse', 'RedirectResponse', 'checkIfRange', 'checkPreconditions', 'defaultPortForScheme', 'parseVersion', 'splitHostPort']
- 

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.log.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.log.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.log.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,13 +0,0 @@
-Index: twisted/web2/log.py
-===================================================================
---- twisted/web2/log.py	(revision 19773)
-+++ twisted/web2/log.py	(working copy)
-@@ -88,7 +88,7 @@
- class LogWrapperResource(resource.WrapperResource):
-     def hook(self, request):
-         # Insert logger
--        request.addResponseFilter(logFilter, atEnd=True)
-+        request.addResponseFilter(logFilter, atEnd=True, onlyOnce=True)
- 
- monthname = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
-              'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.server.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.server.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.server.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,129 +0,0 @@
-Index: twisted/web2/server.py
-===================================================================
---- twisted/web2/server.py	(revision 19773)
-+++ twisted/web2/server.py	(working copy)
-@@ -26,6 +26,7 @@
- from twisted.web2 import http_headers
- from twisted.web2.filter.range import rangefilter
- from twisted.web2 import error
-+from twisted.web2.dav.util import joinURL
- 
- from twisted.web2 import version as web2_version
- from twisted import __version__ as twisted_version
-@@ -143,6 +144,9 @@
-                        error.defaultErrorHandler, defaultHeadersFilter]
-     
-     def __init__(self, *args, **kw):
-+        
-+        self.initTime = time.time()
-+
-         if kw.has_key('site'):
-             self.site = kw['site']
-             del kw['site']
-@@ -150,17 +154,36 @@
-             self._initialprepath = kw['prepathuri']
-             del kw['prepathuri']
- 
-+        self._resourcesByURL = {}
-+        self._urlsByResource = {}
-+
-         # Copy response filters from the class
-         self.responseFilters = self.responseFilters[:]
-         self.files = {}
-         self.resources = []
-         http.Request.__init__(self, *args, **kw)
-+        try:
-+            self.serverInstance = self.chanRequest.channel.transport.server.port
-+        except AttributeError:
-+            self.serverInstance = "Unknown"
- 
--    def addResponseFilter(self, f, atEnd=False):
-+    def addResponseFilter(self, filter, atEnd=False, onlyOnce=False):
-+        """
-+        Add a response filter to this request.
-+        Response filters are applied to the response to this request in order.
-+        @param filter: a callable which takes an response argument and returns
-+            a response object.
-+        @param atEnd: if C{True}, C{filter} is added at the end of the list of
-+            response filters; if C{False}, it is added to the beginning.
-+        @param onlyOnce: if C{True}, C{filter} is not added to the list of
-+            response filters if it already in the list.
-+        """
-+        if onlyOnce and filter in self.responseFilters:
-+            return
-         if atEnd:
--            self.responseFilters.append(f)
-+            self.responseFilters.append(filter)
-         else:
--            self.responseFilters.insert(0, f)
-+            self.responseFilters.insert(0, filter)
- 
-     def unparseURL(self, scheme=None, host=None, port=None,
-                    path=None, params=None, querystring=None, fragment=None):
-@@ -265,6 +288,7 @@
-         
-         d = defer.Deferred()
-         d.addCallback(self._getChild, self.site.resource, self.postpath)
-+        d.addCallback(self._rememberResource, "/" + "/".join(quote(s) for s in self.postpath))
-         d.addCallback(lambda res, req: res.renderHTTP(req), self)
-         d.addCallback(self._cbFinishRender)
-         d.addErrback(self._processingFailed)
-@@ -321,7 +345,6 @@
-         if newpath is StopTraversal:
-             # We need to rethink how to do this.
-             #if newres is res:
--                self._rememberResource(res, url)
-                 return res
-             #else:
-             #    raise ValueError("locateChild must not return StopTraversal with a resource other than self.")
-@@ -337,7 +360,6 @@
-                 self.prepath.append(self.postpath.pop(0))
- 
-         child = self._getChild(None, newres, newpath, updatepaths=updatepaths)
--        self._rememberResource(child, url)
- 
-         return child
- 
-@@ -347,6 +369,7 @@
-         """
-         Remember the URL of a visited resource.
-         """
-+        self._resourcesByURL[url] = resource
-         self._urlsByResource[resource] = url
-         return resource
- 
-@@ -386,7 +409,8 @@
-             The contained response will have a status code of
-             L{responsecode.BAD_REQUEST}.
-         """
--        if url is None: return None
-+        if url is None:
-+            return defer.succeed(None)
- 
-         #
-         # Parse the URL
-@@ -407,9 +431,13 @@
-                 "URL is not on this site (%s://%s/): %s" % (scheme, self.headers.getHeader("host"), url)
-             ))
- 
--        segments = path.split("/")
-+        # Look for cached value
-+        cached = self._resourcesByURL.get(path, None)
-+        if cached is not None:
-+            return defer.succeed(cached)
-+
-+        segments = unquote(path).split("/")
-         assert segments[0] == "", "URL path didn't begin with '/': %s" % (path,)
--        segments = map(unquote, segments[1:])
- 
-         def notFound(f):
-             f.trap(http.HTTPError)
-@@ -417,7 +445,7 @@
-                 return f
-             return None
- 
--        d = defer.maybeDeferred(self._getChild, None, self.site.resource, segments, updatepaths=False)
-+        d = defer.maybeDeferred(self._getChild, None, self.site.resource, segments[1:], updatepaths=False)
-         d.addCallback(self._rememberResource, path)
-         d.addErrback(notFound)
-         return d

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.static.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.static.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.static.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,33 +0,0 @@
-Index: twisted/web2/static.py
-===================================================================
---- twisted/web2/static.py	(revision 19773)
-+++ twisted/web2/static.py	(working copy)
-@@ -9,7 +9,6 @@
- # System Imports
- import os, time, stat
- import tempfile
--import md5
- 
- # Sibling Imports
- from twisted.web2 import http_headers, resource
-@@ -200,7 +199,10 @@
-         super(File, self).__init__()
- 
-         self.putChildren = {}
--        self.fp = filepath.FilePath(path)
-+        if isinstance(path, filepath.FilePath):
-+            self.fp = path
-+        else:
-+            self.fp = filepath.FilePath(path)
-         # Remove the dots from the path to split
-         self.defaultType = defaultType
-         self.ignoredExts = list(ignoredExts)
-@@ -383,7 +385,7 @@
-             return responsecode.NOT_FOUND
- 
-         if self.fp.isdir():
--            if req.uri[-1] != "/":
-+            if req.path[-1] != "/":
-                 # Redirect to include trailing '/' in URI
-                 return http.RedirectResponse(req.unparseURL(path=req.path+'/'))
-             else:

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.test.test_http.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.test.test_http.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.test.test_http.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,23 +0,0 @@
-Index: twisted/web2/test/test_http.py
-===================================================================
---- twisted/web2/test/test_http.py	(revision 19773)
-+++ twisted/web2/test/test_http.py	(working copy)
-@@ -324,6 +324,9 @@
-     def connectionLost(self, reason):
-         self.cmds.append(('connectionLost', reason))
- 
-+    def _finished(self, x):
-+        self._reallyFinished(x)
-+
- class TestResponse(object):
-     implements(iweb.IResponse)
- 
-@@ -1017,6 +1020,8 @@
-         response = TestResponse()
-         if self.uri == "/error":
-             response.code=402
-+        elif self.uri == "/forbidden":
-+            response.code=403
-         else:
-             response.code=404
-             response.write("URI %s unrecognized." % self.uri)

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,243 +0,0 @@
-Index: twisted/web2/test/test_httpauth.py
-===================================================================
---- twisted/web2/test/test_httpauth.py	(revision 19773)
-+++ twisted/web2/test/test_httpauth.py	(working copy)
-@@ -1,3 +1,4 @@
-+from twisted.internet.defer import inlineCallbacks
- import md5
- from twisted.internet import address
- from twisted.trial import unittest
-@@ -41,22 +42,25 @@
-         self.username = 'dreid'
-         self.password = 'S3CuR1Ty'
- 
-+    @inlineCallbacks
-     def testUsernamePassword(self):
-         response = base64.encodestring('%s:%s' % (
-                 self.username,
-                 self.password))
- 
--        creds = self.credentialFactory.decode(response, _trivial_GET)
-+        creds = (yield self.credentialFactory.decode(response, _trivial_GET))
-         self.failUnless(creds.checkPassword(self.password))
- 
-+    @inlineCallbacks
-     def testIncorrectPassword(self):
-         response = base64.encodestring('%s:%s' % (
-                 self.username,
-                 'incorrectPassword'))
- 
--        creds = self.credentialFactory.decode(response, _trivial_GET)
-+        creds = (yield self.credentialFactory.decode(response, _trivial_GET))
-         self.failIf(creds.checkPassword(self.password))
- 
-+    @inlineCallbacks
-     def testIncorrectPadding(self):
-         response = base64.encodestring('%s:%s' % (
-                 self.username,
-@@ -64,7 +68,7 @@
- 
-         response = response.strip('=')
- 
--        creds = self.credentialFactory.decode(response, _trivial_GET)
-+        creds = (yield self.credentialFactory.decode(response, _trivial_GET))
-         self.failUnless(creds.checkPassword(self.password))
- 
-     def testInvalidCredentials(self):
-@@ -135,6 +139,7 @@
-             )
-         return expected
- 
-+    @inlineCallbacks
-     def test_getChallenge(self):
-         """
-         Test that all the required fields exist in the challenge,
-@@ -142,42 +147,44 @@
-         DigestCredentialFactory
-         """
- 
--        challenge = self.credentialFactory.getChallenge(clientAddress)
-+        challenge = (yield self.credentialFactory.getChallenge(clientAddress))
-         self.assertEquals(challenge['qop'], 'auth')
-         self.assertEquals(challenge['realm'], 'test realm')
-         self.assertEquals(challenge['algorithm'], 'md5')
-         self.assertTrue(challenge.has_key("nonce"))
-         self.assertTrue(challenge.has_key("opaque"))
- 
-+    @inlineCallbacks
-     def test_response(self):
-         """
-         Test that we can decode a valid response to our challenge
-         """
- 
--        challenge = self.credentialFactory.getChallenge(clientAddress)
-+        challenge = (yield self.credentialFactory.getChallenge(clientAddress))
- 
-         clientResponse = authRequest1 % (
-             challenge['nonce'],
-             self.getDigestResponse(challenge, "00000001"),
-             challenge['opaque'])
- 
--        creds = self.credentialFactory.decode(clientResponse, _trivial_GET)
-+        creds = (yield self.credentialFactory.decode(clientResponse, _trivial_GET))
-         self.failUnless(creds.checkPassword('password'))
- 
-+    @inlineCallbacks
-     def test_multiResponse(self):
-         """
-         Test that multiple responses to to a single challenge are handled
-         successfully.
-         """
- 
--        challenge = self.credentialFactory.getChallenge(clientAddress)
-+        challenge = (yield self.credentialFactory.getChallenge(clientAddress))
- 
-         clientResponse = authRequest1 % (
-             challenge['nonce'],
-             self.getDigestResponse(challenge, "00000001"),
-             challenge['opaque'])
- 
--        creds = self.credentialFactory.decode(clientResponse, _trivial_GET)
-+        creds = (yield self.credentialFactory.decode(clientResponse, _trivial_GET))
-         self.failUnless(creds.checkPassword('password'))
- 
-         clientResponse = authRequest2 % (
-@@ -185,24 +192,25 @@
-             self.getDigestResponse(challenge, "00000002"),
-             challenge['opaque'])
- 
--        creds = self.credentialFactory.decode(clientResponse, _trivial_GET)
-+        creds = (yield self.credentialFactory.decode(clientResponse, _trivial_GET))
-         self.failUnless(creds.checkPassword('password'))
- 
-+    @inlineCallbacks
-     def test_failsWithDifferentMethod(self):
-         """
-         Test that the response fails if made for a different request method
-         than it is being issued for.
-         """
- 
--        challenge = self.credentialFactory.getChallenge(clientAddress)
-+        challenge = (yield self.credentialFactory.getChallenge(clientAddress))
- 
-         clientResponse = authRequest1 % (
-             challenge['nonce'],
-             self.getDigestResponse(challenge, "00000001"),
-             challenge['opaque'])
- 
--        creds = self.credentialFactory.decode(clientResponse,
--                                              SimpleRequest(None, 'POST', '/'))
-+        creds = (yield self.credentialFactory.decode(clientResponse,
-+                                              SimpleRequest(None, 'POST', '/')))
-         self.failIf(creds.checkPassword('password'))
- 
-     def test_noUsername(self):
-@@ -247,20 +255,21 @@
-                               _trivial_GET)
-         self.assertEquals(str(e), "Invalid response, no opaque given.")
- 
-+    @inlineCallbacks
-     def test_checkHash(self):
-         """
-         Check that given a hash of the form 'username:realm:password'
-         we can verify the digest challenge
-         """
- 
--        challenge = self.credentialFactory.getChallenge(clientAddress)
-+        challenge = (yield self.credentialFactory.getChallenge(clientAddress))
- 
-         clientResponse = authRequest1 % (
-             challenge['nonce'],
-             self.getDigestResponse(challenge, "00000001"),
-             challenge['opaque'])
- 
--        creds = self.credentialFactory.decode(clientResponse, _trivial_GET)
-+        creds = (yield self.credentialFactory.decode(clientResponse, _trivial_GET))
- 
-         self.failUnless(creds.checkHash(
-                 md5.md5('username:test realm:password').hexdigest()))
-@@ -268,6 +277,7 @@
-         self.failIf(creds.checkHash(
-                 md5.md5('username:test realm:bogus').hexdigest()))
- 
-+    @inlineCallbacks
-     def test_invalidOpaque(self):
-         """
-         Test that login fails when the opaque does not contain all the required
-@@ -276,7 +286,7 @@
- 
-         credentialFactory = FakeDigestCredentialFactory('md5', 'test realm')
- 
--        challenge = credentialFactory.getChallenge(clientAddress)
-+        challenge = (yield credentialFactory.getChallenge(clientAddress))
- 
-         self.assertRaises(
-             error.LoginFailed,
-@@ -302,6 +312,7 @@
-             challenge['nonce'],
-             clientAddress.host)
- 
-+    @inlineCallbacks
-     def test_incompatibleNonce(self):
-         """
-         Test that login fails when the given nonce from the response, does not
-@@ -310,7 +321,7 @@
- 
-         credentialFactory = FakeDigestCredentialFactory('md5', 'test realm')
- 
--        challenge = credentialFactory.getChallenge(clientAddress)
-+        challenge = (yield credentialFactory.getChallenge(clientAddress))
- 
-         badNonceOpaque = credentialFactory.generateOpaque(
-             '1234567890',
-@@ -330,6 +341,7 @@
-             '',
-             clientAddress.host)
- 
-+    @inlineCallbacks
-     def test_incompatibleClientIp(self):
-         """
-         Test that the login fails when the request comes from a client ip
-@@ -338,7 +350,7 @@
- 
-         credentialFactory = FakeDigestCredentialFactory('md5', 'test realm')
- 
--        challenge = credentialFactory.getChallenge(clientAddress)
-+        challenge = (yield credentialFactory.getChallenge(clientAddress))
- 
-         badNonceOpaque = credentialFactory.generateOpaque(
-             challenge['nonce'],
-@@ -351,6 +363,7 @@
-             challenge['nonce'],
-             clientAddress.host)
- 
-+    @inlineCallbacks
-     def test_oldNonce(self):
-         """
-         Test that the login fails when the given opaque is older than
-@@ -359,7 +372,7 @@
- 
-         credentialFactory = FakeDigestCredentialFactory('md5', 'test realm')
- 
--        challenge = credentialFactory.getChallenge(clientAddress)
-+        challenge = (yield credentialFactory.getChallenge(clientAddress))
- 
-         key = '%s,%s,%s' % (challenge['nonce'],
-                             clientAddress.host,
-@@ -376,6 +389,7 @@
-             challenge['nonce'],
-             clientAddress.host)
- 
-+    @inlineCallbacks
-     def test_mismatchedOpaqueChecksum(self):
-         """
-         Test that login fails when the opaque checksum fails verification
-@@ -383,7 +397,7 @@
- 
-         credentialFactory = FakeDigestCredentialFactory('md5', 'test realm')
- 
--        challenge = credentialFactory.getChallenge(clientAddress)
-+        challenge = (yield credentialFactory.getChallenge(clientAddress))
- 
- 
-         key = '%s,%s,%s' % (challenge['nonce'],

Deleted: CalendarServer/trunk/lib-patches/Twisted/twisted.words.protocols.jabber.sasl_mechanisms.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.words.protocols.jabber.sasl_mechanisms.patch	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.words.protocols.jabber.sasl_mechanisms.patch	2009-05-01 19:30:58 UTC (rev 4134)
@@ -1,86 +0,0 @@
-Index: twisted/words/protocols/jabber/sasl_mechanisms.py
-===================================================================
---- twisted/words/protocols/jabber/sasl_mechanisms.py	(revision 19773)
-+++ twisted/words/protocols/jabber/sasl_mechanisms.py	(working copy)
-@@ -7,8 +7,13 @@
- Protocol agnostic implementations of SASL authentication mechanisms.
- """
- 
--import md5, binascii, random, time, os
-+import binascii, random, time, os
- 
-+try:
-+    from hashlib import md5
-+except ImportError:
-+    from md5 import new as md5
-+
- from zope.interface import Interface, Attribute, implements
- 
- class ISASLMechanism(Interface):
-@@ -108,16 +113,43 @@
-         @return: challenge directives and their values.
-         @rtype: L{dict} of L{str} to L{str}.
-         """
--        directive_list = challenge.split(',')
--        directives = {}
--        for directive in directive_list:
--            name, value = directive.split('=')
--            value = value.replace("'","")
--            value = value.replace('"','')
--            directives[name] = value
--        return directives
-+        s = challenge
-+        paramDict = {}
-+        cur = 0
-+        remainingParams = True
-+        while remainingParams:
-+            # Parse a param. We can't just split on commas, because there can
-+            # be some commas inside (quoted) param values, e.g.:
-+            # qop="auth,auth-int"
- 
-+            middle = s.index("=", cur)
-+            name = s[cur:middle].lstrip()
-+            middle += 1
-+            if s[middle] == '"':
-+                middle += 1
-+                end = s.index('"', middle)
-+                value = s[middle:end]
-+                cur = s.find(',', end) + 1
-+                if cur == 0:
-+                    remainingParams = False
-+            else:
-+                end = s.find(',', middle)
-+                if end == -1:
-+                    value = s[middle:].rstrip()
-+                    remainingParams = False
-+                else:
-+                    value = s[middle:end].rstrip()
-+                cur = end + 1
-+            paramDict[name] = value
- 
-+        for param in ('qop', 'cipher'):
-+            if param in paramDict:
-+                paramDict[param] = paramDict[param].split(',')
-+
-+        return paramDict
-+
-+
-+
-     def _unparse(self, directives):
-         """
-         Create message string from directives.
-@@ -153,7 +185,7 @@
-         """
- 
-         def H(s):
--            return md5.new(s).digest()
-+            return md5(s).digest()
- 
-         def HEX(n):
-             return binascii.b2a_hex(n)
-@@ -196,4 +228,4 @@
- 
- 
-     def _gen_nonce(self):
--        return md5.new("%s:%s:%s" % (str(random.random()) , str(time.gmtime()),str(os.getpid()))).hexdigest()
-+        return md5("%s:%s:%s" % (str(random.random()) , str(time.gmtime()),str(os.getpid()))).hexdigest()

Modified: CalendarServer/trunk/run
===================================================================
--- CalendarServer/trunk/run	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/run	2009-05-01 19:30:58 UTC (rev 4134)
@@ -104,7 +104,7 @@
     'R')       reactor="-R ${OPTARG}"; ;;
     't')  service_type="${OPTARG}"; ;;
     'K')      read_key="${OPTARG}"; ;;
-    'S')       profile="-p ${OPTARG}"; ;;
+    'S')       profile="--profiler cprofile -p ${OPTARG}"; ;;
     'g') do_get="true" ; do_setup="false"; do_run="false"; ;;
     's') do_get="true" ; do_setup="true" ; do_run="false"; ;;
     'p') do_get="false"; do_setup="false"; do_run="false"; print_path="true"; ;;
@@ -655,8 +655,8 @@
     proto="svn";
     ;;
 esac;
-svn_uri="${proto}://svn.twistedmatrix.com/svn/Twisted/branches/dav-acl-1608-4";
-svn_get "Twisted" "${twisted}" "${svn_uri}" 19773;
+svn_uri="${proto}://svn.twistedmatrix.com/svn/Twisted/branches/dav-take-two-3081-4";
+svn_get "Twisted" "${twisted}" "${svn_uri}" 26741;
 
 # No py_build step, since we tend to do edit Twisted, we want the sources in
 # PYTHONPATH, not a build directory.

Modified: CalendarServer/trunk/twistedcaldav/notify.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/notify.py	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/twistedcaldav/notify.py	2009-05-01 19:30:58 UTC (rev 4134)
@@ -720,7 +720,8 @@
             return
 
         try:
-            iq = IQ(self.xmlStream, type='get')
+            # XXX This codepath is not unit tested
+            iq = IQ(self.xmlStream, 'get')
             child = iq.addElement('pubsub',
                 defaultUri=self.pubsubNS+"#owner")
             child = child.addElement('configure')
@@ -755,7 +756,7 @@
                     formElement = configureElement.firstChildElement()
                     if formElement['type'] == 'form':
                         # We've found the form; start building a response
-                        filledIq = IQ(self.xmlStream, type='set')
+                        filledIq = IQ(self.xmlStream, 'set')
                         filledPubSub = filledIq.addElement('pubsub',
                             defaultUri=self.pubsubNS+"#owner")
                         filledConfigure = filledPubSub.addElement('configure')
@@ -784,7 +785,8 @@
                                         valueElement.addContent(value)
                                         # filledForm.addChild(field)
                         if configMatches:
-                            cancelIq = IQ(self.xmlStream, type='set')
+                            # XXX This codepath is not unit tested
+                            cancelIq = IQ(self.xmlStream, 'set')
                             cancelPubSub = cancelIq.addElement('pubsub',
                                 defaultUri=self.pubsubNS+"#owner")
                             cancelConfig = cancelPubSub.addElement('configure')
@@ -892,7 +894,7 @@
     def requestRoster(self):
         if self.doRoster:
             self.roster = {}
-            rosterIq = IQ(self.xmlStream, type='get')
+            rosterIq = IQ(self.xmlStream, 'get')
             rosterIq.addElement("query", "jabber:iq:roster")
             d = rosterIq.send()
             d.addCallback(self.handleRoster)
@@ -950,7 +952,8 @@
             self.xmlStream.send(response)
 
             # remove from roster as well
-            removal = IQ(self.xmlStream, type='set')
+            # XXX This codepath is not unit tested
+            removal = IQ(self.xmlStream, 'set')
             query = removal.addElement("query", "jabber:iq:roster")
             query.addElement("item")
             query.item["jid"] = iq["from"]

Modified: CalendarServer/trunk/twistedcaldav/test/test_index.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_index.py	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/twistedcaldav/test/test_index.py	2009-05-01 19:30:58 UTC (rev 4134)
@@ -19,7 +19,8 @@
 import twistedcaldav.test.util
 from twistedcaldav.test.util import InMemoryMemcacheProtocol
 from twistedcaldav.index import ReservationError, MemcachedUIDReserver
-from twisted.web2.test.test_http import deferLater
+from twisted.internet import reactor
+from twisted.internet.task import deferLater
 
 class SQLIndexTests (twistedcaldav.test.util.TestCase):
     """
@@ -80,7 +81,7 @@
         d.addCallback(lambda _: self.db.reserveUID(uid))
         d.addCallback(lambda _: self.db.isReservedUID(uid))
         d.addCallback(self.assertTrue)
-        d.addCallback(lambda _: deferLater(2))
+        d.addCallback(lambda _: deferLater(reactor, 2, lambda: None))
         d.addCallback(lambda _: self.db.isReservedUID(uid))
         d.addCallback(self.assertFalse)
         d.addBoth(_finally)

Modified: CalendarServer/trunk/twistedcaldav/test/test_upgrade.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_upgrade.py	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/twistedcaldav/test/test_upgrade.py	2009-05-01 19:30:58 UTC (rev 4134)
@@ -188,7 +188,7 @@
         # Verify these values do require updating:
         #
 
-        expected = "<?xml version='1.0' encoding='UTF-8'?>\r\n<calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n  <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>\r\n"
+        expected = "<?xml version='1.0' encoding='UTF-8'?><calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n  <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>"
 
         # Uncompressed XML
         value = "<?xml version='1.0' encoding='UTF-8'?>\r\n<calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n  <href xmlns='DAV:'>/calendars/users/wsanchez/calendar</href>\r\n</calendar-free-busy-set>\r\n"
@@ -314,7 +314,7 @@
                                 {
                                     "@xattrs" :
                                     {
-                                        freeBusyAttr : zlib.compress("<?xml version='1.0' encoding='UTF-8'?>\r\n<calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n  <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>\r\n"),
+                                        freeBusyAttr : zlib.compress("<?xml version='1.0' encoding='UTF-8'?><calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n  <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>"),
                                     },
                                 },
                             },
@@ -430,7 +430,7 @@
                                 {
                                     "@xattrs" :
                                     {
-                                        freeBusyAttr : zlib.compress("<?xml version='1.0' encoding='UTF-8'?>\r\n<calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n  <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>\r\n"),
+                                        freeBusyAttr : zlib.compress("<?xml version='1.0' encoding='UTF-8'?><calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n  <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>"),
                                     },
                                 },
                             },
@@ -550,7 +550,7 @@
                                 {
                                     "@xattrs" :
                                     {
-                                        freeBusyAttr : zlib.compress("<?xml version='1.0' encoding='UTF-8'?>\r\n<calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n  <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>\r\n"),
+                                        freeBusyAttr : zlib.compress("<?xml version='1.0' encoding='UTF-8'?><calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n  <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>"),
                                     },
                                 },
                             },

Modified: CalendarServer/trunk/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/util.py	2009-05-01 19:03:50 UTC (rev 4133)
+++ CalendarServer/trunk/twistedcaldav/test/util.py	2009-05-01 19:30:58 UTC (rev 4134)
@@ -117,6 +117,7 @@
                             try:
                                 if xattr.getxattr(childPath, attr) != value:
                                     print "Xattr mismatch:", childPath, attr
+                                    print (xattr.getxattr(childPath, attr), " != ", value)
                                     return False
                             except:
                                 return False
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090501/a420ab3c/attachment-0001.html>


More information about the calendarserver-changes mailing list