Skip to content

Commit 5184cb7

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

File tree

2 files changed

+88
-5
lines changed

2 files changed

+88
-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: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,80 @@ 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+
])
409+
->onlyMethods(['getCalendarsForPrincipal'])
410+
->getMock();
411+
$manager->expects(self::once())
412+
->method('getCalendarsForPrincipal')
413+
->willReturn([$userCalendar]);
414+
// construct parameters
415+
$userId = 'attendee1';
416+
$calendar = $this->vCalendar1a;
417+
$calendar->add('METHOD', 'REQUEST');
418+
$calendar->VEVENT->remove('ORGANIZER');
419+
// construct user calendar returns
420+
$userCalendar->expects(self::once())
421+
->method('handleIMipMessage');
422+
// test method
423+
$result = $this->invokePrivate($manager, 'handleIMip', [$userId, $calendar->serialize(), ['recipient' => 'organizer@testing.com']]);
424+
}
425+
426+
public function testHandleImipMissingOrganizerNoRecipient(): void {
427+
// construct mock user calendar
428+
$userCalendar = $this->createMock(ITestCalendar::class);
429+
// construct mock calendar manager and returns
430+
/** @var Manager&MockObject $manager */
431+
$manager = $this->getMockBuilder(Manager::class)
432+
->setConstructorArgs([
433+
$this->coordinator,
434+
$this->container,
435+
$this->logger,
436+
$this->time,
437+
$this->secureRandom,
438+
$this->userManager,
439+
$this->serverFactory,
440+
])
441+
->onlyMethods(['getCalendarsForPrincipal'])
442+
->getMock();
443+
$manager->expects(self::once())
444+
->method('getCalendarsForPrincipal')
445+
->willReturn([$userCalendar]);
446+
// construct parameters
447+
$userId = 'attendee1';
448+
$calendar = $this->vCalendar1a;
449+
$calendar->add('METHOD', 'REQUEST');
450+
$calendar->VEVENT->remove('ORGANIZER');
451+
// Logger expects warning
452+
$this->logger->expects($this->once())
453+
->method('warning')
454+
->with('iMip message event does not contain an organizer and no recipient was provided');
455+
456+
$result = $this->invokePrivate($manager, 'handleIMip', [$userId, $calendar->serialize(), []]);
457+
}
458+
385459
public function testHandleImipWithNoUid(): void {
386460
// construct mock user calendar
387461
$userCalendar = $this->createMock(ITestCalendar::class);

0 commit comments

Comments
 (0)