From 164650adc3fee251fcd4201bb3ef2e7111a87c45 Mon Sep 17 00:00:00 2001 From: "Michael Kaufmann (d00p)" Date: Thu, 8 Mar 2018 11:49:28 +0100 Subject: [PATCH] added Emails.update() and Emails.delete() commands Signed-off-by: Michael Kaufmann (d00p) --- customer_email.php | 153 ++++--------- lib/classes/api/abstract.ApiCommand.php | 15 +- lib/classes/api/commands/class.Customers.php | 8 +- lib/classes/api/commands/class.Emails.php | 215 +++++++++++++++++-- lib/classes/settings/class.Settings.php | 9 + 5 files changed, 253 insertions(+), 147 deletions(-) diff --git a/customer_email.php b/customer_email.php index efed543a..870f243c 100644 --- a/customer_email.php +++ b/customer_email.php @@ -133,65 +133,24 @@ if ($page == 'overview') { eval("echo \"" . getTemplate("email/emails") . "\";"); } elseif ($action == 'delete' && $id != 0) { - $stmt = Database::prepare("SELECT `id`, `email`, `email_full`, `iscatchall`, `destination`, `customerid`, `popaccountid` FROM `" . TABLE_MAIL_VIRTUAL . "` - WHERE `customerid`= :customerid - AND `id`= :id" - ); - $result = Database::pexecute_first($stmt, array("customerid" => $userinfo['customerid'], "id" => $id)); + try { + $json_result = Emails::getLocal($userinfo, array( + 'id' => $id + ))->get(); + } catch (Exception $e) { + dynamic_error($e->getMessage()); + } + $result = json_decode($json_result, true)['data']; if (isset($result['email']) && $result['email'] != '') { if (isset($_POST['send']) && $_POST['send'] == 'send') { - $update_users_query_addon = ''; - - if ($result['destination'] != '') { - $result['destination'] = explode(' ', $result['destination']); - $number_forwarders = count($result['destination']); - - if ($result['popaccountid'] != 0) { - // Free the Quota used by the email account - if (Settings::Get('system.mail_quota_enabled') == 1) { - $stmt = Database::prepare("SELECT `quota` FROM `" . TABLE_MAIL_USERS . "` - WHERE `customerid`= :customerid - AND `id`= :id" - ); - $res_quota = Database::pexecute_first($stmt, array("customerid" => $userinfo['customerid'], "id" => $result['popaccountid'])); - $update_users_query_addon.= " , `email_quota_used` = `email_quota_used` - " . (int)$res_quota['quota'] . " "; - } - - $stmt = Database::prepare("DELETE FROM `" . TABLE_MAIL_USERS . "` - WHERE `customerid`= :customerid - AND `id`= :id" - ); - Database::pexecute($stmt, array("customerid" => $userinfo['customerid'], "id" => $result['popaccountid'])); - $update_users_query_addon .= " , `email_accounts_used` = `email_accounts_used` - 1 "; - $number_forwarders-= 1; - $log->logAction(USR_ACTION, LOG_INFO, "deleted forwarder for email address '" . $result['email'] . "'"); - } - } else { - $number_forwarders = 0; + try { + Emails::getLocal($userinfo, array( + 'id' => $id + ))->delete(); + } catch (Exception $e) { + dynamic_error($e->getMessage()); } - - if (isset($_POST['delete_userfiles']) - && (int)$_POST['delete_userfiles'] == 1 - ) { - inserttask('7', $userinfo['loginname'], $result['email_full']); - } - - $stmt = Database::prepare("DELETE FROM `" . TABLE_MAIL_VIRTUAL . "` - WHERE `customerid`= :customerid - AND `id`= :id" - ); - Database::pexecute($stmt, array("customerid" => $userinfo['customerid'], "id" => $id)); - - $stmt = Database::prepare("UPDATE `" . TABLE_PANEL_CUSTOMERS . "` - SET `emails_used`=`emails_used` - 1 , - `email_forwarders_used` = `email_forwarders_used` - :nforwarders - $update_users_query_addon - WHERE `customerid`= :customerid" - ); - Database::pexecute($stmt, array("nforwarders" => $number_forwarders, "customerid" => $userinfo['customerid'])); - - $log->logAction(USR_ACTION, LOG_INFO, "deleted email address '" . $result['email'] . "'"); redirectTo($filename, array('page' => $page, 's' => $s)); } else { if ($result['popaccountid'] != '0') { @@ -244,14 +203,14 @@ if ($page == 'overview') { standard_error('allresourcesused'); } } elseif ($action == 'edit' && $id != 0) { - $stmt = Database::prepare("SELECT `v`.`id`, `v`.`email`, `v`.`email_full`, `v`.`iscatchall`, `v`.`destination`, `v`.`customerid`, `v`.`popaccountid`, `u`.`quota` - FROM `" . TABLE_MAIL_VIRTUAL . "` `v` - LEFT JOIN `" . TABLE_MAIL_USERS . "` `u` - ON(`v`.`popaccountid` = `u`.`id`) - WHERE `v`.`customerid`= :cid - AND `v`.`id`= :id" - ); - $result = Database::pexecute_first($stmt, array("cid" => $userinfo['customerid'], "id" => $id)); + try { + $json_result = Emails::getLocal($userinfo, array( + 'id' => $id + ))->get(); + } catch (Exception $e) { + dynamic_error($e->getMessage()); + } + $result = json_decode($json_result, true)['data']; if (isset($result['email']) && $result['email'] != '') { $result['email'] = $idna_convert->decode($result['email']); @@ -289,58 +248,24 @@ if ($page == 'overview') { eval("echo \"" . getTemplate("email/emails_edit") . "\";"); } } elseif ($action == 'togglecatchall' && $id != 0) { - if (Settings::Get('catchall.catchall_enabled') == '1') { - $stmt = Database::prepare("SELECT `id`, `email`, `email_full`, `iscatchall`, `destination`, `customerid`, `popaccountid` FROM `" . TABLE_MAIL_VIRTUAL . "` - WHERE `customerid`= :cid - AND `id`= :id" - ); - $result = Database::pexecute_first($stmt, array("cid" => $userinfo['customerid'], "id" => $id)); - - if (isset($result['email']) && $result['email'] != '') { - if ($result['iscatchall'] == '1') { - $stmt = Database::prepare("UPDATE `" . TABLE_MAIL_VIRTUAL . "` - SET `email` = :email, `iscatchall` = '0' - WHERE `customerid`= :cid - AND `id`= :id" - ); - $params = array( - "email" => $result['email_full'], - "cid" => $userinfo['customerid'], - "id" => $id - ); - Database::pexecute($stmt, $params); - } else { - $email_parts = explode('@', $result['email_full']); - $email = '@' . $email_parts[1]; - $stmt = Database::prepare("SELECT `id`, `email`, `email_full`, `iscatchall`, `destination`, `customerid` FROM `" . TABLE_MAIL_VIRTUAL . "` - WHERE `email`= :email - AND `customerid`= :cid" - ); - $email_check = Database::pexecute_first($stmt, array("email" => $email, "cid" => $userinfo['customerid'])); - - if ($email_check['email'] == $email) { - standard_error('youhavealreadyacatchallforthisdomain'); - } else { - $stmt = Database::prepare("UPDATE `" . TABLE_MAIL_VIRTUAL . "` - SET `email` = :email , `iscatchall` = '1' - WHERE `customerid`= :cid - AND `id`= :id" - ); - $params = array( - "email" => $email, - "cid" => $userinfo['customerid'], - "id" => $id - ); - Database::pexecute($stmt, $params); - $log->logAction(USR_ACTION, LOG_INFO, "edited email address '" . $email . "'"); - } - } - - redirectTo($filename, array('page' => $page, 'action' => 'edit', 'id' => $id, 's' => $s)); - } - } else { - standard_error(array('operationnotpermitted', 'featureisdisabled'), 'Catchall'); + try { + $json_result = Emails::getLocal($userinfo, array( + 'id' => $id + ))->get(); + } catch (Exception $e) { + dynamic_error($e->getMessage()); } + $result = json_decode($json_result, true)['data']; + + try { + Emails::getLocal($userinfo, array( + 'id' => $id, + 'iscatchall' => ($result['iscatchall'] == '1' ? 0 : 1) + ))->update(); + } catch (Exception $e) { + dynamic_error($e->getMessage()); + } + redirectTo($filename, array('page' => $page, 'action' => 'edit', 'id' => $id, 's' => $s)); } } elseif ($page == 'accounts') { if ($action == 'add' && $id != 0) { diff --git a/lib/classes/api/abstract.ApiCommand.php b/lib/classes/api/abstract.ApiCommand.php index e3677f9a..0528a79c 100644 --- a/lib/classes/api/abstract.ApiCommand.php +++ b/lib/classes/api/abstract.ApiCommand.php @@ -106,7 +106,7 @@ abstract class ApiCommand $this->version = $version; $this->dbversion = $dbversion; $this->branding = $branding; - + if (! is_null($params)) { $params = $this->trimArray($params); } @@ -417,8 +417,9 @@ abstract class ApiCommand /** * returns an array of customers the current user can access * - * @param string $customer_hide_option optional, when called as customer, some options might be hidden due to the panel.customer_hide_options ettings - * + * @param string $customer_hide_option + * optional, when called as customer, some options might be hidden due to the panel.customer_hide_options ettings + * * @throws Exception * @return array */ @@ -430,7 +431,7 @@ abstract class ApiCommand // or optionally for one specific customer identified by id or loginname $customerid = $this->getParam('customerid', true, 0); $loginname = $this->getParam('loginname', true, ''); - + if (! empty($customerid) || ! empty($loginname)) { $_result = $this->apiCall('Customers.get', array( 'id' => $customerid, @@ -447,7 +448,7 @@ abstract class ApiCommand $customer_ids[] = $customer['customerid']; } } else { - if (!empty($customer_hide_option) && Settings::IsInList('panel.customer_hide_options', $customer_hide_option)) { + if (! empty($customer_hide_option) && Settings::IsInList('panel.customer_hide_options', $customer_hide_option)) { throw new Exception("You cannot access this resource", 405); } $customer_ids = array( @@ -467,11 +468,11 @@ abstract class ApiCommand * @param string $resource * @param string $extra */ - protected static function updateResourceUsage($table = null, $keyfield = null, $key = null, $operator = '+', $resource = null, $extra = null) + protected static function updateResourceUsage($table = null, $keyfield = null, $key = null, $operator = '+', $resource = null, $extra = null, $step = 1) { $stmt = Database::prepare(" UPDATE `" . $table . "` - SET `" . $resource . "` = `" . $resource . "` " . $operator . " 1 " . $extra . " + SET `" . $resource . "` = `" . $resource . "` " . $operator . " " . (int)$step . " " . $extra . " WHERE `" . $keyfield . "` = :key "); Database::pexecute($stmt, array( diff --git a/lib/classes/api/commands/class.Customers.php b/lib/classes/api/commands/class.Customers.php index fdbd42ce..7291dea3 100644 --- a/lib/classes/api/commands/class.Customers.php +++ b/lib/classes/api/commands/class.Customers.php @@ -1547,9 +1547,9 @@ class Customers extends ApiCommand implements ResourceEntity * @param string $extra * optional, default empty */ - public static function increaseUsage($customerid = 0, $resource = null, $extra = '') + public static function increaseUsage($customerid = 0, $resource = null, $extra = '', $increase_by = 1) { - self::updateResourceUsage(TABLE_PANEL_CUSTOMERS, 'customerid', $customerid, '+', $resource, $extra); + self::updateResourceUsage(TABLE_PANEL_CUSTOMERS, 'customerid', $customerid, '+', $resource, $extra, $increase_by); } /** @@ -1560,8 +1560,8 @@ class Customers extends ApiCommand implements ResourceEntity * @param string $extra * optional, default empty */ - public static function decreaseUsage($customerid = 0, $resource = null, $extra = '') + public static function decreaseUsage($customerid = 0, $resource = null, $extra = '', $decrease_by = 1) { - self::updateResourceUsage(TABLE_PANEL_CUSTOMERS, 'customerid', $customerid, '-', $resource, $extra); + self::updateResourceUsage(TABLE_PANEL_CUSTOMERS, 'customerid', $customerid, '-', $resource, $extra, $decrease_by); } } diff --git a/lib/classes/api/commands/class.Emails.php b/lib/classes/api/commands/class.Emails.php index ce45ab72..8f712c31 100644 --- a/lib/classes/api/commands/class.Emails.php +++ b/lib/classes/api/commands/class.Emails.php @@ -17,7 +17,7 @@ */ class Emails extends ApiCommand implements ResourceEntity { - + /** * add a new email address * @@ -30,7 +30,7 @@ class Emails extends ApiCommand implements ResourceEntity if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) { throw new Exception("You cannot access this resource", 405); } - + if ($this->getUserDetail('emails_used') < $this->getUserDetail('emails') || $this->getUserDetail('emails') == '-1') { // required parameters @@ -39,13 +39,13 @@ class Emails extends ApiCommand implements ResourceEntity // parameters $iscatchall = $this->getParam('iscatchall', true, 0); - + // validation if (substr($domain, 0, 4) != 'xn--') { $idna_convert = new idna_convert_wrapper(); $domain = $idna_convert->encode(validate($domain, 'domain', '', '', array(), true)); } - + // check domain and whether it's an email-enabled domain $domain_check = $this->apiCall('SubDomains.get', array( 'domainname' => $domain @@ -53,7 +53,11 @@ class Emails extends ApiCommand implements ResourceEntity if ($domain_check['isemaildomain'] == 0) { standard_error('maindomainnonexist', $domain, true); } - + + if (Settings::Get('catchall.catchall_enabled') != '1') { + $iscatchall = 0; + } + // check for catchall-flag if ($iscatchall) { $iscatchall = '1'; @@ -62,15 +66,15 @@ class Emails extends ApiCommand implements ResourceEntity $iscatchall = '0'; $email = $email_part . '@' . $domain; } - + // full email value $email_full = $email_part . '@' . $domain; - + // validate it - if (!validateEmail($email_full)) { + if (! validateEmail($email_full)) { standard_error('emailiswrong', $email_full, true); } - + // get needed customer info to reduce the email-address-counter by one if ($this->isAdmin()) { // get customer id @@ -86,7 +90,7 @@ class Emails extends ApiCommand implements ResourceEntity $customer_id = $this->getUserDetail('customerid'); $customer = $this->getUserData(); } - + // duplicate check $stmt = Database::prepare(" SELECT `id`, `email`, `email_full`, `iscatchall`, `destination`, `customerid` FROM `" . TABLE_MAIL_VIRTUAL . "` @@ -99,13 +103,13 @@ class Emails extends ApiCommand implements ResourceEntity "cid" => $customer['customerid'] ); $email_check = Database::pexecute_first($stmt, $params, true, true); - + if (strtolower($email_check['email_full']) == strtolower($email_full)) { standard_error('emailexistalready', $email_full, true); } elseif ($email_check['email'] == $email) { standard_error('youhavealreadyacatchallforthisdomain', '', true); } - + $stmt = Database::prepare(" INSERT INTO `" . TABLE_MAIL_VIRTUAL . "` SET `customerid` = :cid, @@ -123,15 +127,15 @@ class Emails extends ApiCommand implements ResourceEntity ); Database::pexecute($stmt, $params, true, true); $address_id = Database::lastInsertId(); - + // update customer usage Customers::increaseUsage($customer_id, 'emails_used'); - + // update admin usage Admins::increaseUsage($customer['adminid'], 'emails_used'); - + $this->logger()->logAction($this->isAdmin() ? ADM_ACTION : USR_ACTION, LOG_INFO, "[API] added email address '" . $email_full . "'"); - + $result = $this->apiCall('Emails.get', array( 'emailaddr' => $email_full )); @@ -139,7 +143,7 @@ class Emails extends ApiCommand implements ResourceEntity } throw new Exception("No more resources available", 406); } - + /** * return a email-address entry by either id or email-address * @@ -147,7 +151,7 @@ class Emails extends ApiCommand implements ResourceEntity * optional, the customer-id * @param string $emailaddr * optional, the email-address - * + * * @access admin, customer * @throws Exception * @return array @@ -177,11 +181,93 @@ class Emails extends ApiCommand implements ResourceEntity $key = ($id > 0 ? "id #" . $id : "emailaddr '" . $emailaddr . "'"); throw new Exception("Email address with " . $key . " could not be found", 404); } - + + /** + * toggle catchall flag of given email address either by id or email-address + * + * @param int $id + * optional, the customer-id + * @param string $emailaddr + * optional, the email-address + * @param boolean $iscatchall + * optional + * @param int $customerid + * optional, required when called as admin/reseller + * + * @access admin, customer + * @throws Exception + * @return array + */ public function update() { + if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) { + throw new Exception("You cannot access this resource", 405); + } + + // if enabling catchall is not allowed by settings, we do not need + // to run update() + if (Settings::Get('catchall.catchall_enabled') != '1') { + standard_error(array( + 'operationnotpermitted', + 'featureisdisabled' + ), 'catchall', true); + } + + $id = $this->getParam('id', true, 0); + $ea_optional = ($id <= 0 ? false : true); + $emailaddr = $this->getParam('emailaddr', $ea_optional, ''); + + $result = $this->apiCall('Emails.get', array( + 'id' => $id, + 'emailaddr' => $emailaddr + )); + $id = $result['id']; + + // parameters + $iscatchall = $this->getParam('iscatchall', true, $result['iscatchall']); + + // get needed customer info to reduce the email-address-counter by one + if ($this->isAdmin()) { + // get customer id + $customer_id = $this->getParam('customerid'); + $customer = $this->apiCall('Customers.get', array( + 'id' => $customer_id + )); + } else { + $customer_id = $this->getUserDetail('customerid'); + $customer = $this->getUserData(); + } + + // check for catchall-flag + if ($iscatchall) { + $iscatchall = '1'; + $email_parts = explode('@', $result['email_full']); + $email = '@' . $email_parts[1]; + } else { + $iscatchall = '0'; + $email = $result['email_full']; + } + + $stmt = Database::prepare(" + UPDATE `" . TABLE_MAIL_VIRTUAL . "` + SET `email` = :email , `iscatchall` = :caflag + WHERE `customerid`= :cid AND `id`= :id + "); + $params = array( + "email" => $email, + "caflag" => $iscatchall, + "cid" => $customer['customerid'], + "id" => $id + ); + Database::pexecute($stmt, $params, true, true); + $this->logger()->logAction($this->isAdmin() ? ADM_ACTION : USR_ACTION, LOG_INFO, "[API] toggled catchall-flag for email address '" . $result['email_full'] . "'"); + + $result = $this->apiCall('Emails.get', array( + 'emailaddr' => $result['email_full'] + )); + return $this->response(200, "successfull", $result); } - + /** * list all email addresses, if called from an admin, list all email addresses of all customers you are allowed to view, or specify id or loginname for one specific customer * @@ -189,7 +275,7 @@ class Emails extends ApiCommand implements ResourceEntity * optional, admin-only, select ftp-users of a specific customer by id * @param string $loginname * optional, admin-only, select ftp-users of a specific customer by loginname - * + * * @access admin, customer * @throws Exception * @return array count|list @@ -216,15 +302,100 @@ class Emails extends ApiCommand implements ResourceEntity 'list' => $result )); } - + /** * delete an email address by either id or username * + * @param int $id + * optional, the customer-id + * @param string $emailaddr + * optional, the email-address + * @param boolean $delete_userfiles + * optional, delete email data from filesystem, default: no + * @param int $customerid + * optional, required when called as admin/reseller + * * @access admin, customer * @throws Exception * @return array */ public function delete() { + if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) { + throw new Exception("You cannot access this resource", 405); + } + + $id = $this->getParam('id', true, 0); + $ea_optional = ($id <= 0 ? false : true); + $emailaddr = $this->getParam('emailaddr', $ea_optional, ''); + + $result = $this->apiCall('Emails.get', array( + 'id' => $id, + 'emailaddr' => $emailaddr + )); + $id = $result['id']; + + // parameters + $delete_userfiles = $this->getParam('delete_userfiles', true, 0); + + // get needed customer info to reduce the email-address-counter by one + if ($this->isAdmin()) { + // get customer id + $customer_id = $this->getParam('customerid'); + $customer = $this->apiCall('Customers.get', array( + 'id' => $customer_id + )); + } else { + $customer_id = $this->getUserDetail('customerid'); + $customer = $this->getUserData(); + } + + // check for forwarders + $number_forwarders = 0; + if ($result['destination'] != '') { + $result['destination'] = explode(' ', $result['destination']); + $number_forwarders = count($result['destination']); + Customers::decreaseUsage($customer['customerid'], 'email_forwarders_used', '', $number_forwarders); + Admins::decreaseUsage($customer['customerid'], 'email_forwarders_used', '', $number_forwarders); + } + // check whether this address is an account + if ($result['popaccountid'] != 0) { + // Free the Quota used by the email account + if (Settings::Get('system.mail_quota_enabled') == 1) { + $stmt = Database::prepare("SELECT `quota` FROM `" . TABLE_MAIL_USERS . "` WHERE `customerid`= :customerid AND `id`= :id"); + $res_quota = Database::pexecute_first($stmt, array( + "customerid" => $customer_id, + "id" => $result['popaccountid'] + ), true, true); + Customers::decreaseUsage($customer['customerid'], 'email_quota_used', '', $res_quota['quota']); + Admins::decreaseUsage($customer['customerid'], 'email_quota_used', '', $res_quota['quota']); + $this->logger()->logAction($this->isAdmin() ? ADM_ACTION : USR_ACTION, LOG_INFO, "[API] deleted quota entries for email address '" . $result['email_full'] . "'"); + } + // delete account + $stmt = Database::prepare("DELETE FROM `" . TABLE_MAIL_USERS . "` WHERE `customerid`= :customerid AND `id`= :id"); + Database::pexecute($stmt, array( + "customerid" => $customer_id, + "id" => $result['popaccountid'] + ), true, true); + Customers::decreaseUsage($customer['customerid'], 'email_accounts_used'); + Admins::decreaseUsage($customer['customerid'], 'email_accounts_used'); + $this->logger()->logAction($this->isAdmin() ? ADM_ACTION : USR_ACTION, LOG_INFO, "[API] deleted email account '" . $result['email_full'] . "'"); + } + + if ($delete_userfiles) { + inserttask('7', $customer['loginname'], $result['email_full']); + } + + // delete address + $stmt = Database::prepare("DELETE FROM `" . TABLE_MAIL_VIRTUAL . "` WHERE `customerid`= :customerid AND `id`= :id"); + Database::pexecute($stmt, array( + "customerid" => $customer_id, + "id" => $id + ), true, true); + Customers::decreaseUsage($customer['customerid'], 'emails_used'); + Admins::decreaseUsage($customer['customerid'], 'emails_used'); + + $this->logger()->logAction($this->isAdmin() ? ADM_ACTION : USR_ACTION, LOG_INFO, "[API] deleted email address '" . $result['email_full'] . "'"); + return $this->response(200, "successfull", $result); } } diff --git a/lib/classes/settings/class.Settings.php b/lib/classes/settings/class.Settings.php index e6b8a37b..3ab57ecb 100644 --- a/lib/classes/settings/class.Settings.php +++ b/lib/classes/settings/class.Settings.php @@ -28,6 +28,13 @@ * @author Froxlor team (2010-) * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt * @package Classes + * + * @method static mixed Get ($setting = null) return a setting-value by its group and varname separated by a dot (group.varname) + * @method static boolean Set ($setting = null, $value = null, $instant_save = true) update a setting / set a new value + * @method static boolean IsInList ($setting = null, $entry = null) tests if a setting-value that i s a comma separated list contains an entry + * @method static boolean AddNew ($setting = null, $value = null) add a new setting to the database (mainly used in updater) + * @method static boolean Flush () Store all un-saved changes to the database and re-read in all settings + * @method static void Stash () forget all un-saved changes to settings */ class Settings { @@ -148,6 +155,8 @@ class Settings { * @param string $setting a group and a varname separated by a dot (group.varname) * @param string $value * @param boolean $instant_save + * + * @return bool */ public function pSet($setting = null, $value = null, $instant_save = true) { // check whether the setting exists