def occurrences(self, start=None, end=None): # XXX fit-to-period recurrences = self.recurrences if start and end: start = _timezone._tz2(start, LOCAL, self._tzinfo) end = _timezone._tz2(end, LOCAL, self._tzinfo) recurrences = recurrences.between(start, end) start_exc_ext = {} for exc, ext in zip(self._exceptions, self._extended_exceptions): start_exc_ext[exc['start_datetime']] = exc, ext for d in recurrences: startdatetime_val = _utils.unixtime_to_rectime(calendar.timegm(d.timetuple())) subject = self.item.subject location = self.item.location exception = False if startdatetime_val in start_exc_ext: exc, ext = start_exc_ext[startdatetime_val] minutes = exc['end_datetime'] - startdatetime_val subject = ext.get('subject', subject) location = ext.get('location', location) basedate_val = exc['original_start_date'] exception = True else: minutes = self._endtime_offset - self._starttime_offset basedate_val = startdatetime_val d = _timezone._to_utc(d, self._tzinfo) e = d + datetime.timedelta(minutes=minutes) occ = Occurrence(self.item, d, e, subject, location, basedate_val=basedate_val, exception=exception) if (not start or occ.end > start) and (not end or occ.start < end): yield occ
def delete_exception(self, basedate, item, copytags): tz = item.get(PidLidTimeZoneStruct) basedate2 = _utils._from_gmt(basedate, tz) 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['start_datetime'] ] 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 _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_exception2(self, basedate): # TODO merge with create_exception # TODO create embedded item tz = self.item.get(PidLidTimeZoneStruct) basedate = _utils._from_gmt(basedate, tz) basedate_val = _utils.unixtime_to_rectime( time.mktime(basedate.timetuple())) - self.starttime_offset # update blob self.deleted_instance_count += 1 self.deleted_instance_dates.append(basedate_val) self.deleted_instance_dates.sort() self.modified_instance_count += 1 self.modified_instance_dates.append(basedate_val) self.modified_instance_dates.sort() exception = { 'start_datetime': basedate_val + self.starttime_offset, 'end_datetime': basedate_val + self.starttime_offset + 30, # TODO 'original_start_date': basedate_val, 'override_flags': 0, } self.exceptions.append(exception) # no evidence of sorting self.extended_exceptions.append({}) self._save() # update calitem self._update_calitem()
def occurrences(self, start=None, end=None): # XXX fit-to-period tz = self.item.get_value(PidLidTimeZoneStruct) recurrences = self.recurrences if start and end: recurrences = recurrences.between(_utils._from_gmt(start, tz), _utils._from_gmt(end, tz)) start_exc_ext = {} for exc, ext in zip(self.exceptions, self.extended_exceptions): start_exc_ext[exc['start_datetime']] = exc, ext for d in recurrences: startdatetime_val = _utils.unixtime_to_rectime( time.mktime(d.timetuple())) subject = self.item.subject location = self.item.location if startdatetime_val in start_exc_ext: exc, ext = start_exc_ext[startdatetime_val] minutes = exc['end_datetime'] - startdatetime_val subject = ext.get('subject', subject) location = ext.get('location', location) else: minutes = self.endtime_offset - self.starttime_offset d = _utils._to_gmt(d, tz) occ = Occurrence(self.item, d, d + datetime.timedelta(minutes=minutes), subject, location) if (not start or occ.end > start) and (not end or occ.start < end): yield occ
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_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 end(self, value): self._end_date = _utils.unixtime_to_rectime(calendar.timegm(value.timetuple())) self.item[PidLidClipEnd] = self.end
def start(self, value): self._start_date = _utils.unixtime_to_rectime(calendar.timegm(value.timetuple())) self.item[PidLidClipStart] = self.start
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()
def _end(self, value): self.end_date = _utils.unixtime_to_rectime( time.mktime(value.date().timetuple())) end = self.item.end self.endtime_offset = end.hour * 60 + end.minute
def _start(self, value): self.start_date = _utils.unixtime_to_rectime( time.mktime(value.date().timetuple())) start = self.item.start self.starttime_offset = start.hour * 60 + start.minute
def modify_exception2(self, basedate, subject=None, start=None, end=None, location=None): # TODO merge with modify_exception tz = self.item.get(PidLidTimeZoneStruct) # update embedded item for message in self.item.items(): # XXX no cal_item? to helper replacetime = message.get(PidLidExceptionReplaceTime) if replacetime and replacetime.date() == basedate.date(): if subject is not None: message.subject = subject # TODO set other args message._attobj.SaveChanges(KEEP_OPEN_READWRITE) break # update blob basedate_val = _utils.unixtime_to_rectime( time.mktime(_utils._from_gmt(basedate, tz).timetuple())) for i, exception in enumerate(self.exceptions): if exception['original_start_date'] in ( basedate_val, basedate_val - self.starttime_offset): # TODO pick one extended_exception = self.extended_exceptions[i] break if subject is not None: exception['override_flags'] |= ARO_SUBJECT exception['subject'] = subject.encode('cp1252', 'replace') extended_exception['subject'] = subject if location is not None: exception['override_flags'] |= ARO_LOCATION exception['location'] = location.encode('cp1252', 'replace') extended_exception['location'] = location if start: startdate_val = _utils.unixtime_to_rectime( time.mktime(_utils._from_gmt(start, tz).timetuple())) exception['start_datetime'] = startdate_val extended_exception['start_datetime'] = startdate_val if end: enddate_val = _utils.unixtime_to_rectime( time.mktime(_utils._from_gmt(end, tz).timetuple())) exception['end_datetime'] = enddate_val extended_exception['end_datetime'] = enddate_val extended_exception['start_datetime'] = exception[ 'start_datetime'] # TODO on creation? extended_exception['end_datetime'] = exception['end_datetime'] extended_exception['original_start_date'] = exception[ 'original_start_date'] self._save() # update calitem self._update_calitem()
def modify_exception(self, basedate, item, copytags=None): # XXX 'item' too MR specific tz = item.get_value(PidLidTimeZoneStruct) cal_item = self.item # update embedded item for message in cal_item.items(): # XXX no cal_item? to helper replacetime = message.get_value(PidLidExceptionReplaceTime) if replacetime and replacetime.date() == basedate.date(): self._update_embedded(basedate, message, item, copytags) icon_index = item.get_value(PR_ICON_INDEX) if not copytags and icon_index is not None: message.set_value(PR_ICON_INDEX, icon_index) message._attobj.SaveChanges(KEEP_OPEN_READWRITE) break else: return # XXX exception if copytags: # XXX bug in php code? (setallrecipients, !empty..) message.set_value(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) recip.append(SPropValue(PR_RECIPIENT_TRACKSTATUS, 0)) message.mapiobj.ModifyRecipients(MODRECIP_MODIFY, recips) message.mapiobj.SaveChanges(KEEP_OPEN_READWRITE) message._attobj.SaveChanges(KEEP_OPEN_READWRITE) cal_item.mapiobj.SaveChanges(KEEP_OPEN_READWRITE) # update blob basedate_val = _utils.unixtime_to_rectime( time.mktime(_utils._from_gmt(basedate, tz).timetuple())) startdate = _utils._from_gmt( message.prop(PidLidAppointmentStartWhole).value, tz) startdate_val = _utils.unixtime_to_rectime( time.mktime(startdate.timetuple())) enddate = _utils._from_gmt( message.prop(PidLidAppointmentEndWhole).value, tz) enddate_val = _utils.unixtime_to_rectime( time.mktime(enddate.timetuple())) for i, exception in enumerate(self.exceptions): if exception['original_start_date'] == basedate_val: 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_exceptions(cal_item, message, startdate_val, enddate_val, basedate_val, exception, extended_exception, copytags, create=False) self._save() # update calitem self._update_calitem(item)