Skip to content

Commit b6739f8

Browse files
fix: iMip reply from outlook.com does not contain organizer property
Signed-off-by: SebastianKrupinski <krupinskis05@gmail.com>
1 parent 93a1bc1 commit b6739f8

File tree

2 files changed

+90
-5
lines changed

2 files changed

+90
-5
lines changed

lib/private/Calendar/Manager.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ public function newQuery(string $principalUri): ICalendarQuery {
227227
protected function handleIMip(
228228
string $userId,
229229
string $message,
230+
array $options = [],
230231
): bool {
231232

232233
$userUri = 'principals/users/' . $userId;
@@ -258,8 +259,13 @@ protected function handleIMip(
258259
}
259260

260261
if (!isset($vEvent->ORGANIZER)) {
261-
$this->logger->warning('iMip message event dose not contains an organizer');
262-
return false;
262+
// quirks mode: for Microsoft Exchange Servers use recipient as organizer if no organizer is set
263+
if (isset($options['recipient']) && $options['recipient'] !== '') {
264+
$vEvent->add('ORGANIZER', 'mailto:' . $options['recipient']);
265+
} else {
266+
$this->logger->warning('iMip message event does not contain an organizer and no recipient was provided');
267+
return false;
268+
}
263269
}
264270

265271
if (!isset($vEvent->ATTENDEE)) {
@@ -308,7 +314,8 @@ public function handleIMipRequest(
308314
return false;
309315
}
310316
$userId = substr($principalUri, 17);
311-
return $this->handleIMip($userId, $calendarData);
317+
$options = ['recipient' => $recipient];
318+
return $this->handleIMip($userId, $calendarData, $options);
312319
}
313320

314321
/**
@@ -327,7 +334,8 @@ public function handleIMipReply(
327334
return false;
328335
}
329336
$userId = substr($principalUri, 17);
330-
return $this->handleIMip($userId, $calendarData);
337+
$options = ['recipient' => $recipient];
338+
return $this->handleIMip($userId, $calendarData, $options);
331339
}
332340

333341
/**
@@ -347,7 +355,8 @@ public function handleIMipCancel(
347355
return false;
348356
}
349357
$userId = substr($principalUri, 17);
350-
return $this->handleIMip($userId, $calendarData);
358+
$options = ['recipient' => $recipient];
359+
return $this->handleIMip($userId, $calendarData, $options);
351360
}
352361

353362
public function createEventBuilder(): ICalendarEventBuilder {

tests/lib/Calendar/ManagerTest.php

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,82 @@ public function testHandleImipWithNoEvent(): void {
382382
$this->assertFalse($result);
383383
}
384384

385+
public function testHandleImipMissingOrganizerWithRecipient(): void {
386+
// construct mock user calendar
387+
$userCalendar = $this->createMock(ITestCalendar::class);
388+
$userCalendar->expects(self::once())
389+
->method('isDeleted')
390+
->willReturn(false);
391+
$userCalendar->expects(self::once())
392+
->method('isWritable')
393+
->willReturn(true);
394+
$userCalendar->expects(self::once())
395+
->method('search')
396+
->willReturn([['uri' => 'principals/user/attendee1/personal']]);
397+
// construct mock calendar manager and returns
398+
/** @var Manager&MockObject $manager */
399+
$manager = $this->getMockBuilder(Manager::class)
400+
->setConstructorArgs([
401+
$this->coordinator,
402+
$this->container,
403+
$this->logger,
404+
$this->time,
405+
$this->secureRandom,
406+
$this->userManager,
407+
$this->serverFactory,
408+
$this->propertyMapper,
409+
])
410+
->onlyMethods(['getCalendarsForPrincipal'])
411+
->getMock();
412+
$manager->expects(self::once())
413+
->method('getCalendarsForPrincipal')
414+
->willReturn([$userCalendar]);
415+
// construct parameters
416+
$userId = 'attendee1';
417+
$calendar = $this->vCalendar1a;
418+
$calendar->add('METHOD', 'REQUEST');
419+
$calendar->VEVENT->remove('ORGANIZER');
420+
// construct user calendar returns
421+
$userCalendar->expects(self::once())
422+
->method('handleIMipMessage');
423+
// test method
424+
$result = $manager->handleIMip($userId, $calendar->serialize(), ['recipient' => 'organizer@testing.com']);
425+
}
426+
427+
public function testHandleImipMissingOrganizerNoRecipient(): void {
428+
// construct mock user calendar
429+
$userCalendar = $this->createMock(ITestCalendar::class);
430+
// construct mock calendar manager and returns
431+
/** @var Manager&MockObject $manager */
432+
$manager = $this->getMockBuilder(Manager::class)
433+
->setConstructorArgs([
434+
$this->coordinator,
435+
$this->container,
436+
$this->logger,
437+
$this->time,
438+
$this->secureRandom,
439+
$this->userManager,
440+
$this->serverFactory,
441+
$this->propertyMapper,
442+
])
443+
->onlyMethods(['getCalendarsForPrincipal'])
444+
->getMock();
445+
$manager->expects(self::once())
446+
->method('getCalendarsForPrincipal')
447+
->willReturn([$userCalendar]);
448+
// construct parameters
449+
$userId = 'attendee1';
450+
$calendar = $this->vCalendar1a;
451+
$calendar->add('METHOD', 'REQUEST');
452+
$calendar->VEVENT->remove('ORGANIZER');
453+
// Logger expects warning
454+
$this->logger->expects($this->once())
455+
->method('warning')
456+
->with('iMip message event does not contain an organizer and no recipient was provided');
457+
458+
$result = $manager->handleIMip($userId, $calendar->serialize(), []);
459+
}
460+
385461
public function testHandleImipWithNoUid(): void {
386462
// construct mock user calendar
387463
$userCalendar = $this->createMock(ITestCalendar::class);

0 commit comments

Comments
 (0)