Beispiel #1
0
    def updateVPOLLData(from_component, to_component, attendee):
        """
        Update VPOLL sub-components with voter's response.

        @param from_component: component to copy from
        @type from_component: L{Component}
        @param to_component: component to copy to
        @type to_component: L{Component}
        @param attendee: attendee being processed
        @type attendee: L{Property}
        """

        responses = {}
        for prop in from_component.properties("POLL-ITEM-ID"):
            responses[prop.value()] = prop

        for component in to_component.subcomponents():
            if component.name() in ignoredComponents:
                continue
            poll_item_id = component.propertyValue("POLL-ITEM-ID")
            if poll_item_id is None:
                continue
            voter = component.getVoterProperty((attendee.value(),))

            # If no response - remove
            if poll_item_id not in responses or not responses[poll_item_id].hasParameter("RESPONSE"):
                if voter is not None:
                    component.removeProperty(voter)
                continue

            # Add or update voter
            if voter is None:
                voter = Property("VOTER", attendee.value())
                component.addProperty(voter)
            voter.setParameter("RESPONSE", responses[poll_item_id].parameterValue("RESPONSE"))
Beispiel #2
0
    def updateAttendeeData(from_component, to_component):
        """
        Called when processing a REPLY only.

        Copy the PARTSTAT of the Attendee in the from_component to the matching ATTENDEE
        in the to_component. Ignore if no match found. Also update the private comments.

        For VPOLL we need to copy POLL-ITEM-ID response values into the actual matching
        polled sub-components as VOTER properties.

        @param from_component: component to copy from
        @type from_component: L{Component}
        @param to_component: component to copy to
        @type to_component: L{Component}
        """

        # Track what changed
        partstat_changed = False
        private_comment_changed = False

        # Get REQUEST-STATUS as we need to write that into the saved ATTENDEE property
        reqstatus = tuple(from_component.properties("REQUEST-STATUS"))
        if reqstatus:
            reqstatus = ",".join(status.value()[0] for status in reqstatus)
        else:
            reqstatus = "2.0"

        # Get attendee in from_component - there MUST be only one
        attendees = tuple(from_component.properties(from_component.recipientPropertyName()))
        if len(attendees) != 1:
            log.error("There must be one and only one ATTENDEE property in a REPLY\n%s" % (str(from_component),))
            return None, False, False

        attendee = attendees[0]
        partstat = attendee.parameterValue("PARTSTAT", "NEEDS-ACTION")

        # Now find matching ATTENDEE in to_component
        existing_attendee = to_component.getAttendeeProperty((attendee.value(),))
        if existing_attendee:
            oldpartstat = existing_attendee.parameterValue("PARTSTAT", "NEEDS-ACTION")
            existing_attendee.setParameter("PARTSTAT", partstat)
            existing_attendee.setParameter("SCHEDULE-STATUS", reqstatus)
            partstat_changed = (oldpartstat != partstat)

            # Always delete RSVP on PARTSTAT change
            if partstat_changed:
                try:
                    existing_attendee.removeParameter("RSVP")
                except KeyError:
                    pass

            # Handle attendee comments
            if config.Scheduling.CalDAV.get("EnablePrivateComments", True):
                # Look for X-CALENDARSERVER-PRIVATE-COMMENT property in iTIP component (State 1 in spec)
                attendee_comment = tuple(from_component.properties("X-CALENDARSERVER-PRIVATE-COMMENT"))
                attendee_comment = attendee_comment[0] if len(attendee_comment) else None

                # Look for matching X-CALENDARSERVER-ATTENDEE-COMMENT property in existing data (State 2 in spec)
                private_comments = tuple(to_component.properties("X-CALENDARSERVER-ATTENDEE-COMMENT"))
                for comment in private_comments:
                    attendeeref = comment.parameterValue("X-CALENDARSERVER-ATTENDEE-REF")
                    if attendeeref == attendee.value():
                        private_comment = comment
                        break
                else:
                    private_comment = None
            else:
                attendee_comment = None
                private_comment = None

            # Now do update logic
            if attendee_comment is None and private_comment is None:
                # Nothing to do
                pass

            elif attendee_comment is None and private_comment is not None:
                # We now remove the private comment on the organizer's side if the attendee removed it
                to_component.removeProperty(private_comment)

                private_comment_changed = True

            elif attendee_comment is not None and private_comment is None:

                # Add new property
                private_comment = Property(
                    "X-CALENDARSERVER-ATTENDEE-COMMENT",
                    attendee_comment.value(),
                    params={
                        "X-CALENDARSERVER-ATTENDEE-REF": attendee.value(),
                        "X-CALENDARSERVER-DTSTAMP": DateTime.getNowUTC().getText(),
                    }
                )
                to_component.addProperty(private_comment)

                private_comment_changed = True

            else:
                # Only change if different
                if private_comment.value() != attendee_comment.value():
                    # Remove all property parameters
                    private_comment.removeAllParameters()

                    # Add default parameters
                    private_comment.setParameter("X-CALENDARSERVER-ATTENDEE-REF", attendee.value())
                    private_comment.setParameter("X-CALENDARSERVER-DTSTAMP", DateTime.getNowUTC().getText())

                    # Set new value
                    private_comment.setValue(attendee_comment.value())

                    private_comment_changed = True

            # Do VPOLL transfer
            if from_component.name() == "VPOLL":
                # TODO: figure out how to report changes back
                iTipProcessing.updateVPOLLData(from_component, to_component, attendee)

        return attendee.value(), partstat_changed, private_comment_changed