merge of '779e2b1c502021e5eb405fa6e452d4a40ce77b6e'

and 'c4b00c603f23bbc97a3d07724c6b2a4e9361c098'

Monotone-Parent: 779e2b1c502021e5eb405fa6e452d4a40ce77b6e
Monotone-Parent: c4b00c603f23bbc97a3d07724c6b2a4e9361c098
Monotone-Revision: b062a471e751aff2d35891675a50d0fff8918047

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2011-04-19T22:06:05
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Wolfgang Sourdeau
2011-04-19 22:06:05 +00:00
11 changed files with 159 additions and 67 deletions

View File

@@ -36,8 +36,28 @@
* OpenChange/MAPIStoreFolder.m (-createMessage): no longer a
mandatory method. Returns nil when not overriden.
2011-04-19 Francis Lachapelle <flachapelle@inverse.ca>
* SoObjects/Appointments/SOGoAppointmentFolder.m
(-_flattenCycleRecord:forRange:intoArray:): fixed the
verification of the event's timezone.
2011-04-15 Francis Lachapelle <flachapelle@inverse.ca>
* SoObjects/Appointments/iCalEvent+SOGo.m (-firstOccurenceRange):
we now compute the end date by looking at the occurrence
interval. This way, we support events with an end date or a duration.
* SoObjects/Appointments/SOGoAppointmentFolder.m
(-_flattenCycleRecord:forRange:intoArray:): also compute the end
date by looking at the occurrence interval.
(-importCalendar:): added a duration to events with no end date nor duration.
* SoObjects/Appointments/SOGoAppointmentObject.m
(-_adjustEventsInRequest:): new method to verify the vCalendar for
any inconsistency or missing attributes. Currently, it only adds a
duration if no end date nor duration is found.
* UI/WebServerResources/ckeditor/config.js: Changed the default
enter mode to use BR instead of P. This matches the behavior of Thunderbird.

View File

@@ -51,6 +51,7 @@
- (BOOL) hasEndDate;
- (NSString *) duration;
- (void) setDuration: (NSString *) _value;
- (BOOL) hasDuration;
- (NSTimeInterval) durationAsTimeInterval;

View File

@@ -73,6 +73,7 @@
#import <SOGo/WOResponse+SOGo.h>
#import "iCalRepeatableEntityObject+SOGo.h"
#import "iCalEvent+SOGo.h"
#import "iCalPerson+SOGo.h"
#import "SOGoAppointmentObject.h"
#import "SOGoAppointmentFolders.h"
@@ -849,9 +850,9 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
NSArray *rules, *exRules, *exDates, *ranges;
NSArray *elements, *components;
NSString *content;
iCalRepeatableEntityObject *component;
id firstStartDate, firstEndDate;
NSCalendarDate *checkStartDate, *checkEndDate;
iCalDateTime *dtstart;
NSCalendarDate *checkStartDate, *checkEndDate, *firstStartDate, *firstEndDate;
iCalEvent *component;
iCalTimeZone *eventTimeZone;
unsigned count, max, offset;
@@ -889,53 +890,55 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
{
// Retrieve the range of the first/master event
component = [components objectAtIndex: 0];
firstStartDate = [component uniqueChildWithTag: @"dtstart"];
firstEndDate = [component uniqueChildWithTag: @"dtend"];
eventTimeZone = [(iCalDateTime*)firstStartDate timeZone];
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: [[[firstStartDate values] lastObject] asCalendarDate]
endDate: [[[firstEndDate values] lastObject] asCalendarDate]];
dtstart = (iCalDateTime *)[component uniqueChildWithTag: @"dtstart"];
firstStartDate = [[[dtstart values] lastObject] asCalendarDate];
firstEndDate = [firstStartDate addTimeInterval: [component occurenceInterval]];
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: firstStartDate
endDate: firstEndDate];
if (eventTimeZone)
{
// Adjust the range to check with respect to the event timezone (extracted from the start date)
checkStartDate = [eventTimeZone computedDateForDate: [theRange startDate]];
checkEndDate = [eventTimeZone computedDateForDate: [theRange endDate]];
recurrenceRange = [NGCalendarDateRange calendarDateRangeWithStartDate: checkStartDate
endDate: checkEndDate];
// Adjust the exception dates
exDates = [eventTimeZone computedDatesForStrings: exDates];
// Adjust the recurrence rules "until" dates
rules = [component recurrenceRulesWithTimeZone: eventTimeZone];
exRules = [component exceptionRulesWithTimeZone: eventTimeZone];
}
else
{
recurrenceRange = theRange;
if ([[theRecord objectForKey: @"c_isallday"] boolValue])
{
// The event lasts all-day and has no timezone (floating); we convert the range of the first event
// to the user's timezone
offset = [timeZone secondsFromGMTForDate: [firstRange startDate]];
firstStartDate = (NSCalendarDate*)[[firstRange startDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
seconds:-offset];
firstEndDate = (NSCalendarDate*)[[firstRange endDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
seconds:-offset];
[firstStartDate setTimeZone: timeZone];
[firstEndDate setTimeZone: timeZone];
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: firstStartDate
endDate: firstEndDate];
}
}
// Calculate the occurrences for the given range
eventTimeZone = [dtstart timeZone];
if (eventTimeZone)
{
// Adjust the range to check with respect to the event timezone (extracted from the start date)
checkStartDate = [eventTimeZone computedDateForDate: [theRange startDate]];
checkEndDate = [eventTimeZone computedDateForDate: [theRange endDate]];
recurrenceRange = [NGCalendarDateRange calendarDateRangeWithStartDate: checkStartDate
endDate: checkEndDate];
// Adjust the exception dates
exDates = [eventTimeZone computedDatesForStrings: exDates];
// Adjust the recurrence rules "until" dates
rules = [component recurrenceRulesWithTimeZone: eventTimeZone];
exRules = [component exceptionRulesWithTimeZone: eventTimeZone];
}
else
{
recurrenceRange = theRange;
if ([[theRecord objectForKey: @"c_isallday"] boolValue])
{
// The event lasts all-day and has no timezone (floating); we convert the range of the first event
// to the user's timezone
offset = [timeZone secondsFromGMTForDate: [firstRange startDate]];
firstStartDate = [[firstRange startDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
seconds:-offset];
firstEndDate = [[firstRange endDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
seconds:-offset];
[firstStartDate setTimeZone: timeZone];
[firstEndDate setTimeZone: timeZone];
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: firstStartDate
endDate: firstEndDate];
}
}
// Calculate the occurrences for the given range
records = [NSMutableArray array];
ranges = [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange: recurrenceRange
firstInstanceCalendarDateRange: firstRange
ranges = [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange: recurrenceRange
firstInstanceCalendarDateRange: firstRange
recurrenceRules: rules
exceptionRules: exRules
exceptionDates: exDates];
exceptionRules: exRules
exceptionDates: exDates];
max = [ranges count];
for (count = 0; count < max; count++)
{
@@ -947,15 +950,15 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
if (fixedRow)
[records addObject: fixedRow];
}
[self _appendCycleExceptionsFromRow: row
firstInstanceCalendarDateRange: firstRange
forRange: theRange
toArray: records];
[theRecords addObjectsFromArray: records];
}
}
}
}
}
else
[self errorWithFormat:@"cyclic record doesn't have content -> %@", theRecord];
@@ -2607,6 +2610,11 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
return ([object saveContentString: content] == nil);
}
/**
* Import all components of a vCalendar.
* @param calendar the calendar to import
* @return the number of components imported
*/
- (int) importCalendar: (iCalCalendar *) calendar
{
NSArray *vtimezones;
@@ -2616,6 +2624,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
iCalEntityObject *element;
iCalDateTime *startDate;
iCalTimeZone *timezone;
iCalEvent *event;
int imported, count, i;
@@ -2651,6 +2660,20 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
{
timezone = [startDate timeZone];
tz = [timezones valueForKey: [timezone tzId]];
if ([element isKindOfClass: [iCalEvent class]])
{
event = (iCalEvent *)element;
if (![event hasEndDate] && ![event hasDuration])
{
// No end date, no duration
if ([event isAllDay])
[event setDuration: @"P1D"];
else
[event setDuration: @"PT1H"];
[self errorWithFormat: @"Importing event with no end date; setting duration to %@", [event duration]];
}
}
}
if ([self importComponent: element
timezone: (tz == nil? @"" : tz)])

View File

@@ -1336,6 +1336,44 @@
[rq setContent: [[calendar versitString] dataUsingEncoding: [rq contentEncoding]]];
}
/**
* Verify vCalendar for any inconsistency or missing attributes.
* Currently only check if the events have an end date or a duration.
* @param rq the HTTP PUT request
*/
- (void) _adjustEventsInRequest: (WORequest *) rq
{
iCalCalendar *calendar;
NSArray *allEvents;
iCalEvent *event;
NSUInteger i;
BOOL modified;
calendar = [iCalCalendar parseSingleFromSource: [rq contentAsString]];
allEvents = [calendar events];
modified = NO;
for (i = 0; i < [allEvents count]; i++)
{
event = [allEvents objectAtIndex: i];
if (![event hasEndDate] && ![event hasDuration])
{
// No end date, no duration
if ([event isAllDay])
[event setDuration: @"P1D"];
else
[event setDuration: @"PT1H"];
modified = YES;
[self errorWithFormat: @"Invalid event: no end date; setting duration to %@", [event duration]];
}
}
if (modified)
[rq setContent: [[calendar versitString] dataUsingEncoding: [rq contentEncoding]]];
}
- (void) _decomposeGroupsInRequest: (WORequest *) rq
{
iCalCalendar *calendar;
@@ -1471,6 +1509,8 @@
{
[self _adjustTransparencyInRequest: rq];
}
[self _adjustEventsInRequest: rq];
}
//

View File

@@ -31,6 +31,7 @@
@interface iCalEvent (SOGoExtensions)
- (BOOL) isStillRelevant;
- (unsigned int) occurenceInterval;
- (NSMutableDictionary *) quickRecord;
- (void) updateRecurrenceRulesUntilDate: (NSCalendarDate *) previousEndDate;

View File

@@ -272,14 +272,22 @@
*/
- (NGCalendarDateRange *) firstOccurenceRange
{
iCalDateTime *firstStartDate, *firstEndDate;
iCalDateTime *firstStartDate;
NSCalendarDate *start, *end;
NGCalendarDateRange *firstRange;
firstStartDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtstart"];
firstEndDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtend"];
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: [[[firstStartDate values] lastObject] asCalendarDate]
endDate: [[[firstEndDate values] lastObject] asCalendarDate]];
firstRange = nil;
firstStartDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtstart"];
if ([[firstStartDate values] count] > 0)
{
start = [[[firstStartDate values] lastObject] asCalendarDate];
end = [start addTimeInterval: [self occurenceInterval]];
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: start
endDate: end];
}
return firstRange;
}

View File

@@ -131,8 +131,8 @@
firstRange = [self firstOccurenceRange];
// Set the range to check with respect to the event timezone (extracted from the start date)
firstStartDate = (iCalDateTime*) [self uniqueChildWithTag: @"dtstart"];
eventTimeZone = [(iCalDateTime*) firstStartDate timeZone];
firstStartDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtstart"];
eventTimeZone = [(iCalDateTime *)firstStartDate timeZone];
if (eventTimeZone)
startDate = [eventTimeZone computedDateForDate: theOccurenceDate];
else
@@ -144,12 +144,12 @@
// to the occurence's timezone.
timeZone = [theOccurenceDate timeZone];
offset = [timeZone secondsFromGMTForDate: [firstRange startDate]];
firstStartDate = (NSCalendarDate*) [[firstRange startDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
firstStartDate = (NSCalendarDate *)[[firstRange startDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
seconds:-offset];
firstEndDate = (NSCalendarDate*) [[firstRange endDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
firstEndDate = (NSCalendarDate *)[[firstRange endDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
seconds:-offset];
[(NSCalendarDate*) firstStartDate setTimeZone: timeZone];
[(NSCalendarDate*) firstEndDate setTimeZone: timeZone];
[(NSCalendarDate *)firstStartDate setTimeZone: timeZone];
[(NSCalendarDate *)firstEndDate setTimeZone: timeZone];
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: firstStartDate
endDate: firstEndDate];
}

View File

@@ -178,7 +178,6 @@ static NSArray *commonSearchFields;
- (void) dealloc
{
NSLog(@"LDAPSource: -dealloc");
[bindDN release];
[hostname release];
[encryption release];

View File

@@ -1295,7 +1295,7 @@ function initContacts(event) {
if (table) {
// Initialize event delegation on contacts table
table.multiselect = true;
var tbody = table.tBodies[0];
var tbody = $(table.tBodies[0]);
tbody.on("mousedown", onContactSelectionChange);
tbody.on("dblclick", onContactRowDblClick);
tbody.on("selectstart", listRowMouseDownHandler);

View File

@@ -141,7 +141,7 @@ SOGoTabsController.prototype = {
this.activeTab = $(clickedTab);
this.activeTab.addClassName("active"); // current LI
content.addClassName("active");
event.stop();
// Prototype alternative
//oldContent.removeClassName("active");

View File

@@ -195,8 +195,8 @@ rm -fr ${RPM_BUILD_ROOT}
%{prefix}/Library/OCSTypeModels/contact-oracle.ocs
%{prefix}/Library/WOxElemBuilders-%{sope_version}/SOGoElements.wox
%config %{_sysconfdir}/httpd/conf.d/SOGo.conf
%config %{_sysconfdir}/sysconfig/sogo
%config(noreplace) %{_sysconfdir}/httpd/conf.d/SOGo.conf
%config(noreplace) %{_sysconfdir}/sysconfig/sogo
%doc ChangeLog NEWS Scripts/sql-update-20070724.sh Scripts/sql-update-20070822.sh Scripts/sql-update-20080303.sh Scripts/sql-update-101_to_102.sh Scripts/sql-update-1.2.2_to_1.3.0.sh Scripts/sql-update-1.2.2_to_1.3.0-mysql.sh Scripts/sql-update-1.3.3_to_1.3.4.sh Scripts/sql-update-1.3.3_to_1.3.4-mysql.sh
%files -n sogo-tool