decodeRemoteUserPrincipal($principal); if ($shareWith === null) { $this->logger->error($baseError . 'Principal of sharee is not belonging to a remote user', [ 'shareable' => $shareable->getName(), 'encodedShareWith' => $principal, ]); return; } [,, $ownerUid] = explode('/', $shareable->getOwner()); $owner = $this->userManager->get($ownerUid); if ($owner === null) { $this->logger->error($baseError . 'Shareable is not owned by a user on this server', [ 'shareable' => $shareable->getName(), 'shareWith' => $shareWith, ]); return; } // Need a calendar instance to extract properties for the protocol $calendar = $shareable; if (!($calendar instanceof Calendar)) { $this->logger->error($baseError . 'Shareable is not a calendar', [ 'shareable' => $shareable->getName(), 'owner' => $owner, 'shareWith' => $shareWith, ]); return; } $getProp = static fn (string $prop) => $calendar->getProperties([$prop])[$prop] ?? null; $displayName = $getProp('{DAV:}displayname') ?? ''; $token = $this->random->generate(32); $share = $this->federationFactory->getCloudFederationShare( $shareWith, $shareable->getName(), $displayName, CalendarFederationProvider::PROVIDER_ID, // Resharing is not possible so the owner is always the sharer $owner->getCloudId(), $owner->getDisplayName(), $owner->getCloudId(), $owner->getDisplayName(), $token, CalendarFederationProvider::USER_SHARE_TYPE, CalendarFederationProvider::CALENDAR_RESOURCE, ); // 2. Send share to federated instance $shareWithEncoded = base64_encode($shareWith); $relativeCalendarUrl = "remote-calendars/$shareWithEncoded/" . $calendar->getName() . '_shared_by_' . $ownerUid; $calendarUrl = $this->url->linkTo('', 'remote.php') . "/dav/$relativeCalendarUrl"; $calendarUrl = $this->url->getAbsoluteURL($calendarUrl); $protocol = new CalendarFederationProtocolV1(); $protocol->setUrl($calendarUrl); $protocol->setDisplayName($displayName); $protocol->setColor($getProp('{http://apple.com/ns/ical/}calendar-color')); $protocol->setAccess($access); $protocol->setComponents(implode(',', $getProp( '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set')?->getValue() ?? [], )); $share->setProtocol([ // Preserve original protocol contents ...$share->getProtocol(), ...$protocol->toProtocol(), ]); try { $response = $this->federationManager->sendCloudShare($share); } catch (OCMProviderException $e) { $this->logger->error($baseError . $e->getMessage(), [ 'exception' => $e, 'owner' => $owner->getUID(), 'calendar' => $shareable->getName(), 'shareWith' => $shareWith, ]); return; } if ($response->getStatusCode() !== Http::STATUS_CREATED) { $this->logger->error($baseError . 'Server replied with code ' . $response->getStatusCode(), [ 'responseBody' => $response->getBody(), 'owner' => $owner->getUID(), 'calendar' => $shareable->getName(), 'shareWith' => $shareWith, ]); return; } // 3. Create a local DAV share to track the token for authentication $shareWithPrincipalUri = RemoteUserPrincipalBackend::PRINCIPAL_PREFIX . '/' . $shareWithEncoded; $this->sharingMapper->deleteShare( $shareable->getResourceId(), 'calendar', $shareWithPrincipalUri, ); $this->sharingMapper->shareWithToken( $shareable->getResourceId(), 'calendar', $access, $shareWithPrincipalUri, $token, ); } }