Passed
Push — master ( 555550...c77cc8 )
by Blizzz
13:10 queued 12s
created
lib/private/Calendar/Manager.php 2 patches
Indentation   +337 added lines, -337 removed lines patch added patch discarded remove patch
@@ -46,341 +46,341 @@
 block discarded – undo
46 46
 
47 47
 class Manager implements IManager {
48 48
 
49
-	/**
50
-	 * @var ICalendar[] holds all registered calendars
51
-	 */
52
-	private $calendars = [];
53
-
54
-	/**
55
-	 * @var \Closure[] to call to load/register calendar providers
56
-	 */
57
-	private $calendarLoaders = [];
58
-
59
-	/** @var Coordinator */
60
-	private $coordinator;
61
-
62
-	/** @var ContainerInterface */
63
-	private $container;
64
-
65
-	/** @var LoggerInterface */
66
-	private $logger;
67
-
68
-	private ITimeFactory $timeFactory;
69
-
70
-
71
-	public function __construct(Coordinator $coordinator,
72
-								ContainerInterface $container,
73
-								LoggerInterface $logger,
74
-								ITimeFactory $timeFactory) {
75
-		$this->coordinator = $coordinator;
76
-		$this->container = $container;
77
-		$this->logger = $logger;
78
-		$this->timeFactory = $timeFactory;
79
-	}
80
-
81
-	/**
82
-	 * This function is used to search and find objects within the user's calendars.
83
-	 * In case $pattern is empty all events/journals/todos will be returned.
84
-	 *
85
-	 * @param string $pattern which should match within the $searchProperties
86
-	 * @param array $searchProperties defines the properties within the query pattern should match
87
-	 * @param array $options - optional parameters:
88
-	 * 	['timerange' => ['start' => new DateTime(...), 'end' => new DateTime(...)]]
89
-	 * @param integer|null $limit - limit number of search results
90
-	 * @param integer|null $offset - offset for paging of search results
91
-	 * @return array an array of events/journals/todos which are arrays of arrays of key-value-pairs
92
-	 * @since 13.0.0
93
-	 */
94
-	public function search($pattern, array $searchProperties = [], array $options = [], $limit = null, $offset = null) {
95
-		$this->loadCalendars();
96
-		$result = [];
97
-		foreach ($this->calendars as $calendar) {
98
-			$r = $calendar->search($pattern, $searchProperties, $options, $limit, $offset);
99
-			foreach ($r as $o) {
100
-				$o['calendar-key'] = $calendar->getKey();
101
-				$result[] = $o;
102
-			}
103
-		}
104
-
105
-		return $result;
106
-	}
107
-
108
-	/**
109
-	 * Check if calendars are available
110
-	 *
111
-	 * @return bool true if enabled, false if not
112
-	 * @since 13.0.0
113
-	 */
114
-	public function isEnabled() {
115
-		return !empty($this->calendars) || !empty($this->calendarLoaders);
116
-	}
117
-
118
-	/**
119
-	 * Registers a calendar
120
-	 *
121
-	 * @param ICalendar $calendar
122
-	 * @return void
123
-	 * @since 13.0.0
124
-	 */
125
-	public function registerCalendar(ICalendar $calendar) {
126
-		$this->calendars[$calendar->getKey()] = $calendar;
127
-	}
128
-
129
-	/**
130
-	 * Unregisters a calendar
131
-	 *
132
-	 * @param ICalendar $calendar
133
-	 * @return void
134
-	 * @since 13.0.0
135
-	 */
136
-	public function unregisterCalendar(ICalendar $calendar) {
137
-		unset($this->calendars[$calendar->getKey()]);
138
-	}
139
-
140
-	/**
141
-	 * In order to improve lazy loading a closure can be registered which will be called in case
142
-	 * calendars are actually requested
143
-	 *
144
-	 * @param \Closure $callable
145
-	 * @return void
146
-	 * @since 13.0.0
147
-	 */
148
-	public function register(\Closure $callable) {
149
-		$this->calendarLoaders[] = $callable;
150
-	}
151
-
152
-	/**
153
-	 * @return ICalendar[]
154
-	 * @since 13.0.0
155
-	 */
156
-	public function getCalendars() {
157
-		$this->loadCalendars();
158
-
159
-		return array_values($this->calendars);
160
-	}
161
-
162
-	/**
163
-	 * removes all registered calendar instances
164
-	 * @return void
165
-	 * @since 13.0.0
166
-	 */
167
-	public function clear() {
168
-		$this->calendars = [];
169
-		$this->calendarLoaders = [];
170
-	}
171
-
172
-	/**
173
-	 * loads all calendars
174
-	 */
175
-	private function loadCalendars() {
176
-		foreach ($this->calendarLoaders as $callable) {
177
-			$callable($this);
178
-		}
179
-		$this->calendarLoaders = [];
180
-	}
181
-
182
-	/**
183
-	 * @param string $principalUri
184
-	 * @param array $calendarUris
185
-	 * @return ICreateFromString[]
186
-	 */
187
-	public function getCalendarsForPrincipal(string $principalUri, array $calendarUris = []): array {
188
-		$context = $this->coordinator->getRegistrationContext();
189
-		if ($context === null) {
190
-			return [];
191
-		}
192
-
193
-		return array_merge(
194
-			...array_map(function ($registration) use ($principalUri, $calendarUris) {
195
-				try {
196
-					/** @var ICalendarProvider $provider */
197
-					$provider = $this->container->get($registration->getService());
198
-				} catch (Throwable $e) {
199
-					$this->logger->error('Could not load calendar provider ' . $registration->getService() . ': ' . $e->getMessage(), [
200
-						'exception' => $e,
201
-					]);
202
-					return [];
203
-				}
204
-
205
-				return $provider->getCalendars($principalUri, $calendarUris);
206
-			}, $context->getCalendarProviders())
207
-		);
208
-	}
209
-
210
-	public function searchForPrincipal(ICalendarQuery $query): array {
211
-		/** @var CalendarQuery $query */
212
-		$calendars = $this->getCalendarsForPrincipal(
213
-			$query->getPrincipalUri(),
214
-			$query->getCalendarUris(),
215
-		);
216
-
217
-		$results = [];
218
-		foreach ($calendars as $calendar) {
219
-			$r = $calendar->search(
220
-				$query->getSearchPattern() ?? '',
221
-				$query->getSearchProperties(),
222
-				$query->getOptions(),
223
-				$query->getLimit(),
224
-				$query->getOffset()
225
-			);
226
-
227
-			foreach ($r as $o) {
228
-				$o['calendar-key'] = $calendar->getKey();
229
-				$results[] = $o;
230
-			}
231
-		}
232
-		return $results;
233
-	}
234
-
235
-	public function newQuery(string $principalUri): ICalendarQuery {
236
-		return new CalendarQuery($principalUri);
237
-	}
238
-
239
-	/**
240
-	 * @throws \OCP\DB\Exception
241
-	 */
242
-	public function handleIMipReply(string $principalUri, string $sender, string $recipient, string $calendarData): bool {
243
-		/** @var VCalendar $vObject */
244
-		$vObject = Reader::read($calendarData);
245
-		/** @var VEvent $vEvent */
246
-		$vEvent = $vObject->{'VEVENT'};
247
-
248
-		// First, we check if the correct method is passed to us
249
-		if (strcasecmp('REPLY', $vObject->{'METHOD'}->getValue()) !== 0) {
250
-			$this->logger->warning('Wrong method provided for processing');
251
-			return false;
252
-		}
253
-
254
-		// check if mail recipient and organizer are one and the same
255
-		$organizer = substr($vEvent->{'ORGANIZER'}->getValue(), 7);
256
-
257
-		if (strcasecmp($recipient, $organizer) !== 0) {
258
-			$this->logger->warning('Recipient and ORGANIZER must be identical');
259
-			return false;
260
-		}
261
-
262
-		//check if the event is in the future
263
-		/** @var DateTime $eventTime */
264
-		$eventTime = $vEvent->{'DTSTART'};
265
-		if ($eventTime->getDateTime()->getTimeStamp() < $this->timeFactory->getTime()) { // this might cause issues with recurrences
266
-			$this->logger->warning('Only events in the future are processed');
267
-			return false;
268
-		}
269
-
270
-		$calendars = $this->getCalendarsForPrincipal($principalUri);
271
-		if (empty($calendars)) {
272
-			$this->logger->warning('Could not find any calendars for principal ' . $principalUri);
273
-			return false;
274
-		}
275
-
276
-		$found = null;
277
-		// if the attendee has been found in at least one calendar event with the UID of the iMIP event
278
-		// we process it.
279
-		// Benefit: no attendee lost
280
-		// Drawback: attendees that have been deleted will still be able to update their partstat
281
-		foreach ($calendars as $calendar) {
282
-			// We should not search in writable calendars
283
-			if ($calendar instanceof ICreateFromString) {
284
-				$o = $calendar->search($sender, ['ATTENDEE'], ['uid' => $vEvent->{'UID'}->getValue()]);
285
-				if (!empty($o)) {
286
-					$found = $calendar;
287
-					$name = $o[0]['uri'];
288
-					break;
289
-				}
290
-			}
291
-		}
292
-
293
-		if (empty($found)) {
294
-			$this->logger->info('Event not found in any calendar for principal ' . $principalUri . 'and UID' . $vEvent->{'UID'}->getValue());
295
-			return false;
296
-		}
297
-
298
-		try {
299
-			$found->handleIMipMessage($name, $calendarData); // sabre will handle the scheduling behind the scenes
300
-		} catch (CalendarException $e) {
301
-			$this->logger->error('Could not update calendar for iMIP processing', ['exception' => $e]);
302
-			return false;
303
-		}
304
-		return true;
305
-	}
306
-
307
-	/**
308
-	 * @since 25.0.0
309
-	 * @throws \OCP\DB\Exception
310
-	 */
311
-	public function handleIMipCancel(string $principalUri, string $sender, ?string $replyTo, string $recipient, string $calendarData): bool {
312
-		$vObject = Reader::read($calendarData);
313
-		/** @var VEvent $vEvent */
314
-		$vEvent = $vObject->{'VEVENT'};
315
-
316
-		// First, we check if the correct method is passed to us
317
-		if (strcasecmp('CANCEL', $vObject->{'METHOD'}->getValue()) !== 0) {
318
-			$this->logger->warning('Wrong method provided for processing');
319
-			return false;
320
-		}
321
-
322
-		$attendee = substr($vEvent->{'ATTENDEE'}->getValue(), 7);
323
-		if (strcasecmp($recipient, $attendee) !== 0) {
324
-			$this->logger->warning('Recipient must be an ATTENDEE of this event');
325
-			return false;
326
-		}
327
-
328
-		// Thirdly, we need to compare the email address the CANCEL is coming from (in Mail)
329
-		// or the Reply- To Address submitted with the CANCEL email
330
-		// to the email address in the ORGANIZER.
331
-		// We don't want to accept a CANCEL request from just anyone
332
-		$organizer = substr($vEvent->{'ORGANIZER'}->getValue(), 7);
333
-		$isNotOrganizer = ($replyTo !== null) ? (strcasecmp($sender, $organizer) !== 0 && strcasecmp($replyTo, $organizer) !== 0) : (strcasecmp($sender, $organizer) !== 0);
334
-		if ($isNotOrganizer) {
335
-			$this->logger->warning('Sender must be the ORGANIZER of this event');
336
-			return false;
337
-		}
338
-
339
-		//check if the event is in the future
340
-		/** @var DateTime $eventTime */
341
-		$eventTime = $vEvent->{'DTSTART'};
342
-		if ($eventTime->getDateTime()->getTimeStamp() < $this->timeFactory->getTime()) { // this might cause issues with recurrences
343
-			$this->logger->warning('Only events in the future are processed');
344
-			return false;
345
-		}
346
-
347
-		// Check if we have a calendar to work with
348
-		$calendars = $this->getCalendarsForPrincipal($principalUri);
349
-		if (empty($calendars)) {
350
-			$this->logger->warning('Could not find any calendars for principal ' . $principalUri);
351
-			return false;
352
-		}
353
-
354
-		$found = null;
355
-		// if the attendee has been found in at least one calendar event with the UID of the iMIP event
356
-		// we process it.
357
-		// Benefit: no attendee lost
358
-		// Drawback: attendees that have been deleted will still be able to update their partstat
359
-		foreach ($calendars as $calendar) {
360
-			// We should not search in writable calendars
361
-			if ($calendar instanceof ICreateFromString) {
362
-				$o = $calendar->search($recipient, ['ATTENDEE'], ['uid' => $vEvent->{'UID'}->getValue()]);
363
-				if (!empty($o)) {
364
-					$found = $calendar;
365
-					$name = $o[0]['uri'];
366
-					break;
367
-				}
368
-			}
369
-		}
370
-
371
-		if (empty($found)) {
372
-			$this->logger->info('Event not found in any calendar for principal ' . $principalUri . 'and UID' . $vEvent->{'UID'}->getValue());
373
-			// this is a safe operation
374
-			// we can ignore events that have been cancelled but were not in the calendar anyway
375
-			return true;
376
-		}
377
-
378
-		try {
379
-			$found->handleIMipMessage($name, $calendarData); // sabre will handle the scheduling behind the scenes
380
-			return true;
381
-		} catch (CalendarException $e) {
382
-			$this->logger->error('Could not update calendar for iMIP processing', ['exception' => $e]);
383
-			return false;
384
-		}
385
-	}
49
+    /**
50
+     * @var ICalendar[] holds all registered calendars
51
+     */
52
+    private $calendars = [];
53
+
54
+    /**
55
+     * @var \Closure[] to call to load/register calendar providers
56
+     */
57
+    private $calendarLoaders = [];
58
+
59
+    /** @var Coordinator */
60
+    private $coordinator;
61
+
62
+    /** @var ContainerInterface */
63
+    private $container;
64
+
65
+    /** @var LoggerInterface */
66
+    private $logger;
67
+
68
+    private ITimeFactory $timeFactory;
69
+
70
+
71
+    public function __construct(Coordinator $coordinator,
72
+                                ContainerInterface $container,
73
+                                LoggerInterface $logger,
74
+                                ITimeFactory $timeFactory) {
75
+        $this->coordinator = $coordinator;
76
+        $this->container = $container;
77
+        $this->logger = $logger;
78
+        $this->timeFactory = $timeFactory;
79
+    }
80
+
81
+    /**
82
+     * This function is used to search and find objects within the user's calendars.
83
+     * In case $pattern is empty all events/journals/todos will be returned.
84
+     *
85
+     * @param string $pattern which should match within the $searchProperties
86
+     * @param array $searchProperties defines the properties within the query pattern should match
87
+     * @param array $options - optional parameters:
88
+     * 	['timerange' => ['start' => new DateTime(...), 'end' => new DateTime(...)]]
89
+     * @param integer|null $limit - limit number of search results
90
+     * @param integer|null $offset - offset for paging of search results
91
+     * @return array an array of events/journals/todos which are arrays of arrays of key-value-pairs
92
+     * @since 13.0.0
93
+     */
94
+    public function search($pattern, array $searchProperties = [], array $options = [], $limit = null, $offset = null) {
95
+        $this->loadCalendars();
96
+        $result = [];
97
+        foreach ($this->calendars as $calendar) {
98
+            $r = $calendar->search($pattern, $searchProperties, $options, $limit, $offset);
99
+            foreach ($r as $o) {
100
+                $o['calendar-key'] = $calendar->getKey();
101
+                $result[] = $o;
102
+            }
103
+        }
104
+
105
+        return $result;
106
+    }
107
+
108
+    /**
109
+     * Check if calendars are available
110
+     *
111
+     * @return bool true if enabled, false if not
112
+     * @since 13.0.0
113
+     */
114
+    public function isEnabled() {
115
+        return !empty($this->calendars) || !empty($this->calendarLoaders);
116
+    }
117
+
118
+    /**
119
+     * Registers a calendar
120
+     *
121
+     * @param ICalendar $calendar
122
+     * @return void
123
+     * @since 13.0.0
124
+     */
125
+    public function registerCalendar(ICalendar $calendar) {
126
+        $this->calendars[$calendar->getKey()] = $calendar;
127
+    }
128
+
129
+    /**
130
+     * Unregisters a calendar
131
+     *
132
+     * @param ICalendar $calendar
133
+     * @return void
134
+     * @since 13.0.0
135
+     */
136
+    public function unregisterCalendar(ICalendar $calendar) {
137
+        unset($this->calendars[$calendar->getKey()]);
138
+    }
139
+
140
+    /**
141
+     * In order to improve lazy loading a closure can be registered which will be called in case
142
+     * calendars are actually requested
143
+     *
144
+     * @param \Closure $callable
145
+     * @return void
146
+     * @since 13.0.0
147
+     */
148
+    public function register(\Closure $callable) {
149
+        $this->calendarLoaders[] = $callable;
150
+    }
151
+
152
+    /**
153
+     * @return ICalendar[]
154
+     * @since 13.0.0
155
+     */
156
+    public function getCalendars() {
157
+        $this->loadCalendars();
158
+
159
+        return array_values($this->calendars);
160
+    }
161
+
162
+    /**
163
+     * removes all registered calendar instances
164
+     * @return void
165
+     * @since 13.0.0
166
+     */
167
+    public function clear() {
168
+        $this->calendars = [];
169
+        $this->calendarLoaders = [];
170
+    }
171
+
172
+    /**
173
+     * loads all calendars
174
+     */
175
+    private function loadCalendars() {
176
+        foreach ($this->calendarLoaders as $callable) {
177
+            $callable($this);
178
+        }
179
+        $this->calendarLoaders = [];
180
+    }
181
+
182
+    /**
183
+     * @param string $principalUri
184
+     * @param array $calendarUris
185
+     * @return ICreateFromString[]
186
+     */
187
+    public function getCalendarsForPrincipal(string $principalUri, array $calendarUris = []): array {
188
+        $context = $this->coordinator->getRegistrationContext();
189
+        if ($context === null) {
190
+            return [];
191
+        }
192
+
193
+        return array_merge(
194
+            ...array_map(function ($registration) use ($principalUri, $calendarUris) {
195
+                try {
196
+                    /** @var ICalendarProvider $provider */
197
+                    $provider = $this->container->get($registration->getService());
198
+                } catch (Throwable $e) {
199
+                    $this->logger->error('Could not load calendar provider ' . $registration->getService() . ': ' . $e->getMessage(), [
200
+                        'exception' => $e,
201
+                    ]);
202
+                    return [];
203
+                }
204
+
205
+                return $provider->getCalendars($principalUri, $calendarUris);
206
+            }, $context->getCalendarProviders())
207
+        );
208
+    }
209
+
210
+    public function searchForPrincipal(ICalendarQuery $query): array {
211
+        /** @var CalendarQuery $query */
212
+        $calendars = $this->getCalendarsForPrincipal(
213
+            $query->getPrincipalUri(),
214
+            $query->getCalendarUris(),
215
+        );
216
+
217
+        $results = [];
218
+        foreach ($calendars as $calendar) {
219
+            $r = $calendar->search(
220
+                $query->getSearchPattern() ?? '',
221
+                $query->getSearchProperties(),
222
+                $query->getOptions(),
223
+                $query->getLimit(),
224
+                $query->getOffset()
225
+            );
226
+
227
+            foreach ($r as $o) {
228
+                $o['calendar-key'] = $calendar->getKey();
229
+                $results[] = $o;
230
+            }
231
+        }
232
+        return $results;
233
+    }
234
+
235
+    public function newQuery(string $principalUri): ICalendarQuery {
236
+        return new CalendarQuery($principalUri);
237
+    }
238
+
239
+    /**
240
+     * @throws \OCP\DB\Exception
241
+     */
242
+    public function handleIMipReply(string $principalUri, string $sender, string $recipient, string $calendarData): bool {
243
+        /** @var VCalendar $vObject */
244
+        $vObject = Reader::read($calendarData);
245
+        /** @var VEvent $vEvent */
246
+        $vEvent = $vObject->{'VEVENT'};
247
+
248
+        // First, we check if the correct method is passed to us
249
+        if (strcasecmp('REPLY', $vObject->{'METHOD'}->getValue()) !== 0) {
250
+            $this->logger->warning('Wrong method provided for processing');
251
+            return false;
252
+        }
253
+
254
+        // check if mail recipient and organizer are one and the same
255
+        $organizer = substr($vEvent->{'ORGANIZER'}->getValue(), 7);
256
+
257
+        if (strcasecmp($recipient, $organizer) !== 0) {
258
+            $this->logger->warning('Recipient and ORGANIZER must be identical');
259
+            return false;
260
+        }
261
+
262
+        //check if the event is in the future
263
+        /** @var DateTime $eventTime */
264
+        $eventTime = $vEvent->{'DTSTART'};
265
+        if ($eventTime->getDateTime()->getTimeStamp() < $this->timeFactory->getTime()) { // this might cause issues with recurrences
266
+            $this->logger->warning('Only events in the future are processed');
267
+            return false;
268
+        }
269
+
270
+        $calendars = $this->getCalendarsForPrincipal($principalUri);
271
+        if (empty($calendars)) {
272
+            $this->logger->warning('Could not find any calendars for principal ' . $principalUri);
273
+            return false;
274
+        }
275
+
276
+        $found = null;
277
+        // if the attendee has been found in at least one calendar event with the UID of the iMIP event
278
+        // we process it.
279
+        // Benefit: no attendee lost
280
+        // Drawback: attendees that have been deleted will still be able to update their partstat
281
+        foreach ($calendars as $calendar) {
282
+            // We should not search in writable calendars
283
+            if ($calendar instanceof ICreateFromString) {
284
+                $o = $calendar->search($sender, ['ATTENDEE'], ['uid' => $vEvent->{'UID'}->getValue()]);
285
+                if (!empty($o)) {
286
+                    $found = $calendar;
287
+                    $name = $o[0]['uri'];
288
+                    break;
289
+                }
290
+            }
291
+        }
292
+
293
+        if (empty($found)) {
294
+            $this->logger->info('Event not found in any calendar for principal ' . $principalUri . 'and UID' . $vEvent->{'UID'}->getValue());
295
+            return false;
296
+        }
297
+
298
+        try {
299
+            $found->handleIMipMessage($name, $calendarData); // sabre will handle the scheduling behind the scenes
300
+        } catch (CalendarException $e) {
301
+            $this->logger->error('Could not update calendar for iMIP processing', ['exception' => $e]);
302
+            return false;
303
+        }
304
+        return true;
305
+    }
306
+
307
+    /**
308
+     * @since 25.0.0
309
+     * @throws \OCP\DB\Exception
310
+     */
311
+    public function handleIMipCancel(string $principalUri, string $sender, ?string $replyTo, string $recipient, string $calendarData): bool {
312
+        $vObject = Reader::read($calendarData);
313
+        /** @var VEvent $vEvent */
314
+        $vEvent = $vObject->{'VEVENT'};
315
+
316
+        // First, we check if the correct method is passed to us
317
+        if (strcasecmp('CANCEL', $vObject->{'METHOD'}->getValue()) !== 0) {
318
+            $this->logger->warning('Wrong method provided for processing');
319
+            return false;
320
+        }
321
+
322
+        $attendee = substr($vEvent->{'ATTENDEE'}->getValue(), 7);
323
+        if (strcasecmp($recipient, $attendee) !== 0) {
324
+            $this->logger->warning('Recipient must be an ATTENDEE of this event');
325
+            return false;
326
+        }
327
+
328
+        // Thirdly, we need to compare the email address the CANCEL is coming from (in Mail)
329
+        // or the Reply- To Address submitted with the CANCEL email
330
+        // to the email address in the ORGANIZER.
331
+        // We don't want to accept a CANCEL request from just anyone
332
+        $organizer = substr($vEvent->{'ORGANIZER'}->getValue(), 7);
333
+        $isNotOrganizer = ($replyTo !== null) ? (strcasecmp($sender, $organizer) !== 0 && strcasecmp($replyTo, $organizer) !== 0) : (strcasecmp($sender, $organizer) !== 0);
334
+        if ($isNotOrganizer) {
335
+            $this->logger->warning('Sender must be the ORGANIZER of this event');
336
+            return false;
337
+        }
338
+
339
+        //check if the event is in the future
340
+        /** @var DateTime $eventTime */
341
+        $eventTime = $vEvent->{'DTSTART'};
342
+        if ($eventTime->getDateTime()->getTimeStamp() < $this->timeFactory->getTime()) { // this might cause issues with recurrences
343
+            $this->logger->warning('Only events in the future are processed');
344
+            return false;
345
+        }
346
+
347
+        // Check if we have a calendar to work with
348
+        $calendars = $this->getCalendarsForPrincipal($principalUri);
349
+        if (empty($calendars)) {
350
+            $this->logger->warning('Could not find any calendars for principal ' . $principalUri);
351
+            return false;
352
+        }
353
+
354
+        $found = null;
355
+        // if the attendee has been found in at least one calendar event with the UID of the iMIP event
356
+        // we process it.
357
+        // Benefit: no attendee lost
358
+        // Drawback: attendees that have been deleted will still be able to update their partstat
359
+        foreach ($calendars as $calendar) {
360
+            // We should not search in writable calendars
361
+            if ($calendar instanceof ICreateFromString) {
362
+                $o = $calendar->search($recipient, ['ATTENDEE'], ['uid' => $vEvent->{'UID'}->getValue()]);
363
+                if (!empty($o)) {
364
+                    $found = $calendar;
365
+                    $name = $o[0]['uri'];
366
+                    break;
367
+                }
368
+            }
369
+        }
370
+
371
+        if (empty($found)) {
372
+            $this->logger->info('Event not found in any calendar for principal ' . $principalUri . 'and UID' . $vEvent->{'UID'}->getValue());
373
+            // this is a safe operation
374
+            // we can ignore events that have been cancelled but were not in the calendar anyway
375
+            return true;
376
+        }
377
+
378
+        try {
379
+            $found->handleIMipMessage($name, $calendarData); // sabre will handle the scheduling behind the scenes
380
+            return true;
381
+        } catch (CalendarException $e) {
382
+            $this->logger->error('Could not update calendar for iMIP processing', ['exception' => $e]);
383
+            return false;
384
+        }
385
+    }
386 386
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -191,12 +191,12 @@  discard block
 block discarded – undo
191 191
 		}
192 192
 
193 193
 		return array_merge(
194
-			...array_map(function ($registration) use ($principalUri, $calendarUris) {
194
+			...array_map(function($registration) use ($principalUri, $calendarUris) {
195 195
 				try {
196 196
 					/** @var ICalendarProvider $provider */
197 197
 					$provider = $this->container->get($registration->getService());
198 198
 				} catch (Throwable $e) {
199
-					$this->logger->error('Could not load calendar provider ' . $registration->getService() . ': ' . $e->getMessage(), [
199
+					$this->logger->error('Could not load calendar provider '.$registration->getService().': '.$e->getMessage(), [
200 200
 						'exception' => $e,
201 201
 					]);
202 202
 					return [];
@@ -269,7 +269,7 @@  discard block
 block discarded – undo
269 269
 
270 270
 		$calendars = $this->getCalendarsForPrincipal($principalUri);
271 271
 		if (empty($calendars)) {
272
-			$this->logger->warning('Could not find any calendars for principal ' . $principalUri);
272
+			$this->logger->warning('Could not find any calendars for principal '.$principalUri);
273 273
 			return false;
274 274
 		}
275 275
 
@@ -291,7 +291,7 @@  discard block
 block discarded – undo
291 291
 		}
292 292
 
293 293
 		if (empty($found)) {
294
-			$this->logger->info('Event not found in any calendar for principal ' . $principalUri . 'and UID' . $vEvent->{'UID'}->getValue());
294
+			$this->logger->info('Event not found in any calendar for principal '.$principalUri.'and UID'.$vEvent->{'UID'}->getValue());
295 295
 			return false;
296 296
 		}
297 297
 
@@ -347,7 +347,7 @@  discard block
 block discarded – undo
347 347
 		// Check if we have a calendar to work with
348 348
 		$calendars = $this->getCalendarsForPrincipal($principalUri);
349 349
 		if (empty($calendars)) {
350
-			$this->logger->warning('Could not find any calendars for principal ' . $principalUri);
350
+			$this->logger->warning('Could not find any calendars for principal '.$principalUri);
351 351
 			return false;
352 352
 		}
353 353
 
@@ -369,7 +369,7 @@  discard block
 block discarded – undo
369 369
 		}
370 370
 
371 371
 		if (empty($found)) {
372
-			$this->logger->info('Event not found in any calendar for principal ' . $principalUri . 'and UID' . $vEvent->{'UID'}->getValue());
372
+			$this->logger->info('Event not found in any calendar for principal '.$principalUri.'and UID'.$vEvent->{'UID'}->getValue());
373 373
 			// this is a safe operation
374 374
 			// we can ignore events that have been cancelled but were not in the calendar anyway
375 375
 			return true;
Please login to merge, or discard this patch.