Manager.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OC\Mail\Provider;
  8. use OC\AppFramework\Bootstrap\Coordinator;
  9. use OCP\Mail\Provider\IManager;
  10. use OCP\Mail\Provider\IProvider;
  11. use OCP\Mail\Provider\IService;
  12. use Psr\Container\ContainerInterface;
  13. use Psr\Log\LoggerInterface;
  14. use Throwable;
  15. class Manager implements IManager {
  16. protected ?array $providersCollection = null;
  17. public function __construct(
  18. private Coordinator $coordinator,
  19. private ContainerInterface $container,
  20. private LoggerInterface $logger,
  21. ) {
  22. }
  23. /**
  24. * Determine if any mail providers are registered
  25. *
  26. * @since 30.0.0
  27. *
  28. * @return bool
  29. */
  30. public function has(): bool {
  31. // return true if collection has any providers
  32. return !empty($this->providers());
  33. }
  34. /**
  35. * Retrieve a count of how many mail providers are registered
  36. *
  37. * @since 30.0.0
  38. *
  39. * @return int
  40. */
  41. public function count(): int {
  42. // return count of providers in collection
  43. return count($this->providers());
  44. }
  45. /**
  46. * Retrieve which mail providers are registered
  47. *
  48. * @since 30.0.0
  49. *
  50. * @return array<string,string> collection of provider id and label ['jmap' => 'JMap Connector']
  51. */
  52. public function types(): array {
  53. // construct types collection
  54. $types = [];
  55. // extract id and name from providers collection
  56. foreach ($this->providers() as $entry) {
  57. $types[$entry->id()] = $entry->label();
  58. }
  59. // return types collection
  60. return $types;
  61. }
  62. /**
  63. * Retrieve all registered mail providers
  64. *
  65. * @since 30.0.0
  66. *
  67. * @return array<string,IProvider> collection of provider id and object ['jmap' => IProviderObject]
  68. */
  69. public function providers(): array {
  70. // evaluate if we already have a cached collection of providers and return the collection if we do
  71. if (is_array($this->providersCollection)) {
  72. return $this->providersCollection;
  73. }
  74. // retrieve server registration context
  75. $context = $this->coordinator->getRegistrationContext();
  76. // evaluate if registration context was returned
  77. if ($context === null) {
  78. return [];
  79. }
  80. // initilize cached collection
  81. $this->providersCollection = [];
  82. // iterate through all registered mail providers
  83. foreach ($context->getMailProviders() as $entry) {
  84. try {
  85. /** @var IProvider $provider */
  86. // object provider
  87. $provider = $this->container->get($entry->getService());
  88. // add provider to cache collection
  89. $this->providersCollection[$provider->id()] = $provider;
  90. } catch (Throwable $e) {
  91. $this->logger->error(
  92. 'Could not load mail provider ' . $entry->getService() . ': ' . $e->getMessage(),
  93. ['exception' => $e]
  94. );
  95. }
  96. }
  97. // return mail provider collection
  98. return $this->providersCollection;
  99. }
  100. /**
  101. * Retrieve a provider with a specific id
  102. *
  103. * @since 30.0.0
  104. *
  105. * @param string $providerId provider id
  106. *
  107. * @return IProvider|null
  108. */
  109. public function findProviderById(string $providerId): ?IProvider {
  110. // evaluate if we already have a cached collection of providers
  111. if (!is_array($this->providersCollection)) {
  112. $this->providers();
  113. }
  114. if (isset($this->providersCollection[$providerId])) {
  115. return $this->providersCollection[$providerId];
  116. }
  117. // return null if provider was not found
  118. return null;
  119. }
  120. /**
  121. * Retrieve all services for all registered mail providers
  122. *
  123. * @since 30.0.0
  124. *
  125. * @param string $userId user id
  126. *
  127. * @return array<string,array<string,IService>> collection of provider id, service id and object ['jmap' => ['Service1' => IServiceObject]]
  128. */
  129. public function services(string $userId): array {
  130. // initilize collection
  131. $services = [];
  132. // retrieve and iterate through mail providers
  133. foreach ($this->providers() as $entry) {
  134. // retrieve collection of services
  135. $mailServices = $entry->listServices($userId);
  136. // evaluate if mail services collection is not empty and add results to services collection
  137. if (!empty($mailServices)) {
  138. $services[$entry->id()] = $mailServices;
  139. }
  140. }
  141. // return collection
  142. return $services;
  143. }
  144. /**
  145. * Retrieve a service with a specific id
  146. *
  147. * @since 30.0.0
  148. *
  149. * @param string $userId user id
  150. * @param string $serviceId service id
  151. * @param string $providerId provider id
  152. *
  153. * @return IService|null returns service object or null if none found
  154. */
  155. public function findServiceById(string $userId, string $serviceId, ?string $providerId = null): ?IService {
  156. // evaluate if provider id was specified
  157. if ($providerId !== null) {
  158. // find provider
  159. $provider = $this->findProviderById($providerId);
  160. // evaluate if provider was found
  161. if ($provider instanceof IProvider) {
  162. // find service with specific id
  163. $service = $provider->findServiceById($userId, $serviceId);
  164. // evaluate if mail service was found
  165. if ($service instanceof IService) {
  166. return $service;
  167. }
  168. }
  169. } else {
  170. // retrieve and iterate through mail providers
  171. foreach ($this->providers() as $provider) {
  172. // find service with specific id
  173. $service = $provider->findServiceById($userId, $serviceId);
  174. // evaluate if mail service was found
  175. if ($service instanceof IService) {
  176. return $service;
  177. }
  178. }
  179. }
  180. // return null if no match was found
  181. return null;
  182. }
  183. /**
  184. * Retrieve a service for a specific mail address
  185. * returns first service with specific primary address
  186. *
  187. * @since 30.0.0
  188. *
  189. * @param string $userId user id
  190. * @param string $address mail address (e.g. test@example.com)
  191. * @param string $providerId provider id
  192. *
  193. * @return IService|null returns service object or null if none found
  194. */
  195. public function findServiceByAddress(string $userId, string $address, ?string $providerId = null): ?IService {
  196. // evaluate if provider id was specified
  197. if ($providerId !== null) {
  198. // find provider
  199. $provider = $this->findProviderById($providerId);
  200. // evaluate if provider was found
  201. if ($provider instanceof IProvider) {
  202. // find service with specific mail address
  203. $service = $provider->findServiceByAddress($userId, $address);
  204. // evaluate if mail service was found
  205. if ($service instanceof IService) {
  206. return $service;
  207. }
  208. }
  209. } else {
  210. // retrieve and iterate through mail providers
  211. foreach ($this->providers() as $provider) {
  212. // find service with specific mail address
  213. $service = $provider->findServiceByAddress($userId, $address);
  214. // evaluate if mail service was found
  215. if ($service instanceof IService) {
  216. return $service;
  217. }
  218. }
  219. }
  220. // return null if no match was found
  221. return null;
  222. }
  223. }