merge of '3f8608c82d9c379cc9e0fea6ffe853cc1949a24b'

and '7634b9d503d61b6240548e75e7f872081debc6b4'

Monotone-Parent: 3f8608c82d9c379cc9e0fea6ffe853cc1949a24b
Monotone-Parent: 7634b9d503d61b6240548e75e7f872081debc6b4
Monotone-Revision: a4c7e35d642045e63467a131fae8049524f450e4

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2012-06-30T18:20:30
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Francis Lachapelle
2012-06-30 18:20:30 +00:00
26 changed files with 500 additions and 177 deletions
@@ -67,4 +67,4 @@ vtodo_class2 = "(Skrytý úkol)";
= "%{Attendee} %{SentByText}dosud o Vaší pozvánce k události nerozhodl/a.";
/* Resources */
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\"." = "Maximální počet současných rezervací (%{NumberOfSimultaneousBookings}) byl dosažen pro zdroj \"%{Cn} %{SystemEmail}\".";
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "Byl dosažen maximální počet současných rezervací\n(%{NumberOfSimultaneousBookings}) pro zdroj \"%{Cn} %{SystemEmail}\". Konfliktní událost je \"%{EventTitle}\" a začíná %{StartDate}.";
+36 -1
View File
@@ -2764,7 +2764,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
iCalEvent *event;
int imported, count, i;
imported = 0;
if (calendar)
@@ -2799,6 +2799,41 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
tzId = [startDate value: 0 ofAttribute: @"tzid"];
if ([tzId length])
timezone = [timezones valueForKey: tzId];
else
{
// If the start date is a "floating time", let's use the user's timezone
// during the import for both the start and end dates.
NSString *s;
s = [[startDate valuesAtIndex: 0 forKey: @""] objectAtIndex: 0];
if ([element isKindOfClass: [iCalEvent class]] &&
![(iCalEvent *)element isAllDay] &&
![s hasSuffix: @"Z"] &&
![s hasSuffix: @"z"])
{
iCalDateTime *endDate;
int delta;
timezone = [iCalTimeZone timeZoneForName: [[[self->context activeUser] userDefaults] timeZoneName]];
[calendar addTimeZone: timezone];
delta = [[timezone periodForDate: [startDate dateTime]] secondsOffsetFromGMT];
event = (iCalEvent *)element;
[event setStartDate: [[event startDate] dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: -delta]];
[startDate setTimeZone: timezone];
endDate = (iCalDateTime *) [element uniqueChildWithTag: @"dtend"];
if (endDate)
{
[event setEndDate: [[event endDate] dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: -delta]];
[endDate setTimeZone: timezone];
}
}
}
if ([element isKindOfClass: [iCalEvent class]])
{
event = (iCalEvent *)element;
+57 -5
View File
@@ -1,5 +1,5 @@
/*
Copyright (C) 2007-2011 Inverse inc.
Copyright (C) 2007-2012 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of SOGo
@@ -456,8 +456,12 @@
{
SOGoAppointmentFolder *folder;
NSCalendarDate *start, *end;
NGCalendarDateRange *range;
NSMutableArray *fbInfo;
int i;
NSArray *allOccurences;
BOOL must_delete;
int i, j;
// We get the start/end date for our conflict range. If the event to be added is recurring, we
// check for at least a year to start with.
@@ -486,12 +490,50 @@
// We first remove any occurences in the freebusy that corresponds to the
// current event. We do this to avoid raising a conflict if we move a 1 hour
// meeting from 12:00-13:00 to 12:15-13:15. We would overlap on ourself otherwise.
//
// We must also check here for repetitive events that don't overlap our event.
// We remove all events that don't overlap. The events here are already
// decomposed.
//
if ([theEvent isRecurrent])
allOccurences = [theEvent recurrenceRangesWithinCalendarDateRange: [NGCalendarDateRange calendarDateRangeWithStartDate: start
endDate: end]
firstInstanceCalendarDateRange: [NGCalendarDateRange calendarDateRangeWithStartDate: [theEvent startDate]
endDate: [theEvent endDate]]];
else
allOccurences = nil;
for (i = [fbInfo count]-1; i >= 0; i--)
{
range = [NGCalendarDateRange calendarDateRangeWithStartDate: [[fbInfo objectAtIndex: i] objectForKey: @"startDate"]
endDate: [[fbInfo objectAtIndex: i] objectForKey: @"endDate"]];
if ([[[fbInfo objectAtIndex: i] objectForKey: @"c_uid"] compare: [theEvent uid]] == NSOrderedSame)
[fbInfo removeObjectAtIndex: i];
}
{
[fbInfo removeObjectAtIndex: i];
continue;
}
// No need to check if the event isn't recurrent here as it's handled correctly
// when we compute the "end" date.
if ([allOccurences count])
{
must_delete = YES;
for (j = 0; j < [allOccurences count]; j++)
{
if ([range doesIntersectWithDateRange: [allOccurences objectAtIndex: j]])
{
must_delete = NO;
break;
}
}
if (must_delete)
[fbInfo removeObjectAtIndex: i];
}
}
if ([fbInfo count])
{
// If we always force the auto-accept if numberOfSimultaneousBookings == 0 (ie., no limit
@@ -1714,15 +1756,25 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
{
iCalCalendar *calendar;
SOGoUser *ownerUser;
iCalEvent *event;
iCalEvent *event, *conflictingEvent;
NSString *eventUID;
BOOL scheduling;
calendar = [iCalCalendar parseSingleFromSource: [rq contentAsString]];
event = [[calendar events] objectAtIndex: 0];
eventUID = [event uid];
ownerUser = [SOGoUser userWithLogin: owner];
scheduling = [self _shouldScheduleEvent: [event organizer]];
// make sure eventUID doesn't conflict with an existing event - see bug #1853
// TODO: send out a no-uid-conflict (DAV:href) xml element (rfc4791 section 5.3.2.1)
if (conflictingEvent = [container resourceNameForEventUID: eventUID])
{
NSString *reason = [NSString stringWithFormat: @"Event UID already in use. (%s)", eventUID];
return [NSException exceptionWithHTTPStatus:403 reason: reason];
}
//
// New event and we're the organizer -- send invitation to all attendees
+23 -8
View File
@@ -516,19 +516,23 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence,
//
// Returs "YES" if a a group was decomposed among attendees.
//
// It can also return yes if an attendee was found in the list
// matching the organizer. In which case, it was removed.
//
- (BOOL) expandGroupsInEvent: (iCalEvent *) theEvent
{
NSMutableArray *allAttendees;
NSEnumerator *enumerator;
NSString *organizerEmail, *domain;
NSMutableArray *allAttendees;
iCalPerson *currentAttendee;
NSEnumerator *enumerator;
SOGoGroup *group;
BOOL doesIncludeGroup;
BOOL eventWasModified;
unsigned int i;
domain = [[context activeUser] domain];
organizerEmail = [[theEvent organizer] rfc822Email];
doesIncludeGroup = NO;
eventWasModified = NO;
allAttendees = [NSMutableArray arrayWithArray: [theEvent attendees]];
enumerator = [[theEvent attendees] objectEnumerator];
while ((currentAttendee = [enumerator nextObject]))
@@ -548,7 +552,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence,
for (i = 0; i < [members count]; i++)
{
user = [members objectAtIndex: i];
doesIncludeGroup = YES;
eventWasModified = YES;
// If the organizer is part of the group, we skip it from
// the addition to the attendees' list
@@ -565,12 +569,23 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence,
[allAttendees addObject: person];
}
}
}
else
{
// We remove any attendees matching the organizer. Apple iCal will do that when
// you invite someone. It'll add the organizer in the attendee list, which will
// confuse itself!
if ([[currentAttendee rfc822Email] caseInsensitiveCompare: organizerEmail] == NSOrderedSame)
{
[allAttendees removeObject: currentAttendee];
eventWasModified = YES;
}
}
} // while (currentAttendee ...
if (doesIncludeGroup)
if (eventWasModified)
[theEvent setAttendees: allAttendees];
return doesIncludeGroup;
return eventWasModified;
}
- (void) _updateRecurrenceIDsWithEvent: (iCalRepeatableEntityObject*) newEvent
+2
View File
@@ -70,4 +70,6 @@
SOGoReminderEnabled = YES;
SOGoRemindWithASound = YES;
SOGoSearchMinimumWordLength = 2;
}
+2
View File
@@ -77,6 +77,8 @@
- (BOOL) hideSystemEMail;
- (int) searchMinimumWordLength;
@end
#endif /* SOGODOMAINDEFAULTS_H */
+5
View File
@@ -319,4 +319,9 @@
return [self boolForKey: @"SOGoHideSystemEMail"];
}
- (int) searchMinimumWordLength
{
return [self integerForKey: @"SOGoSearchMinimumWordLength"];
}
@end