def __init__(self, parent, proxyType):
        """
        @param parent: the parent of this resource.
        @param proxyType: a C{str} containing the name of the resource.
        """
        if self.isCollection():
            slash = "/"
        else:
            slash = ""

        url = joinURL(parent.principalURL(), proxyType) + slash

        super(CalendarUserProxyPrincipalResource, self).__init__()
        DAVResourceWithChildrenMixin.__init__(self)

        self.parent = parent
        self.proxyType = proxyType
        self._url = url

        # FIXME: if this is supposed to be public, it needs a better name:
        self.pcollection = self.parent.parent.parent

        # Principal UID is parent's GUID plus the proxy type; this we can easily
        # map back to a principal.
        self.uid = "%s#%s" % (self.parent.principalUID(), proxyType)
        self._alternate_urls = tuple(
            joinURL(url, proxyType) + slash
            for url in parent.alternateURIs()
            if url.startswith("/")
        )
Example #2
0
    def __init__(self, parent, record):
        """
        @param parent: the parent of this resource.
        @param record: the L{IDirectoryRecord} that this resource represents.
        """
        super(DirectoryPrincipalResource, self).__init__()

        self.cacheNotifier = self.cacheNotifierFactory(self, cacheHandle="PrincipalToken")

        if self.isCollection():
            slash = "/"
        else:
            slash = ""

        assert record is not None, "Principal must have a directory record"

        self.record = record
        self.parent = parent

        url = joinURL(parent.principalCollectionURL(), self.principalUID()) + slash
        self._url = url

        self._alternate_urls = tuple([
            joinURL(
                parent.parent.principalCollectionURL(),
                record.service.recordTypeToOldName(record.recordType),
                quote(shortName.encode("utf-8"))
            ) + slash
            for shortName in getattr(record, "shortNames", [])
        ])
    def __init__(self, parent, proxyType):
        """
        @param parent: the parent of this resource.
        @param proxyType: a C{str} containing the name of the resource.
        """
        if self.isCollection():
            slash = "/"
        else:
            slash = ""

        url = joinURL(parent.principalURL(), proxyType) + slash

        super(CalendarUserProxyPrincipalResource, self).__init__()
        DAVResourceWithChildrenMixin.__init__(self)

        self.parent          = parent
        self.proxyType       = proxyType
        self._url            = url

        # FIXME: if this is supposed to be public, it needs a better name:
        self.pcollection     = self.parent.parent.parent

        # Principal UID is parent's GUID plus the proxy type; this we can easily
        # map back to a principal.
        self.uid             = "%s#%s" % (self.parent.principalUID(), proxyType)
        self._alternate_urls = tuple(
            joinURL(url, proxyType) + slash
            for url in parent.alternateURIs()
            if url.startswith("/")
        )
Example #4
0
    def __init__(self, parent, record):
        """
        @param parent: the parent of this resource.
        @param record: the L{IDirectoryRecord} that this resource represents.
        """
        super(DirectoryPrincipalResource, self).__init__()

        self.cacheNotifier = self.cacheNotifierFactory(
            self, cacheHandle="PrincipalToken")

        if self.isCollection():
            slash = "/"
        else:
            slash = ""

        assert record is not None, "Principal must have a directory record"

        self.record = record
        self.parent = parent

        url = joinURL(parent.principalCollectionURL(),
                      self.principalUID()) + slash
        self._url = url

        self._alternate_urls = tuple([
            joinURL(parent.parent.principalCollectionURL(),
                    record.service.recordTypeToOldName(record.recordType),
                    quote(shortName.encode("utf-8"))) + slash
            for shortName in getattr(record, "shortNames", [])
        ])
    def addressbook_query(self, addressbook_uri, query, got_xml, data, no_init):

        if not no_init:
            ''' FIXME: clear address book, possibly by removing
            mkcol = """<?xml version="1.0" encoding="utf-8" ?>
<D:mkcol xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">
<D:set>
<D:prop>
<D:resourcetype><D:collection/><C:addressbook/></D:resourcetype>
</D:prop>
</D:set>
</D:mkcol>
"""
            response = yield self.send(SimpleStoreRequest(self, "MKCOL", addressbook_uri, content=mkcol, authPrincipal=self.authPrincipal))

            response = IResponse(response)

            if response.code != responsecode.CREATED:
                self.fail("MKCOL failed: %s" % (response.code,))
            '''
            if data:
                for filename, icaldata in data.iteritems():
                    request = SimpleStoreRequest(
                        self,
                        "PUT",
                        joinURL(addressbook_uri, filename + ".vcf"),
                        headers=Headers({"content-type": MimeType.fromString("text/vcard")}),
                        authPrincipal=self.authPrincipal
                    )
                    request.stream = MemoryStream(icaldata)
                    yield self.send(request)
            else:
                # Add vcards to addressbook
                for child in FilePath(self.vcards_dir).children():
                    if os.path.splitext(child.basename())[1] != ".vcf":
                        continue
                    request = SimpleStoreRequest(
                        self,
                        "PUT",
                        joinURL(addressbook_uri, child.basename()),
                        headers=Headers({"content-type": MimeType.fromString("text/vcard")}),
                        authPrincipal=self.authPrincipal
                    )
                    request.stream = MemoryStream(child.getContent())
                    yield self.send(request)

        request = SimpleStoreRequest(self, "REPORT", addressbook_uri, authPrincipal=self.authPrincipal)
        request.stream = MemoryStream(query.toxml())
        response = yield self.send(request)

        response = IResponse(response)

        if response.code != responsecode.MULTI_STATUS:
            self.fail("REPORT failed: %s" % (response.code,))

        returnValue(
            (yield davXMLFromStream(response.stream).addCallback(got_xml))
        )
Example #6
0
    def calendar_query(self, calendar_uri, query, got_xml, data, no_init):

        if not no_init:
            response = yield self.send(
                SimpleStoreRequest(self,
                                   "MKCALENDAR",
                                   calendar_uri,
                                   authPrincipal=self.authPrincipal))
            response = IResponse(response)
            if response.code != responsecode.CREATED:
                self.fail("MKCALENDAR failed: %s" % (response.code, ))

            if data:
                for filename, icaldata in data.iteritems():
                    request = SimpleStoreRequest(
                        self,
                        "PUT",
                        joinURL(calendar_uri, filename + ".ics"),
                        headers=Headers({
                            "content-type":
                            MimeType.fromString("text/calendar")
                        }),
                        authPrincipal=self.authPrincipal)
                    request.stream = MemoryStream(icaldata)
                    yield self.send(request)
            else:
                # Add holiday events to calendar
                for child in FilePath(self.holidays_dir).children():
                    if os.path.splitext(child.basename())[1] != ".ics":
                        continue
                    request = SimpleStoreRequest(
                        self,
                        "PUT",
                        joinURL(calendar_uri, child.basename()),
                        headers=Headers({
                            "content-type":
                            MimeType.fromString("text/calendar")
                        }),
                        authPrincipal=self.authPrincipal)
                    request.stream = MemoryStream(child.getContent())
                    yield self.send(request)

        request = SimpleStoreRequest(self,
                                     "REPORT",
                                     calendar_uri,
                                     authPrincipal=self.authPrincipal)
        request.stream = MemoryStream(query.toxml())
        response = yield self.send(request)

        response = IResponse(response)

        if response.code != responsecode.MULTI_STATUS:
            self.fail("REPORT failed: %s" % (response.code, ))

        returnValue((yield
                     davXMLFromStream(response.stream).addCallback(got_xml)))
    def actionCapabilities(self, request):
        """
        Return the capabilities of this server.
        """

        if len(request.args) != 0:
            self.problemReport("invalid-action", "Invalid request-URI query parameters", responsecode.BAD_REQUEST)

        urlbase = request.path.rsplit("/", 1)[0]
        result = {
            "version": "1",
            "info": {
                "primary-source" if self.primary else "secondary_source": self.info_source,
                "formats": self.formats,
                "contacts": [],
            },
            "actions": [
                {
                    "name": "capabilities",
                    "uri-template": joinURL(urlbase, "capabilities"),
                    "parameters": [],
                },
                {
                    "name": "list",
                    "uri-template": joinURL(urlbase, "zones{?changedsince}"),
                    "parameters": [
                        {"name": "changedsince", "required": False, "multi": False, },
                    ],
                },
                {
                    "name": "get",
                    "uri-template": joinURL(urlbase, "zones{/tzid}{?start,end}"),
                    "parameters": [
                        {"name": "start", "required": False, "multi": False},
                        {"name": "stop", "required": False, "multi": False, },
                    ],
                },
                {
                    "name": "expand",
                    "uri-template": joinURL(urlbase, "zones{/tzid}/observances{?start,end}"),
                    "parameters": [
                        {"name": "start", "required": True, "multi": False, },
                        {"name": "end", "required": True, "multi": False, },
                    ],
                },
                {
                    "name": "find",
                    "uri-template": joinURL(urlbase, "zones{?pattern}"),
                    "parameters": [
                        {"name": "pattern", "required": True, "multi": False, },
                    ],
                },
            ]
        }
        return JSONResponse(responsecode.OK, result, pretty=config.TimezoneService.PrettyPrintJSON)
    def actionCapabilities(self, request):
        """
        Return the capabilities of this server.
        """

        if len(request.args) != 0:
            self.problemReport("invalid-action", "Invalid request-URI query parameters", responsecode.BAD_REQUEST)

        urlbase = request.path.rsplit("/", 1)[0]
        result = {
            "version": "1",
            "info" : {
                "primary-source" if self.primary else "secondary_source": self.info_source,
                "formats": self.formats,
                "contacts" : [],
            },
            "actions" : [
                {
                    "name": "capabilities",
                    "uri-template": joinURL(urlbase, "capabilities"),
                    "parameters": [],
                },
                {
                    "name": "list",
                    "uri-template": joinURL(urlbase, "zones{?changedsince}"),
                    "parameters": [
                        {"name": "changedsince", "required": False, "multi": False, },
                    ],
                },
                {
                    "name": "get",
                    "uri-template": joinURL(urlbase, "zones{/tzid}{?start,end}"),
                    "parameters": [
                        {"name": "start", "required": False, "multi": False},
                        {"name": "stop", "required": False, "multi": False, },
                    ],
                },
                {
                    "name": "expand",
                    "uri-template": joinURL(urlbase, "zones{/tzid}/observances{?start,end}"),
                    "parameters": [
                        {"name": "start", "required": True, "multi": False, },
                        {"name": "end", "required": True, "multi": False, },
                    ],
                },
                {
                    "name": "find",
                    "uri-template": joinURL(urlbase, "zones{?pattern}"),
                    "parameters": [
                        {"name": "pattern", "required": True, "multi": False, },
                    ],
                },
            ]
        }
        return JSONResponse(responsecode.OK, result, pretty=config.TimezoneService.PrettyPrintJSON)
Example #9
0
    def acceptShare(self, request, inviteUID, summary):

        # Accept the share
        try:
            shareeView = yield self._newStoreHome.acceptShare(
                inviteUID, summary)
        except DirectoryRecordNotFoundError:
            # Missing sharer record => fail request
            raise HTTPError(
                ErrorResponse(
                    responsecode.FORBIDDEN,
                    (calendarserver_namespace, "invalid-share"),
                    "Invite UID not valid",
                ))
        if shareeView is None:
            raise HTTPError(
                ErrorResponse(
                    responsecode.FORBIDDEN,
                    (calendarserver_namespace, "invalid-share"),
                    "Invite UID not valid",
                ))

        # Return the URL of the shared collection
        sharedAsURL = joinURL(self.url(), shareeView.shareName())
        returnValue(
            XMLResponse(code=responsecode.OK,
                        element=customxml.SharedAs(
                            element.HRef.fromString(sharedAsURL))))
        def queryCalendarObjectResource(resource, uri, name, calendar, timezone, query_ok=False, isowner=True):
            """
            Run a query on the specified calendar.
            @param resource: the L{CalDAVResource} for the calendar.
            @param uri: the uri of the resource.
            @param name: the name of the resource.
            @param calendar: the L{Component} calendar read from the resource.
            """

            # Handle private events access restrictions
            if not isowner:
                access = resource.accessMode
            else:
                access = None

            if query_ok or filter.match(calendar, access):
                # Check size of results is within limit
                matchcount[0] += 1
                if max_number_of_results[0] is not None and matchcount[0] > max_number_of_results[0]:
                    raise NumberOfMatchesWithinLimits(max_number_of_results[0])

                if name:
                    href = davxml.HRef.fromString(joinURL(uri, name))
                else:
                    href = davxml.HRef.fromString(uri)

                try:
                    yield report_common.responseForHref(request, responses, href, resource, propertiesForResource, props, isowner, calendar=calendar, timezone=timezone)
                except ConcurrentModification:
                    # This can happen because of a race-condition between the
                    # time we determine which resources exist and the deletion
                    # of one of these resources in another request.  In this
                    # case, we ignore the now missing resource rather
                    # than raise an error for the entire report.
                    log.error("Missing resource during query: %s" % (href,))
Example #11
0
    def accessControlList(self, request, *args, **kwargs):
        """
        Override this to give write proxies DAV:write-acl privilege so they can add attachments too.
        """

        acl = (yield super(DropBoxHomeResource, self).accessControlList(request, *args, **kwargs))

        if config.EnableProxyPrincipals:
            owner = (yield self.ownerPrincipal(request))

            newaces = tuple(acl.children)
            newaces += (
                # DAV:write-acl access for this principal's calendar-proxy-write users.
                davxml.ACE(
                    davxml.Principal(davxml.HRef(joinURL(owner.principalURL(), "calendar-proxy-write/"))),
                    davxml.Grant(
                        davxml.Privilege(davxml.WriteACL()),
                    ),
                    davxml.Protected(),
                    TwistedACLInheritable(),
                ),
            )

            returnValue(davxml.ACL(*newaces))

        else:
            returnValue(acl)
    def test_collection_in_calendar(self):
        """
        Make (regular) collection in calendar
        """
        calendar_uri = "/calendars/users/wsanchez/collection_in_calendar/"

        principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
        request = SimpleStoreRequest(self,
                                     "MKCALENDAR",
                                     calendar_uri,
                                     authPrincipal=principal)
        response = yield self.send(request)
        response = IResponse(response)
        if response.code != responsecode.CREATED:
            self.fail("MKCALENDAR failed: %s" % (response.code, ))
            nested_uri = joinURL(calendar_uri, "nested")

            request = SimpleStoreRequest(self,
                                         "MKCOL",
                                         nested_uri,
                                         authPrincipal=principal)
            response = yield self.send(request)
            response = IResponse(response)

            if response.code != responsecode.FORBIDDEN:
                self.fail("Incorrect response to nested MKCOL: %s" %
                          (response.code, ))
Example #13
0
    def readProperty(self, property, request):
        if type(property) is tuple:
            qname = property
        else:
            qname = property.qname()

        if qname == caldavxml.CalendarFreeBusySet.qname():
            # Synthesize value for calendar transparency state
            top = self.parent.url()
            values = []
            for cal in (yield self.parent._newStoreHome.calendars()):
                if cal.isUsedForFreeBusy():
                    values.append(HRef(joinURL(top, cal.name()) + "/"))
            returnValue(CalendarFreeBusySet(*values))

        elif qname == customxml.CalendarAvailability.qname():
            availability = self.parent._newStoreHome.getAvailability()
            returnValue(customxml.CalendarAvailability.fromString(str(availability)) if availability else None)

        elif qname in (caldavxml.ScheduleDefaultCalendarURL.qname(), customxml.ScheduleDefaultTasksURL.qname()):
            result = (yield self.readDefaultCalendarProperty(request, qname))
            returnValue(result)

        result = (yield super(ScheduleInboxResource, self).readProperty(property, request))
        returnValue(result)
Example #14
0
    def doRequest(self):
        """
        Execute the actual HTTP request.
        """
        hrefs = [
            joinURL(self.sessions[0].calendarHref, "%d.ics" % (i + 1, ))
            for i in range(self.count)
        ]
        props = (
            davxml.getetag,
            caldavxml.calendar_data,
            caldavxml.schedule_tag,
        )

        # Create CalDAV multiget
        request = Multiget(self.sessions[0], self.sessions[0].calendarHref,
                           hrefs, props)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.sessions[0].runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:
            pass
        else:
            raise RuntimeError("Muliget request failed: %s" %
                               (request.getStatusCode(), ))
        def queryAddressBookObjectResource(resource, uri, name, vcard, query_ok=False):
            """
            Run a query on the specified vcard.
            @param resource: the L{CalDAVResource} for the vcard.
            @param uri: the uri of the resource.
            @param name: the name of the resource.
            @param vcard: the L{Component} vcard read from the resource.
            """

            if query_ok or filter.match(vcard):
                # Check size of results is within limit
                checkMaxResults()

                if name:
                    href = davxml.HRef.fromString(joinURL(uri, name))
                else:
                    href = davxml.HRef.fromString(uri)

                try:
                    yield report_common.responseForHref(request, responses, href, resource, propertiesForResource, query, vcard=vcard)
                except ConcurrentModification:
                    # This can happen because of a race-condition between the
                    # time we determine which resources exist and the deletion
                    # of one of these resources in another request.  In this
                    # case, we ignore the now missing resource rather
                    # than raise an error for the entire report.
                    log.error("Missing resource during sync: {href}", href=href)
Example #16
0
 def cleanup(self):
     """
     Do some cleanup after the real request.
     """
     # Remove created resources
     href = joinURL(self.sessions[0].calendarHref, "put.ics")
     self.sessions[0].deleteResource(URL(path=href))
Example #17
0
    def acceptShare(self, request, inviteUID, summary):

        # Accept the share
        try:
            shareeView = yield self._newStoreHome.acceptShare(inviteUID, summary)
        except DirectoryRecordNotFoundError:
            # Missing sharer record => fail request
            raise HTTPError(ErrorResponse(
                responsecode.FORBIDDEN,
                (calendarserver_namespace, "invalid-share"),
                "Invite UID not valid",
            ))
        if shareeView is None:
            raise HTTPError(ErrorResponse(
                responsecode.FORBIDDEN,
                (calendarserver_namespace, "invalid-share"),
                "Invite UID not valid",
            ))

        # Return the URL of the shared collection
        sharedAsURL = joinURL(self.url(), shareeView.shareName())
        returnValue(XMLResponse(
            code=responsecode.OK,
            element=customxml.SharedAs(
                element.HRef.fromString(sharedAsURL)
            )
        ))
Example #18
0
    def __init__(self, base_uri, errors):
        """
        An error response which is due to unsufficient privileges, as
        determined by L{DAVResource.checkPrivileges}.
        @param base_uri: the base URI for the resources with errors (the URI of
            the resource on which C{checkPrivileges} was called).
        @param errors: a sequence of tuples, as returned by
            C{checkPrivileges}.
        """
        denials = []

        for subpath, privileges in errors:
            if subpath is None:
                uri = base_uri
            else:
                uri = joinURL(base_uri, subpath)

            for p in privileges:
                denials.append(
                    element.Resource(element.HRef(uri), element.Privilege(p))
                )

        super(NeedPrivilegesResponse, self).__init__(
            responsecode.FORBIDDEN, element.NeedPrivileges(*denials)
        )
Example #19
0
    def readProperty(self, property, request):
        if type(property) is tuple:
            qname = property
        else:
            qname = property.qname()

        if qname == caldavxml.CalendarFreeBusySet.qname():
            # Synthesize value for calendar transparency state
            top = self.parent.url()
            values = []
            for cal in (yield self.parent._newStoreHome.calendars()):
                if cal.isUsedForFreeBusy():
                    values.append(HRef(joinURL(top, cal.name()) + "/"))
            returnValue(CalendarFreeBusySet(*values))

        elif qname == customxml.CalendarAvailability.qname():
            availability = self.parent._newStoreHome.getAvailability()
            returnValue(
                customxml.CalendarAvailability.
                fromString(str(availability)) if availability else None)

        elif qname in (caldavxml.ScheduleDefaultCalendarURL.qname(),
                       customxml.ScheduleDefaultTasksURL.qname()):
            result = (yield self.readDefaultCalendarProperty(request, qname))
            returnValue(result)

        result = (yield super(ScheduleInboxResource,
                              self).readProperty(property, request))
        returnValue(result)
Example #20
0
    def accessControlList(self, request, *args, **kwargs):
        """
        Override this to give write proxies DAV:write-acl privilege so they can add attachments too.
        """

        acl = (yield super(DropBoxHomeResource,
                           self).accessControlList(request, *args, **kwargs))

        if config.EnableProxyPrincipals:
            owner = (yield self.ownerPrincipal(request))

            newaces = tuple(acl.children)
            newaces += (
                # DAV:write-acl access for this principal's calendar-proxy-write users.
                davxml.ACE(
                    davxml.Principal(
                        davxml.HRef(
                            joinURL(owner.principalURL(),
                                    "calendar-proxy-write/"))),
                    davxml.Grant(davxml.Privilege(davxml.WriteACL()), ),
                    davxml.Protected(),
                    TwistedACLInheritable(),
                ), )

            returnValue(davxml.ACL(*newaces))

        else:
            returnValue(acl)
    def _test_file_in_calendar(self, what, *work):
        """
        Creates a calendar collection, then PUTs a resource into that collection
        with the data from given stream and verifies that the response code from the
        PUT request matches the given response_code.
        """
        calendar_uri = "/calendars/users/wsanchez/testing_calendar/"

        principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
        request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authPrincipal=principal)
        response = yield self.send(request)
        response = IResponse(response)
        if response.code != responsecode.CREATED:
            self.fail("MKCALENDAR failed: %s" % (response.code,))

        c = 0
        for stream, response_code in work:
            dst_uri = joinURL(calendar_uri, "dst%d.ics" % (c,))
            request = SimpleStoreRequest(self, "PUT", dst_uri, authPrincipal=principal)
            request.headers.setHeader("if-none-match", "*")
            request.headers.setHeader("content-type", MimeType("text", "calendar"))
            request.stream = stream
            response = yield self.send(request)
            response = IResponse(response)

            if response.code != response_code:
                self.fail("Incorrect response to %s: %s (!= %s)" % (what, response.code, response_code))

            c += 1
    def _test_file_in_calendar(self, what, *work):
        """
        Creates a calendar collection, then PUTs a resource into that collection
        with the data from given stream and verifies that the response code from the
        PUT request matches the given response_code.
        """
        calendar_uri = "/calendars/users/wsanchez/testing_calendar/"

        principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
        request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authPrincipal=principal)
        response = yield self.send(request)
        response = IResponse(response)
        if response.code != responsecode.CREATED:
            self.fail("MKCALENDAR failed: %s" % (response.code,))

        c = 0
        for stream, response_code in work:
            dst_uri = joinURL(calendar_uri, "dst%d.ics" % (c,))
            request = SimpleStoreRequest(self, "PUT", dst_uri, authPrincipal=principal)
            request.headers.setHeader("if-none-match", "*")
            request.headers.setHeader("content-type", MimeType("text", "calendar"))
            request.stream = stream
            response = yield self.send(request)
            response = IResponse(response)

            if response.code != response_code:
                self.fail("Incorrect response to %s: %s (!= %s)" % (what, response.code, response_code))

            c += 1
Example #23
0
 def cleanup(self):
     """
     Do some cleanup after the real request.
     """
     # Remove created resources
     href = joinURL(self.sessions[0].calendarHref, "put.ics")
     self.sessions[0].deleteResource(URL(path=href))
Example #24
0
 def cleanup(self):
     """
     Do some cleanup after the real request.
     """
     # Remove created resources
     for i in range(self.count):
         href = joinURL(self.sessions[0].calendarHref, "tr-query-%d.ics" % (i + 1,))
         self.sessions[0].deleteResource(URL(path=href))
Example #25
0
    def doRequest(self):
        """
        Execute the actual HTTP request.
        """

        now = DateTime.getNowUTC()
        href = joinURL(self.sessions[0].calendarHref, "put.ics")
        self.sessions[0].writeData(URL(path=href), ICAL % (now.getYear() + 1,), "text/calendar")
Example #26
0
    def doRequest(self):
        """
        Execute the actual HTTP request.
        """

        now = DateTime.getNowUTC()
        href = joinURL(self.sessions[0].calendarHref, "put.ics")
        self.sessions[0].writeData(URL(path=href), ICAL % (now.getYear() + 1,), "text/calendar")
Example #27
0
 def cleanup(self):
     """
     Do some cleanup after the real request.
     """
     # Remove created resources
     for i in range(self.count):
         href = joinURL(self.sessions[0].calendarHref, "tr-query-%d.ics" % (i + 1,))
         self.sessions[0].deleteResource(URL(path=href))
    def calendar_query(self, calendar_uri, query, got_xml, data, no_init):

        if not no_init:
            response = yield self.send(SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authid="wsanchez"))
            response = IResponse(response)
            if response.code != responsecode.CREATED:
                self.fail("MKCALENDAR failed: %s" % (response.code,))

            if data:
                for filename, icaldata in data.iteritems():
                    request = SimpleStoreRequest(
                        self,
                        "PUT",
                        joinURL(calendar_uri, filename + ".ics"),
                        headers=Headers({"content-type": MimeType.fromString("text/calendar")}),
                        authid="wsanchez"
                    )
                    request.stream = MemoryStream(icaldata)
                    yield self.send(request)
            else:
                # Add holiday events to calendar
                for child in FilePath(self.holidays_dir).children():
                    if os.path.splitext(child.basename())[1] != ".ics":
                        continue
                    request = SimpleStoreRequest(
                        self,
                        "PUT",
                        joinURL(calendar_uri, child.basename()),
                        headers=Headers({"content-type": MimeType.fromString("text/calendar")}),
                        authid="wsanchez"
                    )
                    request.stream = MemoryStream(child.getContent())
                    yield self.send(request)

        request = SimpleStoreRequest(self, "REPORT", calendar_uri, authid="wsanchez")
        request.stream = MemoryStream(query.toxml())
        response = yield self.send(request)

        response = IResponse(response)

        if response.code != responsecode.MULTI_STATUS:
            self.fail("REPORT failed: %s" % (response.code,))

        returnValue(
            (yield davXMLFromStream(response.stream).addCallback(got_xml))
        )
Example #29
0
    def mkdtemp(self, prefix):
        """
        Creates a new directory in the document root and returns its path and
        URI.
        """
        path = mkdtemp(prefix=prefix + "_", dir=self.docroot)
        uri = joinURL("/", url_quote(os.path.basename(path))) + "/"

        return (os.path.abspath(path), uri)
Example #30
0
    def mkdtemp(self, prefix):
        """
        Creates a new directory in the document root and returns its path and
        URI.
        """
        path = mkdtemp(prefix=prefix + "_", dir=self.docroot)
        uri = joinURL("/", url_quote(os.path.basename(path))) + "/"

        return (os.path.abspath(path), uri)
Example #31
0
    def _addressBookHomeChildURL(self, name):
        if not hasattr(self, "addressBookHomeURL"):
            if self.parent.parent.addressBookCollection is None:
                return None
            self.addressBookHomeURL = joinURL(
                self.parent.parent.addressBookCollection.url(),
                uidsResourceName, self.record.uid) + "/"

            # Prefix with other server if needed
            if not self.thisServer():
                self.addressBookHomeURL = joinURL(self.serverURI(),
                                                  self.addressBookHomeURL)

        url = self.addressBookHomeURL
        if url is None:
            return None
        else:
            return joinURL(url, name) if name else url
Example #32
0
    def writeProperty(self, property, request):
        assert isinstance(property, davxml.WebDAVElement)

        # Strictly speaking CS:calendar-availability is a live property in the sense that the
        # server enforces what can be stored, however it need not actually
        # exist so we cannot list it in liveProperties on this resource, since its
        # its presence there means that hasProperty will always return True for it.
        if property.qname() == customxml.CalendarAvailability.qname():
            if not property.valid():
                raise HTTPError(ErrorResponse(
                    responsecode.CONFLICT,
                    (caldav_namespace, "valid-calendar-data"),
                    description="Invalid property"
                ))
            yield self.parent._newStoreHome.setAvailability(property.calendar())
            returnValue(None)

        elif property.qname() == caldavxml.CalendarFreeBusySet.qname():
            # Verify that the calendars added in the PROPPATCH are valid. We do not check
            # whether existing items in the property are still valid - only new ones.
            property.children = [davxml.HRef(normalizeURL(str(href))) for href in property.children]
            new_calendars = set([str(href) for href in property.children])
            old_calendars = set()
            for cal in (yield self.parent._newStoreHome.calendars()):
                if cal.isUsedForFreeBusy():
                    old_calendars.add(HRef(joinURL(self.parent.url(), cal.name())))
            added_calendars = new_calendars.difference(old_calendars)
            for href in added_calendars:
                cal = (yield request.locateResource(str(href)))
                if cal is None or not cal.exists() or not isCalendarCollectionResource(cal):
                    # Validate that href's point to a valid calendar.
                    raise HTTPError(ErrorResponse(
                        responsecode.CONFLICT,
                        (caldav_namespace, "valid-calendar-url"),
                        "Invalid URI",
                    ))

            # Remove old ones
            for href in old_calendars.difference(new_calendars):
                cal = (yield request.locateResource(str(href)))
                if cal is not None and cal.exists() and isCalendarCollectionResource(cal) and cal._newStoreObject.isUsedForFreeBusy():
                    yield cal._newStoreObject.setUsedForFreeBusy(False)

            # Add new ones
            for href in new_calendars:
                cal = (yield request.locateResource(str(href)))
                if cal is not None and cal.exists() and isCalendarCollectionResource(cal) and not cal._newStoreObject.isUsedForFreeBusy():
                    yield cal._newStoreObject.setUsedForFreeBusy(True)

            returnValue(None)

        elif property.qname() in (caldavxml.ScheduleDefaultCalendarURL.qname(), customxml.ScheduleDefaultTasksURL.qname()):
            yield self.writeDefaultCalendarProperty(request, property)
            returnValue(None)

        yield super(ScheduleInboxResource, self).writeProperty(property, request)
    def simple_vcard_query(self, vcard_uri, vcard_filter, uids, withData=True, limit=None):

        vcard_uri = joinURL("/addressbooks/users/wsanchez", vcard_uri)

        props = (davxml.GETETag(),)
        if withData:
            props += (carddavxml.AddressData(),)
        query = carddavxml.AddressBookQuery(davxml.PropertyContainer(*props), carddavxml.Filter(vcard_filter))

        def got_xml(doc):
            if not isinstance(doc.root_element, davxml.MultiStatus):
                self.fail("REPORT response XML root element is not multistatus: %r" % (doc.root_element,))

            count = 0
            for response in doc.root_element.childrenOfType(davxml.PropertyStatusResponse):
                for propstat in response.childrenOfType(davxml.PropertyStatus):
                    status = propstat.childOfType(davxml.Status)

                    if status.code == responsecode.INSUFFICIENT_STORAGE_SPACE and limit is not None:
                        continue
                    if status.code != responsecode.OK:
                        self.fail("REPORT failed (status %s) to locate properties: %r" % (status.code, propstat))
                    elif limit is not None:
                        count += 1
                        continue

                    properties = propstat.childOfType(davxml.PropertyContainer).children

                    for property in properties:
                        qname = property.qname()
                        if qname == (davxml.dav_namespace, "getetag"):
                            continue
                        if qname != (carddavxml.carddav_namespace, "address-data"):
                            self.fail("Response included unexpected property %r" % (property,))

                        result_addressbook = property.address()

                        if result_addressbook is None:
                            self.fail("Invalid response CardDAV:address-data: %r" % (property,))

                        uid = result_addressbook.resourceUID()

                        if uid in uids:
                            uids.remove(uid)
                        else:
                            self.fail("Got addressbook for unexpected UID %r" % (uid,))

                        original_filename = file(os.path.join(self.vcards_dir, uid + ".vcf"))
                        original_addressbook = vcard.Component.fromStream(original_filename)

                        self.assertEqual(result_addressbook, original_addressbook)

                if limit is not None and count != limit:
                    self.fail("Wrong number of limited results: %d" % (count,))

        return self.addressbook_query(vcard_uri, query, got_xml)
Example #34
0
    def writeProperty(self, property, request):
        assert isinstance(property, davxml.WebDAVElement)

        # Strictly speaking CS:calendar-availability is a live property in the sense that the
        # server enforces what can be stored, however it need not actually
        # exist so we cannot list it in liveProperties on this resource, since its
        # its presence there means that hasProperty will always return True for it.
        if property.qname() == customxml.CalendarAvailability.qname():
            if not property.valid():
                raise HTTPError(ErrorResponse(
                    responsecode.CONFLICT,
                    (caldav_namespace, "valid-calendar-data"),
                    description="Invalid property"
                ))
            yield self.parent._newStoreHome.setAvailability(property.calendar())
            returnValue(None)

        elif property.qname() == caldavxml.CalendarFreeBusySet.qname():
            # Verify that the calendars added in the PROPPATCH are valid. We do not check
            # whether existing items in the property are still valid - only new ones.
            property.children = [davxml.HRef(normalizeURL(str(href))) for href in property.children]
            new_calendars = set([str(href) for href in property.children])
            old_calendars = set()
            for cal in (yield self.parent._newStoreHome.calendars()):
                if cal.isUsedForFreeBusy():
                    old_calendars.add(HRef(joinURL(self.parent.url(), cal.name())))
            added_calendars = new_calendars.difference(old_calendars)
            for href in added_calendars:
                cal = (yield request.locateResource(str(href)))
                if cal is None or not cal.exists() or not isCalendarCollectionResource(cal):
                    # Validate that href's point to a valid calendar.
                    raise HTTPError(ErrorResponse(
                        responsecode.CONFLICT,
                        (caldav_namespace, "valid-calendar-url"),
                        "Invalid URI",
                    ))

            # Remove old ones
            for href in old_calendars.difference(new_calendars):
                cal = (yield request.locateResource(str(href)))
                if cal is not None and cal.exists() and isCalendarCollectionResource(cal) and cal._newStoreObject.isUsedForFreeBusy():
                    yield cal._newStoreObject.setUsedForFreeBusy(False)

            # Add new ones
            for href in new_calendars:
                cal = (yield request.locateResource(str(href)))
                if cal is not None and cal.exists() and isCalendarCollectionResource(cal) and not cal._newStoreObject.isUsedForFreeBusy():
                    yield cal._newStoreObject.setUsedForFreeBusy(True)

            returnValue(None)

        elif property.qname() in (caldavxml.ScheduleDefaultCalendarURL.qname(), customxml.ScheduleDefaultTasksURL.qname()):
            yield self.writeDefaultCalendarProperty(request, property)
            returnValue(None)

        yield super(ScheduleInboxResource, self).writeProperty(property, request)
Example #35
0
    def _addressBookHomeChildURL(self, name):
        if not hasattr(self, "addressBookHomeURL"):
            if not hasattr(self.record.service, "addressBookHomesCollection"):
                return None
            self.addressBookHomeURL = joinURL(
                self.record.service.addressBookHomesCollection.url(),
                uidsResourceName,
                self.record.uid
            ) + "/"

            # Prefix with other server if needed
            if not self.thisServer():
                self.addressBookHomeURL = joinURL(self.serverURI(), self.addressBookHomeURL)

        url = self.addressBookHomeURL
        if url is None:
            return None
        else:
            return joinURL(url, name) if name else url
Example #36
0
    def _homeChildURL(self, name):
        if not hasattr(self, "calendarHomeURL"):
            if not hasattr(self.record.service, "calendarHomesCollection"):
                return None
            self.calendarHomeURL = joinURL(
                self.record.service.calendarHomesCollection.url(),
                uidsResourceName,
                self.record.uid
            ) + "/"

            # Prefix with other server if needed
            if not self.thisServer():
                self.calendarHomeURL = joinURL(self.serverURI(), self.calendarHomeURL)

        url = self.calendarHomeURL
        if url is None:
            return None
        else:
            return joinURL(url, name) if name else url
Example #37
0
    def _homeChildURL(self, name):
        if not hasattr(self, "calendarHomeURL"):
            if self.parent.parent.calendarCollection is None:
                return None
            self.calendarHomeURL = joinURL(
                self.parent.parent.calendarCollection.url(),
                uidsResourceName,
                self.record.uid
            ) + "/"

            # Prefix with other server if needed
            if not self.thisServer():
                self.calendarHomeURL = joinURL(self.serverURI(), self.calendarHomeURL)

        url = self.calendarHomeURL
        if url is None:
            return None
        else:
            return joinURL(url, name) if name else url
Example #38
0
    def __init__(self, parent):
        """
        @param directory: an L{IDirectoryService} to provision calendars from.
        @param recordType: the directory record type to provision.
        """
        DirectoryProvisioningResource.__init__(
            self,
            joinURL(parent.principalCollectionURL(), uidsResourceName) + "/",
            parent.directory)

        self.parent = parent
Example #39
0
 def provisionShare(self, child, request=None):
     """
     Set shared state and check access control.
     """
     if child._newStoreObject is not None and not child._newStoreObject.owned():
         ownerHomeURL = (yield self._otherPrincipalHomeURL(child._newStoreObject.ownerHome().uid()))
         ownerView = yield child._newStoreObject.ownerView()
         child.setShare(joinURL(ownerHomeURL, ownerView.name()) if ownerHomeURL else None)
         access = yield child._checkAccessControl()
         if access is None:
             returnValue(None)
     returnValue(child)
Example #40
0
 def provisionShare(self, child, request=None):
     """
     Set shared state and check access control.
     """
     if child._newStoreObject is not None and not child._newStoreObject.owned():
         ownerHomeURL = (yield self._otherPrincipalHomeURL(child._newStoreObject.ownerHome().uid()))
         ownerView = yield child._newStoreObject.ownerView()
         child.setShare(joinURL(ownerHomeURL, ownerView.name()) if ownerHomeURL else None)
         access = yield child._checkAccessControl()
         if access is None:
             returnValue(None)
     returnValue(child)
Example #41
0
    def __init__(self, parent):
        """
        @param directory: an L{IDirectoryService} to provision calendars from.
        @param recordType: the directory record type to provision.
        """
        DirectoryProvisioningResource.__init__(
            self,
            joinURL(parent.principalCollectionURL(), uidsResourceName) + "/",
            parent.directory
        )

        self.parent = parent
Example #42
0
    def __init__(self, parent, name, recordType):
        """
        @param parent: the parent L{DirectoryPrincipalProvisioningResource}.
        @param recordType: the directory record type to provision.
        """
        DirectoryProvisioningResource.__init__(
            self,
            joinURL(parent.principalCollectionURL(), name) + "/",
            parent.directory)

        self.recordType = recordType
        self.parent = parent
Example #43
0
 def prepare(self):
     """
     Do some setup prior to the real request.
     """
     # Add resources to create required number of changes
     self.start = DateTime.getNowUTC()
     self.start.setHHMMSS(12, 0, 0)
     self.end = self.start.duplicate()
     self.end.offsetHours(1)
     for i in range(self.count):
         href = joinURL(self.sessions[0].calendarHref, "tr-query-%d.ics" % (i + 1,))
         self.sessions[0].writeData(URL(path=href), ICAL % (self.start.getText(), i + 1,), "text/calendar")
Example #44
0
 def prepare(self):
     """
     Do some setup prior to the real request.
     """
     # Add resources to create required number of changes
     self.start = DateTime.getNowUTC()
     self.start.setHHMMSS(12, 0, 0)
     self.end = self.start.duplicate()
     self.end.offsetHours(1)
     for i in range(self.count):
         href = joinURL(self.sessions[0].calendarHref, "tr-query-%d.ics" % (i + 1,))
         self.sessions[0].writeData(URL(path=href), ICAL % (self.start.getText(), i + 1,), "text/calendar")
Example #45
0
    def __init__(self, parent, name, recordType):
        """
        @param parent: the parent L{DirectoryPrincipalProvisioningResource}.
        @param recordType: the directory record type to provision.
        """
        DirectoryProvisioningResource.__init__(
            self,
            joinURL(parent.principalCollectionURL(), name) + "/",
            parent.directory
        )

        self.recordType = recordType
        self.parent = parent
Example #46
0
    def ensureEvents(self, session, calendarhref, n):
        """
        Make sure the required number of events are present in the calendar.

        @param n: number of events
        @type n: C{int}
        """
        now = DateTime.getNowUTC()
        for i in range(n - self.currentCount):
            index = self.currentCount + i + 1
            href = joinURL(calendarhref, "%d.ics" % (index,))
            session.writeData(URL(path=href), ICAL % (now.getYear() + 1, index,), "text/calendar")

        self.currentCount = n
Example #47
0
    def defaultCalendar(self, request, componentType):
        """
        Find the default calendar for the supplied iCalendar component type. If one does
        not exist, automatically provision it.
        """

        # This property now comes direct from the calendar home new store object
        default = (yield self.parent._newStoreHome.defaultCalendar(componentType, create=False))

        # Need L{DAVResource} object to return not new store object
        if default is not None:
            default = (yield request.locateResource(joinURL(self.parent.url(), default.name())))

        returnValue(default)
Example #48
0
    def doRequest(self):
        """
        Execute the actual HTTP request.
        """

        # Invite as user02
        now = DateTime.getNowUTC()
        href = joinURL(self.sessions[1].calendarHref, "organizer.ics")
        attendees = "\r\n".join(["ATTENDEE:mailto:[email protected]"] + [ATTENDEE % (ctr + 3,) for ctr in range(self.count - 1)])
        self.sessions[1].writeData(
            URL(path=href),
            ICAL.format(year=now.getYear() + 1, count=self.count, attendees=attendees),
            "text/calendar",
        )
Example #49
0
    def prepare(self):
        """
        Do some setup prior to the real request.
        """
        if not self.full:
            # Get current sync token
            results, _ignore_bad = self.sessions[0].getProperties(URL(path=self.sessions[0].calendarHref), (davxml.sync_token,))
            self.synctoken = results[davxml.sync_token]

            # Add resources to create required number of changes
            now = DateTime.getNowUTC()
            for i in range(self.count):
                href = joinURL(self.sessions[0].calendarHref, "sync-collection-%d.ics" % (i + 1,))
                self.sessions[0].writeData(URL(path=href), ICAL % (now.getYear() + 1, i + 1,), "text/calendar")
Example #50
0
    def ensureEvents(self, session, calendarhref, n):
        """
        Make sure the required number of events are present in the calendar.

        @param n: number of events
        @type n: C{int}
        """
        now = DateTime.getNowUTC()
        for i in range(n - self.currentCount):
            index = self.currentCount + i + 1
            href = joinURL(calendarhref, "%d.ics" % (index,))
            session.writeData(URL(path=href), ICAL % (now.getYear() + 1, index), "text/calendar")

        self.currentCount = n
Example #51
0
    def prepare(self):
        """
        Do some setup prior to the real request.
        """
        if not self.full:
            # Get current sync token
            results, _ignore_bad = self.sessions[0].getProperties(URL(path=self.sessions[0].calendarHref), (davxml.sync_token,))
            self.synctoken = results[davxml.sync_token]

            # Add resources to create required number of changes
            now = DateTime.getNowUTC()
            for i in range(self.count):
                href = joinURL(self.sessions[0].calendarHref, "sync-collection-%d.ics" % (i + 1,))
                self.sessions[0].writeData(URL(path=href), ICAL % (now.getYear() + 1, i + 1,), "text/calendar")
Example #52
0
    def doRequest(self):
        """
        Execute the actual HTTP request.
        """

        # Invite as user02
        now = DateTime.getNowUTC()
        href = joinURL(self.sessions[1].calendarHref, "organizer.ics")
        attendees = "\r\n".join(["ATTENDEE:mailto:[email protected]"] + [ATTENDEE % (ctr + 3,) for ctr in range(self.count - 1)])
        self.sessions[1].writeData(
            URL(path=href),
            ICAL.format(year=now.getYear() + 1, count=self.count, attendees=attendees),
            "text/calendar",
        )
Example #53
0
    def defaultCalendar(self, request, componentType):
        """
        Find the default calendar for the supplied iCalendar component type. If one does
        not exist, automatically provision it.
        """

        # This property now comes direct from the calendar home new store object
        default = (yield self.parent._newStoreHome.defaultCalendar(componentType, create=False))

        # Need L{DAVResource} object to return not new store object
        if default is not None:
            default = (yield request.locateResource(joinURL(self.parent.url(), default.name())))

        returnValue(default)
Example #54
0
    def render(self, request):
        output = """<html>
<head>
<title>DomainKey Resource</title>
</head>
<body>
<h1>DomainKey Resource.</h1>
<a href="%s">Domain: %s<br>
Selector: %s</a>
</body
</html>""" % (joinURL(request.uri, self.domain, self.selector), self.domain, self.selector,)

        response = Response(200, {}, output)
        response.headers.setHeader("content-type", MimeType("text", "html"))
        return response
Example #55
0
    def render(self, request):
        output = """<html>
<head>
<title>DomainKey Resource</title>
</head>
<body>
<h1>DomainKey Resource.</h1>
<a href="%s">Domain: %s<br>
Selector: %s</a>
</body
</html>""" % (joinURL(request.uri, self.domain, self.selector), self.domain, self.selector,)

        response = Response(200, {}, output)
        response.headers.setHeader("content-type", MimeType("text", "html"))
        return response
Example #56
0
    def readDefaultCalendarProperty(self, request, qname):
        """
        Read either the default VEVENT or VTODO calendar property. Try to pick one if not present.
        """

        tasks = qname == customxml.ScheduleDefaultTasksURL.qname()
        componentType = "VTODO" if tasks else "VEVENT"
        prop_to_set = customxml.ScheduleDefaultTasksURL if tasks else caldavxml.ScheduleDefaultCalendarURL

        # This property now comes direct from the calendar home new store object
        default = (yield self.parent._newStoreHome.defaultCalendar(componentType, create=False))
        if default is None:
            returnValue(prop_to_set())
        else:
            defaultURL = joinURL(self.parent.url(), default.name())
            returnValue(prop_to_set(davxml.HRef(defaultURL)))
Example #57
0
    def readDefaultCalendarProperty(self, request, qname):
        """
        Read either the default VEVENT or VTODO calendar property. Try to pick one if not present.
        """

        tasks = qname == customxml.ScheduleDefaultTasksURL.qname()
        componentType = "VTODO" if tasks else "VEVENT"
        prop_to_set = customxml.ScheduleDefaultTasksURL if tasks else caldavxml.ScheduleDefaultCalendarURL

        # This property now comes direct from the calendar home new store object
        default = (yield self.parent._newStoreHome.defaultCalendar(componentType, create=False))
        if default is None:
            returnValue(prop_to_set())
        else:
            defaultURL = joinURL(self.parent.url(), default.name())
            returnValue(prop_to_set(davxml.HRef(defaultURL)))
    def addressbook_query(self, addressbook_uri, query, got_xml):
        ''' FIXME: clear address book, possibly by removing
        mkcol = """<?xml version="1.0" encoding="utf-8" ?>
<D:mkcol xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">
<D:set>
<D:prop>
<D:resourcetype><D:collection/><C:addressbook/></D:resourcetype>
</D:prop>
</D:set>
</D:mkcol>
"""
        response = yield self.send(SimpleStoreRequest(self, "MKCOL", addressbook_uri, content=mkcol, authid="wsanchez"))

        response = IResponse(response)

        if response.code != responsecode.CREATED:
            self.fail("MKCOL failed: %s" % (response.code,))
        '''
        principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez")
        # Add vCards to addressbook
        for child in FilePath(self.vcards_dir).children():
            if os.path.splitext(child.basename())[1] != ".vcf":
                continue
            request = SimpleStoreRequest(self,
                                         "PUT",
                                         joinURL(addressbook_uri,
                                                 child.basename()),
                                         authPrincipal=principal)
            request.stream = MemoryStream(child.getContent())
            yield self.send(request)

        request = SimpleStoreRequest(self,
                                     "REPORT",
                                     addressbook_uri,
                                     authPrincipal=principal)
        request.stream = MemoryStream(query.toxml())
        response = yield self.send(request)

        response = IResponse(response)

        if response.code != responsecode.MULTI_STATUS:
            self.fail("REPORT failed: %s" % (response.code, ))

        returnValue((yield
                     davXMLFromStream(response.stream).addCallback(got_xml)))
Example #59
0
    def cleanup(self):
        """
        Do some cleanup after the real request.
        """
        # Remove created resources
        href = joinURL(self.sessions[1].calendarHref, "organizer.ics")
        self.sessions[1].deleteResource(URL(path=href))

        # Remove the attendee event and inbox items
        props = (davxml.resourcetype,)
        results = self.sessions[0].getPropertiesOnHierarchy(URL(path=self.sessions[0].calendarHref), props)
        for href in results.keys():
            if len(href.split("/")[-1]) > 10:
                self.sessions[0].deleteResource(URL(path=href))
        results = self.sessions[0].getPropertiesOnHierarchy(URL(path=self.sessions[0].inboxHref), props)
        for href in results.keys():
            if href != self.sessions[0].inboxHref:
                self.sessions[0].deleteResource(URL(path=href))