From d6b8eb08c0940c7cd237c39a56b5ef72d420bcbc Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 28 Apr 2024 13:49:07 +0200 Subject: [PATCH] add delete-userfiles flag for Domain.delete() to remove email-account data on the filesystem (if any); fixes #1239 Signed-off-by: Michael Kaufmann --- admin_domains.php | 2 +- customer_domains.php | 2 +- lib/Froxlor/Api/Commands/Domains.php | 13 +++++++- lib/Froxlor/Api/Commands/EmailAccounts.php | 2 +- lib/Froxlor/Cron/System/TasksCron.php | 35 ++++------------------ lib/Froxlor/System/Cronjob.php | 2 +- lng/de.lng.php | 2 +- lng/en.lng.php | 2 +- 8 files changed, 23 insertions(+), 37 deletions(-) diff --git a/admin_domains.php b/admin_domains.php index 4675e9faf..1caeb42ee 100644 --- a/admin_domains.php +++ b/admin_domains.php @@ -113,7 +113,7 @@ } elseif ($alias_check['count'] > 0) { Response::standardError('domains_cantdeletedomainwithaliases'); } else { - HTML::askYesNo('admin_domain_reallydelete', $filename, [ + HTML::askYesNoWithCheckbox('admin_domain_reallydelete', 'admin_customer_alsoremovemail', $filename, [ 'id' => $id, 'page' => $page, 'action' => $action diff --git a/customer_domains.php b/customer_domains.php index 94add191d..e06010a0b 100644 --- a/customer_domains.php +++ b/customer_domains.php @@ -26,7 +26,7 @@ const AREA = 'customer'; require __DIR__ . '/lib/init.php'; -use Froxlor\Api\Commands\SubDomains as SubDomains; +use Froxlor\Api\Commands\SubDomains; use Froxlor\CurrentUser; use Froxlor\Database\Database; use Froxlor\Domain\Domain; diff --git a/lib/Froxlor/Api/Commands/Domains.php b/lib/Froxlor/Api/Commands/Domains.php index ad0d4c554..52e204e79 100644 --- a/lib/Froxlor/Api/Commands/Domains.php +++ b/lib/Froxlor/Api/Commands/Domains.php @@ -2098,6 +2098,8 @@ public function update() * @param bool $is_stdsubdomain * optional, default false, specify whether it's a std-subdomain you are deleting as it does not count * as subdomain-resource + * @param bool $delete_userfiles + * optional, delete email account files on filesystem (if any), default false * * @access admin * @return string json-encoded array @@ -2109,7 +2111,8 @@ public function delete() $id = $this->getParam('id', true, 0); $dn_optional = $id > 0; $domainname = $this->getParam('domainname', $dn_optional, ''); - $is_stdsubdomain = $this->getParam('is_stdsubdomain', true, 0); + $is_stdsubdomain = $this->getBoolParam('is_stdsubdomain', true, 0); + $delete_user_emailfiles = $this->getBoolParam('delete_userfiles', true, 0); $result = $this->apiCall('Domains.get', [ 'id' => $id, @@ -2133,6 +2136,14 @@ public function delete() $idString = implode(' OR ', $idString); if ($idString != '') { + if ($delete_user_emailfiles) { + // determine all connected email-accounts + $emailaccount_sel = Database::prepare("SELECT `email`, `homedir`, `maildir` FROM `" . TABLE_MAIL_USERS . "` WHERE " . $idString); + Database::pexecute($emailaccount_sel, $paramString, true, true); + while ($emailacc_row = $emailaccount_sel->fetch(PDO::FETCH_ASSOC)) { + Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $emailacc_row['email'], FileDir::makeCorrectDir($emailacc_row['homedir'] . '/' . $emailacc_row['maildir'])); + } + } $del_stmt = Database::prepare(" DELETE FROM `" . TABLE_MAIL_USERS . "` WHERE " . $idString); Database::pexecute($del_stmt, $paramString, true, true); diff --git a/lib/Froxlor/Api/Commands/EmailAccounts.php b/lib/Froxlor/Api/Commands/EmailAccounts.php index b69da105e..4c2cfc3be 100644 --- a/lib/Froxlor/Api/Commands/EmailAccounts.php +++ b/lib/Froxlor/Api/Commands/EmailAccounts.php @@ -563,7 +563,7 @@ public function delete() } if ($delete_userfiles) { - Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $customer['loginname'], $result['email_full']); + Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $customer['loginname'], FileDir::makeCorrectDir($result['homedir'] . '/' . $result['maildir'])); } // decrease usage for customer diff --git a/lib/Froxlor/Cron/System/TasksCron.php b/lib/Froxlor/Cron/System/TasksCron.php index 83cfdd3f7..b339141fd 100644 --- a/lib/Froxlor/Cron/System/TasksCron.php +++ b/lib/Froxlor/Cron/System/TasksCron.php @@ -348,24 +348,16 @@ private static function deleteEmailData($row = null) FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'TasksCron: Task7 started - deleting customer e-mail data'); if (is_array($row['data'])) { - if (isset($row['data']['loginname']) && isset($row['data']['email'])) { + if (isset($row['data']['loginname']) && isset($row['data']['emailpath'])) { // remove specific maildir - $email_full = $row['data']['email']; + $email_full = $row['data']['emailpath']; if (empty($email_full)) { - FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, 'FATAL: Task7 asks to delete a email account but email field is empty!'); - } - $email_user = substr($email_full, 0, strrpos($email_full, "@")); - $email_domain = substr($email_full, strrpos($email_full, "@") + 1); - $maildirname = trim(Settings::Get('system.vmail_maildirname')); - // Add trailing slash to Maildir if needed - $maildirpath = $maildirname; - if (!empty($maildirname) and substr($maildirname, -1) != "/") { - $maildirpath .= "/"; + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, 'FATAL: Task7 asks to delete a email account but emailpath field is empty!'); } - $maildir = FileDir::makeCorrectDir(Settings::Get('system.vmail_homedir') . '/' . $row['data']['loginname'] . '/' . $email_domain . '/' . $email_user); + $maildir = FileDir::makeCorrectDir($email_full); - if ($maildir != '/' && !empty($maildir) && !empty($email_full) && $maildir != Settings::Get('system.vmail_homedir') && substr($maildir, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir) && is_dir(FileDir::makeCorrectDir($maildir . '/' . $maildirpath)) && fileowner($maildir) == Settings::Get('system.vmail_uid') && filegroup($maildir) == Settings::Get('system.vmail_gid')) { + if ($maildir != '/' && !empty($maildir) && $maildir != Settings::Get('system.vmail_homedir') && substr($maildir, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir) && fileowner($maildir) == Settings::Get('system.vmail_uid') && filegroup($maildir) == Settings::Get('system.vmail_gid')) { FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($maildir)); // mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part $return = false; @@ -377,23 +369,6 @@ private static function deleteEmailData($row = null) '~', '?' ]); - } else { - // backward-compatibility for old folder-structure - $maildir_old = FileDir::makeCorrectDir(Settings::Get('system.vmail_homedir') . '/' . $row['data']['loginname'] . '/' . $row['data']['email']); - - if ($maildir_old != '/' && !empty($maildir_old) && $maildir_old != Settings::Get('system.vmail_homedir') && substr($maildir_old, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir_old) && fileowner($maildir_old) == Settings::Get('system.vmail_uid') && filegroup($maildir_old) == Settings::Get('system.vmail_gid')) { - FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($maildir_old)); - // mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part - $return = false; - FileDir::safe_exec('rm -rf ' . escapeshellarg($maildir_old), $return, [ - '|', - '&', - '`', - '$', - '~', - '?' - ]); - } } } } diff --git a/lib/Froxlor/System/Cronjob.php b/lib/Froxlor/System/Cronjob.php index b4be07ac2..16021b334 100644 --- a/lib/Froxlor/System/Cronjob.php +++ b/lib/Froxlor/System/Cronjob.php @@ -183,7 +183,7 @@ public static function inserttask(int $type, ...$params) } elseif ($type == TaskId::DELETE_EMAIL_DATA && count($params) == 2 && $params[0] != '' && $params[1] != '') { $data = []; $data['loginname'] = $params[0]; - $data['email'] = $params[1]; + $data['emailpath'] = $params[1]; $data = json_encode($data); Database::pexecute($ins_stmt, [ 'type' => TaskId::DELETE_EMAIL_DATA, diff --git a/lng/de.lng.php b/lng/de.lng.php index 63923c56f..104a95fa8 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -1283,7 +1283,7 @@ 'question' => [ 'question' => 'Sicherheitsabfrage', 'admin_customer_reallydelete' => 'Wollen Sie den Kunden "%s" wirklich löschen?
ACHTUNG! Alle Daten gehen unwiderruflich verloren! Nach dem Vorgang müssen die Daten manuell aus dem Dateisystem entfernt werden.', - 'admin_domain_reallydelete' => 'Wollen Sie die Domain "%s" wirklich löschen?', + 'admin_domain_reallydelete' => 'Wollen Sie die Domain "%s" wirklich löschen?
ACHTUNG: Alle Subdomains, FTP-Konten und E-Mail Adressen/Konten, welche mit dieser Domain verbunden sind, werden gelöscht!', 'admin_domain_reallydisablesecuritysetting' => 'Wollen Sie die wichtige Sicherheitseinstellung \'OpenBasedir\' wirklich deaktivieren?', 'admin_admin_reallydelete' => 'Wollen Sie den Admin "%s" wirklich löschen?
Alle Kunden und Domains dieses Admins werden Ihnen zugeteilt.', 'admin_template_reallydelete' => 'Wollen Sie die Vorlage "%s" wirklich löschen?', diff --git a/lng/en.lng.php b/lng/en.lng.php index c1e7bcce5..ba2c76533 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -1398,7 +1398,7 @@ 'question' => [ 'question' => 'Security question', 'admin_customer_reallydelete' => 'Do you really want to delete the customer %s? This cannot be undone!', - 'admin_domain_reallydelete' => 'Do you really want to delete the domain %s?', + 'admin_domain_reallydelete' => 'Do you really want to delete the domain %s?
NOTE: All subdomains, ftp-accounts and email-addresses/accounts connected to this domain will be removed!', 'admin_domain_reallydisablesecuritysetting' => 'Do you really want to disable this security setting OpenBasedir?', 'admin_admin_reallydelete' => 'Do you really want to delete the admin %s? Every customer and domain will be reassigned to your account.', 'admin_template_reallydelete' => 'Do you really want to delete the template \'%s\'?',