diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index a013a3df57..fba1881ded 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -184,7 +184,7 @@ jobs:
run: echo "SELECT * FROM mysql.slow_log WHERE sql_text LIKE '%oc_mail%' AND sql_text NOT LIKE '%information_schema%'" | mysql -h 127.0.0.1 -u root -pmy-secret-pw
- name: Print debug logs
if: ${{ always() }}
- run: cat nextcloud/data/horde_*.log
+ run: cat nextcloud/data/mail-*-*-imap.log
- name: Report coverage
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0
if: ${{ always() && matrix.db == 'mysql' }}
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 7d2bcbbbd9..24ce87ff96 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -80,6 +80,7 @@ Learn more about the Nextcloud Ethical AI Rating [in our blog](https://nextcloud
OCA\Mail\Command\CleanUp
OCA\Mail\Command\CreateAccount
OCA\Mail\Command\CreateTagMigrationJobEntry
+ OCA\Mail\Command\DebugAccount
OCA\Mail\Command\DeleteAccount
OCA\Mail\Command\DiagnoseAccount
OCA\Mail\Command\ExportAccount
diff --git a/lib/Account.php b/lib/Account.php
index f234e4886f..e294e75af2 100644
--- a/lib/Account.php
+++ b/lib/Account.php
@@ -61,6 +61,13 @@ public function getUserId() {
return $this->account->getUserId();
}
+ /**
+ * @return int
+ */
+ public function getDebug(): int {
+ return $this->account->getDebug();
+ }
+
/**
* Set the quota percentage
* @param Quota $quota
diff --git a/lib/Command/DebugAccount.php b/lib/Command/DebugAccount.php
new file mode 100644
index 0000000000..25d53bcdf7
--- /dev/null
+++ b/lib/Command/DebugAccount.php
@@ -0,0 +1,78 @@
+setName('mail:account:debug');
+ $this->setDescription('Enable or Disable IMAP/SMTP debugging on a account');
+ $this->addArgument(self::ARGUMENT_ACCOUNT_ID, InputArgument::REQUIRED);
+ $this->addOption(self::OPTION_IMAP_DEFAULT, null, InputOption::VALUE_NONE);
+ $this->addOption(self::OPTION_IMAP_FULL, null, InputOption::VALUE_NONE);
+ $this->addOption(self::OPTION_SMTP_DEFAULT, null, InputOption::VALUE_NONE);
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $accountId = (int)$input->getArgument(self::ARGUMENT_ACCOUNT_ID);
+ $imapDefault = $input->getOption(self::OPTION_IMAP_DEFAULT);
+ $imapFull = $input->getOption(self::OPTION_IMAP_FULL);
+ $smtpDefault = $input->getOption(self::OPTION_SMTP_DEFAULT);
+ $debug = 0;
+ $debugImapDefault = 1 << 0; // 1 (0000 0001)
+ $debugImapFull = 1 << 1; // 2 (0000 0010)
+ $debugSmtpDefault = 1 << 4; // 16 (0001 0000)
+
+ try {
+ $account = $this->accountService->findById($accountId)->getMailAccount();
+ } catch (DoesNotExistException $e) {
+ $output->writeln("Account $accountId does not exist");
+ return 1;
+ }
+
+ if ($imapDefault) {
+ $debug += $debugImapDefault;
+ } elseif ($imapFull) {
+ $debug += $debugImapFull;
+ }
+
+ if ($smtpDefault) {
+ $debug += $debugSmtpDefault;
+ }
+
+ $account->setDebug($debug);
+ $this->accountService->save($account);
+
+ return 0;
+ }
+}
diff --git a/lib/Db/MailAccount.php b/lib/Db/MailAccount.php
index 17099f0123..b99b8000b8 100644
--- a/lib/Db/MailAccount.php
+++ b/lib/Db/MailAccount.php
@@ -101,6 +101,8 @@
* @method void setSearchBody(bool $searchBody)
* @method bool|null getOooFollowsSystem()
* @method void setOooFollowsSystem(bool $oooFollowsSystem)
+ * @method int getDebug()
+ * @method void setDebug(int $debug)
*/
class MailAccount extends Entity {
public const SIGNATURE_MODE_PLAIN = 0;
@@ -183,6 +185,8 @@ class MailAccount extends Entity {
/** @var bool|null */
protected $oooFollowsSystem;
+ protected int $debug = 0;
+
/**
* @param array $params
*/
@@ -240,6 +244,9 @@ public function __construct(array $params = []) {
if (isset($params['outOfOfficeFollowsSystem'])) {
$this->setOutOfOfficeFollowsSystem($params['outOfOfficeFollowsSystem']);
}
+ if (isset($params['debug'])) {
+ $this->setDebug($params['debug']);
+ }
$this->addType('inboundPort', 'integer');
$this->addType('outboundPort', 'integer');
@@ -263,6 +270,7 @@ public function __construct(array $params = []) {
$this->addType('junkMailboxId', 'integer');
$this->addType('searchBody', 'boolean');
$this->addType('oooFollowsSystem', 'boolean');
+ $this->addType('debug', 'integer');
}
public function getOutOfOfficeFollowsSystem(): bool {
@@ -310,6 +318,7 @@ public function toJson() {
'junkMailboxId' => $this->getJunkMailboxId(),
'searchBody' => $this->getSearchBody(),
'outOfOfficeFollowsSystem' => $this->getOutOfOfficeFollowsSystem(),
+ 'debug' => $this->getDebug(),
];
if (!is_null($this->getOutboundHost())) {
diff --git a/lib/IMAP/IMAPClientFactory.php b/lib/IMAP/IMAPClientFactory.php
index 3f6d5d2c45..a3ccefd059 100644
--- a/lib/IMAP/IMAPClientFactory.php
+++ b/lib/IMAP/IMAPClientFactory.php
@@ -40,6 +40,9 @@ class IMAPClientFactory {
private ITimeFactory $timeFactory;
private HordeCacheFactory $hordeCacheFactory;
+ private int $debugDefault = 1 << 0; // 1 (0000 0001)
+ private int $debugFull = 1 << 1; // 2 (0000 0010)
+
public function __construct(ICrypto $crypto,
IConfig $config,
ICacheFactory $cacheFactory,
@@ -117,8 +120,13 @@ public function getClient(Account $account, bool $useCache = true): Horde_Imap_C
'backend' => $this->hordeCacheFactory->newCache($account),
];
}
- if ($this->config->getSystemValue('debug', false)) {
- $params['debug'] = $this->config->getSystemValue('datadirectory') . '/horde_imap.log';
+ $debug = $account->getDebug();
+ if ($debug & $this->debugDefault || $debug & $this->debugFull) {
+ $fn = 'mail-' . $account->getUserId() . '-' . $account->getId() . '-imap.log';
+ $params['debug'] = $this->config->getSystemValue('datadirectory') . '/' . $fn;
+ if ($debug & $this->debugFull) {
+ $params['debug_literal'] = true;
+ }
}
$client = new HordeImapClient($params);
diff --git a/lib/Migration/Version4100Date20241028000000.php b/lib/Migration/Version4100Date20241028000000.php
new file mode 100644
index 0000000000..69eae2dab9
--- /dev/null
+++ b/lib/Migration/Version4100Date20241028000000.php
@@ -0,0 +1,38 @@
+getTable('mail_accounts');
+ if (!$accountsTable->hasColumn('debug')) {
+ $accountsTable->addColumn('debug', Types::SMALLINT, [
+ 'notnull' => false,
+ 'default' => 0,
+ ]);
+ }
+ return $schema;
+ }
+}
diff --git a/lib/SMTP/SmtpClientFactory.php b/lib/SMTP/SmtpClientFactory.php
index 3d63195fba..14c9da3b05 100644
--- a/lib/SMTP/SmtpClientFactory.php
+++ b/lib/SMTP/SmtpClientFactory.php
@@ -28,6 +28,8 @@ class SmtpClientFactory {
/** @var HostNameFactory */
private $hostNameFactory;
+ private int $debugDefault = 1 << 4; // 16 (0001 0000)
+
public function __construct(IConfig $config,
ICrypto $crypto,
HostNameFactory $hostNameFactory) {
@@ -77,8 +79,9 @@ public function create(Account $account): Horde_Mail_Transport {
$decryptedAccessToken,
);
}
- if ($this->config->getSystemValue('debug', false)) {
- $params['debug'] = $this->config->getSystemValue('datadirectory') . '/horde_smtp.log';
+ if ($account->getDebug() & $this->debugDefault) {
+ $fn = 'mail-' . $account->getUserId() . '-' . $account->getId() . '-smtp.log';
+ $params['debug'] = $this->config->getSystemValue('datadirectory') . '/' . $fn;
}
return new Horde_Mail_Transport_Smtphorde($params);
}
diff --git a/tests/Integration/Db/MailAccountTest.php b/tests/Integration/Db/MailAccountTest.php
index d960e46b3a..632d275ed5 100644
--- a/tests/Integration/Db/MailAccountTest.php
+++ b/tests/Integration/Db/MailAccountTest.php
@@ -54,7 +54,7 @@ public function testToAPI() {
'editorMode' => 'html',
'provisioningId' => null,
'order' => 13,
- 'showSubscribedOnly' => null,
+ 'showSubscribedOnly' => false,
'personalNamespace' => null,
'draftsMailboxId' => null,
'sentMailboxId' => null,
@@ -70,6 +70,7 @@ public function testToAPI() {
'snoozeMailboxId' => null,
'searchBody' => false,
'outOfOfficeFollowsSystem' => true,
+ 'debug' => 0,
], $a->toJson());
}
@@ -107,6 +108,7 @@ public function testMailAccountConstruct() {
'snoozeMailboxId' => null,
'searchBody' => false,
'outOfOfficeFollowsSystem' => false,
+ 'debug' => 0,
];
$a = new MailAccount($expected);
// TODO: fix inconsistency
diff --git a/tests/Integration/Framework/ImapTestAccount.php b/tests/Integration/Framework/ImapTestAccount.php
index c55941ae6a..2017bb465e 100644
--- a/tests/Integration/Framework/ImapTestAccount.php
+++ b/tests/Integration/Framework/ImapTestAccount.php
@@ -47,6 +47,7 @@ public function createTestAccount(?string $userId = null) {
$mailAccount->setOutboundUser('user@domain.tld');
$mailAccount->setOutboundPassword(OC::$server->getCrypto()->encrypt('mypassword'));
$mailAccount->setOutboundSslMode('none');
+ $mailAccount->setDebug(1);
$acc = $accountService->save($mailAccount);
/** @var MailboxSync $mbSync */