Exemple #1
0
def http_PUT(self, request):

    parentURL = parentForURL(request.uri)
    parent = (yield request.locateResource(parentURL))

    if isPseudoCalendarCollectionResource(parent):

        # Content-type check
        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"),
                "Invalid MIME type for calendar collection",
            ))

        # Read the calendar component from the stream
        try:
            calendardata = (yield allDataFromStream(request.stream))
            if not hasattr(request, "extendedLogItems"):
                request.extendedLogItems = {}
            request.extendedLogItems["cl"] = str(len(calendardata)) if calendardata else "0"

            # We must have some data at this point
            if calendardata is None:
                # Use correct DAV:error response
                raise HTTPError(ErrorResponse(
                    responsecode.FORBIDDEN,
                    (caldav_namespace, "valid-calendar-data"),
                    description="No calendar data"
                ))

            storer = StoreCalendarObjectResource(
                request=request,
                destination=self,
                destination_uri=request.uri,
                destinationcal=True,
                destinationparent=parent,
                calendar=calendardata,
            )
            result = (yield storer.run())

            # Look for Prefer header
            prefer = request.headers.getHeader("prefer", {})
            returnRepresentation = any([key == "return" and value == "representation" for key, value, _ignore_args in prefer])

            if returnRepresentation and result.code / 100 == 2:
                oldcode = result.code
                result = (yield self.http_GET(request))
                if oldcode == responsecode.CREATED:
                    result.code = responsecode.CREATED
                result.headers.setHeader("content-location", request.path)

            returnValue(result)

        except ValueError, e:
            log.err("Error while handling (calendar) PUT: %s" % (e,))
            raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
Exemple #2
0
def http_ACL(self, request):
    #
    # Override base ACL request handling to ensure that the calendar/address book
    # homes cannot have ACL's set, and calendar/address object resources too.
    #

    if self.exists():
        if isinstance(self, CalendarHomeResource) or isinstance(self, AddressBookHomeResource):
            raise HTTPError(responsecode.NOT_ALLOWED)

        parentURL = parentForURL(request.uri)
        parent = (yield request.locateResource(parentURL))
        if isPseudoCalendarCollectionResource(parent) or isAddressBookCollectionResource(parent):
            raise HTTPError(responsecode.NOT_ALLOWED)

    # Do normal ACL behavior
    response = (yield super(CalDAVResource, self).http_ACL(request))
    returnValue(response)
Exemple #3
0
def http_ACL(self, request):
    #
    # Override base ACL request handling to ensure that the calendar/address book
    # homes cannot have ACL's set, and calendar/address object resources too.
    #

    if self.exists():
        if isinstance(self, CalendarHomeResource) or isinstance(
                self, AddressBookHomeResource):
            raise HTTPError(responsecode.NOT_ALLOWED)

        parentURL = parentForURL(request.uri)
        parent = (yield request.locateResource(parentURL))
        if isPseudoCalendarCollectionResource(
                parent) or isAddressBookCollectionResource(parent):
            raise HTTPError(responsecode.NOT_ALLOWED)

    # Do normal ACL behavior
    response = (yield super(CalDAVResource, self).http_ACL(request))
    returnValue(response)
Exemple #4
0
                calendarHome = config.directory.calendarHomeForRecord(record)
                if not calendarHome:
                    pass
                else:
                    calendarHomes.add(calendarHome)

    calendarCollections = set()

    for calendarHome in calendarHomes:
        #print calendarHome
        #sys.stdout.write("*")
        readProperties(calendarHome)

        for childName in calendarHome.listChildren():
            child = calendarHome.getChild(childName)
            if isPseudoCalendarCollectionResource(child):
                calendarCollections.add(child)

    for calendarCollection in calendarCollections:
        try:
            for name, uid, type in calendarCollection.index().indexedSearch(None):
                child = calendarCollection.getChild(name)

                #sys.stdout.write("+")
                child._text()

                readProperties(child)

        except sqlite3.OperationalError:
            # Outbox doesn't live on disk
            if calendarCollection.fp.basename() != "outbox":
Exemple #5
0
def http_GET(self, request):

    if self.exists():
        # Special sharing request on a calendar or address book
        if self.isCalendarCollection() or self.isAddressBookCollection():

            # Check for action=share
            if request.args:
                action = request.args.get("action", ("",))
                if len(action) != 1:
                    raise HTTPError(ErrorResponse(
                        responsecode.BAD_REQUEST,
                        (calendarserver_namespace, "valid-action"),
                        "Invalid action parameter: %s" % (action,),
                    ))
                action = action[0]

                dispatch = {
                    "share": self.directShare,
                }.get(action, None)

                if dispatch is None:
                    raise HTTPError(ErrorResponse(
                        responsecode.BAD_REQUEST,
                        (calendarserver_namespace, "supported-action"),
                        "Action not supported: %s" % (action,),
                    ))

                response = (yield dispatch(request))
                returnValue(response)

        else:
            # FIXME: this should be implemented in storebridge.CalendarObject.render

            # Look for calendar access restriction on existing resource.
            parentURL = parentForURL(request.uri)
            parent = (yield request.locateResource(parentURL))
            if isPseudoCalendarCollectionResource(parent):

                # Check authorization first
                yield self.authorize(request, (davxml.Read(),))

                # Accept header handling
                accepted_type = bestAcceptType(request.headers.getHeader("accept"), Component.allowedTypes())
                if accepted_type is None:
                    raise HTTPError(StatusResponse(responsecode.NOT_ACCEPTABLE, "Cannot generate requested data type"))

                caldata = (yield self.componentForUser())

                # Filter any attendee hidden instances
                caldata = HiddenInstanceFilter().filter(caldata)

                if self.accessMode:

                    # Non DAV:owner's have limited access to the data
                    isowner = (yield self.isOwner(request))

                    # Now "filter" the resource calendar data
                    caldata = PrivateEventFilter(self.accessMode, isowner).filter(caldata)

                response = Response()
                response.stream = MemoryStream(caldata.getTextWithTimezones(includeTimezones=not config.EnableTimezonesByReference, format=accepted_type))
                response.headers.setHeader("content-type", MimeType.fromString("%s; charset=utf-8" % (accepted_type,)))

                # Add Schedule-Tag header if property is present
                if self.scheduleTag:
                    response.headers.setHeader("Schedule-Tag", self.scheduleTag)

                returnValue(response)

    # Do normal GET behavior
    response = (yield super(CalDAVResource, self).http_GET(request))
    returnValue(response)
Exemple #6
0
def http_GET(self, request):

    if self.exists():
        # Special sharing request on a calendar or address book
        if self.isCalendarCollection() or self.isAddressBookCollection():

            # Check for action=share
            if request.args:
                action = request.args.get("action", ("",))
                if len(action) != 1:
                    raise HTTPError(ErrorResponse(
                        responsecode.BAD_REQUEST,
                        (calendarserver_namespace, "valid-action"),
                        "Invalid action parameter: %s" % (action,),
                    ))
                action = action[0]

                dispatch = {
                    "share"   : self.directShare,
                }.get(action, None)

                if dispatch is None:
                    raise HTTPError(ErrorResponse(
                        responsecode.BAD_REQUEST,
                        (calendarserver_namespace, "supported-action"),
                        "Action not supported: %s" % (action,),
                    ))

                response = (yield dispatch(request))
                returnValue(response)

        else:
            # FIXME: this should be implemented in storebridge.CalendarObject.render

            # Look for calendar access restriction on existing resource.
            parentURL = parentForURL(request.uri)
            parent = (yield request.locateResource(parentURL))
            if isPseudoCalendarCollectionResource(parent):

                # Check authorization first
                yield self.authorize(request, (davxml.Read(),))

                # Accept header handling
                accepted_type = bestAcceptType(request.headers.getHeader("accept"), Component.allowedTypes())
                if accepted_type is None:
                    raise HTTPError(StatusResponse(responsecode.NOT_ACCEPTABLE, "Cannot generate requested data type"))

                caldata = (yield self.iCalendarForUser(request))

                # Filter any attendee hidden instances
                caldata = HiddenInstanceFilter().filter(caldata)

                if self.accessMode:

                    # Non DAV:owner's have limited access to the data
                    isowner = (yield self.isOwner(request))

                    # Now "filter" the resource calendar data
                    caldata = PrivateEventFilter(self.accessMode, isowner).filter(caldata)

                response = Response()
                response.stream = MemoryStream(caldata.getTextWithTimezones(includeTimezones=not config.EnableTimezonesByReference, format=accepted_type))
                response.headers.setHeader("content-type", MimeType.fromString("%s; charset=utf-8" % (accepted_type,)))

                # Add Schedule-Tag header if property is present
                if self.scheduleTag:
                    response.headers.setHeader("Schedule-Tag", self.scheduleTag)

                returnValue(response)

    # Do normal GET behavior
    response = (yield super(CalDAVResource, self).http_GET(request))
    returnValue(response)
def http_COPY(self, request):
    """
    Special handling of COPY request if parents are calendar collections.
    When copying we do not have to worry about the source resource as it
    is not being changed in any way. We do need to do an index update for
    the destination if its a calendar collection.
    """

    # Copy of calendar collections isn't allowed.
    if isPseudoCalendarCollectionResource(self):
        returnValue(responsecode.FORBIDDEN)

    result, sourcecal, sourceparent, destination_uri, destination, destinationcal, destinationparent = (yield checkForCalendarAction(self, request))
    if not result or not destinationcal:
        # Check with CardDAV first (XXX might want to check EnableCardDAV switch?)
        result = yield maybeCOPYContact(self, request)
        if result is KEEP_GOING:
            result = yield super(CalDAVFile, self).http_COPY(request)
        returnValue(result)

    #
    # Check authentication and access controls
    #
    yield self.authorize(request, (davxml.Read(),), recurse=True)

    if destination.exists():
        yield destination.authorize(request, (davxml.WriteContent(), davxml.WriteProperties()), recurse=True)
    else:
        destparent = (yield request.locateResource(parentForURL(destination_uri)))
        yield destparent.authorize(request, (davxml.Bind(),))

    # Check for existing destination resource
    overwrite = request.headers.getHeader("overwrite", True)
    if destination.exists() and not overwrite:
        log.err("Attempt to copy onto existing resource without overwrite flag enabled: %s"
                % (destination,))
        raise HTTPError(StatusResponse(
            responsecode.PRECONDITION_FAILED,
            "Destination %s already exists." % (destination_uri,))
        )

    # Checks for copying a calendar collection
    if self.isCalendarCollection():
        log.err("Attempt to copy a calendar collection into another calendar collection %s" % destination)
        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "calendar-collection-location-ok")))

    # We also do not allow regular collections in calendar collections
    if self.isCollection():
        log.err("Attempt to copy a collection into a calendar collection")
        raise HTTPError(StatusResponse(
            responsecode.FORBIDDEN,
            "Cannot create collection within special collection %s" % (destination,))
        )

    # May need to add a location header
    addLocation(request, destination_uri)

    storer = StoreCalendarObjectResource(
        request = request,
        source = self,
        source_uri = request.uri,
        sourceparent = sourceparent,
        sourcecal = sourcecal,
        destination = destination,
        destination_uri = destination_uri,
        destinationparent = destinationparent,
        destinationcal = destinationcal,
    )
    result = (yield storer.run())
    returnValue(result)
def http_MOVE(self, request):
    """
    Special handling of MOVE request if parent is a calendar collection.
    When moving we may need to remove the index entry for the source resource
    since its effectively being deleted. We do need to do an index update for
    the destination if its a calendar collection
    """
    result, sourcecal, sourceparent, destination_uri, destination, destinationcal, destinationparent = (yield checkForCalendarAction(self, request))
    if not result:
        is_calendar_collection = isPseudoCalendarCollectionResource(self)
        defaultCalendar = (yield self.isDefaultCalendar(request)) if is_calendar_collection else False

        if not is_calendar_collection:
            result = yield maybeMOVEContact(self, request)
            if result is not KEEP_GOING:
                returnValue(result)

        # Do default WebDAV action
        result = (yield super(CalDAVFile, self).http_MOVE(request))
        
        if is_calendar_collection:
            # Do some clean up
            yield self.movedCalendar(request, defaultCalendar, destination, destination_uri)

        returnValue(result)
        
    #
    # Check authentication and access controls
    #
    parent = (yield request.locateResource(parentForURL(request.uri)))
    yield parent.authorize(request, (davxml.Unbind(),))

    if destination.exists():
        yield destination.authorize(request, (davxml.Bind(), davxml.Unbind()), recurse=True)
    else:
        destparent = (yield request.locateResource(parentForURL(destination_uri)))
        yield destparent.authorize(request, (davxml.Bind(),))

    # Check for existing destination resource
    overwrite = request.headers.getHeader("overwrite", True)
    if destination.exists() and not overwrite:
        log.err("Attempt to copy onto existing resource without overwrite flag enabled: %s"
                % (destination,))
        raise HTTPError(StatusResponse(
            responsecode.PRECONDITION_FAILED,
            "Destination %s already exists." % (destination_uri,)
        ))

    if destinationcal:
        # Checks for copying a calendar collection
        if self.isCalendarCollection():
            log.err("Attempt to move a calendar collection into another calendar collection %s" % destination)
            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "calendar-collection-location-ok")))
    
        # We also do not allow regular collections in calendar collections
        if self.isCollection():
            log.err("Attempt to move a collection into a calendar collection")
            raise HTTPError(StatusResponse(
                responsecode.FORBIDDEN,
                "Cannot create collection within special collection %s" % (destination,)
            ))

    # May need to add a location header
    addLocation(request, destination_uri)

    storer = StoreCalendarObjectResource(
        request = request,
        source = self,
        source_uri = request.uri,
        sourceparent = sourceparent,
        sourcecal = sourcecal,
        deletesource = True,
        destination = destination,
        destination_uri = destination_uri,
        destinationparent = destinationparent,
        destinationcal = destinationcal,
    )
    result = (yield storer.run())
    returnValue(result)
Exemple #9
0
def http_GET(self, request):

    if self.exists():
        # Special sharing request on a calendar or address book
        if self.isCalendarCollection() or self.isAddressBookCollection():
            
            # Check for action=share
            if request.args:
                action = request.args.get("action", ("",))
                if len(action) != 1:
                    raise HTTPError(ErrorResponse(responsecode.BAD_REQUEST, (calendarserver_namespace, "valid-action")))
                action = action[0]
                    
                dispatch = {
                    "share"   : self.directShare,
                }.get(action, None)
                
                if dispatch is None:
                    raise HTTPError(ErrorResponse(responsecode.BAD_REQUEST, (calendarserver_namespace, "supported-action")))
        
                response = (yield dispatch(request))
                returnValue(response)
        
        else:
            # Look for calendar access restriction on existing resource.
            parentURL = parentForURL(request.uri)
            parent = (yield request.locateResource(parentURL))
            if isPseudoCalendarCollectionResource(parent):
        
                # Check authorization first
                yield self.authorize(request, (davxml.Read(),))
    
                caldata = (yield self.iCalendarForUser(request))
    
                try:
                    access = self.readDeadProperty(TwistedCalendarAccessProperty)
                except HTTPError:
                    access = None
                    
                if access:
            
                    # Non DAV:owner's have limited access to the data
                    isowner = (yield self.isOwner(request, adminprincipals=True, readprincipals=True))
                    
                    # Now "filter" the resource calendar data
                    caldata = PrivateEventFilter(access, isowner).filter(caldata)
        
                response = Response()
                response.stream = MemoryStream(str(caldata))
                response.headers.setHeader("content-type", MimeType.fromString("text/calendar; charset=utf-8"))
        
                # Add Schedule-Tag header if property is present
                if self.hasDeadProperty(ScheduleTag):
                    scheduletag = self.readDeadProperty(ScheduleTag)
                    if scheduletag:
                        response.headers.setHeader("Schedule-Tag", str(scheduletag))
            
                returnValue(response)

    # Do normal GET behavior
    response = (yield super(CalDAVResource, self).http_GET(request))
    returnValue(response)