setMessages($messages) ->setRepository($repository) ->setRemoteService($remoteService) ->setDecrypt($decrypt) ->setFolder($attachments_folder) ->setLogger($logger); } protected Messages $messages; protected Attachment $repository; protected Remote\Attachments $remoteService; protected Decrypt $decrypt; protected string $folder; public function getMessages(): Messages { return $this->messages; } public function getRepository(): Attachment { return $this->repository; } public function getRemoteService(): Remote\Attachments { return $this->remoteService; } public function getDecrypt(): Decrypt { return $this->decrypt; } public function getFolder(): string { return $this->folder; } public function setMessages(Messages $messages): Attachments { $this->messages = $messages; return $this; } public function setRepository(Attachment $repository): Attachments { $this->repository = $repository; return $this; } public function setRemoteService(Remote\Attachments $service): Attachments { $this->remoteService = $service; return $this; } public function setDecrypt(Decrypt $decrypt): Attachments { $this->decrypt = $decrypt; return $this; } public function setFolder(string $folder): Attachments { $this->folder = $folder; return $this; } public function getLocalAttachment(Message $message, string $relative_filename): \ProVM\Emails\Model\Attachment { return $this->getRepository()->fetchByMessageAndFilename($message->getId(), $relative_filename); } public function getRemoteAttachment(Message $message, string $relative_filename): AttachmentInterface { $remote_message = $this->getMessages()->getRemoteMessage($message->getUID()); return $this->getRemoteService()->get($remote_message, $relative_filename); } public function getFile(int $attachment_id): string { $attachment = $this->getRepository()->fetchById($attachment_id); $filename = implode(DIRECTORY_SEPARATOR, [ $this->getFolder(), $attachment->getFullFilename() ]); if ($attachment->isDecrypted()) { $filename = implode(DIRECTORY_SEPARATOR, [ $this->getFolder(), 'decrypted', $attachment->getFullFilename() ]); } return file_get_contents($filename); } public function getAll(): array { return $this->getRepository()->fetchAll(); } public function getDownloadedFiles(): array { $downloaded = []; $folder = $this->getFolder(); $files = new \FilesystemIterator($folder); foreach ($files as $file) { if ($file->isDir()) { continue; } $name = $file->getBasename(".{$file->getExtension()}"); list($date, $subject, $filename) = explode(' - ', $name); try { $message = $this->getMessages()->find($subject, $date)[0]; $filename = "{$filename}.{$file->getExtension()}"; $downloaded []= compact('message', 'filename'); } catch (BlankResult $e) { } } return $downloaded; } public function create(int $message_id): array { $message = $this->getMessages()->getRepository()->fetchById($message_id); $remote_message = $this->getMessages()->getRemoteMessage($message->getUID()); if (!$remote_message->hasAttachments()) { throw new NoAttachments($remote_message); } $attachments = []; foreach ($remote_message->getAttachments() as $attachment) { if (!$this->getMessages()->validateAttachment($attachment)) { continue; } if ($this->save($message, $attachment, false)) { $attachments []= $attachment->getFilename(); } } return $attachments; } public function grab(int $message_id): array { $message = $this->getMessages()->getRepository()->fetchById($message_id); $remote_message = $this->getMessages()->getRemoteMessage($message->getUID()); if (!$remote_message->hasAttachments()) { throw new NoAttachments($remote_message); } $attachments = []; foreach ($remote_message->getAttachments() as $attachment) { if (!$this->getMessages()->validateAttachment($attachment)) { continue; } if ($this->save($message, $attachment)) { $attachments []= $attachment->getFilename(); } } return $attachments; } public function save(Message $message, AttachmentInterface $remote_attachment, bool $upload = true): bool { $data = [ 'message_id' => $message->getId(), 'filename' => $remote_attachment->getFilename() ]; try { $attachment = $this->getRepository()->create($data); $this->getRepository()->save($attachment); if ($upload and $this->upload($attachment, $remote_attachment)) { $attachment->itIsDownloaded(); $message->doesHaveDownloadedAttachments(); $this->getMessages()->getRepository()->save($message); if ($this->isFileEncrypted($attachment->getMessage(), $attachment->getFilename())) { $attachment->itIsEncrypted(); if ($this->isFileDecrypted($attachment->getMessage(), $attachment->getFilename())) { $attachment->itIsDecrypted(); } else { if ($this->decrypt($attachment->getMessage(), $attachment->getFilename())) { $attachment->itIsDecrypted(); } } } } $this->getRepository()->save($attachment); return true; } catch (PDOException $e) { $this->getLogger()->error($e); return false; } } public function upload(\ProVM\Emails\Model\Attachment $attachment, AttachmentInterface $remote_attachment): bool { $destination = implode(DIRECTORY_SEPARATOR, [ $this->getFolder(), $attachment->getFullFilename() ]); try { file_put_contents($destination, $remote_attachment->getDecodedContent()); return true; } catch (FilesystemException $e) { $this->getLogger()->error($e); return false; } } public function isFileEncrypted(Message $message, string $relative_filename): bool { $attachment = $this->getLocalAttachment($message, $relative_filename); $filename = implode(DIRECTORY_SEPARATOR, [ $this->getFolder(), $attachment->getFullFilename() ]); try { return $this->getDecrypt()->isEncrypted($filename); } catch (\InvalidArgumentException $e) { return false; } } public function isFileDecrypted(Message $message, string $relative_filename): bool { $attachment = $this->getLocalAttachment($message, $relative_filename); $filename = implode(DIRECTORY_SEPARATOR, [ $this->getFolder(), 'decrypted', $attachment->getFullFilename() ]); try { return !$this->getDecrypt()->isEncrypted($filename); } catch (\InvalidArgumentException $e) { return false; } } public function decrypt(Message $message, string $relative_filename): bool { $attachment = $this->getLocalAttachment($message, $relative_filename); $source = implode(DIRECTORY_SEPARATOR, [ $this->getFolder(), $attachment->getFullFilename() ]); $destination = implode(DIRECTORY_SEPARATOR, [ $this->getFolder(), 'decrypted', $attachment->getFullFilename() ]); return $this->getDecrypt()->runCommand($source, $destination); } public function isDownloaded(Message $message, MessageInterface $remote_message): bool { if (!$message->hasValidAttachments()) { return false; } if ($message->hasDownloadedAttachments()) { return true; } foreach ($remote_message->getAttachments() as $attachment) { if (!str_contains($attachment->getFilename(), '.pdf')) { continue; } $attachment = $this->getLocalAttachment($message, $attachment->getFilename()); if (!$attachment->isDownloaded()) { return false; } } return true; } public function find(Message $message, string $filename): \ProVM\Emails\Model\Attachment { return $this->getRepository()->fetchByMessageAndFilename($message->getId(), $filename); } public function exists(Message $message, string $filename): bool { try { $this->find($message, $filename); return true; } catch (BlankResult $e) { return false; } } public function add(Message $message, string $filename): bool { $data = [ 'message_id' => $message->getId(), 'filename' => $filename ]; try { $attachment = $this->getRepository()->create($data); $attachment->itIsDownloaded(); $this->getRepository()->save($attachment); $message->doesHaveDownloadedAttachments(); $this->getMessages()->getRepository()->save($message); return true; } catch (PDOException $e) { $this->getLogger()->error($e); return false; } } public function checkDownloaded(): void { $data = $this->getDownloadedFiles(); foreach ($data as $info) { if (!$this->exists($info['message'], $info['filename'])) { $this->logger->info("Updating attachment {$info['filename']} for message {$info['message']->getSubject()}"); $this->add($info['message'], $info['filename']); } } } public function getDownloaded(): array { return $this->getRepository()->fetchDownloaded(); } public function checkEncryption(): void { $attachments = $this->getDownloaded(); foreach ($attachments as $attachment) { if ($attachment->isEncrypted() and !$attachment->isDecrypted()) { $this->logger->notice("Schedule decrypt for {$attachment->getFullFilename()}"); $this->decrypt($attachment->getMessage(), $attachment->getFilename()); } } } }