Example #1
0
    def _delete_exception(self, basedate, item, copytags):
        basedate2 = _timezone._from_utc(basedate, self._tzinfo)
        basedate_val = _utils.unixtime_to_rectime(time.mktime(basedate2.timetuple()))

        if self._is_exception(basedate):
            self._modify_exception(basedate, item, copytags)

            for i, exc in enumerate(self._exceptions):
                if exc['original_start_date'] == basedate_val:
                    break

            self._modified_instance_count -= 1
            self._modified_instance_dates = [m for m in self._modified_instance_dates if m != exc['original_start_date']]

            del self._exceptions[i]
            del self._extended_exceptions[i]

        else:
            self.deleted_instance_count += 1

            self._deleted_instance_dates.append(basedate_val)
            self._deleted_instance_dates.sort()

        self._save()
        self._update_calitem()
Example #2
0
    def _create_exception(self, basedate, item=None, copytags=None, merge=False, recips_from=None):
        cal_item = self.item

        # create embedded item
        message_flags = MSGFLAG_READ
        if item and item.get(PR_MESSAGE_FLAGS) == 0: # XXX wut/php compat
            message_flags |= MSGFLAG_UNSENT
        message = cal_item.create_item(message_flags, hidden=True)

        self._update_embedded(basedate, message, item, copytags, create=True)

        message[PidLidResponseStatus] = respDeclined | respOrganized # XXX php bug for merge case?
        if copytags:
            message[PidLidBusyStatus] = 0

        # copy over recipients (XXX check php delta stuff..)
        item = item or recips_from
        if item:
            table = item.mapiobj.OpenProperty(PR_MESSAGE_RECIPIENTS, IID_IMAPITable, MAPI_UNICODE, 0)
            table.SetColumns(_meetingrequest.RECIP_PROPS, 0)
            recips = list(table.QueryRows(-1, 0))

            for recip in recips:
                flags = PpropFindProp(recip, PR_RECIPIENT_FLAGS)
                if not flags:
                    recip.append(SPropValue(PR_RECIPIENT_FLAGS, recipExceptionalResponse | recipSendable))

            if copytags:
                for recip in recips:
                    recip.append(SPropValue(PR_RECIPIENT_FLAGS, recipExceptionalDeleted | recipSendable))
                    recip.append(SPropValue(PR_RECIPIENT_TRACKSTATUS, 0))

            organiser = _meetingrequest._organizer_props(cal_item, item)
            if organiser and not merge: # XXX merge -> initialize?
                recips.insert(0, organiser)

            message.mapiobj.ModifyRecipients(MODRECIP_ADD, recips)

        _utils._save(message.mapiobj)
        _utils._save(message._attobj)
        _utils._save(cal_item.mapiobj)

        # XXX attachments?

        # update blob
        self.deleted_instance_count += 1
        deldate = _timezone._from_utc(basedate, self._tzinfo)
        deldate_val = _utils.unixtime_to_rectime(time.mktime(deldate.timetuple()))
        self._deleted_instance_dates.append(deldate_val)
        self._deleted_instance_dates.sort()

        self._modified_instance_count += 1
        moddate = message.prop(PidLidAppointmentStartWhole).value
        daystart = moddate - datetime.timedelta(hours=moddate.hour, minutes=moddate.minute) # XXX different approach in php? seconds?
        localdaystart = _timezone._from_utc(daystart, self._tzinfo)
        moddate_val = _utils.unixtime_to_rectime(time.mktime(localdaystart.timetuple()))
        self._modified_instance_dates.append(moddate_val)
        self._modified_instance_dates.sort()

        exception = {}
        extended_exception = {}
        self._update_exception(cal_item, message, deldate_val, exception, extended_exception, copytags, create=True, orig_item=item)
        self._exceptions.append(exception) # no evidence of sorting
        self._extended_exceptions.append(extended_exception)

        self._save()

        # update calitem
        self._update_calitem()
Example #3
0
    def _update_embedded(self, basedate, message, item=None, copytags=None, create=False, **kwargs):
        basetime = basedate + datetime.timedelta(minutes=self._starttime_offset)
        cal_item = self.item

        item2 = item or cal_item
        if copytags:
            props = item2.mapiobj.GetProps(copytags, 0)
            message.mapiobj.SetProps(props)
        elif not kwargs:
            props = [p.mapiobj for p in item2.props() if p.proptag != PR_ICON_INDEX]
            message.mapiobj.SetProps(props)
            message.recurring = False

        if not item:
            if kwargs:
                if 'start' in kwargs:
                    message[PidLidAppointmentStartWhole] = kwargs['start']
                if 'end' in kwargs:
                    message[PidLidAppointmentEndWhole] = kwargs['end']
            else:
                message[PidLidAppointmentStartWhole] = basedate + datetime.timedelta(minutes=self._starttime_offset)
                message[PidLidAppointmentEndWhole] = basedate + datetime.timedelta(minutes=self._endtime_offset)

        message[PR_MESSAGE_CLASS_W] = u'IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}'
        message[PidLidExceptionReplaceTime] = basetime

        intended_busystatus = cal_item.get(PidLidIntendedBusyStatus) # XXX tentative? merge with modify_exc?
        if intended_busystatus is not None:
            message[PidLidBusyStatus] = intended_busystatus

        sub_type = cal_item.get(PidLidAppointmentSubType)
        if sub_type is not None:
            message[PidLidAppointmentSubType] = sub_type

        props = [
            SPropValue(PR_ATTACHMENT_FLAGS, 2), # XXX cannot find spec
            SPropValue(PR_ATTACHMENT_HIDDEN, True),
            SPropValue(PR_ATTACHMENT_LINKID, 0),
            SPropValue(PR_ATTACH_FLAGS, 0),
            SPropValue(PR_ATTACH_METHOD, ATTACH_EMBEDDED_MSG),
            SPropValue(PR_DISPLAY_NAME_W, u'Exception'),
        ]

        if 'subject' in kwargs:
            props.append(SPropValue(PR_SUBJECT_W, kwargs['subject']))

        if 'location' in kwargs:
            message[PidLidLocation] = kwargs['location']

        if item is None: # TODO pick up kwargs['start/end']
            start = basetime
            end = basetime + datetime.timedelta(minutes=self._endtime_offset-self._starttime_offset)
        else:
            start = message.get(PidLidAppointmentStartWhole)
            end = message.prop(PidLidAppointmentEndWhole).value

        if start is not None:
            start_local = unixtime(time.mktime(_timezone._from_utc(start, self._tzinfo).timetuple())) # XXX why local??
            props.append(SPropValue(PR_EXCEPTION_STARTTIME, start_local))

        if end is not None:
            end_local = unixtime(time.mktime(_timezone._from_utc(end, self._tzinfo).timetuple())) # XXX why local??
            props.append(SPropValue(PR_EXCEPTION_ENDTIME, end_local))

        message._attobj.SetProps(props)
        if not create: # XXX php bug?
            props = props[:-2]
        message.mapiobj.SetProps(props)

        if 'canceled' in kwargs:
            message[PidLidAppointmentStateFlags] |= ASF_CANCELED

        _utils._save(message.mapiobj)
        _utils._save(message._attobj)
Example #4
0
    def _update_exception(self, cal_item, item, basedate_val, exception, extended_exception, copytags=None, create=False, orig_item=None, **kwargs): # XXX kill copytags, create args, just pass all properties as in php
        # TODO get start/end from cal_item if not in item?

        startdate = kwargs.get('start')
        if orig_item or (startdate is None and 'start_datetime' not in exception):
            startdate = item.get(PidLidAppointmentStartWhole)

        if startdate is not None:
            startdate_val = _utils.unixtime_to_rectime(time.mktime(_timezone._from_utc(startdate, self._tzinfo).timetuple()))
            exception['start_datetime'] = startdate_val

        enddate = kwargs.get('end')
        if orig_item or (enddate is None and 'end_datetime' not in exception):
            enddate = item.get(PidLidAppointmentEndWhole)

        if enddate is not None:
            enddate_val = _utils.unixtime_to_rectime(time.mktime(_timezone._from_utc(enddate, self._tzinfo).timetuple()))
            exception['end_datetime'] = enddate_val

        exception['original_start_date'] = basedate_val # TODO why set again?
        exception['override_flags'] = 0

        extended = False

        subject = kwargs.get('subject')
        if orig_item or (subject is None and 'subject' not in exception):
            subject = item.get(PR_NORMALIZED_SUBJECT_W)
        if subject is not None or 'subject' in exception:
            exception['override_flags'] |= ARO_SUBJECT
        if subject is not None:
            exception['subject'] = subject.encode('cp1252', 'replace')
            extended = True
            extended_exception['subject'] = subject

        location = kwargs.get('location')
        if orig_item or (location is None and 'location' not in exception):
            location = item.get(PidLidLocation)
        if location is not None or 'location' in exception:
            exception['override_flags'] |= ARO_LOCATION
        if location is not None:
            exception['location'] = location.encode('cp1252', 'replace')
            extended = True
            extended_exception['location'] = location

        # skip ARO_MEETINGTYPE (like php)

        reminder_delta = item.get(PidLidReminderDelta)
        if reminder_delta is not None:
            exception['override_flags'] |= ARO_REMINDERDELTA
            exception['reminder_delta'] = reminder_delta

        reminder_set = item.get(PidLidReminderSet)
        if reminder_set is not None:
            exception['override_flags'] |= ARO_REMINDERSET
            exception['reminder_set'] = reminder_set

        busy_status = item.get(PidLidBusyStatus)
        if busy_status is not None:
            exception['override_flags'] |= ARO_BUSYSTATUS
            exception['busy_status'] = busy_status

        # skip ARO_ATTACHMENT (like php)

        # XXX php doesn't set the following by accident? ("alldayevent" not in copytags..)
        if not copytags or not create:
            sub_type = item.get(PidLidAppointmentSubType)
            if sub_type is not None:
                exception['override_flags'] |= ARO_SUBTYPE
                exception['sub_type'] = sub_type

        appointment_color = item.get(PidLidAppointmentColor)
        if appointment_color is not None:
            exception['override_flags'] |= ARO_APPTCOLOR
            exception['appointment_color'] = appointment_color

        if extended:
            if startdate:
                extended_exception['start_datetime'] = startdate_val
            if enddate:
                extended_exception['end_datetime'] = enddate_val
            extended_exception['original_start_date'] = basedate_val
Example #5
0
    def _modify_exception(self, basedate, item=None, copytags=None, **kwargs): # XXX 'item' too MR specific
        cal_item = self.item

        # update embedded item
        for message in cal_item.items(): # XXX no cal_item? to helper
            replacetime = message.get(PidLidExceptionReplaceTime)
            if replacetime and replacetime.date() == basedate.date():
                self._update_embedded(basedate, message, item, copytags, **kwargs)

                if item:
                    icon_index = item.get(PR_ICON_INDEX)
                    if not copytags and icon_index is not None:
                        message[PR_ICON_INDEX] = icon_index

                _utils._save(message._attobj)
                break
        else:
            return # XXX exception

        if copytags: # XXX bug in php code? (setallrecipients, !empty..)
            message[PidLidBusyStatus] = 0

            table = message.mapiobj.OpenProperty(PR_MESSAGE_RECIPIENTS, IID_IMAPITable, MAPI_UNICODE, 0)
            table.SetColumns(_meetingrequest.RECIP_PROPS, 0)

            recips = list(table.QueryRows(-1, 0))
            for recip in recips:
                flags = PpropFindProp(recip, PR_RECIPIENT_FLAGS)
                if flags and flags.Value != (recipOrganizer | recipSendable):
                    flags.Value = recipExceptionalDeleted | recipSendable
                    trackstatus = PpropFindProp(recip, PR_RECIPIENT_TRACKSTATUS)
                    if not trackstatus:
                        recip.append(SPropValue(PR_RECIPIENT_TRACKSTATUS, 0))

            message.mapiobj.ModifyRecipients(MODRECIP_MODIFY, recips)

            _utils._save(message.mapiobj)
            _utils._save(message._attobj)
            _utils._save(cal_item.mapiobj)

        # update blob
        basedate_val = _utils.unixtime_to_rectime(time.mktime(_timezone._from_utc(basedate, self._tzinfo).timetuple()))

        startdate = _timezone._from_utc(message.prop(PidLidAppointmentStartWhole).value, self._tzinfo)
        startdate_val = _utils.unixtime_to_rectime(time.mktime(startdate.timetuple()))

        for i, exception in enumerate(self._exceptions):
            if exception['original_start_date'] == basedate_val: # TODO offset, as below?
                current_startdate_val = exception['start_datetime'] - self._starttime_offset

                for j, val in enumerate(self._modified_instance_dates):
                    if val == current_startdate_val:
                        self._modified_instance_dates[j] = startdate_val - self._starttime_offset
                        self._modified_instance_dates.sort()
                        break

                extended_exception = self._extended_exceptions[i]
                self._update_exception(cal_item, message, basedate_val, exception, extended_exception, copytags, create=False, orig_item=item, **kwargs)

        self._save()

        # update calitem
        self._update_calitem()