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()
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()
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)
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
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()