Skip to content

Commit 4cae924

Browse files
Merge pull request #55763 from nextcloud/backport/54819/stable32
[stable32] fix: iMip reply from outlook.com does not contain organizer property
2 parents a4df2f5 + 34f92a0 commit 4cae924

File tree

3 files changed

+90
-6
lines changed

3 files changed

+90
-6
lines changed

lib/private/Calendar/Manager.php

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,13 @@ public function handleIMip(
261261
}
262262

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

268273
if (!isset($vEvent->ATTENDEE)) {
@@ -335,7 +340,8 @@ public function handleIMipRequest(
335340
return false;
336341
}
337342
$userId = substr($principalUri, 17);
338-
return $this->handleIMip($userId, $calendarData);
343+
$options = ['recipient' => $recipient];
344+
return $this->handleIMip($userId, $calendarData, $options);
339345
}
340346

341347
/**
@@ -354,7 +360,8 @@ public function handleIMipReply(
354360
return false;
355361
}
356362
$userId = substr($principalUri, 17);
357-
return $this->handleIMip($userId, $calendarData);
363+
$options = ['recipient' => $recipient];
364+
return $this->handleIMip($userId, $calendarData, $options);
358365
}
359366

360367
/**
@@ -374,7 +381,8 @@ public function handleIMipCancel(
374381
return false;
375382
}
376383
$userId = substr($principalUri, 17);
377-
return $this->handleIMip($userId, $calendarData);
384+
$options = ['recipient' => $recipient];
385+
return $this->handleIMip($userId, $calendarData, $options);
378386
}
379387

380388
public function createEventBuilder(): ICalendarEventBuilder {

lib/public/Calendar/IManager.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public function newQuery(string $principalUri) : ICalendarQuery;
143143
/**
144144
* Handles a iMip message
145145
*
146-
* @param array{absent?: "create"} $options
146+
* @param array{absent?: "create", recipient?: string} $options
147147
*
148148
* @throws \OCP\DB\Exception
149149
*

tests/lib/Calendar/ManagerTest.php

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

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

0 commit comments

Comments
 (0)