From 8a8dcae0298b81a486ad454bd58b90821eec6894 Mon Sep 17 00:00:00 2001 From: smizrahi Date: Wed, 21 Jun 2023 15:51:18 +0200 Subject: [PATCH] fix(calendar): Add negative timestamp support to use date before 1970-01-01. Fixes #4914 (partial) --- .../Appointments/SOGoAppointmentFolder.m | 23 ++- UI/Scheduler/UIxCalListingActions.m | 158 +++++++++--------- 2 files changed, 89 insertions(+), 92 deletions(-) diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 5adddb782..034ec5f22 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -664,18 +664,23 @@ static Class iCalEventK = nil; cycle: (BOOL) _isCycle { NSString *format; - unsigned int start, end; + long long start, end; - start = (unsigned int) [_startDate timeIntervalSince1970]; - end = (unsigned int) [_endDate timeIntervalSince1970]; + start = (long long) [_startDate timeIntervalSince1970]; + end = (long long) [_endDate timeIntervalSince1970]; // vTODOs don't necessarily have start/end dates - if (_isCycle) - format = (@"(c_startdate = NULL OR c_startdate <= %u)" - @" AND (c_cycleenddate = NULL OR c_cycleenddate >= %u)"); - else - format = (@"(c_startdate = NULL OR c_startdate <= %u)" - @" AND (c_enddate = NULL OR c_enddate >= %u)"); + if (start < 0 && end < 0) { + format = (@"(c_startdate = NULL OR c_startdate <= %lld)" + @" AND (c_cycleenddate = NULL OR c_cycleenddate >= %lld)"); + } else { + if (_isCycle) + format = (@"(c_startdate = NULL OR c_startdate <= %lld)" + @" AND (c_cycleenddate = NULL OR c_cycleenddate >= %lld)"); + else + format = (@"(c_startdate = NULL OR c_startdate <= %lld)" + @" AND (c_enddate = NULL OR c_enddate >= %lld )"); + } return [NSString stringWithFormat: format, end, start]; } diff --git a/UI/Scheduler/UIxCalListingActions.m b/UI/Scheduler/UIxCalListingActions.m index c1d125196..2aac0c1b8 100644 --- a/UI/Scheduler/UIxCalListingActions.m +++ b/UI/Scheduler/UIxCalListingActions.m @@ -1070,98 +1070,90 @@ static inline void _feedBlockWithDayBasedData (NSMutableDictionary *block, unsig withEvent: (NSArray *) event withNumber: (NSNumber *) number { - int currentDayStart, startSecs, endsSecs, currentStart, eventStart, - eventEnd, computedEventEnd, offset, recurrenceTime, swap; + int offset, recurrenceTime; + long long startSecs, endsSecs, swap, currentDayStart, currentStart, eventStart, + eventEnd, computedEventEnd; NSMutableArray *currentDay; NSMutableDictionary *eventBlock; NSString *userState; eventStart = [[event objectAtIndex: eventStartDateIndex] intValue]; - if (eventStart < 0) - [self errorWithFormat: @"event '%@' has negative start: %d (skipped)", - [event objectAtIndex: eventNameIndex], eventStart]; + eventEnd = [[event objectAtIndex: eventEndDateIndex] intValue]; + + if ((eventEnd < eventStart && eventEnd > 0) + || (eventStart > 0 && eventEnd < 0) + || (eventStart > eventEnd && eventStart < 0 && eventEnd < 0)) + { + swap = eventStart; + eventStart = eventEnd; + eventEnd = swap; + [self warnWithFormat: @"event '%@' has end < start: %d < %d", + [event objectAtIndex: eventNameIndex], eventEnd, eventStart]; + } + + startSecs = (long long) [startDate timeIntervalSince1970]; + endsSecs = (long long) [endDate timeIntervalSince1970]; + + if ([[event objectAtIndex: eventIsCycleIndex] boolValue]) + recurrenceTime = [[event objectAtIndex: eventRecurrenceIdIndex] unsignedIntValue]; + else + recurrenceTime = 0; + + currentStart = eventStart; + if (currentStart < startSecs) + { + currentStart = startSecs; + offset = 0; + } + else + offset = ((currentStart - startSecs) / dayLength); + if (offset >= [blocks count]) + [self errorWithFormat: @"event '%@' has a computed offset that" + @" overflows the amount of blocks (skipped)", + [event objectAtIndex: eventNameIndex]]; else { - eventEnd = [[event objectAtIndex: eventEndDateIndex] intValue]; - if (eventEnd < 0) - [self errorWithFormat: @"event '%@' has negative end: %d (skipped)", - [event objectAtIndex: eventNameIndex], eventEnd]; - else + currentDay = [blocks objectAtIndex: offset]; + currentDayStart = startSecs + dayLength * offset; + + if (eventEnd > endsSecs) + eventEnd = endsSecs; + + if (eventEnd < startSecs) + // The event doesn't end in the covered period. + // This special case occurs with a DST change. + return; + + userState = _userStateInEvent(event); + while (currentDayStart + dayLength < eventEnd) { - if (eventEnd < eventStart) - { - swap = eventStart; - eventStart = eventEnd; - eventEnd = swap; - [self warnWithFormat: @"event '%@' has end < start: %d < %d", - [event objectAtIndex: eventNameIndex], eventEnd, eventStart]; - } - - startSecs = (unsigned int) [startDate timeIntervalSince1970]; - endsSecs = (unsigned int) [endDate timeIntervalSince1970]; - - if ([[event objectAtIndex: eventIsCycleIndex] boolValue]) - recurrenceTime = [[event objectAtIndex: eventRecurrenceIdIndex] unsignedIntValue]; - else - recurrenceTime = 0; - - currentStart = eventStart; - if (currentStart < startSecs) - { - currentStart = startSecs; - offset = 0; - } - else - offset = ((currentStart - startSecs) / dayLength); - if (offset >= [blocks count]) - [self errorWithFormat: @"event '%@' has a computed offset that" - @" overflows the amount of blocks (skipped)", - [event objectAtIndex: eventNameIndex]]; - else - { - currentDay = [blocks objectAtIndex: offset]; - currentDayStart = startSecs + dayLength * offset; - - if (eventEnd > endsSecs) - eventEnd = endsSecs; - - if (eventEnd < startSecs) - // The event doesn't end in the covered period. - // This special case occurs with a DST change. - return; - - userState = _userStateInEvent(event); - while (currentDayStart + dayLength < eventEnd) - { - eventBlock = [self _eventBlockWithStart: currentStart - end: currentDayStart + dayLength - 1 - number: number - onDay: currentDayStart - recurrenceTime: recurrenceTime - userState: userState]; - [currentDay addObject: eventBlock]; - currentDayStart += dayLength; - currentStart = currentDayStart; - offset++; - currentDay = [blocks objectAtIndex: offset]; - } - - computedEventEnd = eventEnd; - - // We add 5 mins to the end date of an event if the end date - // is equal or smaller than the event's start date. - if (eventEnd <= currentStart) - computedEventEnd = currentStart + (5*60); - - eventBlock = [self _eventBlockWithStart: currentStart - end: computedEventEnd - number: number - onDay: currentDayStart - recurrenceTime: recurrenceTime - userState: userState]; - [currentDay addObject: eventBlock]; - } + eventBlock = [self _eventBlockWithStart: currentStart + end: currentDayStart + dayLength - 1 + number: number + onDay: currentDayStart + recurrenceTime: recurrenceTime + userState: userState]; + [currentDay addObject: eventBlock]; + currentDayStart += dayLength; + currentStart = currentDayStart; + offset++; + currentDay = [blocks objectAtIndex: offset]; } + + computedEventEnd = eventEnd; + + // We add 5 mins to the end date of an event if the end date + // is equal or smaller than the event's start date. + if (eventEnd <= currentStart) + computedEventEnd = currentStart + (5*60); + + eventBlock = [self _eventBlockWithStart: currentStart + end: computedEventEnd + number: number + onDay: currentDayStart + recurrenceTime: recurrenceTime + userState: userState]; + [currentDay addObject: eventBlock]; } }