Page MenuHomePhorge

D5586.1775244168.diff
No OneTemporary

Authored By
Unknown
Size
9 KB
Referenced Files
None
Subscribers
None

D5586.1775244168.diff

diff --git a/src/app/Backends/IMAP.php b/src/app/Backends/IMAP.php
--- a/src/app/Backends/IMAP.php
+++ b/src/app/Backends/IMAP.php
@@ -472,6 +472,106 @@
return true;
}
+ /**
+ * Copy a folder.
+ *
+ * @param string $sourceMailbox Source Mailbox
+ * @param string $targetMailbox Target Mailbox
+ * @param array $metadata Metadata entries to copy
+ *
+ * @return bool True if the mailbox was copied successfully, False otherwise
+ *
+ * @throws \Exception
+ */
+ public static function copyMailbox($sourceMailbox, $targetMailbox, $metadata = []): bool
+ {
+ $config = self::getConfig();
+ $imap = self::initIMAP($config);
+
+ $sourceMailbox = self::toUTF7($sourceMailbox);
+ $targetMailbox = self::toUTF7($targetMailbox);
+
+ if (!empty($targetMailbox) && $targetMailbox != $sourceMailbox) {
+ // We assume the mailbox already exists if this fails
+ $imap->createFolder($targetMailbox);
+
+ if (!empty($metadata)) {
+ if ($meta = $imap->getMetadata($sourceMailbox, $metadata)[$sourceMailbox] ?? null) {
+ if (!$imap->setMetadata($targetMailbox, $meta)) {
+ \Log::error("Failed to set mailbox metadata on {$targetMailbox}");
+ $imap->closeConnection();
+ return false;
+ }
+ }
+ }
+
+ // The cyrus user needs permissions to select the mailbox, and to copy write the messages to the folder.
+ $result = $imap->setACL($sourceMailbox, $config['user'], 'lr');
+ $result = $imap->setACL($targetMailbox, $config['user'], 'lrswi');
+ if (!$imap->copy("1:*", $sourceMailbox, $targetMailbox)) {
+ \Log::error("Failed to copy messages from mailbox {$sourceMailbox} to {$targetMailbox}");
+ $imap->closeConnection();
+ return false;
+ }
+ $result = $imap->deleteACL($sourceMailbox, $config['user']);
+ $result = $imap->deleteACL($targetMailbox, $config['user']);
+ }
+
+ $imap->closeConnection();
+
+ return true;
+ }
+
+ /**
+ * subscribe to the user mailbox
+ *
+ * @param string $user user email address
+ * @param string $mailbox mailbox name
+ *
+ * @return bool True if the mailbox was subscribed successfully, False otherwise
+ *
+ * @throws \Exception
+ */
+ public static function subscribeMailbox($user, $mailbox): bool
+ {
+ $config = self::getConfig();
+ $imap = self::initIMAP($config, $user);
+ $ret = $imap->subscribe($mailbox);
+ $imap->closeConnection();
+
+ return $ret;
+ }
+
+ /**
+ * unsubscribe from the user mailbox
+ *
+ * @param string $user user email address
+ * @param string $mailbox mailbox name
+ *
+ * @return bool True if the mailbox was unsubscribed successfully, False otherwise
+ *
+ * @throws \Exception
+ */
+ public static function unsubscribeMailbox($user, $mailbox): bool
+ {
+ $config = self::getConfig();
+ $imap = self::initIMAP($config, $user);
+ $ret = $imap->unsubscribe($mailbox);
+ $imap->closeConnection();
+
+ return $ret;
+ }
+
+ /**
+ * get the user mailbox name for cyrus-imap
+ *
+ * @param string $user user email address
+ * @param string $mailbox mailbox name
+ *
+ * @return string user mailbox in user/ namespace
+ *
+ * @throws \Exception
+ */
public static function userMailbox(string $user, string $mailbox): string
{
[$localpart, $domain] = explode('@', $user, 2);
@@ -481,6 +581,22 @@
return "user/{$localpart}/{$mailbox}@{$domain}";
}
+ /**
+ * get the folder name from a full mailbox name for cyrus-imap
+ *
+ * @param string $mailbox mailbox name
+ *
+ * @return string folder name
+ */
+ public static function folderName(string $mailbox): string
+ {
+ [$localpart, $domain] = explode('@', $mailbox, 2);
+ $parts = explode('/', $localpart);
+ array_shift($parts);
+ array_shift($parts);
+ return implode('/', $parts);
+ }
+
/**
* List user mailboxes.
*
diff --git a/src/app/Console/Commands/Imap/CopyCommand.php b/src/app/Console/Commands/Imap/CopyCommand.php
new file mode 100644
--- /dev/null
+++ b/src/app/Console/Commands/Imap/CopyCommand.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace App\Console\Commands\Imap;
+
+use App\Console\Command;
+use App\Support\Facades\IMAP;
+
+class CopyCommand extends Command
+{
+ /**
+ * The name and signature of the console command.
+ *
+ * @var string
+ */
+ protected $signature = 'imap:copy {sourceUser} {sourceMailbox} {targetUser} {targetMailbox} {--metadata=*}';
+
+ /**
+ * The console command description.
+ *
+ * @var string
+ */
+ protected $description = "Copy IMAP Folder";
+
+ /**
+ * Execute the console command.
+ *
+ * @return mixed
+ */
+ public function handle()
+ {
+ $sourceUser = $this->argument('sourceUser');
+ $targetUser = $this->argument('targetUser');
+ $sourceMailbox = $this->argument('sourceMailbox');
+ $targetMailbox = $this->argument('targetMailbox');
+
+ if ($sourceMailbox == "*") {
+ $mailboxes = IMAP::listMailboxes($sourceUser);
+ foreach ($mailboxes as $mailbox) {
+ IMAP::copyMailbox(
+ $mailbox,
+ IMAP::userMailbox($targetUser, IMAP::folderName($mailbox)),
+ $this->option('metadata')
+ );
+ }
+ IMAP::copyMailbox(
+ IMAP::userMailbox($sourceUser, "INBOX"),
+ IMAP::userMailbox($targetUser, "INBOX"),
+ $this->option('metadata')
+ );
+ } else {
+ IMAP::copyMailbox(
+ IMAP::userMailbox($sourceUser, $sourceMailbox),
+ IMAP::userMailbox($targetUser, $targetMailbox),
+ $this->option('metadata')
+ );
+ }
+ }
+}
diff --git a/src/app/Console/Commands/Imap/SubscribeCommand.php b/src/app/Console/Commands/Imap/SubscribeCommand.php
new file mode 100644
--- /dev/null
+++ b/src/app/Console/Commands/Imap/SubscribeCommand.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace App\Console\Commands\Imap;
+
+use App\Console\Command;
+use App\Support\Facades\IMAP;
+
+class SubscribeCommand extends Command
+{
+ /**
+ * The name and signature of the console command.
+ *
+ * @var string
+ */
+ protected $signature = 'imap:subscribe {user} {mailbox} {--clear : Clear the subscription state instead}';
+
+ /**
+ * The console command description.
+ *
+ * @var string
+ */
+ protected $description = "Subscribe IMAP Folders";
+
+ /**
+ * Execute the console command.
+ *
+ * @return mixed
+ */
+ public function handle()
+ {
+ $user = $this->argument('user');
+ $mailbox = $this->argument('mailbox');
+ if ($mailbox == "*") {
+ $mailboxes = IMAP::listMailboxes($user);
+ } else {
+ $mailboxes = [$mailbox];
+ }
+ foreach ($mailboxes as $mailbox) {
+ if ($this->option('clear')) {
+ IMAP::unsubscribeMailbox($user, IMAP::folderName($mailbox));
+ } else {
+ IMAP::subscribeMailbox($user, IMAP::folderName($mailbox));
+ }
+ }
+ }
+}
diff --git a/src/tests/Feature/Backends/IMAPTest.php b/src/tests/Feature/Backends/IMAPTest.php
--- a/src/tests/Feature/Backends/IMAPTest.php
+++ b/src/tests/Feature/Backends/IMAPTest.php
@@ -37,7 +37,7 @@
$this->deleteTestUser($this->user->email, true);
}
if ($this->user2) {
- $this->deleteTestUser($this->user2->email);
+ $this->deleteTestUser($this->user2->email, true);
}
if ($this->group) {
$this->deleteTestGroup($this->group->email, true);
@@ -477,6 +477,40 @@
$this->assertFalse(in_array(IMAP::userMailbox("john@kolab.org", "renametest1"), $result));
}
+ /**
+ * Test copyMailbox
+ *
+ * @group imap
+ */
+ public function testCopyMailbox(): void
+ {
+ $ts = str_replace('.', '', (string) microtime(true));
+ $this->user = $user = $this->getTestUser("test-{$ts}@" . \config('app.domain'), [], true);
+ $this->user2 = $user2 = $this->getTestUser("test2-{$ts}@" . \config('app.domain'), [], true);
+
+ $imap = $this->getImap($user->email);
+ $imap->createFolder("copytest1");
+
+ # TODO add messages
+
+ $result = IMAP::copyMailbox(
+ IMAP::userMailbox($user->email, "copytest1"),
+ IMAP::userMailbox($user2->email, "copytest2")
+ );
+
+ $this->assertTrue($result);
+
+ // Target was created
+ $result = IMAP::listMailboxes($user2->email);
+ $this->assertTrue(in_array(IMAP::userMailbox($user2->email, "copytest2"), $result));
+
+ // Source is still ok
+ $result = IMAP::listMailboxes($user->email);
+ $this->assertTrue(in_array(IMAP::userMailbox($user->email, "copytest1"), $result));
+
+ # TODO verify messages
+ }
+
/**
* Get configured/initialized rcube_imap_generic instance
*/
diff --git a/src/tests/TestCaseTrait.php b/src/tests/TestCaseTrait.php
--- a/src/tests/TestCaseTrait.php
+++ b/src/tests/TestCaseTrait.php
@@ -599,6 +599,7 @@
}
if ($createInBackends) {
+ $user->assignSku(Sku::firstOrCreate(['title' => 'mailbox']));
$job = new CreateJob($user->id);
$job->handle();
}

File Metadata

Mime Type
text/plain
Expires
Fri, Apr 3, 7:22 PM (20 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18824599
Default Alt Text
D5586.1775244168.diff (9 KB)

Event Timeline