1.1 --- a/imiptools/client.py Thu Sep 03 21:50:57 2015 +0200
1.2 +++ b/imiptools/client.py Thu Sep 03 22:51:37 2015 +0200
1.3 @@ -380,11 +380,14 @@
1.4
1.5 return can_schedule(freebusy, periods, self.uid, self.recurrenceid)
1.6
1.7 - def have_new_object(self, obj=None):
1.8 + def have_new_object(self, obj=None, strict=True):
1.9
1.10 """
1.11 Return whether the current object is new to the current user (or if the
1.12 - given 'obj' is new).
1.13 + given 'obj' is new). If 'strict' is specified and is a false value, the
1.14 + DTSTAMP test will be ignored. This is useful in handling responses from
1.15 + attendees from clients (like Claws Mail) that erase time information
1.16 + from DTSTAMP and make it invalid.
1.17 """
1.18
1.19 obj = obj or self.get_stored_object_version()
1.20 @@ -398,37 +401,10 @@
1.21 # If the request refers to an older version of the object, ignore
1.22 # it.
1.23
1.24 - return is_new_object(sequence, self.sequence, dtstamp, self.dtstamp,
1.25 - self.is_partstat_updated(obj))
1.26 + return is_new_object(sequence, self.sequence, dtstamp, self.dtstamp, not strict)
1.27
1.28 return True
1.29
1.30 - def is_partstat_updated(self, obj):
1.31 -
1.32 - """
1.33 - Return whether the participant status has been updated in the current
1.34 - object in comparison to the given 'obj'.
1.35 -
1.36 - NOTE: Some clients like Claws Mail erase time information from DTSTAMP
1.37 - NOTE: and make it invalid. Thus, such attendance information may also be
1.38 - NOTE: incorporated into any new object assessment.
1.39 - """
1.40 -
1.41 - old_attendees = uri_dict(obj.get_value_map("ATTENDEE"))
1.42 - new_attendees = uri_dict(self.obj.get_value_map("ATTENDEE"))
1.43 -
1.44 - for attendee, attr in old_attendees.items():
1.45 - old_partstat = attr.get("PARTSTAT")
1.46 - new_attr = new_attendees.get(attendee)
1.47 - new_partstat = new_attr and new_attr.get("PARTSTAT")
1.48 -
1.49 - if old_partstat == "NEEDS-ACTION" and new_partstat and \
1.50 - new_partstat != old_partstat:
1.51 -
1.52 - return True
1.53 -
1.54 - return False
1.55 -
1.56 def possibly_recurring_indefinitely(self):
1.57
1.58 "Return whether the object recurs indefinitely."
2.1 --- a/imiptools/data.py Thu Sep 03 21:50:57 2015 +0200
2.2 +++ b/imiptools/data.py Thu Sep 03 22:51:37 2015 +0200
2.3 @@ -706,11 +706,11 @@
2.4
2.5 # Operations on structure data.
2.6
2.7 -def is_new_object(old_sequence, new_sequence, old_dtstamp, new_dtstamp, partstat_set):
2.8 +def is_new_object(old_sequence, new_sequence, old_dtstamp, new_dtstamp, ignore_dtstamp):
2.9
2.10 """
2.11 Return for the given 'old_sequence' and 'new_sequence', 'old_dtstamp' and
2.12 - 'new_dtstamp', and the 'partstat_set' indication, whether the object
2.13 + 'new_dtstamp', and the 'ignore_dtstamp' indication, whether the object
2.14 providing the new information is really newer than the object providing the
2.15 old information.
2.16 """
2.17 @@ -726,7 +726,7 @@
2.18 is_same_sequence and is_old_dtstamp
2.19 )
2.20
2.21 - return is_same_sequence and partstat_set or not is_old_sequence
2.22 + return is_same_sequence and ignore_dtstamp or not is_old_sequence
2.23
2.24 def get_periods(obj, tzid, end=None, inclusive=False):
2.25
3.1 --- a/imiptools/handlers/person_outgoing.py Thu Sep 03 21:50:57 2015 +0200
3.2 +++ b/imiptools/handlers/person_outgoing.py Thu Sep 03 22:51:37 2015 +0200
3.3 @@ -47,9 +47,10 @@
3.4
3.5 self.set_identity(from_organiser)
3.6
3.7 - # Check for event using UID.
3.8 + # Check for a new event, tolerating not-strictly-new events if the
3.9 + # attendee is responding.
3.10
3.11 - if not self.have_new_object():
3.12 + if not self.have_new_object(strict=from_organiser):
3.13 return False
3.14
3.15 # Update the object.