blob: d9f2bb68b9e66a069acf53f9a9bb983387b20d85 [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001<?php
2
3declare(strict_types=1);
4
5namespace Ddeboer\Imap;
6
7use Ddeboer\Imap\Exception\CreateMailboxException;
8use Ddeboer\Imap\Exception\DeleteMailboxException;
9use Ddeboer\Imap\Exception\ImapGetmailboxesException;
10use Ddeboer\Imap\Exception\ImapNumMsgException;
11use Ddeboer\Imap\Exception\ImapQuotaException;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010012use Ddeboer\Imap\Exception\MailboxDoesNotExistException;
13
14/**
15 * A connection to an IMAP server that is authenticated for a user.
16 */
17final class Connection implements ConnectionInterface
18{
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020019 private ImapResourceInterface $resource;
20 private string $server;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010021 /**
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020022 * @var null|MailboxInterface[]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010023 */
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020024 private ?array $mailboxes = null;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010025 /**
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020026 * @var null|array<int|string, \stdClass>
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010027 */
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020028 private ?array $mailboxNames = null;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010029
30 /**
31 * Constructor.
32 *
33 * @throws \InvalidArgumentException
34 */
35 public function __construct(ImapResourceInterface $resource, string $server)
36 {
37 $this->resource = $resource;
38 $this->server = $server;
39 }
40
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010041 public function getResource(): ImapResourceInterface
42 {
43 return $this->resource;
44 }
45
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010046 public function expunge(): bool
47 {
48 return \imap_expunge($this->resource->getStream());
49 }
50
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010051 public function close(int $flag = 0): bool
52 {
53 $this->resource->clearLastMailboxUsedCache();
54
55 return \imap_close($this->resource->getStream(), $flag);
56 }
57
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010058 public function getQuota(string $root = 'INBOX'): array
59 {
60 $errorMessage = null;
61 $errorNumber = 0;
62 \set_error_handler(static function ($nr, $message) use (&$errorMessage, &$errorNumber): bool {
63 $errorMessage = $message;
64 $errorNumber = $nr;
65
66 return true;
67 });
68
69 $return = \imap_get_quotaroot($this->resource->getStream(), $root);
70
71 \restore_error_handler();
72
73 if (false === $return || null !== $errorMessage) {
74 throw new ImapQuotaException(
75 \sprintf(
76 'IMAP Quota request failed for "%s"%s',
77 $root,
78 null !== $errorMessage ? ': ' . $errorMessage : ''
79 ),
80 $errorNumber
81 );
82 }
83
84 return $return;
85 }
86
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010087 public function getMailboxes(): array
88 {
89 $this->initMailboxNames();
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020090 \assert(null !== $this->mailboxNames);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010091
92 if (null === $this->mailboxes) {
93 $this->mailboxes = [];
94 foreach ($this->mailboxNames as $mailboxName => $mailboxInfo) {
95 $this->mailboxes[(string) $mailboxName] = $this->getMailbox((string) $mailboxName);
96 }
97 }
98
99 return $this->mailboxes;
100 }
101
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100102 public function hasMailbox(string $name): bool
103 {
104 $this->initMailboxNames();
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200105 \assert(null !== $this->mailboxNames);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100106
107 return isset($this->mailboxNames[$name]);
108 }
109
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100110 public function getMailbox(string $name): MailboxInterface
111 {
112 if (false === $this->hasMailbox($name)) {
113 throw new MailboxDoesNotExistException(\sprintf('Mailbox name "%s" does not exist', $name));
114 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200115 \assert(isset($this->mailboxNames[$name]));
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100116
117 return new Mailbox($this->resource, $name, $this->mailboxNames[$name]);
118 }
119
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100120 public function count()
121 {
122 $return = \imap_num_msg($this->resource->getStream());
123
124 if (false === $return) {
125 throw new ImapNumMsgException('imap_num_msg failed');
126 }
127
128 return $return;
129 }
130
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100131 public function ping(): bool
132 {
133 return \imap_ping($this->resource->getStream());
134 }
135
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100136 public function createMailbox(string $name): MailboxInterface
137 {
138 if (false === \imap_createmailbox($this->resource->getStream(), $this->server . \mb_convert_encoding($name, 'UTF7-IMAP', 'UTF-8'))) {
139 throw new CreateMailboxException(\sprintf('Can not create "%s" mailbox at "%s"', $name, $this->server));
140 }
141
142 $this->mailboxNames = $this->mailboxes = null;
143 $this->resource->clearLastMailboxUsedCache();
144
145 return $this->getMailbox($name);
146 }
147
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100148 public function deleteMailbox(MailboxInterface $mailbox): void
149 {
150 if (false === \imap_deletemailbox($this->resource->getStream(), $mailbox->getFullEncodedName())) {
151 throw new DeleteMailboxException(\sprintf('Mailbox "%s" could not be deleted', $mailbox->getName()));
152 }
153
154 $this->mailboxes = $this->mailboxNames = null;
155 $this->resource->clearLastMailboxUsedCache();
156 }
157
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100158 private function initMailboxNames(): void
159 {
160 if (null !== $this->mailboxNames) {
161 return;
162 }
163
164 $this->mailboxNames = [];
165 $mailboxesInfo = \imap_getmailboxes($this->resource->getStream(), $this->server, '*');
166 if (!\is_array($mailboxesInfo)) {
167 throw new ImapGetmailboxesException('imap_getmailboxes failed');
168 }
169
170 foreach ($mailboxesInfo as $mailboxInfo) {
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200171 $name = \mb_convert_encoding(\str_replace($this->server, '', $mailboxInfo->name), 'UTF-8', 'UTF7-IMAP');
Matthias Andreas Benkarde39c4f82021-01-06 17:59:39 +0100172 \assert(\is_string($name));
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200173
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100174 $this->mailboxNames[$name] = $mailboxInfo;
175 }
176 }
177}