(feat) better support for RFC 6638 (schedule-agent) (fixes #2599)
This commit is contained in:
parent
9882052e81
commit
ab1c699bc7
|
@ -369,6 +369,48 @@
|
||||||
return listHasChanged;
|
return listHasChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
- (BOOL) _shouldScheduleEvent: (iCalPerson *) thePerson
|
||||||
|
{
|
||||||
|
NSArray *userAgents;
|
||||||
|
NSString *v;
|
||||||
|
BOOL b;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
b = YES;
|
||||||
|
|
||||||
|
if (thePerson && (v = [thePerson value: 0 ofAttribute: @"SCHEDULE-AGENT"]))
|
||||||
|
{
|
||||||
|
if ([v caseInsensitiveCompare: @"NONE"] == NSOrderedSame ||
|
||||||
|
[v caseInsensitiveCompare: @"CLIENT"] == NSOrderedSame)
|
||||||
|
b = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// If we have to deal with Thunderbird/Lightning, we always send invitation
|
||||||
|
// reponses, as Lightning v2.6 (at least this version) sets SCHEDULE-AGENT
|
||||||
|
// to NONE/CLIENT when responding to an external invitation received by
|
||||||
|
// SOGo - so no invitation responses are ever sent by Lightning. See
|
||||||
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=865726 and
|
||||||
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=997784
|
||||||
|
//
|
||||||
|
userAgents = [[context request] headersForKey: @"User-Agent"];
|
||||||
|
|
||||||
|
for (i = 0; i < [userAgents count]; i++)
|
||||||
|
{
|
||||||
|
if ([[userAgents objectAtIndex: i] rangeOfString: @"Thunderbird"].location != NSNotFound &&
|
||||||
|
[[userAgents objectAtIndex: i] rangeOfString: @"Lightning"].location != NSNotFound)
|
||||||
|
{
|
||||||
|
b = YES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -394,11 +436,12 @@
|
||||||
owner: owner];
|
owner: owner];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self sendEMailUsingTemplateNamed: @"Update"
|
if ([self _shouldScheduleEvent: [newEvent organizer]])
|
||||||
forObject: [newEvent itipEntryWithMethod: @"request"]
|
[self sendEMailUsingTemplateNamed: @"Update"
|
||||||
previousObject: oldEvent
|
forObject: [newEvent itipEntryWithMethod: @"request"]
|
||||||
toAttendees: updateAttendees
|
previousObject: oldEvent
|
||||||
withType: @"calendar:invitation-update"];
|
toAttendees: updateAttendees
|
||||||
|
withType: @"calendar:invitation-update"];
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method scans the list of attendees.
|
// This method scans the list of attendees.
|
||||||
|
@ -823,11 +866,12 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
{
|
{
|
||||||
[self _handleRemovedUsers: deletedAttendees
|
[self _handleRemovedUsers: deletedAttendees
|
||||||
withRecurrenceId: [newEvent recurrenceId]];
|
withRecurrenceId: [newEvent recurrenceId]];
|
||||||
[self sendEMailUsingTemplateNamed: @"Deletion"
|
if ([self _shouldScheduleEvent: [newEvent organizer]])
|
||||||
forObject: [newEvent itipEntryWithMethod: @"cancel"]
|
[self sendEMailUsingTemplateNamed: @"Deletion"
|
||||||
previousObject: oldEvent
|
forObject: [newEvent itipEntryWithMethod: @"cancel"]
|
||||||
toAttendees: deletedAttendees
|
previousObject: oldEvent
|
||||||
withType: @"calendar:cancellation"];
|
toAttendees: deletedAttendees
|
||||||
|
withType: @"calendar:cancellation"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ex = [self _handleAttendeesConflicts: [newEvent attendees] forEvent: newEvent force: forceSave]))
|
if ((ex = [self _handleAttendeesConflicts: [newEvent attendees] forEvent: newEvent force: forceSave]))
|
||||||
|
@ -883,12 +927,13 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
// Send an invitation to new attendees
|
// Send an invitation to new attendees
|
||||||
if ((ex = [self _handleAddedUsers: addedAttendees fromEvent: newEvent force: forceSave]))
|
if ((ex = [self _handleAddedUsers: addedAttendees fromEvent: newEvent force: forceSave]))
|
||||||
return ex;
|
return ex;
|
||||||
|
|
||||||
[self sendEMailUsingTemplateNamed: @"Invitation"
|
if ([self _shouldScheduleEvent: [newEvent organizer]])
|
||||||
forObject: [newEvent itipEntryWithMethod: @"request"]
|
[self sendEMailUsingTemplateNamed: @"Invitation"
|
||||||
previousObject: oldEvent
|
forObject: [newEvent itipEntryWithMethod: @"request"]
|
||||||
toAttendees: addedAttendees
|
previousObject: oldEvent
|
||||||
withType: @"calendar:invitation"];
|
toAttendees: addedAttendees
|
||||||
|
withType: @"calendar:invitation"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([changes hasMajorChanges])
|
if ([changes hasMajorChanges])
|
||||||
|
@ -962,11 +1007,12 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
|
|
||||||
if ([attendees count])
|
if ([attendees count])
|
||||||
{
|
{
|
||||||
[self sendEMailUsingTemplateNamed: @"Invitation"
|
if ([self _shouldScheduleEvent: [newEvent organizer]])
|
||||||
forObject: [newEvent itipEntryWithMethod: @"request"]
|
[self sendEMailUsingTemplateNamed: @"Invitation"
|
||||||
previousObject: nil
|
forObject: [newEvent itipEntryWithMethod: @"request"]
|
||||||
toAttendees: attendees
|
previousObject: nil
|
||||||
withType: @"calendar:invitation"];
|
toAttendees: attendees
|
||||||
|
withType: @"calendar:invitation"];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self sendReceiptEmailForObject: newEvent
|
[self sendReceiptEmailForObject: newEvent
|
||||||
|
@ -1166,19 +1212,17 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
statusChange: (NSString *) newStatus
|
statusChange: (NSString *) newStatus
|
||||||
inEvent: (iCalEvent *) event
|
inEvent: (iCalEvent *) event
|
||||||
{
|
{
|
||||||
|
iCalPerson *otherAttendee, *otherDelegate;
|
||||||
NSString *currentStatus, *organizerUID;
|
NSString *currentStatus, *organizerUID;
|
||||||
SOGoUser *ownerUser, *currentUser;
|
SOGoUser *ownerUser, *currentUser;
|
||||||
|
NSString *delegateEmail;
|
||||||
NSException *ex;
|
NSException *ex;
|
||||||
|
|
||||||
ex = nil;
|
BOOL addDelegate, removeDelegate;
|
||||||
|
|
||||||
currentStatus = [attendee partStat];
|
currentStatus = [attendee partStat];
|
||||||
|
|
||||||
iCalPerson *otherAttendee, *otherDelegate;
|
|
||||||
NSString *delegateEmail;
|
|
||||||
BOOL addDelegate, removeDelegate;
|
|
||||||
|
|
||||||
otherAttendee = attendee;
|
otherAttendee = attendee;
|
||||||
|
ex = nil;
|
||||||
|
|
||||||
delegateEmail = [otherAttendee delegatedTo];
|
delegateEmail = [otherAttendee delegatedTo];
|
||||||
if ([delegateEmail length])
|
if ([delegateEmail length])
|
||||||
|
@ -1189,7 +1233,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
else
|
else
|
||||||
otherDelegate = nil;
|
otherDelegate = nil;
|
||||||
|
|
||||||
/* We handle the addition/deletion of delegate users */
|
// We handle the addition/deletion of delegate users
|
||||||
addDelegate = NO;
|
addDelegate = NO;
|
||||||
removeDelegate = NO;
|
removeDelegate = NO;
|
||||||
if (delegate)
|
if (delegate)
|
||||||
|
@ -1272,12 +1316,13 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
else
|
else
|
||||||
otherDelegate = nil;
|
otherDelegate = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self sendEMailUsingTemplateNamed: @"Deletion"
|
if ([self _shouldScheduleEvent: [event organizer]])
|
||||||
forObject: [event itipEntryWithMethod: @"cancel"]
|
[self sendEMailUsingTemplateNamed: @"Deletion"
|
||||||
previousObject: nil
|
forObject: [event itipEntryWithMethod: @"cancel"]
|
||||||
toAttendees: delegates
|
previousObject: nil
|
||||||
withType: @"calendar:cancellation"];
|
toAttendees: delegates
|
||||||
|
withType: @"calendar:cancellation"];
|
||||||
} // if (removeDelegate)
|
} // if (removeDelegate)
|
||||||
|
|
||||||
if (addDelegate)
|
if (addDelegate)
|
||||||
|
@ -1291,12 +1336,13 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
[self _addOrUpdateEvent: event
|
[self _addOrUpdateEvent: event
|
||||||
forUID: delegatedUID
|
forUID: delegatedUID
|
||||||
owner: [theOwnerUser login]];
|
owner: [theOwnerUser login]];
|
||||||
|
|
||||||
[self sendEMailUsingTemplateNamed: @"Invitation"
|
if ([self _shouldScheduleEvent: [event organizer]])
|
||||||
forObject: [event itipEntryWithMethod: @"request"]
|
[self sendEMailUsingTemplateNamed: @"Invitation"
|
||||||
previousObject: nil
|
forObject: [event itipEntryWithMethod: @"request"]
|
||||||
toAttendees: delegates
|
previousObject: nil
|
||||||
withType: @"calendar:invitation"];
|
toAttendees: delegates
|
||||||
|
withType: @"calendar:invitation"];
|
||||||
} // if (addDelegate)
|
} // if (addDelegate)
|
||||||
|
|
||||||
// If the current user isn't the organizer of the event
|
// If the current user isn't the organizer of the event
|
||||||
|
@ -1477,9 +1523,9 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
// within the repeating vEvent.
|
// within the repeating vEvent.
|
||||||
recurrenceTime = [NSString stringWithFormat: @"%f", [_recurrenceId timeIntervalSince1970]];
|
recurrenceTime = [NSString stringWithFormat: @"%f", [_recurrenceId timeIntervalSince1970]];
|
||||||
event = (iCalEvent*)[self lookupOccurrence: recurrenceTime];
|
event = (iCalEvent*)[self lookupOccurrence: recurrenceTime];
|
||||||
|
|
||||||
|
// If no occurence found, create one
|
||||||
if (event == nil)
|
if (event == nil)
|
||||||
// If no occurence found, create one
|
|
||||||
event = (iCalEvent*)[self newOccurenceWithID: recurrenceTime];
|
event = (iCalEvent*)[self newOccurenceWithID: recurrenceTime];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1558,50 +1604,6 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
return ex;
|
return ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
- (BOOL) _shouldScheduleEvent: (iCalPerson *) theOrganizer
|
|
||||||
{
|
|
||||||
NSArray *userAgents;
|
|
||||||
NSString *v;
|
|
||||||
BOOL b;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
b = YES;
|
|
||||||
|
|
||||||
if (theOrganizer && (v = [theOrganizer value: 0 ofAttribute: @"SCHEDULE-AGENT"]))
|
|
||||||
{
|
|
||||||
if ([v caseInsensitiveCompare: @"NONE"] == NSOrderedSame ||
|
|
||||||
[v caseInsensitiveCompare: @"CLIENT"] == NSOrderedSame)
|
|
||||||
b = NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// If we have to deal with Thunderbird/Lightning, we always send invitation
|
|
||||||
// reponses, as Lightning v2.6 (at least this version) sets SCHEDULE-AGENT
|
|
||||||
// to NONE/CLIENT when responding to an external invitation received by
|
|
||||||
// SOGo - so no invitation responses are ever sent by Lightning. See
|
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=865726 and
|
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=997784
|
|
||||||
//
|
|
||||||
userAgents = [[context request] headersForKey: @"User-Agent"];
|
|
||||||
|
|
||||||
for (i = 0; i < [userAgents count]; i++)
|
|
||||||
{
|
|
||||||
if ([[userAgents objectAtIndex: i] rangeOfString: @"Thunderbird"].location != NSNotFound &&
|
|
||||||
[[userAgents objectAtIndex: i] rangeOfString: @"Lightning"].location != NSNotFound)
|
|
||||||
{
|
|
||||||
b = YES;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -1613,14 +1615,10 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
iCalEvent *event;
|
iCalEvent *event;
|
||||||
BOOL send_receipt;
|
BOOL send_receipt;
|
||||||
|
|
||||||
|
|
||||||
ownerUser = [SOGoUser userWithLogin: owner];
|
ownerUser = [SOGoUser userWithLogin: owner];
|
||||||
event = [self component: NO secure: NO];
|
event = [self component: NO secure: NO];
|
||||||
send_receipt = YES;
|
send_receipt = YES;
|
||||||
|
|
||||||
if (![self _shouldScheduleEvent: [event organizer]])
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (occurence == nil)
|
if (occurence == nil)
|
||||||
{
|
{
|
||||||
// No occurence specified; use the master event.
|
// No occurence specified; use the master event.
|
||||||
|
@ -1646,11 +1644,13 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
// and send them an email.
|
// and send them an email.
|
||||||
[self _handleRemovedUsers: attendees
|
[self _handleRemovedUsers: attendees
|
||||||
withRecurrenceId: recurrenceId];
|
withRecurrenceId: recurrenceId];
|
||||||
[self sendEMailUsingTemplateNamed: @"Deletion"
|
|
||||||
forObject: [occurence itipEntryWithMethod: @"cancel"]
|
if ([self _shouldScheduleEvent: [event organizer]])
|
||||||
previousObject: nil
|
[self sendEMailUsingTemplateNamed: @"Deletion"
|
||||||
toAttendees: attendees
|
forObject: [occurence itipEntryWithMethod: @"cancel"]
|
||||||
withType: @"calendar:cancellation"];
|
previousObject: nil
|
||||||
|
toAttendees: attendees
|
||||||
|
withType: @"calendar:cancellation"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ([occurence userIsAttendee: ownerUser])
|
else if ([occurence userIsAttendee: ownerUser])
|
||||||
|
@ -1664,12 +1664,12 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
send_receipt = NO;
|
send_receipt = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (send_receipt)
|
if (send_receipt)
|
||||||
[self sendReceiptEmailForObject: event
|
[self sendReceiptEmailForObject: event
|
||||||
addedAttendees: nil
|
addedAttendees: nil
|
||||||
deletedAttendees: nil
|
deletedAttendees: nil
|
||||||
updatedAttendees: nil
|
updatedAttendees: nil
|
||||||
operation: EventDeleted];
|
operation: EventDeleted];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSException *) prepareDelete
|
- (NSException *) prepareDelete
|
||||||
|
@ -1984,13 +1984,10 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
iCalEvent *event;
|
iCalEvent *event;
|
||||||
NSArray *attendees;
|
NSArray *attendees;
|
||||||
NSString *eventUID;
|
NSString *eventUID;
|
||||||
BOOL scheduling;
|
|
||||||
|
|
||||||
attendees = nil;
|
|
||||||
|
|
||||||
event = [[calendar events] objectAtIndex: 0];
|
event = [[calendar events] objectAtIndex: 0];
|
||||||
eventUID = [event uid];
|
eventUID = [event uid];
|
||||||
scheduling = [self _shouldScheduleEvent: [event organizer]];
|
attendees = nil;
|
||||||
|
|
||||||
// make sure eventUID doesn't conflict with an existing event - see bug #1853
|
// 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)
|
// TODO: send out a no-uid-conflict (DAV:href) xml element (rfc4791 section 5.3.2.1)
|
||||||
|
@ -2003,34 +2000,35 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||||
//
|
//
|
||||||
// New event and we're the organizer -- send invitation to all attendees
|
// New event and we're the organizer -- send invitation to all attendees
|
||||||
//
|
//
|
||||||
if (scheduling && [event userIsOrganizer: ownerUser])
|
if ([event userIsOrganizer: ownerUser])
|
||||||
{
|
{
|
||||||
attendees = [event attendeesWithoutUser: ownerUser];
|
attendees = [event attendeesWithoutUser: ownerUser];
|
||||||
if ([attendees count])
|
if ([attendees count])
|
||||||
{
|
{
|
||||||
if ((ex = [self _handleAddedUsers: attendees fromEvent: event force: YES]))
|
if ((ex = [self _handleAddedUsers: attendees fromEvent: event force: YES]))
|
||||||
return ex;
|
return ex;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We might have auto-accepted resources here. If that's the
|
// We might have auto-accepted resources here. If that's the
|
||||||
// case, let's regenerate the versitstring and replace the
|
// case, let's regenerate the versitstring and replace the
|
||||||
// one from the request.
|
// one from the request.
|
||||||
[rq setContent: [[[event parent] versitString] dataUsingEncoding: [rq contentEncoding]]];
|
[rq setContent: [[[event parent] versitString] dataUsingEncoding: [rq contentEncoding]]];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self sendEMailUsingTemplateNamed: @"Invitation"
|
if ([self _shouldScheduleEvent: [event organizer]])
|
||||||
forObject: [event itipEntryWithMethod: @"request"]
|
[self sendEMailUsingTemplateNamed: @"Invitation"
|
||||||
previousObject: nil
|
forObject: [event itipEntryWithMethod: @"request"]
|
||||||
toAttendees: attendees
|
previousObject: nil
|
||||||
withType: @"calendar:invitation"];
|
toAttendees: attendees
|
||||||
}
|
withType: @"calendar:invitation"];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// We aren't the organizer but we're an attendee. That can happen when
|
// We aren't the organizer but we're an attendee. That can happen when
|
||||||
// we receive an external invitation (IMIP/ITIP) and we accept it
|
// we receive an external invitation (IMIP/ITIP) and we accept it
|
||||||
// from a CUA - it gets added to a specific CalDAV calendar using a PUT
|
// from a CUA - it gets added to a specific CalDAV calendar using a PUT
|
||||||
//
|
//
|
||||||
else if (scheduling && [event userIsAttendee: ownerUser])
|
else if ([event userIsAttendee: ownerUser] && [self _shouldScheduleEvent: [event userAsAttendee: ownerUser]])
|
||||||
{
|
{
|
||||||
[self sendIMIPReplyForEvent: event
|
[self sendIMIPReplyForEvent: event
|
||||||
from: ownerUser
|
from: ownerUser
|
||||||
|
|
Loading…
Reference in a new issue