[CalendarServer-changes] [706] CalendarServer/trunk/twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Tue Dec 5 16:35:45 PST 2006


Revision: 706
          http://trac.macosforge.org/projects/calendarserver/changeset/706
Author:   wsanchez at apple.com
Date:     2006-12-05 16:35:44 -0800 (Tue, 05 Dec 2006)

Log Message:
-----------
Move scheduling resource implementation to new schedule.py.
Removes POST method from classes other than ScheduleOutboxResource.
Removes need for isScheduleInboxResource(), isScheduleOutboxResource(), ICalendarSchedulingCollectionResource.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/__init__.py
    CalendarServer/trunk/twistedcaldav/directory/__init__.py
    CalendarServer/trunk/twistedcaldav/extensions.py
    CalendarServer/trunk/twistedcaldav/icaldav.py
    CalendarServer/trunk/twistedcaldav/itip.py
    CalendarServer/trunk/twistedcaldav/method/__init__.py
    CalendarServer/trunk/twistedcaldav/method/mkcol.py
    CalendarServer/trunk/twistedcaldav/resource.py
    CalendarServer/trunk/twistedcaldav/static.py

Removed Paths:
-------------
    CalendarServer/trunk/twistedcaldav/http.py
    CalendarServer/trunk/twistedcaldav/method/post.py
    CalendarServer/trunk/twistedcaldav/method/schedule_common.py

Modified: CalendarServer/trunk/twistedcaldav/__init__.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/__init__.py	2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/__init__.py	2006-12-06 00:35:44 UTC (rev 706)
@@ -25,17 +25,25 @@
 from twisted.web2.static import File, loadMimeTypes
 
 __all__ = [
+    "authkerb",
     "caldavxml",
     "customxml",
     "dateops",
     "db",
     "directory",
     "dropbox",
+    "extensions",
     "ical",
+    "icaldav",
     "index",
     "instance",
+    "itip",
+    "logging",
+    "notifications",
     "principalindex",
     "resource",
+    "root",
+    "schedule",
     "sql",
     "static",
 ]

Modified: CalendarServer/trunk/twistedcaldav/directory/__init__.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/__init__.py	2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/directory/__init__.py	2006-12-06 00:35:44 UTC (rev 706)
@@ -21,11 +21,11 @@
 """
 
 __all__ = [
+    "apache",
     "appleopendirectory",
-    "cred",
     "directory",
     "idirectory",
-    "resource",
+    "principal",
     "sqldb",
     "xmlfile",
 ]

Modified: CalendarServer/trunk/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/extensions.py	2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/extensions.py	2006-12-06 00:35:44 UTC (rev 706)
@@ -29,11 +29,14 @@
 import urllib
 import time
 
+from twisted.internet.defer import succeed
 from twisted.web2 import responsecode
 from twisted.web2.http import HTTPError, Response, RedirectResponse
 from twisted.web2.http_headers import MimeType
 from twisted.web2.stream import FileStream
 from twisted.web2.static import MetaDataMixin
+from twisted.web2.dav import davxml
+from twisted.web2.dav.davxml import dav_namespace
 from twisted.web2.dav.http import StatusResponse
 from twisted.web2.dav.static import DAVFile as SuperDAVFile
 from twisted.web2.dav.resource import DAVResource as SuperDAVResource
@@ -47,6 +50,25 @@
     """
     Extended L{twisted.web2.dav.static.DAVFile} implementation.
     """
+    def readProperty(self, property, request):
+        if type(property) is tuple:
+            qname = property
+        else:
+            qname = property.qname()
+
+        if qname == (dav_namespace, "resourcetype"):
+            return succeed(self.resourceType())
+
+        return super(DAVFile, self).readProperty(property, request)
+
+    def resourceType(self):
+        # Allow live property to be overriden by dead property
+        if self.deadProperties().contains((dav_namespace, "resourcetype")):
+            return self.deadProperties().get((dav_namespace, "resourcetype"))
+        if self.isCollection():
+            return davxml.ResourceType.collection
+        return davxml.ResourceType.empty
+
     def render(self, req):
         """You know what you doing."""
         if not self.fp.exists():

Deleted: CalendarServer/trunk/twistedcaldav/http.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/http.py	2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/http.py	2006-12-06 00:35:44 UTC (rev 706)
@@ -1,121 +0,0 @@
-##
-# Copyright (c) 2005-2006 Apple Computer, 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: Wilfredo Sanchez, wsanchez at apple.com
-##
-
-__all__ = [
-    "ScheduleResponseResponse",
-    "ScheduleResponseQueue"
-]
-
-from twisted.python import log
-from twisted.python.failure import Failure
-from twisted.web2 import responsecode
-from twisted.web2.dav import davxml
-from twisted.web2.dav.http import errorForFailure, messageForFailure, statusForFailure
-from twisted.web2.http import Response
-from twisted.web2.http_headers import MimeType
-
-from twistedcaldav import caldavxml
-
-class ScheduleResponseResponse (Response):
-    """
-    ScheduleResponse L{Response} object.
-    Renders itself as a CalDAV:schedule-response XML document.
-    """
-    def __init__(self, xml_responses, location=None):
-        """
-        @param xml_responses: an interable of davxml.Response objects.
-        @param location:      the value of the location header to return in the response,
-                              or None.
-        """
-
-        Response.__init__(self, code=responsecode.OK,
-                          stream=caldavxml.ScheduleResponse(*xml_responses).toxml())
-
-        self.headers.setHeader("content-type", MimeType("text", "xml"))
-    
-        if location is not None:
-            self.headers.setHeader("location", location)
-
-class ScheduleResponseQueue (object):
-    """
-    Stores a list of (typically error) responses for use in a
-    L{ScheduleResponse}.
-    """
-    def __init__(self, method, success_response):
-        """
-        @param method: the name of the method generating the queue.
-        @param success_response: the response to return in lieu of a
-            L{ScheduleResponse} if no responses are added to this queue.
-        """
-        self.responses         = []
-        self.method            = method
-        self.success_response  = success_response
-        self.location          = None
-
-    def setLocation(self, location):
-        """
-        @param location:      the value of the location header to return in the response,
-                              or None.
-        """
-        self.location = location
-
-    def add(self, recipient, what, reqstatus=None, calendar=None):
-        """
-        Add a response.
-        @param recipient: the recipient for this response.
-        @param what: a status code or a L{Failure} for the given recipient.
-        @param status: the iTIP request-status for the given recipient.
-        @param calendar: the calendar data for the given recipient response.
-        """
-        if type(what) is int:
-            code    = what
-            error   = None
-            message = responsecode.RESPONSES[code]
-        elif isinstance(what, Failure):
-            code    = statusForFailure(what)
-            error   = errorForFailure(what)
-            message = messageForFailure(what)
-        else:
-            raise AssertionError("Unknown data type: %r" % (what,))
-
-        if code > 400: # Error codes only
-            log.err("Error during %s for %s: %s" % (self.method, recipient, message))
-
-        children = []
-        children.append(caldavxml.Recipient(davxml.HRef.fromString(recipient)))
-        children.append(caldavxml.RequestStatus(reqstatus))
-        if calendar is not None:
-            children.append(caldavxml.CalendarData.fromCalendar(calendar))
-        if error is not None:
-            children.append(error)
-        if message is not None:
-            children.append(davxml.ResponseDescription(message))
-        self.responses.append(caldavxml.Response(*children))
-
-    def response(self):
-        """
-        Generate a L{ScheduleResponseResponse} with the responses contained in the
-        queue or, if no such responses, return the C{success_response} provided
-        to L{__init__}.
-        @return: the response.
-        """
-        if self.responses:
-            return ScheduleResponseResponse(self.responses, self.location)
-        else:
-            return self.success_response
-

Modified: CalendarServer/trunk/twistedcaldav/icaldav.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/icaldav.py	2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/icaldav.py	2006-12-06 00:35:44 UTC (rev 706)
@@ -107,20 +107,6 @@
             iCalendar data for the requested resource.
         """
 
-class ICalendarSchedulingCollectionResource(ICalDAVResource):
-    """
-    CalDAV scheduling collection resource type, e.g. schedule INBOX.
-    """
-    def isScheduleInbox():
-        """
-        True if this is a schedule Inbox.
-        """
-
-    def isScheduleOutbox():
-        """
-        True if this is an schedule Outbox.
-        """
-
 class ICalendarPrincipalResource(IDAVResource):
     """
     CalDAV principle resource.

Modified: CalendarServer/trunk/twistedcaldav/itip.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/itip.py	2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/itip.py	2006-12-06 00:35:44 UTC (rev 706)
@@ -47,7 +47,7 @@
 from twistedcaldav.ical import Property, iCalendarProductID
 from twistedcaldav.method import report_common
 from twistedcaldav.method.put_common import storeCalendarObjectResource
-from twistedcaldav.resource import CalendarPrincipalCollectionResource, isCalendarCollectionResource
+from twistedcaldav.resource import isCalendarCollectionResource
 
 __version__ = "0.0"
 

Modified: CalendarServer/trunk/twistedcaldav/method/__init__.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/__init__.py	2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/method/__init__.py	2006-12-06 00:35:44 UTC (rev 706)
@@ -28,14 +28,10 @@
     "delete",
     "mkcalendar",
     "mkcol",
-    "post",
     "put",
-    "put_common",
-    "report_common",
     "report_calquery",
-    "report_multiget",
     "report_freebusy",
-    "schedule_common",
+    "report_multiget",
     "x_apple_subscribe",
     "x_apple_unsubscribe",
 ]

Modified: CalendarServer/trunk/twistedcaldav/method/mkcol.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/mkcol.py	2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/method/mkcol.py	2006-12-06 00:35:44 UTC (rev 706)
@@ -29,6 +29,7 @@
 from twisted.web2.http import HTTPError, StatusResponse
 
 from twistedcaldav import customxml
+from twistedcaldav.icaldav import ICalDAVResource
 
 def http_MKCOL(self, request):
     #

Deleted: CalendarServer/trunk/twistedcaldav/method/post.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/post.py	2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/method/post.py	2006-12-06 00:35:44 UTC (rev 706)
@@ -1,44 +0,0 @@
-##
-# Copyright (c) 2006 Apple Computer, 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
-##
-
-"""
-CalDAV POST method.
-"""
-
-__all__ = ["http_POST"]
-
-from twisted.web2.dav.util import parentForURL
-
-from twistedcaldav import caldavxml
-from twistedcaldav.method.schedule_common import processScheduleRequest
-
-def http_POST(self, request):
-    """
-    The CalDAV POST method.
-    
-    This uses a generator function yielding either L{waitForDeferred} objects or L{Response} objects.
-    This allows for code that follows a 'linear' execution pattern rather than having to use nested
-    L{Deferred} callbacks. The logic is easier to follow this way plus we don't run into deep nesting
-    issues which the other approach would have with large numbers of recipients.
-    """
-    d = request.locateResource(parentForURL(request.uri))
-    # Check authentication and access controls
-    d.addCallback(lambda parent: parent.authorize(request, (caldavxml.Schedule(),)))
-    # Do the work
-    d.addCallback(lambda _: processScheduleRequest(self, "POST", request))
-    return d

Deleted: CalendarServer/trunk/twistedcaldav/method/schedule_common.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/schedule_common.py	2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/method/schedule_common.py	2006-12-06 00:35:44 UTC (rev 706)
@@ -1,374 +0,0 @@
-##
-# Copyright (c) 2006 Apple Computer, 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
-##
-
-"""
-CalDAV Schedule processing.
-"""
-
-__all__ = ["processScheduleRequest"]
-
-from twisted.internet import reactor
-from twisted.internet.defer import deferredGenerator, maybeDeferred, waitForDeferred
-from twisted.python import failure, log
-from twisted.web2 import responsecode
-from twisted.web2.dav import davxml
-from twisted.web2.dav.http import ErrorResponse
-from twisted.web2.dav.util import joinURL
-from twisted.web2.http import HTTPError
-
-from twistedcaldav import caldavxml
-from twistedcaldav import customxml
-from twistedcaldav import itip
-from twistedcaldav.caldavxml import caldav_namespace, TimeRange
-from twistedcaldav.http import ScheduleResponseQueue
-from twistedcaldav.ical import Component
-from twistedcaldav.method import report_common
-from twistedcaldav.method.put_common import storeCalendarObjectResource
-from twistedcaldav.resource import CalendarPrincipalCollectionResource, isScheduleOutboxResource, isCalendarCollectionResource
-
-import md5
-import time
-
-def processScheduleRequest(self, method, request):
-    """
-    This is a generator function that yields L{waitForDeffered} or L{Response} objects. It handles processing of scheduling
-    requests on an Outbox. These can currently come from either a SCHEDULE or POST method. SCHEDULE will be deprecated soon.
-
-    @param method: the C{str} containing the current HTTP method.
-    @param request: the L{twisted.web2.server.Request} for the current HTTP request.
-    """
-
-    # Must be targetting an OUTBOX
-    if not isScheduleOutboxResource(self):
-        log.err("%s must target an schedule Outbox collection: %s" % (method, self,))
-        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "supported-collection")))
-
-    # Must be content-type text/calendar
-    content_type = request.headers.getHeader("content-type")
-    if content_type is not None and (content_type.mediaType, content_type.mediaSubtype) != ("text", "calendar"):
-        log.err("MIME type %s not allowed in calendar collection" % (content_type,))
-        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "supported-calendar-data")))
-    
-    # Must have Originator header
-    originator = request.headers.getRawHeaders("originator")
-    if originator is None or (len(originator) != 1):
-        log.err("%s request must have Originator header" % (method,))
-        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-specified")))
-    else:
-        originator = originator[0]
-    
-    # Verify that Originator is a valid calendar user (has an INBOX)
-    inboxURL = None
-    oprincipal = self.principalForCalendarUserAddress(originator)
-    if oprincipal is not None:
-        inboxURL = oprincipal.scheduleInboxURL()
-    if inboxURL is None:
-        log.err("Could not find Inbox for originator: %s" % (originator,))
-        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
-    
-    # Get list of Recipient headers
-    rawrecipients = request.headers.getRawHeaders("recipient")
-    if rawrecipients is None or (len(rawrecipients) == 0):
-        log.err("%s request must have at least one Recipient header" % (method,))
-        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "recipient-specified")))
-
-    # Recipient header may be comma separated list
-    recipients = []
-    for rawrecipient in rawrecipients:
-        for r in rawrecipient.split(","):
-            r = r.strip()
-            if len(r):
-                recipients.append(r)
-
-    timerange = TimeRange(start="20000101", end="20000102")
-    recipients_state = {"OK":0, "BAD":0}
-
-    # Parse the calendar object from the HTTP request stream
-    try:
-        d = waitForDeferred(Component.fromIStream(request.stream))
-        yield d
-        calendar = d.getResult()
-    except:
-        log.err("Error while handling %s: %s" % (method, failure.Failure(),))
-        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
- 
-    # Must be a valid calendar
-    try:
-        calendar.validCalendarForCalDAV()
-    except ValueError:
-        log.err("%s request calendar component is not valid: %s" % (method, calendar,))
-        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
-
-    # Must have a METHOD
-    if not calendar.isValidMethod():
-        log.err("%s request must have valid METHOD property in calendar component: %s" % (method, calendar,))
-        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
-        
-    # Verify iTIP behaviour
-    if not calendar.isValidITIP():
-        log.err("%s request must have a calendar component that satisfies iTIP requirements: %s" % (method, calendar,))
-        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
-    
-    # Verify that the ORGANIZER's cu address maps to the request.uri
-    outboxURL = None
-    organizer = calendar.getOrganizer()
-    if organizer is not None:
-        oprincipal = self.principalForCalendarUserAddress(organizer)
-        if oprincipal is not None:
-            outboxURL = oprincipal.scheduleOutboxURL()
-    if outboxURL is None:
-        log.err("ORGANIZER in calendar data is not valid: %s" % (calendar,))
-        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "organizer-allowed")))
-
-    # Prevent spoofing of ORGANIZER with specific METHODs
-    if (calendar.propertyValue("METHOD") in ("PUBLISH", "REQUEST", "ADD", "CANCEL", "DECLINECOUNTER")) and (outboxURL != request.uri):
-        log.err("ORGANIZER in calendar data does not match owner of Outbox: %s" % (calendar,))
-        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "organizer-allowed")))
-
-    # Prevent spoofing when doing reply-like METHODs
-    if calendar.propertyValue("METHOD") in ("REPLY", "COUNTER", "REFRESH"):
-        # Verify that there is a single ATTENDEE property and that the Originator has permission
-        # to send on behalf of that ATTENDEE
-        attendees = calendar.getAttendees()
-        
-        # Must have only one
-        if len(attendees) != 1:
-            log.err("ATTENDEE list in calendar data is wrong: %s" % (calendar,))
-            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
-            
-        # Attendee's Outbox MUST be the request URI
-        aoutboxURL = None
-        aprincipal = self.principalForCalendarUserAddress(attendees[0])
-        if aprincipal is not None:
-            aoutboxURL = aprincipal.scheduleOutboxURL()
-        if aoutboxURL is None or aoutboxURL != request.uri:
-            log.err("ATTENDEE in calendar data does not match owner of Outbox: %s" % (calendar,))
-            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
-
-    # For free-busy do immediate determination of iTIP result rather than fan-out
-    if (calendar.propertyValue("METHOD") == "REQUEST") and (calendar.mainType() == "VFREEBUSY"):
-        # Extract time range from VFREEBUSY object
-        vfreebusies = [v for v in calendar.subcomponents() if v.name() == "VFREEBUSY"]
-        if len(vfreebusies) != 1:
-            log.err("iTIP data is not valid for a VFREEBUSY request: %s" % (calendar,))
-            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
-        dtstart = vfreebusies[0].getStartDateUTC()
-        dtend = vfreebusies[0].getEndDateUTC()
-        if dtstart is None or dtend is None:
-            log.err("VFREEBUSY start/end not valid: %s" % (calendar,))
-            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
-        timerange.start = dtstart
-        timerange.end = dtend
-
-        # Do free busy operation
-        freebusy = True
-    else:
-        # Do regular invite (fan-out)
-        freebusy = False
-
-    # Prepare for multiple responses
-    responses = ScheduleResponseQueue(method, responsecode.OK)
-    
-    # Outbox copy is saved when not doing free busy request
-    if not freebusy:
-        # Hash the iCalendar data for use as the last path element of the URI path
-        name = md5.new(str(calendar) + str(time.time()) + self.fp.path).hexdigest() + ".ics"
-        
-        # Save a copy of the calendar data into the Outbox
-        childURL = joinURL(request.uri, name)
-        child = waitForDeferred(request.locateResource(childURL))
-        yield child
-        child = child.getResult()
-        responses.setLocation(childURL)
-        
-        try:
-            d = waitForDeferred(
-                    maybeDeferred(
-                        storeCalendarObjectResource,
-                        request=request,
-                        sourcecal = False,
-                        destination = child,
-                        destination_uri = childURL,
-                        calendardata = str(calendar),
-                        destinationparent = self,
-                        destinationcal = True,
-                        isiTIP = True
-                    )
-                )
-            yield d
-            d.getResult()
-        except:
-            log.err("Error while handling %s: %s" % (method, failure.Failure(),))
-            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "outbox-copy")))
-        
-        # Store CALDAV:originator property
-        child.writeDeadProperty(caldavxml.Originator(davxml.HRef.fromString(originator)))
-        
-        # Store CALDAV:recipient property
-        child.writeDeadProperty(caldavxml.Recipient(*map(davxml.HRef.fromString, recipients)))
- 
-        # Extract the ORGANIZER property and UID value from the calendar data  for use later
-    organizerProp = calendar.getOrganizerProperty()
-    uid = calendar.resourceUID()
-
-    # Loop over each recipient and do appropriate action.
-    autoresponses = []
-    for recipient in recipients:
-        # Get the principal resource for this recipient
-        principal = self.principalForCalendarUserAddress(recipient)
-
-        # Map recipient to their inbox
-        inbox = None
-        if principal is not None:
-            inboxURL = principal.scheduleInboxURL()
-            if inboxURL:
-                inbox = waitForDeferred(request.locateResource(inboxURL))
-                yield inbox
-                inbox = inbox.getResult()
-        if inbox is None:
-            log.err("Could not find Inbox for recipient: %s" % (recipient,))
-            err = HTTPError(ErrorResponse(responsecode.NOT_FOUND, (caldav_namespace, "recipient-exists")))
-            responses.add(recipient, failure.Failure(exc_value=err), reqstatus="3.7;Invalid Calendar User")
-            recipients_state["BAD"] += 1
-            
-            # Process next recipient
-            continue
-        else:
-
-            #
-            # Check access controls
-            #
-            try:
-                d = waitForDeferred(inbox.checkPrivileges(request, (caldavxml.Schedule(),), principal=davxml.Principal(davxml.HRef.fromString(oprincipal))))
-                yield d
-                d.getResult()
-            except:
-                log.err("Could not access Inbox for recipient: %s" % (recipient,))
-                err = HTTPError(ErrorResponse(responsecode.NOT_FOUND, (caldav_namespace, "recipient-permisions")))
-                responses.add(recipient, failure.Failure(exc_value=err), reqstatus="3.8;No authority")
-                recipients_state["BAD"] += 1
-                
-                # Process next recipient
-                continue
-    
-            # Different behaviour for free-busy vs regular invite
-            if freebusy:
-                # Extract the ATTENDEE property matching current recipient from the calendar data
-                cuas = principal.calendarUserAddresses()
-                attendeeProp = calendar.getAttendeeProperty(cuas)
-            
-                # Find the current recipients calendar-free-busy-set
-                fbset = waitForDeferred(principal.calendarFreeBusyURIs(request))
-                yield fbset
-                fbset = fbset.getResult()
-
-                # First list is BUSY, second BUSY-TENTATIVE, third BUSY-UNAVAILABLE
-                fbinfo = ([], [], [])
-                
-                try:
-                    matchtotal = 0
-                    for calURL in fbset:
-                        cal = waitForDeferred(request.locateResource(calURL))
-                        yield cal
-                        cal = cal.getResult()
-                        if cal is None or not cal.exists() or not isCalendarCollectionResource(cal):
-                            # We will ignore missing calendars. If the recipient has failed to
-                            # properly manage the free busy set that should not prevent us from working.
-                            continue
-                         
-                        matchtotal = waitForDeferred(report_common.generateFreeBusyInfo(request, cal, fbinfo, timerange, matchtotal))
-                        yield matchtotal
-                        matchtotal = matchtotal.getResult()
-                    
-                    # Build VFREEBUSY iTIP reply for this recipient
-                    fbresult = report_common.buildFreeBusyResult(fbinfo, timerange, organizer=organizerProp, attendee=attendeeProp, uid=uid)
-
-                    responses.add(recipient, responsecode.OK, reqstatus="2.0;Success", calendar=fbresult)
-                    recipients_state["OK"] += 1
-                
-                except:
-                    log.err("Could not determine free busy information: %s" % (recipient,))
-                    err = HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "recipient-permissions")))
-                    responses.add(recipient, failure.Failure(exc_value=err), reqstatus="3.8;No authority")
-                    recipients_state["BAD"] += 1
-                
-            else:
-                # Hash the iCalendar data for use as the last path element of the URI path
-                name = md5.new(str(calendar) + str(time.time()) + inbox.fp.path).hexdigest() + ".ics"
-                
-                # Get a resource for the new item
-                childURL = joinURL(inboxURL, name)
-                child = waitForDeferred(request.locateResource(childURL))
-                yield child
-                child = child.getResult()
-            
-                # Copy calendar to inbox (doing fan-out)
-                d = waitForDeferred(
-                        maybeDeferred(
-                            storeCalendarObjectResource,
-                            request=request,
-                            sourcecal = False,
-                            destination = child,
-                            destination_uri = childURL,
-                            calendardata = str(calendar),
-                            destinationparent = inbox,
-                            destinationcal = True,
-                            isiTIP = True
-                        )
-                     )
-                yield d
-                try:
-                    d.getResult()
-                    responses.add(recipient, responsecode.OK, reqstatus="2.0;Success")
-                    recipients_state["OK"] += 1
-        
-                    # Store CALDAV:originator property
-                    child.writeDeadProperty(caldavxml.Originator(davxml.HRef.fromString(originator)))
-                    
-                    # Store CALDAV:recipient property
-                    child.writeDeadProperty(caldavxml.Recipient(davxml.HRef.fromString(recipient)))
-                    
-                    # Store CALDAV:schedule-state property
-                    child.writeDeadProperty(caldavxml.ScheduleState(caldavxml.NotProcessed()))
-                    
-                    # Look for auto-respond option
-                    if inbox.hasDeadProperty(customxml.TwistedScheduleAutoRespond):
-                        autoresponses.append((principal, inbox, child))
-                except:
-                    log.err("Could not store data in Inbox : %s" % (inbox,))
-                    err = HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "recipient-permissions")))
-                    responses.add(recipient, failure.Failure(exc_value=err), reqstatus="3.8;No authority")
-                    recipients_state["BAD"] += 1
-
-    # Now we have to do auto-respond
-    if len(autoresponses) != 0:
-        # First check that we have a method that we can auto-respond to
-        if not itip.canAutoRespond(calendar):
-            autoresponses = []
-            
-    # Now do the actual auto response
-    for principal, inbox, child in autoresponses:
-        # Add delayed reactor task to handle iTIP responses
-        reactor.callLater(5.0, itip.handleRequest, *(request, principal, inbox, calendar.duplicate(), child)) #@UndefinedVariable
-        #reactor.callInThread(itip.handleRequest, *(request, principal, inbox, calendar.duplicate(), child)) #@UndefinedVariable
-
-    # Return with final response if we are done
-    yield responses.response()
-
-processScheduleRequest = deferredGenerator(processScheduleRequest)
-

Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/resource.py	2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/resource.py	2006-12-06 00:35:44 UTC (rev 706)
@@ -17,7 +17,7 @@
 ##
 
 """
-CalDAV-aware static resources.
+CalDAV-aware resources.
 """
 
 __all__ = [
@@ -25,12 +25,8 @@
     "CalendarPrincipalCollectionResource",
     "CalendarPrincipalResource",
     "CalendarSchedulingCollectionResource",
-    "ScheduleInboxResource",
-    "ScheduleOutboxResource",
     "isCalendarCollectionResource",
     "isPseudoCalendarCollectionResource",
-    "isScheduleInboxResource",
-    "isScheduleOutboxResource",
 ]
 
 from zope.interface import implements
@@ -56,7 +52,7 @@
 import twistedcaldav
 from twistedcaldav import caldavxml, customxml
 from twistedcaldav.extensions import DAVResource
-from twistedcaldav.icaldav import ICalDAVResource, ICalendarPrincipalResource, ICalendarSchedulingCollectionResource
+from twistedcaldav.icaldav import ICalDAVResource, ICalendarPrincipalResource
 from twistedcaldav.caldavxml import caldav_namespace
 from twistedcaldav.customxml import apple_namespace
 from twistedcaldav.ical import Component as iComponent
@@ -677,74 +673,6 @@
             return joinURL(home, DropBox.notificationName)
         return None
 
-class CalendarSchedulingCollectionResource (CalDAVResource):
-    """
-    CalDAV principal resource.
-
-    Extends L{DAVResource} to provide CalDAV scheduling collection
-    functionality.
-    """
-    implements(ICalendarSchedulingCollectionResource)
-
-    def isCollection(self):
-        return True
-
-    def isCalendarCollection(self):
-        return False
-
-    def isPseudoCalendarCollection(self):
-        return True
-
-    def isScheduleInbox(self):
-        return False
-    
-    def isScheduleOutbox(self):
-        return False
-
-    def readProperty(self, property, request):
-        if type(property) is tuple:
-            qname = property
-        else:
-            qname = property.qname()
-
-        namespace, name = qname
-
-        if namespace == dav_namespace:
-            if name == "resourcetype":
-                types = [davxml.Collection()]
-
-                if self.isScheduleInbox(): types.append(caldavxml.ScheduleInbox())
-                if self.isScheduleOutbox(): types.append(caldavxml.ScheduleOutbox())
-
-                return succeed(davxml.ResourceType(*types))
-
-        return super(CalendarSchedulingCollectionResource, self).readProperty(property, request)
-
-    def supportedReports(self):
-        result = super(CalDAVResource, self).supportedReports()
-        result.append(davxml.Report(caldavxml.CalendarQuery(),))
-        result.append(davxml.Report(caldavxml.CalendarMultiGet(),))
-        # free-busy report not allowed
-        return result
-
-class ScheduleInboxResource (CalendarSchedulingCollectionResource):
-    """
-    CalDAV schedule Inbox resource.
-
-    Extends L{DAVResource} to provide CalDAV functionality.
-    """
-    def isScheduleInbox(self):
-        return True
-
-class ScheduleOutboxResource (CalendarSchedulingCollectionResource):
-    """
-    CalDAV schedule Outbox resource.
-
-    Extends L{DAVResource} to provide CalDAV functionality.
-    """
-    def isScheduleOutbox(self):
-        return True
-
 ##
 # Utilities
 ##
@@ -771,19 +699,3 @@
         return False
     else:
         return resource.isPseudoCalendarCollection()
-
-def isScheduleInboxResource(resource):
-    try:
-        resource = ICalendarSchedulingCollectionResource(resource)
-    except TypeError:
-        return False
-    else:
-        return resource.isScheduleInbox()
-
-def isScheduleOutboxResource(resource):
-    try:
-        resource = ICalendarSchedulingCollectionResource(resource)
-    except TypeError:
-        return False
-    else:
-        return resource.isScheduleOutbox()

Modified: CalendarServer/trunk/twistedcaldav/static.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/static.py	2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/static.py	2006-12-06 00:35:44 UTC (rev 706)
@@ -49,10 +49,11 @@
 from twistedcaldav.extensions import ReadOnlyResourceMixIn
 from twistedcaldav.ical import Component as iComponent
 from twistedcaldav.ical import Property as iProperty
+from twistedcaldav.icaldav import ICalDAVResource
 from twistedcaldav.index import Index, IndexSchedule, db_basename
 from twistedcaldav.resource import CalDAVResource
-from twistedcaldav.resource import ScheduleInboxResource, ScheduleOutboxResource
 from twistedcaldav.resource import isCalendarCollectionResource
+from twistedcaldav.schedule import ScheduleInboxResource, ScheduleOutboxResource
 from twistedcaldav.extensions import DAVFile
 from twistedcaldav.dropbox import DropBox
 from twistedcaldav.directory.idirectory import IDirectoryService
@@ -421,21 +422,6 @@
     def __repr__(self):
         return "<%s (calendar inbox collection): %s>" % (self.__class__.__name__, self.fp.path)
 
-    ##
-    # ACL
-    ##
-
-    def defaultAccessControlList(self):
-        return davxml.ACL(
-            # CalDAV:schedule for any authenticated user
-            davxml.ACE(
-                davxml.Principal(davxml.Authenticated()),
-                davxml.Grant(
-                    davxml.Privilege(caldavxml.Schedule()),
-                ),
-            ),
-        )
-
 class ScheduleOutboxFile (ScheduleOutboxResource, ScheduleFile):
     """
     Calendar scheduling outbox collection resource.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20061205/3c51ee27/attachment.html


More information about the calendarserver-changes mailing list