Page MenuHomePhorge

D5586.1775227352.diff
No OneTemporary

Authored By
Unknown
Size
6 KB
Referenced Files
None
Subscribers
None

D5586.1775227352.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,73 @@
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;
+ }
+
+ public static function subscribeMailbox($user, $mailbox): bool
+ {
+ $config = self::getConfig();
+ $imap = self::initIMAP($config, $user);
+ return $imap->subscribe($mailbox);
+ }
+
+ /**
+ * 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 +548,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/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
@@ -477,6 +477,33 @@
$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'), []);
+ $this->user2 = $user2 = $this->getTestUser("test2-{$ts}@" . \config('app.domain'), []);
+
+ $imap = $this->getImap($user->email);
+ $imap->createFolder("copytest1");
+
+ # TODO add messages
+
+ $result = IMAP::copyMailbox(
+ IMAP::userMailbox($user->email, "copytest1"),
+ IMAP::userMailbox($user2->email, "copytest2")
+ );
+
+ $result = IMAP::listMailboxes($user2->email);
+ $this->assertTrue(in_array(IMAP::userMailbox($user2->email, "copytest2"), $result));
+
+ # TODO verify messages
+ }
+
/**
* Get configured/initialized rcube_imap_generic instance
*/

File Metadata

Mime Type
text/plain
Expires
Fri, Apr 3, 2:42 PM (16 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18824338
Default Alt Text
D5586.1775227352.diff (6 KB)

Event Timeline