diff --git a/WebsitePanel.WHMCSModule/changelog.html b/WebsitePanel.WHMCSModule/changelog.html new file mode 100644 index 00000000..cd86f995 --- /dev/null +++ b/WebsitePanel.WHMCSModule/changelog.html @@ -0,0 +1,38 @@ + + + + +WHMCS WebsitePanel Server Module / Addons + + + +

WHMCS WebsitePanel Server Module

+

DO NOT CONTACT WHMCS FOR SUPPORT WITH THIS MODULE

+

Changelog / Updates

+

10-25-2014 (v3.0.4)

+ +

2-24-2014 (v3.0.3)

+ +

2-23-2014 (v3.0.2)

+ +

2-22-2014 (v3.0.1)

+ + + diff --git a/WebsitePanel.WHMCSModule/changelog.log b/WebsitePanel.WHMCSModule/changelog.log deleted file mode 100644 index e570fc7b..00000000 --- a/WebsitePanel.WHMCSModule/changelog.log +++ /dev/null @@ -1,6 +0,0 @@ -04/16/2013 (1.3) -* Some refactoring done - -01/29/2013 (1.2) -* WebsitePanel addons no longer require the storage of the Enterprise Server credentials -* Error codes are not properly resolved to their text responses \ No newline at end of file diff --git a/WebsitePanel.WHMCSModule/how-to-upgrade.html b/WebsitePanel.WHMCSModule/how-to-upgrade.html new file mode 100644 index 00000000..272d88e0 --- /dev/null +++ b/WebsitePanel.WHMCSModule/how-to-upgrade.html @@ -0,0 +1,14 @@ +WHMCS WebsitePanel Server Module / Addons +

WHMCS WebsitePanel Server Module

+

DO NOT CONTACT WHMCS FOR SUPPORT WITH THIS MODULE

+

Update from the previous available version... (The version prior to 2-23-2014)

+
    +
  1. Backup all files / directories before deleting!!
  2. +
  3. Delete includes/hooks/websitepanel_sync.php
  4. +
  5. Delete includes/hooks/websitepanel_addons.php
  6. +
  7. Delete modules/servers/websitepanel
  8. +
  9. Delete modules/addons/websitepanel_sync
  10. +
  11. Delete modules/addons/websitepanel_addons
  12. +
  13. Upload the contents of the ZIP to your WHMCS root
  14. +
+

All new files should have version 3.x.x listed in their headers

diff --git a/WebsitePanel.WHMCSModule/includes/hooks/websitepanel_addons.php b/WebsitePanel.WHMCSModule/includes/hooks/websitepanel_addons.php deleted file mode 100644 index b8a0fe99..00000000 --- a/WebsitePanel.WHMCSModule/includes/hooks/websitepanel_addons.php +++ /dev/null @@ -1,137 +0,0 @@ - 0) - { - // Include the WebsitePanel ES Class - require_once(ROOTDIR . '/modules/servers/websitepanel/websitepanel.class.php'); - require_once(ROOTDIR . '/modules/servers/websitepanel/websitepanel.functions.php'); - - // Retrieve the WebsitePanel Addons module settings - $modSettings = websitepanel_addons_GetSettings(); - $srvSettings = websitepanel_GetServerSettings(); - if (empty($modSettings['serverhost']) || empty($modSettings['serverport']) || empty($srvSettings['username']) || empty($srvSettings['password'])) - { - // The module is disabled or has not yet been configured - stop - return; - } - - // Get the associated WebsitePanel username from WHMCS - $results = select_query('tblhosting', 'username', array('id' => $params['serviceid'])); - $username = mysql_fetch_array($results); - $username = $username['username']; - if (empty($username)) - { - // The username is required - if missing we cannot continue - return; - } - - // Create the WebsitePanel object instance - $wsp = new WebsitePanel($srvSettings['username'], $srvSettings['password'], $modSettings['serverhost'], $modSettings['serverport'], (($modSettings['serversecured']) == 'on' ? TRUE : FALSE)); - - // Grab the user's details from WebsitePanel in order to get the user's id - $user = $wsp->getUserByUsername($username); - if (empty($user)) - { - return; - } - - // Get the user's current WebsitePanel hosting space Id (Hosting Plan) - $package = $wsp->getUserPackages($user['UserId']); - $packageId = $package['PackageId']; - if (empty($packageId)) - { - return; - } - - // Get the associated WebsitePanel addon id - $results = select_query('mod_wspaddons', 'wsp_id,is_ipaddress', array('whmcs_id' => $params['addonid'])); - $addon = mysql_fetch_array($results); - $addonPlanId = $addon['wsp_id']; - $addonIsIpAddress = $addon['is_ipaddress']; - - // Add the Addon Plan to the customer's WebsitePanel package / hosting space - $results = $wsp->addPackageAddonById($packageId, $addonPlanId); - - // Check the results to verify that the addon has been successfully allocated - if ($results['Result'] > 0) - { - // If this addon is an IP address addon - attempt to randomly allocate an IP address to the customer's hosting space - if ($addonIsIpAddress) - { - $wsp->packageAllocateIpAddress($packageId); - } - } - } -} - -/* Addon Activation - WebsitePanel */ -add_hook('AddonActivation', 1, 'websitepanel_addons_AddonActivation'); - -/* Addon Activation - WebsitePanel */ -add_hook('AddonActivated', 1, 'websitepanel_addons_AddonActivation'); - -/** - * websitepanel_addons_GetSettings - * - * @access public - * @return array - */ -function websitepanel_addons_GetSettings() -{ - $settings = array(); - - // Retrieve the settings from the modules configuration table - $results = select_query('tbladdonmodules', 'setting,value', array('module' => 'websitepanel_addons')); - while (($row = mysql_fetch_array($results)) != false) - { - $settings[$row[0]] = $row[1]; - } - return $settings; -} \ No newline at end of file diff --git a/WebsitePanel.WHMCSModule/includes/hooks/websitepanel_sync.php b/WebsitePanel.WHMCSModule/includes/hooks/websitepanel_sync.php deleted file mode 100644 index d9129b62..00000000 --- a/WebsitePanel.WHMCSModule/includes/hooks/websitepanel_sync.php +++ /dev/null @@ -1,114 +0,0 @@ - 0) - { - // Include the WebsitePanel ES Class - require_once(ROOTDIR . '/modules/servers/websitepanel/websitepanel.class.php'); - require_once(ROOTDIR . '/modules/servers/websitepanel/websitepanel.functions.php'); - - // Retrieve the WebsitePanel Addons module settings - $modSettings = websitepanel_sync_GetSettings(); - $srvSettings = websitepanel_GetServerSettings(); - if (empty($modSettings['serverhost']) || empty($modSettings['serverport']) || empty($srvSettings['username']) || empty($srvSettings['password'])) - { - // The module is disabled or has not yet been configured - stop - return; - } - - // Create the WebsitePanel object instance - $wsp = new WebsitePanel($srvSettings['username'], $srvSettings['password'], $modSettings['serverhost'], $modSettings['serverport'], (($modSettings['serversecured']) == 'on' ? TRUE : FALSE)); - - // Get all WSP users with the old email - $items = (array)$wsp->getUsersPagedRecursive(1, 'Email', $params['olddata']['email'], 0, 0, ''); - - // Load / parse the XML response - $xml = simplexml_load_string($items['any']); - $rootPath = $xml->NewDataSet; - - // Total number of elements to update - $total = $rootPath->Table->Column1; - - // Begin updating WebsitePanel accounts - for ($i = 0; $i < $total; $i++) - { - // Set the current root element and get the users details from WebsitePanel - // We cannot use the details provided by the get_users_paged_recursive method as it does not return all the required elements to fully update the user - $currentRoot = $rootPath->Table1->$i; - $userDetails = (array)$wsp->getUserByUsername($currentRoot->Username); - - // Update the current user - $wsp->updateUserDetails($userDetails['RoleId'], (($userDetails['RoleId'] == 2) ? 'Reseller' : 'User'), $userDetails['StatusId'], $userDetails['Status'], $userDetails['LoginStatusId'], $userDetails['LoginStatus'], $userDetails['FailedLogins'], $userDetails['UserId'], $userDetails['OwnerId'], $userDetails['Created'], $userDetails['Changed'], $userDetails['IsDemo'], $userDetails['IsPeer'], $currentRoot->Comments, $userDetails['Username'], $userDetails['Password'], $params['firstname'], $params['lastname'], $params['email'], $params['phonenumber'], $params['postcode'], '', '', '', '', $params['country'], $params['address1'] . (!empty($params['address2']) ? " {$params['address2']}" : ''), $params['city'], $params['state'], TRUE, $params['companyname'], (($userDetails['RoleId'] == 2) ? TRUE : FALSE)); - - // Add log entry to client log - logactivity("WebsitePanel Sync - Account {$currentRoot->Username} contact details updated successfully", $params['userid']); - } - } -} - -/* Update Client Contact Details - WebsitePanel */ -add_hook('ClientEdit', 1, 'websitepanel_sync_ClientEdit'); - -/** - * websitepanel_addons_GetSettings - * - * @access public - * @return array - */ -function websitepanel_sync_GetSettings() -{ - $settings = array(); - - // Retrieve the settings from the modules configuration table - $results = select_query('tbladdonmodules', 'setting,value', array('module' => 'websitepanel_sync')); - while (($row = mysql_fetch_array($results)) != false) - { - $settings[$row['setting']] = $row['value']; - } - return $settings; -} \ No newline at end of file diff --git a/WebsitePanel.WHMCSModule/modules/addons/websitepanel_addons/hooks.php b/WebsitePanel.WHMCSModule/modules/addons/websitepanel_addons/hooks.php new file mode 100644 index 00000000..90c5b4f8 --- /dev/null +++ b/WebsitePanel.WHMCSModule/modules/addons/websitepanel_addons/hooks.php @@ -0,0 +1,128 @@ + 0) + { + // Get the results of the query + $row = mysql_fetch_assoc($result); + + // Start processing the users addon + $username = $row['username']; + $serverUsername = $row['serverusername']; + $serverPassword = decrypt($row['serverpassword']); + $serverPort = $row['configoption6']; + $serverHost = empty($row['serverhostname']) ? $row['serverip'] : $row['serverhostname']; + $serverSecure = $row['serversecure'] == 'on' ? TRUE : FALSE; + + try + { + // Create the WebsitePanel Enterprise Server Client object instance + $wsp = new websitepanel_EnterpriseServer($serverUsername, $serverPassword, $serverHost, $serverPort, $serverSecure); + + // Get the user's details from WebsitePanel - We need the UserId + $user = $wsp->getUserByUsername($username); + if (empty($user)) + { + throw new Exception("User {$username} does not exist - Cannot allocate addon for unknown user"); + } + + // Get the user's package details from WebsitePanel - We need the PackageId + $package = $wsp->getUserPackages($user['UserId']); + $packageId = $package['PackageId']; + + // Get the associated WebsitePanel addon id + $results = select_query('mod_wspaddons', 'wsp_id,is_ipaddress', array('whmcs_id' => $addonId)); + $addon = mysql_fetch_array($results); + $addonPlanId = $addon['wsp_id']; + $addonIsIpAddress = $addon['is_ipaddress']; + + // Add the Addon Plan to the customer's WebsitePanel package / hosting space + $results = $wsp->addPackageAddonById($packageId, $addonPlanId); + + // Check the results to verify that the addon has been successfully allocated + if ($results['Result'] > 0) + { + // If this addon is an IP address addon - attempt to randomly allocate an IP address to the customer's hosting space + if ($addonIsIpAddress) + { + $wsp->allocatePackageIPAddresses($packageId); + } + + // Add log entry to client log + logactivity("WebsitePanel Addon - Account {$username} addon successfully completed - Addon ID: {$addonId}", $userId); + } + else + { + // Add log entry to client log + throw new Exception("Unknown", $results['Result']); + } + } + catch (Exception $e) + { + // Error message to log / return + $errorMessage = "websitepanel_addons_AddonActivation Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}, Service ID: {$serviceId})"; + + // Log to WHMCS + logactivity($errorMessage, $userId); + } + } +} + +/* Addon Activation - WebsitePanel */ +add_hook('AddonActivation', 1, 'websitepanel_addons_AddonActivation'); \ No newline at end of file diff --git a/WebsitePanel.WHMCSModule/modules/addons/websitepanel_addons/websitepanel_addons.php b/WebsitePanel.WHMCSModule/modules/addons/websitepanel_addons/websitepanel_addons.php index d71cb9b7..106ab070 100644 --- a/WebsitePanel.WHMCSModule/modules/addons/websitepanel_addons/websitepanel_addons.php +++ b/WebsitePanel.WHMCSModule/modules/addons/websitepanel_addons/websitepanel_addons.php @@ -1,197 +1,195 @@ - 'WebsitePanel Addons Automation', - 'description' => 'Automates WHMCS product addons with WebsitePanel', - 'version' => '1.2', - 'author' => 'Christopher York', - 'fields' => array('serverhost' => array('FriendlyName', 'Enterprise Server Host', 'Type' => 'text', 'Size' => 25, 'Description' => 'Enterprise Server hostname / IP address', 'Default' => '127.0.0.1'), - 'serverport' => array('FriendlyName', 'Enterprise Server Port', 'Type' => 'text', 'Size' => 4, 'Description' => 'Enterprise Server port', 'Default' => 9002), - 'serversecured' => array('FriendlyName', 'Use Secured Connection', 'Type' => 'yesno', 'Description' => 'Tick to use SSL secured connection'), - ) - ); - return $configarray; -} - -/** - * websitepanel_addons_activate - * - * @access public - * @return array - */ -function websitepanel_addons_activate() -{ - // Create the WebsitePanel Addons table - $query = "CREATE TABLE `mod_wspaddons` ( - `whmcs_id` int(11) NOT NULL, - `wsp_id` int(11) NOT NULL, - `is_ipaddress` bit(1) NOT NULL DEFAULT 0, - PRIMARY KEY (`whmcs_id`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8;"; - $result = full_query($query); - - // Check the results to verify that the table has been created properly - if (!$result) - { - return array('status' => 'error', 'description' => 'There was an error while activating the module'); - } - else - { - return array('status' => 'success', 'description' => 'The module has been activated successfully'); - } -} - -/** - * websitepanel_addons_deactivate - * - * @access public - * @return array - */ -function websitepanel_addons_deactivate() -{ - // Drop the WebsitePanel Addons table - $result = full_query('DROP TABLE `mod_wspaddons`'); - - // Check the results to verify that the table has been created properly - if (!$result) - { - return array('status' => 'error', 'description' => 'There was an error while deactiviting the module'); - } - else - { - return array('status' => 'success', 'description' => 'The module has been deactivated successfully'); - } -} - -/** - * websitepanel_addons_upgrade - * - * @param $vars array - * @access public - * @return array - */ -function websitepanel_addons_upgrade($vars) -{ - - $version = $vars['version']; - - // Adjust the table name and remove the WebsitePanel credentials - if ($version < 1.2) - { - full_query('RENAME TABLE `tblwspaddons` TO `mod_wspaddons`'); - full_query("DELETE FROM `tbladdonmodules` WHERE `module` = 'websitepanel_addons' AND `setting` = 'username'"); - full_query("DELETE FROM `tbladdonmodules` WHERE `module` = 'websitepanel_addons' AND `setting` = 'password'"); - } -} - -/** - * websitepanel_addons_output - * - * @access public - * @return mixed - */ -function websitepanel_addons_output($params) -{ - // Delete the requested WebsitePanel addon - if (isset($_GET['action']) && $_GET['action'] == 'delete') - { - delete_query('mod_wspaddons', array('whmcs_id' => $_GET['id'])); - } - - // Add the requested WebsitePanel addon - if ($_POST && isset($_POST['action']) && $_POST['action'] == 'add') - { - // Sanity check to make sure the WHMCS addon ID exists - $results = select_query('tbladdons', 'id', array('id' => $_POST['whmcs_id'])); - if (mysql_num_rows($results) > 0) - { - $results = select_query('mod_wspaddons', 'whmcs_id', array('whmcs_id' => $_POST['whmcs_id'])); - if (mysql_num_rows($results) > 0) - { - echo '

Duplicate WHMCS Addon ID. The WHMCS Addon ID Is Assigned To Another WebsitePanel Addon.

'; - } - else - { - insert_query('mod_wspaddons', array('whmcs_id' => $_POST['whmcs_id'], 'wsp_id' => $_POST['wsp_id'], 'is_ipaddress' => $_POST['is_ipaddress'])); - } - } - else - { - echo '

WHMCS Addon Not Found! Check The ID And Try Again.

'; - } - } - - // Get all the assigned addons and display them to the user - $results = full_query('SELECT a.name AS `name`, a.id AS `whmcs_id`, w.wsp_id AS `wsp_id` FROM `tbladdons` AS a, `mod_wspaddons` AS w WHERE w.whmcs_id = a.id'); - - // Build the table / data grid - echo '
'; - echo ''; - echo ''; - if (mysql_num_rows($results) > 0) - { - while (($row = mysql_fetch_array($results)) != false) - { - echo ""; - } - } - else - { - echo ''; - } - echo '
Addon NameWHMCS IDWebsitePanel ID
{$row['name']}{$row['whmcs_id']}{$row['wsp_id']}Delete
No Addon Data Found
'; - - // Build the add addon form - echo '

Add WebsitePanel Addon

'; - echo "
"; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo '
WHMCS Addon ID
WebsitePanel Addon ID
Dedicated IP Addon
'; + 'WebsitePanel Addons Automation', + 'description' => 'Automates WHMCS product addons with WebsitePanel Addons', + 'version' => '3.0.4', + 'author' => 'Christopher York'); +} + +/** + * websitepanel_addons_activate + * + * @access public + * @return array + */ +function websitepanel_addons_activate() +{ + // Create the WebsitePanel Addons table + $query = "CREATE TABLE IF NOT EXISTS `mod_wspaddons` ( + `whmcs_id` int(11) NOT NULL, + `wsp_id` int(11) NOT NULL, + `is_ipaddress` bit(1) NOT NULL DEFAULT b'0', + PRIMARY KEY (`whmcs_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;"; + $result = full_query($query); + + // Check the results to verify that the table has been created properly + if (!$result) + { + return array('status' => 'error', 'description' => 'There was an error while activating the module'); + } + else + { + return array('status' => 'success', 'description' => 'The module has been activated successfully'); + } +} + +/** + * websitepanel_addons_deactivate + * + * @access public + * @return array + */ +function websitepanel_addons_deactivate() +{ + // Drop the WebsitePanel Addons table + $result = full_query('DROP TABLE `mod_wspaddons`'); + + // Check the results to verify that the table has been created properly + if (!$result) + { + return array('status' => 'error', 'description' => 'There was an error while deactiviting the module'); + } + else + { + return array('status' => 'success', 'description' => 'The module has been deactivated successfully'); + } +} + +/** + * websitepanel_addons_upgrade + * + * @param $vars array + * @access public + * @return array + */ +function websitepanel_addons_upgrade($vars) +{ + // Module versions + $version = $vars['version']; + + // Adjust the table name and remove the WebsitePanel credentials + if ($version < 1.2) + { + full_query('RENAME TABLE `tblwspaddons` TO `mod_wspaddons`'); + full_query("DELETE FROM `tbladdonmodules` WHERE `module` = 'websitepanel_addons' AND `setting` = 'username'"); + full_query("DELETE FROM `tbladdonmodules` WHERE `module` = 'websitepanel_addons' AND `setting` = 'password'"); + } +} + +/** + * Displays the WebsitePanel Addons module output + * + * @access public + * @return mixed + */ +function websitepanel_addons_output($params) +{ + // Delete the requested WebsitePanel addon + if (isset($_GET['action']) && $_GET['action'] == 'delete') + { + delete_query('mod_wspaddons', array('whmcs_id' => $_GET['id'])); + } + + // Add the requested WebsitePanel addon + if ($_POST && isset($_POST['action']) && $_POST['action'] == 'add') + { + // Sanity check to make sure the WHMCS addon ID exists + $results = select_query('tbladdons', 'id', array('id' => $_POST['whmcs_id'])); + if (mysql_num_rows($results) > 0) + { + $results = select_query('mod_wspaddons', 'whmcs_id', array('whmcs_id' => $_POST['whmcs_id'])); + if (mysql_num_rows($results) > 0) + { + echo '

Duplicate WHMCS Addon ID. The WHMCS Addon ID Is Assigned To Another WebsitePanel Addon.

'; + } + else + { + insert_query('mod_wspaddons', array('whmcs_id' => $_POST['whmcs_id'], 'wsp_id' => $_POST['wsp_id'], 'is_ipaddress' => $_POST['is_ipaddress'])); + } + } + else + { + echo '

WHMCS Addon Not Found! Check The ID And Try Again.

'; + } + } + + // Get all the assigned addons and display them to the user + $results = full_query('SELECT a.name AS `name`, a.id AS `whmcs_id`, w.wsp_id AS `wsp_id` FROM `tbladdons` AS a, `mod_wspaddons` AS w WHERE w.whmcs_id = a.id'); + + // Build the table / data grid + echo '
'; + echo ''; + echo ''; + if (mysql_num_rows($results) > 0) + { + while (($row = mysql_fetch_array($results)) != false) + { + echo ""; + } + } + else + { + echo ''; + } + echo '
Addon NameWHMCS IDWebsitePanel ID
{$row['name']}{$row['whmcs_id']}{$row['wsp_id']}Delete
No Addon Data Found
'; + + // Build the add addon form + echo '

Add WebsitePanel Addon

'; + echo "
"; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo '
WHMCS Addon ID
WebsitePanel Addon ID
Dedicated IP Addon
'; } \ No newline at end of file diff --git a/WebsitePanel.WHMCSModule/modules/addons/websitepanel_sync/hooks.php b/WebsitePanel.WHMCSModule/modules/addons/websitepanel_sync/hooks.php new file mode 100644 index 00000000..1f2c6077 --- /dev/null +++ b/WebsitePanel.WHMCSModule/modules/addons/websitepanel_sync/hooks.php @@ -0,0 +1,136 @@ +getUserByUsername($username); + if (empty($user)) + { + throw new Exception("User {$username} does not exist - Cannot update account details for unknown user"); + } + + // Update the user's account details using the previous details + WHMCS's details (address, city, state etc.) + $userParams = array('RoleId' => $user['RoleId'], + 'Role' => $user['Role'], + 'StatusId' => $user['StatusId'], + 'Status' => $user['Status'], + 'LoginStatusId' => $user['LoginStatusId'], + 'LoginStatus' => $user['LoginStatus'], + 'FailedLogins' => $user['FailedLogins'], + 'UserId' => $user['UserId'], + 'OwnerId' => $user['OwnerId'], + 'IsPeer' => $user['IsPeer'], + 'Created' => $user['Created'], + 'Changed' => $user['Changed'], + 'IsDemo' => $user['IsDemo'], + 'Comments' => $user['Comments'], + 'LastName' => $clientsDetails['lastname'], + 'Username' => $user['Username'], + 'Password' => $user['Password'], + 'FirstName' => $clientsDetails['firstname'], + 'Email' => $clientsDetails['email'], + 'PrimaryPhone' => $clientsDetails['phonenumber'], + 'Zip' => $clientsDetails['postcode'], + 'InstantMessenger' => '', + 'Fax' => '', + 'SecondaryPhone' => '', + 'SecondaryEmail' => '', + 'Country' => $clientsDetails['country'], + 'Address' => $clientsDetails['address1'], + 'City' => $clientsDetails['city'], + 'State' => $clientsDetails['state'], + 'HtmlMail' => $user['HtmlMail'], + 'CompanyName' => $clientsDetails['companyname'], + 'EcommerceEnabled' => $user['EcommerceEnabled'], + 'SubscriberNumber' => ''); + + // Execute the UpdateUserDetails method + $wsp->updateUserDetails($userParams); + + // Add log entry to client log + logactivity("WebsitePanel Sync - Account {$username} contact details updated successfully", $userId); + } + catch (Exception $e) + { + // Error message to log / return + $errorMessage = "websitepanel_sync_ClientEdit Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}, Service ID: {$serviceId})"; + + // Log to WHMCS + logactivity($errorMessage, $userId); + } + } +} + +/* Update Client Contact Details - WebsitePanel */ +add_hook('ClientEdit', 1, 'websitepanel_sync_ClientEdit'); \ No newline at end of file diff --git a/WebsitePanel.WHMCSModule/modules/addons/websitepanel_sync/websitepanel_sync.php b/WebsitePanel.WHMCSModule/modules/addons/websitepanel_sync/websitepanel_sync.php index 1db0d327..d9a56c4e 100644 --- a/WebsitePanel.WHMCSModule/modules/addons/websitepanel_sync/websitepanel_sync.php +++ b/WebsitePanel.WHMCSModule/modules/addons/websitepanel_sync/websitepanel_sync.php @@ -1,77 +1,73 @@ - 'WebsitePanel Sync Automation', - 'description' => 'Syncs WHMCS client details / contact changes with WebsitePanel', - 'version' => '1.2', - 'author' => 'Christopher York', - 'fields' => array('serverhost' => array('FriendlyName', 'Enterprise Server Host', 'Type' => 'text', 'Size' => 25, 'Description' => 'Enterprise Server hostname / IP address', 'Default' => '127.0.0.1'), - 'serverport' => array('FriendlyName', 'Enterprise Server Port', 'Type' => 'text', 'Size' => 4, 'Description' => 'Enterprise Server port', 'Default' => 9002), - 'serversecured' => array('FriendlyName', 'Use Secured Connection', 'Type' => 'yesno', 'Description' => 'Tick to use SSL secured connection'), - ) - ); - return $configarray; -} - -/** - * websitepanel_addons_upgrade - * - * @param $vars array - * @access public - * @return array - */ -function websitepanel_sync_upgrade($vars) -{ - - $version = $vars['version']; - - // Remove the WebsitePanel credentials - if ($version < 1.2) - { - full_query("DELETE FROM `tbladdonmodules` WHERE `module` = 'websitepanel_sync' AND `setting` = 'username'"); - full_query("DELETE FROM `tbladdonmodules` WHERE `module` = 'websitepanel_sync' AND `setting` = 'password'"); - } + 'WebsitePanel Sync Automation', + 'description' => 'Syncs WHMCS client details / contact changes with WebsitePanel accounts', + 'version' => '3.0.4', + 'author' => 'Christopher York'); +} + +/** + * Returns the WebsitePanel Sync configuration options + * + * @param $vars array WHMCS parameters + * @access public + * @return array + */ +function websitepanel_sync_upgrade($vars) +{ + // Module version + $version = $vars['version']; + + // Remove the WebsitePanel credentials + if ($version < 1.2) + { + full_query("DELETE FROM `tbladdonmodules` WHERE `module` = 'websitepanel_sync' AND `setting` = 'username'"); + full_query("DELETE FROM `tbladdonmodules` WHERE `module` = 'websitepanel_sync' AND `setting` = 'password'"); + } } \ No newline at end of file diff --git a/WebsitePanel.WHMCSModule/modules/servers/websitepanel/clientarea.tpl b/WebsitePanel.WHMCSModule/modules/servers/websitepanel/clientarea.tpl new file mode 100644 index 00000000..df6b10ec --- /dev/null +++ b/WebsitePanel.WHMCSModule/modules/servers/websitepanel/clientarea.tpl @@ -0,0 +1,2 @@ +
+
\ No newline at end of file diff --git a/WebsitePanel.WHMCSModule/modules/servers/websitepanel/enterpriseserver.php b/WebsitePanel.WHMCSModule/modules/servers/websitepanel/enterpriseserver.php new file mode 100644 index 00000000..deb693fa --- /dev/null +++ b/WebsitePanel.WHMCSModule/modules/servers/websitepanel/enterpriseserver.php @@ -0,0 +1,502 @@ +_username = $username; + $this->_password = $password; + $this->_host = $host; + $this->_port = $port; + $this->_secured = $secured; + $this->_caching = $caching; + $this->_compression = $compression; + } + + /** + * Executes the "CreateUserWizard" method + * + * @param array $params CreateUserWizard method parameters + * @throws Exception + * @return int + */ + public function createUserWizard($params) + { + try + { + return $this->execute('esPackages.asmx', 'CreateUserWizard', $params)->CreateUserWizardResult; + } + catch (Exception $e) + { + throw new Exception("ChangeUserStatus Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}", $e->getCode(), $e); + } + } + + /** + * Executes the "UpdateUser" method + * + * @access private + * @param array $params + * @throws Exception + * @return int + */ + public function updateUserDetails($params) + { + try + { + return $this->execute('esUsers.asmx', 'UpdateUser', array('user' => $params))->UpdateUserResult; + } + catch (Exception $e) + { + throw new Exception("UpdateUser Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}", $e->getCode(), $e); + } + } + + /** + * Executes the "DeleteUser" method + * + * @access public + * @param int $userId User's WebsitePanel userId + * @throws Exception + * @return int + */ + public function deleteUser($userId) + { + try + { + return $this->execute('esUsers.asmx', 'DeleteUser', array('userId' => $userId))->DeleteUserResult; + } + catch (Exception $e) + { + throw new Exception("ChangeUserStatus Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}", $e->getCode(), $e); + } + } + + /** + * Executes the "GetUserByUsername" method + * + * @access public + * @param string $username Websitepanel username + * @throws Exception + * @return array + */ + public function getUserByUsername($username) + { + try + { + return $this->convertArray($this->execute('esUsers.asmx', 'GetUserByUsername', array('username' => $username))->GetUserByUsernameResult); + } + catch (Exception $e) + { + throw new Exception("GetUserByUsername Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()})", $e->getCode(), $e); + } + } + + /** + * Executes the "ChangeUserStatus" method + * + * @access public + * @param int $userId User's WebsitePanel userId + * @param string $status Account status (Active, Suspended, Cancelled, Pending) + * @throws Exception + * @return int + */ + public function changeUserStatus($userId, $status) + { + try + { + return $this->execute('esUsers.asmx', 'ChangeUserStatus', array('userId' => $userId, 'status' => $status))->ChangeUserStatusResult; + } + catch (Exception $e) + { + throw new Exception("ChangeUserStatus Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}", $e->getCode(), $e); + } + } + + /** + * Executes the "ChangeUserPassword" method + * + * @access public + * @param int $userId User's WebsitePanel userId + * @param string $password User's new password + * @throws Exception + * @return int + */ + public function changeUserPassword($userId, $password) + { + try + { + return $this->execute('esUsers.asmx', 'ChangeUserPassword', array('userId' => $userId, 'password' => $password))->ChangeUserPasswordResult; + } + catch (Exception $e) + { + throw new Exception("ChangeUserPassword Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}", $e->getCode(), $e); + } + } + + /** + * Executes the "GetMyPackages" method + * + * @access public + * @param int $userId User's WebsitePanel userId + * @throws Exception + * @return array + */ + public function getUserPackages($userId) + { + try + { + return $this->convertArray($this->execute('esPackages.asmx', 'GetMyPackages', array('userId' => $userId))->GetMyPackagesResult->PackageInfo); + } + catch (Exception $e) + { + throw new Exception("GetMyPackages Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}", $e->getCode(), $e); + } + } + + /** + * Executes the "GetUsersPagedRecursive" method + * + * @access public + * @param unknown $userId Users's WebsitePanel userId + * @param unknown $filterColumn Column value to filter against + * @param unknown $filterValue Filter value + * @param unknown $statusId Users's account status id + * @param unknown $roleId User's account role id + * @param unknown $sortColumn Column value to sort against + * @param number $startRow Start value + * @param string $maximumRows Maximum rows to return + * @throws Exception + * @return object + */ + public function getUsersPagedRecursive($userId, $filterColumn, $filterValue, $statusId, $roleId, $sortColumn, $startRow = 0, $maximumRows = PHP_INT_MAX) + { + try + { + $result = (array)$this->execute('esUsers.asmx', 'GetUsersPagedRecursive', array('userId' => $userId, 'filterColumn' => $filterColumn, 'filterValue' => $filterValue, 'statusId' => $statusId, 'roleId' => $roleId, 'sortColumn' => $sortColumn, 'startRow' => $startRow, 'maximumRows' => $maximumRows))->GetUsersPagedRecursiveResult; + return $this->convertArray($result['any'], TRUE); + } + catch (Exception $e) + { + throw new Exception("GetUsersPagedRecursive Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}", $e->getCode(), $e); + } + } + + /** + * Executes the "UpdatePackageLiteral" method + * + * @access public + * @param int $packageId Package's WebsitePanel packageId + * @param int $statusId Package's status id + * @param int $planId Package's WebsitePanel planid + * @param string $purchaseDate Package's purchase date + * @param string $packageName Package's name + * @param string $packageComments Package's comments + * @throws Exception + * @return array + */ + public function updatePackageLiteral($packageId, $statusId, $planId, $purchaseDate, $packageName, $packageComments) + { + try + { + return $this->convertArray($this->execute('esPackages.asmx', 'UpdatePackageLiteral', array('packageId' => $packageId, 'statusId' => $statusId, 'planId' => $planId, 'purchaseDate' => $purchaseDate, 'packageName' => $packageName, 'packageComments' => $packageComments))->UpdatePackageLiteralResult); + } + catch (Exception $e) + { + throw new Exception("UpdatePackageLiteral Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}", $e->getCode(), $e); + } + } + + /** + * Executes the "AddPackageAddonById" method + * + * @access public + * @param unknown $packageId WebsitePanel package Id + * @param unknown $addonPlanId WebsitePanel addon id + * @param number $quantity Number of addons to add :) + * @throws Exception + * @return array + */ + public function addPackageAddonById($packageId, $addonPlanId, $quantity = 1) + { + try + { + return $this->convertArray($this->execute('esPackages.asmx', 'AddPackageAddonById', array('packageId' => $packageId, 'addonPlanId' => $addonPlanId, 'quantity' => $quantity))->AddPackageAddonByIdResult); + } + catch (Exception $e) + { + throw new Exception("AddPackageAddonById Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}", $e->getCode(), $e); + } + } + + /** + * Executes the "GetPackageBandwidth" method + * + * @access public + * @param unknown $packageId WebsitePanel package id + * @param unknown $startDate Calculation start date + * @param unknown $endDate Calculation end date + * @throws Exception + * @return object + */ + public function getPackageBandwidthUsage($packageId, $startDate, $endDate) + { + try + { + $result = (array)$this->execute('esPackages.asmx', 'GetPackageBandwidth', array('packageId' => $packageId, 'startDate' => $startDate, 'endDate' => $endDate))->GetPackageBandwidthResult; + return $this->convertArray($result['any'], TRUE); + } + catch (Exception $e) + { + throw new Exception("GetPackageBandwidth Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}", $e->getCode(), $e); + } + } + + /** + * Executes the "GetPackageDiskspace" method + * + * @access public + * @param unknown $packageId WebsitePanel package id + * @throws Exception + * @return object + */ + public function getPackageDiskspaceUsage($packageId) + { + try + { + $result = (array)$this->execute('esPackages.asmx', 'GetPackageDiskspace', array('packageId' => $packageId))->GetPackageDiskspaceResult; + return $this->convertArray($result['any'], TRUE); + } + catch (Exception $e) + { + throw new Exception("GetPackageDiskspace Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}", $e->getCode(), $e); + } + } + + /** + * Executes the "AllocatePackageIPAddresses" method + * + * @access public + * @param int $packageId WebsitePanel package id + * @param string $groupName WebsitePanel IP address group name + * @param string $pool WebsitePanel IP address pool + * @param int $addressesNumber Number of IP addresses to allocate + * @param string $allocateRandom Allocate randomly + * @throws Exception + * @return object + */ + public function allocatePackageIPAddresses($packageId, $groupName = 'Web', $pool = 'WebSites', $addressesNumber = 1, $allocateRandom = TRUE) + { + try + { + return $this->convertArray($this->execute('esServers.asmx', 'AllocatePackageIPAddresses', array('packageId' => $packageId, 'groupName' => $groupName, 'pool' => $pool, 'addressesNumber' => $addressesNumber, 'allocateRandom' => $allocateRandom))->AllocatePackageIPAddressesResult); + } + catch (Exception $e) + { + throw new Exception("AllocatePackageIPAddresses Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}", $e->getCode(), $e); + } + } + + /** + * Converts the WebsitePanel error code to a friendly human-readable message + * + * @access public + * @param int $code WebsitePanel error code + * @return string + */ + public static function getFriendlyError($code) + { + $errors = array(-100 => 'Username not available, already in use', + -101 => 'Username not found, invalid username', + -102 => 'User\'s account has child accounts', + -300 => 'Hosting package could not be found', + -301 => 'Hosting package has child hosting spaces', + -501 => 'The sub-domain belongs to an existing hosting space that does not allow sub-domains to be created', + -502 => 'The domain or sub-domain exists in another hosting space / user account', + -511 => 'Instant alias is enabled, but not configured', + -601 => 'The website already exists on the target hosting space or server', + -700 => 'The email domain already exists on the target hosting space or server', + -1100 => 'User already exists'); + + // Find the error and return it, else a general error will do! + if (array_key_exists($code, $errors)) + { + return $errors[$code]; + } + else + { + return "An unknown error occured (Code: {$code}). Please reference WebsitePanel BusinessErrorCodes for further information"; + } + } + + /** + * Executes the request on the Enterprise Server and returns the results + * + * @param unknown $service + * @param unknown $method + * @param unknown $params + * @throws Exception + */ + private function execute($service, $method, $params) + { + // Set the Enterprise Server full URL + $host = (($this->_secured) ? 'https' : 'http') . "://{$this->_host}:{$this->_port}/{$service}?WSDL"; + try + { + // Create the SoapClient + $client = new SoapClient($host, array('login' => $this->_username, 'password' => $this->_password, 'compression' => (($this->_compression) ? (SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP) : ''), 'cache_wsdl' => ($this->_caching) ? 1 : 0)); + + // Execute the request and process the results + return call_user_func(array($client, $method), $params); + } + catch (SoapFault $e) + { + throw new Exception("SOAP Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()})"); + } + catch (Exception $e) + { + throw new Exception("General Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()})"); + } + } + + /** + * Converts an object or an XML string to an array + * + * @access private + * @param mixed $value Object or an XML string + * @param boolean $loadXml Loads the string into the SimpleXML object + * @return array + */ + private function convertArray($value, $loadXml = FALSE) + { + // This is silly, but it works, and it works very well for what we are doing :) + return json_decode(json_encode(($loadXml ? simplexml_load_string($value) : $value)), TRUE); + } +} \ No newline at end of file diff --git a/WebsitePanel.WHMCSModule/modules/servers/websitepanel/functions.php b/WebsitePanel.WHMCSModule/modules/servers/websitepanel/functions.php new file mode 100644 index 00000000..8afd5a84 --- /dev/null +++ b/WebsitePanel.WHMCSModule/modules/servers/websitepanel/functions.php @@ -0,0 +1,146 @@ + (int)$_SESSION['adminid'])); + $results = mysql_fetch_assoc($result); + $selectedLanguage = !empty($results['language']) ? $results['language'] : 'english'; + } + + // Load the language file + $languageFile = dirname(__FILE__) . "/lang/{$selectedLanguage}.php"; + if (file_exists($languageFile)) + { + require_once($languageFile); + } + else + { + // Load the default (English) language file + require_once(dirname(__FILE__) . '/lang/english.php'); + } + + // Process the module language entries + if (is_array($_MOD_LANG)) + { + foreach ($_MOD_LANG as $key => $value) + { + if (empty($_LANG[$key])) + { + $_LANG[$key] = $value; + } + } + } + + // Add to the template + if (isset($smarty)) + { + $smarty->assign('LANG', $_LANG); + } + + return $_MOD_LANG; +} \ No newline at end of file diff --git a/WebsitePanel.WHMCSModule/modules/servers/websitepanel/websitepanel.errorcodes.php b/WebsitePanel.WHMCSModule/modules/servers/websitepanel/lang/english.php similarity index 57% rename from WebsitePanel.WHMCSModule/modules/servers/websitepanel/websitepanel.errorcodes.php rename to WebsitePanel.WHMCSModule/modules/servers/websitepanel/lang/english.php index 5bde4a57..6d4d1809 100644 --- a/WebsitePanel.WHMCSModule/modules/servers/websitepanel/websitepanel.errorcodes.php +++ b/WebsitePanel.WHMCSModule/modules/servers/websitepanel/lang/english.php @@ -1,60 +1,42 @@ - 'User already exists', - -101 => 'User not found', - -102 => 'User has child user accounts', - -300 => 'Hosting package could not be found', - -301 => 'Hosting package has child hosting spaces', - -501 => 'The sub-domain belongs to an existing hosting space that does not allow sub-domains to be created', - -502 => 'The domain or sub-domain exists within another hosting space', - -511 => 'Instant alias is enabled, but not configured', - -601 => 'The website already exists on the target hosting space', - -700 => 'The email domain already exists on the target hosting space', - -1100 => 'User already exists'); - return $esErrorCodes; -} \ No newline at end of file +_esUsername = $esUsername; - $this->_esPassword = $esPassword; - $this->_esServerUrl = $esServerUrl; - $this->_esServerPort = $esServerPort; - $this->_esUseSsl = $useSsl; - } - - /** - * WebsitePanel::CreateAccount() - * - * @param string $username Account username - * @param string $password Account password - * @param string $roleId Account role id - * @param string $firstName Account holders firstname - * @param string $lastName Account holders lastname - * @param string $email Account holders email address - * @param string $planId WebsitePanel plan id - * @param integer $parentPackageId Parent space / package id - * @param string $domainName Account domain name - * @param string $hostName Website hostname (if createWebsite is TRUE) - * @param bool $htmlMail Send HTML email - * @param bool $sendAccountLetter Send WebsitePanel "Account Summary" letter - * @param bool $sendPackageLetter Send WebsitePanel "Hosting Space Summary" letter - * @param bool $createPackage Create hostingspace / package on user creation - * @param bool $tempDomain Create temporary domain on hostingspace / package creation - * @param bool $createWebSite Create Website on hostingspace / package creation - * @param bool $createFtpAccount Create FTP account on hostingspace / package creation - * @param string $ftpAcountName FTP account name to create (if createFtpAccount is TRUE) - * @param bool $createMailAccount Create default mail account on hostingspace / package creation - * @param bool $createZoneRecord Create domain DNS zone record (if createMailAccount OR createWebSite are TRUE) - * @return int - */ - public function createUserWizard($username, $password, $roleId, $firstName, $lastName, $email, $planId, $parentPackageId, $domainName, $hostName, $htmlMail = TRUE, $sendAccountLetter = TRUE, $sendPackageLetter = TRUE, $createPackage = TRUE, $tempDomain = FALSE, $createWebSite = FALSE, $createFtpAccount = FALSE, $ftpAcountName = '', $createMailAccount = FALSE, $createZoneRecord = FALSE) - { - $params = array(); - foreach (get_defined_vars() as $key => $value) - { - if ($key == 'params') - continue; - - $params[$key] = $value; - } - return $this->executeServerMethod(WebsitePanel::SERVICEFILE_PACKAGES, 'CreateUserWizard', $params)->CreateUserWizardResult; - } - - /** - * WebsitePanel::UpdateUserDetails() - * - * @access public - * @param int $RoleId Account role id - * @param string $Role Account role - * @param int $StatusId Account status id - * @param string $Status Account status - * @param int $UserId Account user id - * @param int $OwnerId Account owner id - * @param string $Created Account creation date - * @param string $Changed Account changed date - * @param bool $IsDemo Demo account - * @param bool $IsPeer Peer account - * @param string $Comments Account comments - * @param string $Username Account username - * @param string $Password Account password - * @param string $FirstName Account holders firstname - * @param string $LastName Account holders lastname - * @param string $Email Account holders email address - * @param string $PrimaryPhone Account holders phone number - * @param string $Zip Account holders postal code - * @param string $InstantMessenger Account holders IM - * @param string $Fax Account holders fax number - * @param string $SecondaryPhone Account holders secondary phone number - * @param string $SecondaryEmail Account holders secondary email - * @param string $Country Account holders country - * @param string $Address Account holders physical address - * @param string $City Account holders city - * @param string $State Account holders state - * @param bool $HtmlMail Send HTML email - * @param string $CompanyName Account holders Company name - * @param bool $EcommerceEnabled Ecommerce enabled - * @return void - */ - public function updateUserDetails($RoleId, $Role, $StatusId, $Status, $LoginStatusId, $LoginStatus, $FailedLogins, $UserId, $OwnerId, $Created, $Changed, $IsDemo, $IsPeer, $Comments, $Username, $Password, $FirstName, $LastName, $Email, $PrimaryPhone, $Zip, $InstantMessenger, $Fax, $SecondaryPhone, $SecondaryEmail, $Country, $Address, $City, $State, $HtmlMail, $CompanyName, $EcommerceEnabled) - { - $params = array(); - foreach (get_defined_vars() as $key => $value) - { - if ($key == 'params') - continue; - - $params[$key] = $value; - } - return $this->executeServerMethod(WebsitePanel::SERVICEFILE_USERS, 'UpdateUser', array('user' => $params))->UpdateUserResult; - } - - /** - * WebsitePanel::DeleteUser() - * - * @access public - * @param int $userid User id - * @return int - */ - public function deleteUser($userId) - { - return $this->executeServerMethod(WebsitePanel::SERVICEFILE_USERS, 'DeleteUser', array('userId' => $userId))->DeleteUserResult; - } - - /** - * WebsitePanel::GetUserByUsername() - * - * @access public - * @param string $username Username - * @return array - */ - public function getUserByUsername($username) - { - return (array)$this->executeServerMethod(WebsitePanel::SERVICEFILE_USERS, 'GetUserByUsername', array('username' => $username))->GetUserByUsernameResult; - } - - /** - * WebsitePanel::ChangeUserStatus() - * - * @param int $userId User id - * @param string $status Account status (Active, Suspended, Cancelled, Pending) - * @return int - */ - public function changeUserStatus($userId, $status) - { - return $this->executeServerMethod(WebsitePanel::SERVICEFILE_USERS, 'ChangeUserStatus', array('userId' => $userId, 'status' => $status))->ChangeUserStatusResult; - } - - /** - * WebsitePanel::ChangeUserPassword() - * - * @access public - * @param int $userId User id - * @param string $password New password - * @return int - */ - public function changeUserPassword($userId, $password) - { - return $this->executeServerMethod(WebsitePanel::SERVICEFILE_USERS, 'ChangeUserPassword', array('userId' => $userId, 'password' => $password))->ChangeUserPasswordResult; - } - - /** - * WebsitePanel::GetUserPackages() - * - * @access public - * @param int $userid User id - * @return array - */ - public function getUserPackages($userid) - { - return (array)$this->executeServerMethod(WebsitePanel::SERVICEFILE_PACKAGES, 'GetMyPackages', array('userId' => $userid))->GetMyPackagesResult->PackageInfo; - } - - /** - * WebsitePanel::getUsersPagedRecursive() - * - * @param int $userId User id - * @param string $filterColumn Column name to filter on - * @param string $filterValue Filter value - * @param int $statusId Status id - * @param int $roleId Role id - * @param string $sortColumn Column name to sort on - * @param int $startRow Row to start at - * @param int $maximumRows Maximum rows to return - */ - public function getUsersPagedRecursive($userId, $filterColumn, $filterValue, $statusId, $roleId, $sortColumn, $startRow = 0, $maximumRows = 999) - { - $params = array(); - foreach (get_defined_vars() as $key => $value) - { - if ($key == 'params') - continue; - - $params[$key] = $value; - } - return $this->executeServerMethod(WebSitePanel::SERVICEFILE_USERS, 'GetUsersPagedRecursive', $params)->GetUsersPagedRecursiveResult; - } - - /** - * WebsitePanel::UpdatePackageLiteral() - * - * @access public - * @param int $packageId Package id - * @param int $statusId Status id - * @param int $planId Plan id - * @param string $purchaseDate Purchase date - * @param string $packageName Package name - * @param string $packageComments Package comments - * @return array - */ - public function updatePackageLiteral($packageId, $statusId, $planId, $purchaseDate, $packageName, $packageComments) - { - $params = array(); - foreach (get_defined_vars() as $key => $value) - { - if ($key == 'params') - continue; - - $params[$key] = $value; - } - return (array)$this->executeServerMethod(WebsitePanel::SERVICEFILE_PACKAGES, 'UpdatePackageLiteral', $params)->UpdatePackageLiteralResult; - } - - /** - * WebsitePanel::addPackageAddonById() - * - * @access public - * @param mixed $packageId Package id - * @param mixed $addonPlanId Addon plan od - * @param integer $quantity Quantity - * @return array - */ - public function addPackageAddonById($packageId, $addonPlanId, $quantity = 1) - { - return (array)$this->executeServerMethod(WebsitePanel::SERVICEFILE_PACKAGES, 'AddPackageAddonById', array('packageId' => $packageId, 'addonPlanId' => $addonPlanId, 'quantity' => $quantity))->AddPackageAddonByIdResult; - } - - /** - * WebsitePanel::GetSpaceBandwidthUsage() - * - * @access public - * @param int $packageId Package id - * @param string $startDate Start date - * @param string $endDate Ending date - * @return object - */ - public function getSpaceBandwidthUsage($packageId, $startDate, $endDate) - { - return $this->executeServerMethod(WebsitePanel::SERVICEFILE_PACKAGES, 'GetPackageBandwidth', array('packageId' => $packageId, 'startDate' => $startDate, 'endDate' => $endDate))->GetPackageBandwidthResult; - } - - /** - * WebsitePanel::GetSpaceDiskspaceUsage() - * - * @access private - * @param int $packageId Package Id - * @return object - */ - public function getSpaceDiskspaceUsage($packageId) - { - return $this->executeServerMethod(WebsitePanel::SERVICEFILE_PACKAGES, 'GetPackageDiskspace', array('packageId' => $packageId))->GetPackageDiskspaceResult; - } - - /** - * WebsitePanel::packageAllocateIpAddress() - * - * @param mixed $packageId Package id - * @param mixed $groupName Group name - * @param mixed $pool Address pool - * @param integer $addressesNumber Number of IP addresses - * @param bool $allocateRandom Allocate IP addresses randomly - * @return object - */ - public function packageAllocateIpAddress($packageId, $groupName = WebsitePanel::IPADDRESS_POOL_WEB, $pool = WebsitePanel::IPADDRESS_GROUP_WEBSITES, $addressesNumber = 1, $allocateRandom = TRUE) - { - $params = array(); - foreach (get_defined_vars() as $key => $value) - { - if ($key == 'params') - continue; - - $params[$key] = $value; - } - return $this->executeServerMethod(WebsitePanel::SERVICEFILE_SERVERS, 'AllocatePackageIPAddresses', $params)->AllocatePackageIPAddressesResult; - } - - /** - * Executes the requested Enterprise Server method / parameters and returns the results - * - * @access private - * @param string $serviceFile Enterprise Server service filename - * @param string $serviceMethod Enterprise Server service method name - * @param array $methodParameters Method parameters - * @throws Exception - * @return object - */ - private function executeServerMethod($serviceFile, $serviceMethod, $methodParameters = array()) - { - $esUrl = (($this->_esUseSsl ? "https" : "http") . "://{$this->_esServerUrl}:{$this->_esServerPort}/{$serviceFile}?WSDL"); - $soapParams = array('login' => $this->_esUsername, - 'password' => $this->_esPassword, - 'cache_wsdl' => WSDL_CACHE_NONE // WSDL caching is an annoying nightmare - we will disable it - ); - try - { - $client = new SoapClient($esUrl, $soapParams); - $result = $client->$serviceMethod($methodParameters); - if (is_soap_fault($result)) - { - throw new Exception($result->faultstring); - } - return $result; - } - catch (Exception $e) - { - throw new Exception($e->getMessage()); - } - } -} \ No newline at end of file diff --git a/WebsitePanel.WHMCSModule/modules/servers/websitepanel/websitepanel.functions.php b/WebsitePanel.WHMCSModule/modules/servers/websitepanel/websitepanel.functions.php deleted file mode 100644 index 32e0eb6b..00000000 --- a/WebsitePanel.WHMCSModule/modules/servers/websitepanel/websitepanel.functions.php +++ /dev/null @@ -1,197 +0,0 @@ -getSpaceBandwidthUsage($packageId, $startDate, date('Y-m-d', time())); - return websitepanel_CalculateUsage($result, WebsitePanel::USAGE_BANDWIDTH); - } - catch (Exception $e) - { - // Do nothing, just catch the Exception to keep PHP from exploding :) - } -} - -/** - * websitepanel_CalculateDiskspaceUsage() - * - * @access public - * @param mixed $params - * @param mixed $packageId - * @return int - */ -function websitepanel_CalculateDiskspaceUsage($params, $packageId) -{ - // Create the ASPnix websitepanel_EnterpriseServer class object - $wsp = new WebsitePanel($params['serverusername'], $params['serverpassword'], $params['serverip'], $params['configoption6'], $params['serversecure']); - - try - { - $result = $wsp->getSpaceDiskspaceUsage($packageId); - return websitepanel_CalculateUsage($result, WebsitePanel::USAGE_DISKSPACE); - } - catch (Exception $e) - { - // Do nothing, just catch the Exception to keep PHP from exploding :) - } -} - -/** - * websitepanel_CalculateUsage() - * - * @access public - * @param mixed $result - * @param int $usageType - * @return int - */ -function websitepanel_CalculateUsage($result, $usageType) -{ - // Process results - $xml = simplexml_load_string($result->any); - $total = 0; - if (count($xml->NewDataSet->Table) > 0) - { - foreach ($xml->NewDataSet->Table as $table) - { - switch ($usageType) - { - case WebsitePanel::USAGE_BANDWIDTH: - $total = $total + $table[0]->MegaBytesTotal; - break; - - case WebsitePanel::USAGE_DISKSPACE: - $total = $total + $table[0]->Diskspace; - break; - - default: - $total = $total + $table[0]->MegaBytesTotal; - break; - } - } - } - return $total; -} - -/** - * websitepanel_GetServerSettings - * - * @access public - * @return array - */ -function websitepanel_GetServerSettings() -{ - $settings = array('username' => '', 'password' => ''); - - // Retrieve the settings from the modules configuration table - $results = select_query('tblservers', 'username,password', array('type' => 'websitepanel')); - if (mysql_num_rows($results) != 0) - { - $row = mysql_fetch_array($results, MYSQL_ASSOC); - $settings['username'] = $row['username']; - $settings['password'] = decrypt($row['password']); - } - return $settings; -} \ No newline at end of file diff --git a/WebsitePanel.WHMCSModule/modules/servers/websitepanel/websitepanel.php b/WebsitePanel.WHMCSModule/modules/servers/websitepanel/websitepanel.php index f322d709..a3ef3fda 100644 --- a/WebsitePanel.WHMCSModule/modules/servers/websitepanel/websitepanel.php +++ b/WebsitePanel.WHMCSModule/modules/servers/websitepanel/websitepanel.php @@ -1,465 +1,702 @@ - array( 'Type' => 'text', 'Size' => 25, 'Description' => 'Package Name'), - 'Web Space Quota' => array( 'Type' => 'text', 'Size' => 5, 'Description' => 'MB'), - 'Bandwidth Limit' => array( 'Type' => 'text', 'Size' => 5, 'Description' => 'MB'), - 'Plan ID' => array( 'Type' => 'text', 'Size' => 4, 'Description' => 'WebsitePanel hosting plan id'), - 'Parent Space ID' => array( 'Type' => 'text', 'Size' => 3, 'Description' => '* SpaceID that all accounts are created under', 'Default' => 1), - 'Enterprise Server Port' => array( 'Type' => 'text', 'Size' => 5, 'Description' => '* Required', 'Default' => 9002), - 'Different Potal URL' => array( 'Type' => 'yesno', 'Description' => 'Tick if portal address is different to server address'), - 'Portal URL' => array( 'Type' => 'text', 'Size' => 25, 'Description' => 'Portal URL, with http://, no trailing slash' ), - 'Send Account Summary Email' => array( 'Type' => 'yesno', 'Description' => 'Tick to send the "Account Summary" letter' ), - 'Send Hosting Space Summary Email' => array( 'Type' => 'yesno', 'Description' => 'Tick to send the "Hosting Space Summary" letter'), - 'Create Mail Account' => array( 'Type' => 'yesno', 'Description' => 'Tick to create mail account' ), - 'Create FTP Account' => array( 'Type' => 'yesno', 'Description' => 'Tick to create FTP account' ), - 'Create Temporary Domain' => array( 'Type' => 'yesno', 'Description' => 'Tick to create a temporary domain' ), - 'Send HTML Email' => array( 'Type' => 'yesno', 'Description' => 'Tick enable HTML email from WebsitePanel' ), - 'Create Website' => array( 'Type' => 'yesno', 'Description' => 'Tick to create Website' ), - 'Count Bandwidth / Diskspace' => array( 'Type' => 'yesno', 'Description' => 'Tick to update diskpace / bandwidth in WHMCS'), - 'Default Pointer' => array( 'Type' => 'text', 'Size' => 25, 'Description' => 'The default pointer (hostname) to use when creating a Website' ), - 'Create DNS Zone' => array( 'Type' => 'yesno', 'Description' => 'Tick to create domain DNS zone' ) - ); - return $configarray; -} - -/** - * websitepanel_CreateAccount() - * - * @access public - * @param array $params - * @return string - */ -function websitepanel_CreateAccount($params) -{ - // Create the WebsitePanel object instance - $wsp = new WebsitePanel($params['serverusername'], $params['serverpassword'], $params['serverip'], $params['configoption6'], $params['serversecure']); - - // WHMCS server parameters & package parameters - $username = $params['username']; - $password = $params['password']; - $accountId = $params['accountid']; - $packageId = $params['packageid']; - $domain = $params['domain']; - $packageType = $params['type']; - $clientsDetails = $params['clientsdetails']; - - // WebsitePanel API parameters - $planId = $params['configoption4']; - $parentPackageId = $params['configoption5']; - $roleId = ($packageType == 'reselleraccount') ? 2 : 3; - $htmlMail = ($params['configoption14'] == 'on') ? TRUE : FALSE; - $sendAccountLetter = ($params['configoption9'] == 'on') ? TRUE : FALSE; - $sendPackageLetter = ($params['configoption10'] == 'on') ? TRUE : FALSE; - $createMailAccount = ($params['configoption11'] == 'on') ? TRUE : FALSE; - $createTempDomain = ($params['configoption13'] == 'on') ? TRUE : FALSE; - $createFtpAccount = ($params['configoption12'] == 'on') ? TRUE : FALSE; - $createWebsite = ($params['configoption15'] == 'on') ? TRUE : FALSE; - $websitePointerName = $params['configoption17']; - $createZoneRecord = ($params['configoption18'] == 'on') ? TRUE : FALSE; - - try - { - // Attempt to create the WSP user account and his / her package / hosting space - $result = $wsp->createUserWizard($username, $password, $roleId, $clientsDetails['firstname'], $clientsDetails['lastname'], $clientsDetails['email'], $planId, $parentPackageId, $domain, $websitePointerName, $htmlMail, $sendAccountLetter, $sendPackageLetter, TRUE, $createTempDomain, $createWebsite, $createFtpAccount, $username, $createMailAccount, $createZoneRecord); - if ($result >= 0) - { - // Grab the user's details from WebsitePanel - $user = $wsp->getUserByUsername($username); - - // Update the user's account with his / her WHMCS contact details - $wsp->updateUserDetails($user['RoleId'], $user['Role'], $user['StatusId'], $user['Status'], $user['LoginStatusId'], $user['LoginStatus'], $user['FailedLogins'], $user['UserId'], $user['OwnerId'], $user['Created'], $user['Changed'], $user['IsDemo'], $user['IsPeer'], $user['Comments'], $username, $password, $clientsDetails['firstname'], $clientsDetails['lastname'], $clientsDetails['email'], $clientsDetails['phonenumber'], $clientsDetails['postcode'], '', '', '', '', $clientsDetails['country'], $clientsDetails['address1'], $clientsDetails['city'], $clientsDetails['state'], $htmlMail, $clientsDetails['companyname'], (($roleId == 2) ? TRUE : FALSE)); - - // Success - Alert WHMCS - return 'success'; - } - else - { - // Failed - Alert WHMCS of the returned Enterprise Server error code - return websitepanel_GetErrorMessage($result); - } - } - catch (Exception $e) - { - return $e->getMessage(); - } -} - -/** - * websitepanel_TerminateAccount() - * - * @access public - * @param array $params - * @return string - */ -function websitepanel_TerminateAccount($params) -{ - // Create the WebsitePanel object instance - $wsp = new WebsitePanel($params['serverusername'], $params['serverpassword'], $params['serverip'], $params['configoption6'], $params['serversecure']); - - // WHMCS server parameters & package parameters - $username = $params['username']; - - try - { - // Grab the user's details from WebsitePanel in order to get the user's id - $user = $wsp->getUserByUsername($username); - if (empty($user)) - { - return "The specified user {$username} does not exist"; - } - else - { - // Attempt to delete the users account and package / hosting space - $result = $wsp->deleteUser($user['UserId']); - if ($result >= 0) - { - // Success - Alert WHMCS - return 'success'; - } - else - { - // Failed - Alert WHMCS of the returned Enterprise Server error code - return websitepanel_GetErrorMessage($result); - } - } - } - catch (Exception $e) - { - return $e->getMessage(); - } -} - -/** - * websitepanel_SuspendAccount() - * - * @access public - * @param array $params - * @return string - */ -function websitepanel_SuspendAccount($params) -{ - // Create the WebsitePanel object instance - $wsp = new WebsitePanel($params['serverusername'], $params['serverpassword'], $params['serverip'], $params['configoption6'], $params['serversecure']); - - // WHMCS server parameters & package parameters - $username = $params['username']; - - try - { - // Grab the user's details from WebsitePanel in order to get the user's id - $user = $wsp->getUserByUsername($username); - if (empty($user)) - { - return "The specified user {$username} does not exist"; - } - else - { - // Attempt to suspend the users account and package / hosting space - $result = $wsp->changeUserStatus($user['UserId'], WebsitePanel::USERSTATUS_SUSPENDED); - if ($result >= 0) - { - // Success - Alert WHMCS - return 'success'; - } - else - { - // Failed - Alert WHMCS of the returned Enterprise Server error code - return websitepanel_GetErrorMessage($result); - } - } - } - catch (Exception $e) - { - return $e->getMessage(); - } -} - -/** - * websitepanel_UnsuspendAccount() - * - * @access public - * @param array $params - * @return string - */ -function websitepanel_UnsuspendAccount($params) -{ - // Create the WebsitePanel object instance - $wsp = new WebsitePanel($params['serverusername'], $params['serverpassword'], $params['serverip'], $params['configoption6'], $params['serversecure']); - - // WHMCS server parameters & package parameters - $username = $params['username']; - - try - { - // Grab the user's details from WebsitePanel in order to get the user's id - $user = $wsp->getUserByUsername($username); - if (empty($user)) - { - return "The specified user {$username} does not exist"; - } - else - { - // Attempt to activate the users account and package / hosting space - $result = $wsp->changeUserStatus($user['UserId'], WebsitePanel::USERSTATUS_ACTIVE); - if ($result >= 0) - { - // Success - Alert WHMCS - return 'success'; - } - else - { - // Failed - Alert WHMCS of the returned Enterprise Server error code - return websitepanel_GetErrorMessage($result); - } - } - } - catch (Exception $e) - { - return $e->getMessage(); - } -} - -/** - * websitepanel_ChangePassword() - * - * @access public - * @param array $params - * @return int - */ -function websitepanel_ChangePassword($params) -{ - // Create the WebsitePanel object instance - $wsp = new WebsitePanel($params['serverusername'], $params['serverpassword'], $params['serverip'], $params['configoption6'], $params['serversecure']); - - // WHMCS server parameters & package parameters - $serviceId = $params['serviceid']; - $username = $params['username']; - $password = $params['password']; - $userId = $params['clientsdetails']['userid']; - - try - { - // Grab the user's details from WebsitePanel in order to get the user's id - $user = $wsp->getUserByUsername($username); - if (empty($user)) - { - return "The specified user {$username} does not exist"; - } - else - { - // Attempt to change the user's account password - $result = $wsp->changeUserPassword($user['UserId'], $password); - if ($result >= 0) - { - // Log this action for logging / tracking purposes incase the client complains we have record of what went on and why - logActivity("Control Panel Password Updated - Service ID: {$serviceId}", $userId); - - // Success - Alert WHMCS - return 'success'; - } - else - { - // Failed - Alert WHMCS of the returned Enterprise Server error code - return websitepanel_GetErrorMessage($result); - } - } - } - catch (Exception $e) - { - return $e->getMessage(); - } -} - -/** - * websitepanel_ChangePackage() - * - * @access public - * @param array $params - * @return string - */ -function websitepanel_ChangePackage($params) -{ - // Create the WebsitePanel object instance - $wsp = new WebsitePanel($params['serverusername'], $params['serverpassword'], $params['serverip'], $params['configoption6'], $params['serversecure']); - - // WHMCS server parameters & package parameters - $username = $params['username']; - - // WebsitePanel API parameters - $planId = $params['configoption4']; - $packageName = $params['configoption1']; - - try - { - // Grab the user's details from WebsitePanel in order to get the user's id - $user = $wsp->getUserByUsername($username); - if (empty($user)) - { - return "The specified user {$username} does not exist"; - } - else - { - // Get the user's current WebsitePanel hosting space Id (Hosting Plan) - $package = $wsp->getUserPackages($user['UserId']); - $packageId = $package['PackageId']; - - // Update the user's package - $result = $wsp->updatePackageLiteral($packageId, $package['StatusId'], $planId, $package['PurchaseDate'], $packageName, ''); - $result = $result['Result']; - if ($result >= 0) - { - // Success - Alert WHMCS - return 'success'; - } - else - { - // Failed - Alert WHMCS of the returned Enterprise Server error code - return websitepanel_GetErrorMessage($result); - } - } - } - catch (Exception $e) - { - return $e->getMessage(); - } -} - -/** - * websitepanel_LoginLink() - * - * @access public - * @param array $params - * @return string - */ -function websitepanel_LoginLink($params) -{ - echo "Login to Control Panel (One-Click Login)"; -} - -/** - * websitepanel_ClientArea() - * - * @access public - * @param array $params - * @return string - */ -function websitepanel_ClientArea($params) -{ - return "Login to Control Panel (One-Click Login)"; -} - -/** - * websitepanel_UsageUpdate() - * - * @access public - * @param array $params - * @return void - */ -function websitepanel_UsageUpdate($params) -{ - // WHMCS server parameters & package parameters - $serverid = $params['serverid']; - $serverip = $params['serverip']; - - // Query for all active or suspended users under the specified server - $query = full_query("SELECT `username`, `packageid`, `regdate` FROM `tblhosting` WHERE `server` = {$serverid} AND `domainstatus` IN ('Active', 'Suspended') AND `username` <> ''"); - while (($row = mysql_fetch_array($query)) != false) - { - try - { - // Start processing the specified users usage - $username = $row['username']; - $packageId = $row['packageid']; - - // Get the packages ConfigOptions - $packageQuery = select_query('tblproducts', 'configoption2,configoption3,configoption6,configoption16', array('id' => $packageId, 'configoption16' => 'on')); - $cfgOptions = mysql_fetch_array($packageQuery); - $params['configoption6'] = $cfgOptions['configoption6']; - - // Diskspace and Bandwidth limits for this package - $diskLimit = $cfgOptions['configoption2']; - $bwidthLimit = $cfgOptions['configoption3']; - - // Create the WebsitePanel object instance - $wsp = new WebsitePanel($params['serverusername'], $params['serverpassword'], $serverip, $params['configoption6'], $params['serversecure']); - - // Get the specified user details - // Get the Package id of the user's package - $user = $wsp->getUserByUsername($username); - $package = $wsp->getUserPackages($user['UserId']); - - // Gather the bandwidth / diskspace usage stats - $bandwidthUsage = websitepanel_CalculateBandwidthUsage($params, $package['PackageId'], websitepanel_CreateBandwidthDate($row['regdate'])); - $diskSpaceUsage = websitepanel_CalculateDiskspaceUsage($params, $package['PackageId']); - - // Update the package details - update_query('tblhosting', array('diskusage' => $diskSpaceUsage, 'disklimit' => $diskLimit, 'bwusage' => $bandwidthUsage, 'bwlimit' => $bwidthLimit, 'lastupdate' => date('Y-m-d H:i:s')), array('username' => $username, 'server' => $serverid)); - } - catch (Exception $e) - { - // Nothing - } - } + array( 'Type' => 'text', 'Size' => 25, 'Description' => 'Package Name'), + 'Web Space Quota' => array( 'Type' => 'text', 'Size' => 5, 'Description' => 'MB'), + 'Bandwidth Limit' => array( 'Type' => 'text', 'Size' => 5, 'Description' => 'MB'), + 'WebsitePanel Plan ID' => array( 'Type' => 'text', 'Size' => 4, 'Description' => 'WebsitePanel hosting plan id'), + 'Parent Space ID' => array( 'Type' => 'text', 'Size' => 3, 'Description' => '* SpaceID that all accounts are created under', 'Default' => 1), + 'Enterprise Server Port' => array( 'Type' => 'text', 'Size' => 5, 'Description' => '* Required', 'Default' => 9002), + 'Different Potal URL' => array( 'Type' => 'yesno', 'Description' => 'Tick if portal address is different to server address'), + 'Portal URL' => array( 'Type' => 'text', 'Size' => 25, 'Description' => 'Portal URL, with http(s)://, no trailing slash' ), + 'Send Account Summary Email' => array( 'Type' => 'yesno', 'Description' => 'Tick to send the "Account Summary" letter' ), + 'Send Hosting Space Summary Email' => array( 'Type' => 'yesno', 'Description' => 'Tick to send the "Hosting Space Summary" letter'), + 'Create Mail Account' => array( 'Type' => 'yesno', 'Description' => 'Tick to create mail account' ), + 'Create FTP Account' => array( 'Type' => 'yesno', 'Description' => 'Tick to create FTP account' ), + 'Create Temporary Domain' => array( 'Type' => 'yesno', 'Description' => 'Tick to create a temporary domain' ), + 'Send HTML Email' => array( 'Type' => 'yesno', 'Description' => 'Tick enable HTML email from WebsitePanel' ), + 'Create Website' => array( 'Type' => 'yesno', 'Description' => 'Tick to create Website' ), + 'Count Bandwidth / Diskspace' => array( 'Type' => 'yesno', 'Description' => 'Tick to update diskpace / bandwidth in WHMCS'), + 'Default Pointer' => array( 'Type' => 'text', 'Size' => 25, 'Description' => 'The default pointer (hostname) to use when creating a Website' ), + 'Create DNS Zone' => array( 'Type' => 'yesno', 'Description' => 'Tick to create domain DNS zone')); +} + +/** + * Creates the WebsitePanel user account and package + * + * @param array $params WHMCS parameters + * @throws Exception + * @return string + */ +function websitepanel_CreateAccount($params) +{ + // WHMCS server parameters & package parameters + $serverUsername = $params['serverusername']; + $serverPassword = $params['serverpassword']; + $serverPort = $params['configoption6']; + $serverHost = (empty($params['serverhostname']) ? $params['serverip'] : $params['serverhostname']); + $serverSecure = $params['serversecure']; + $username = $params['username']; + $password = $params['password']; + $domain = $params['domain']; + $packageType = $params['type']; + $clientsDetails = $params['clientsdetails']; + $userId = $clientsDetails['userid']; + $serviceId = $params['serviceid']; + + // WebsitePanel API parameters + $planId = $params['configoption4']; + $parentPackageId = $params['configoption5']; + $roleId = (($packageType == 'reselleraccount') ? 2 : 3); + $htmlMail = ($params['configoption14'] == 'on'); + $sendAccountLetter = ($params['configoption9'] == 'on'); + $sendPackageLetter = ($params['configoption10'] == 'on'); + $createMailAccount = ($params['configoption11'] == 'on'); + $createTempDomain = ($params['configoption13'] == 'on'); + $createFtpAccount = ($params['configoption12'] == 'on'); + $createWebsite = ($params['configoption15'] == 'on'); + $websitePointerName = $params['configoption17']; + $createZoneRecord = ($params['configoption18'] == 'on'); + + try + { + // Create the WebsitePanel Enterprise Server Client object instance + $wsp = new websitepanel_EnterpriseServer($serverUsername, $serverPassword, $serverHost, $serverPort, $serverSecure); + + // Create the user's new account using the CreateUserWizard method + $userParams = array('parentPackageId' => $parentPackageId, + 'username' => $username, + 'password' => $password, + 'roleId' => $roleId, + 'firstName' => $clientsDetails['firstname'], + 'lastname' => $clientsDetails['lastname'], + 'email' => $clientsDetails['email'], + 'secondaryEmail' => '', + 'htmlMail' => $htmlMail, + 'sendAccountLetter' => $sendAccountLetter, + 'createPackage' => TRUE, + 'planId' => $planId, + 'sendPackageLetter' => $sendPackageLetter, + 'domainName' => $domain, + 'tempDomain' => $createTempDomain, + 'createWebSite' => $createWebsite, + 'createFtpAccount' => $createFtpAccount, + 'ftpAccountName' => $username, + 'createMailAccount' => $createMailAccount, + 'hostName' => $websitePointerName, + 'createZoneRecord' => $createZoneRecord); + + // Execute the CreateUserWizard method + $result = $wsp->createUserWizard($userParams); + if ($result < 0) + { + // Something went wrong + throw new Exception('Fault: ' . websitepanel_EnterpriseServer::getFriendlyError($result), $result); + } + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $result); + + // Get the newly created user's details from WebsitePanel so we can update the account details completely + $user = $wsp->getUserByUsername($username); + + // Update the user's account details using the previous details + WHMCS's details (address, city, state etc.) + $userParams = array('RoleId' => $roleId, + 'Role' => $user['Role'], + 'StatusId' => $user['StatusId'], + 'Status' => $user['Status'], + 'LoginStatusId' => $user['LoginStatusId'], + 'LoginStatus' => $user['LoginStatus'], + 'FailedLogins' => $user['FailedLogins'], + 'UserId' => $user['UserId'], + 'OwnerId' => $user['OwnerId'], + 'IsPeer' => $user['IsPeer'], + 'Created' => $user['Created'], + 'Changed' => $user['Changed'], + 'IsDemo' => $user['IsDemo'], + 'Comments' => $user['Comments'], + 'LastName' => $clientsDetails['lastname'], + 'Username' => $username, + 'Password' => $password, + 'FirstName' => $clientsDetails['firstname'], + 'Email' => $clientsDetails['email'], + 'PrimaryPhone' => $clientsDetails['phonenumber'], + 'Zip' => $clientsDetails['postcode'], + 'InstantMessenger' => '', + 'Fax' => '', + 'SecondaryPhone' => '', + 'SecondaryEmail' => '', + 'Country' => $clientsDetails['country'], + 'Address' => $clientsDetails['address1'], + 'City' => $clientsDetails['city'], + 'State' => $clientsDetails['state'], + 'HtmlMail' => $htmlMail, + 'CompanyName' => $clientsDetails['companyname'], + 'EcommerceEnabled' => ($roleId == 2), + 'SubscriberNumber' => ''); + + // Execute the UpdateUserDetails method + $wsp->updateUserDetails($userParams); + + // Notify success + return 'success'; + } + catch (Exception $e) + { + // Error message to log / return + $errorMessage = "CreateAccount Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}, Service ID: {$serviceId})"; + + // Log to WHMCS + logactivity($errorMessage, $userId); + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $e->getMessage()); + + // Notify failure - Houston we have a problem! + return $errorMessage; + } +} + +/** + * Terminates the WebsitePanel user account and package + * + * @param array $params WHMCS parameters + * @throws Exception + * @return string + */ +function websitepanel_TerminateAccount($params) +{ + // WHMCS server parameters & package parameters + $serverUsername = $params['serverusername']; + $serverPassword = $params['serverpassword']; + $serverPort = $params['configoption6']; + $serverHost = (empty($params['serverhostname']) ? $params['serverip'] : $params['serverhostname']); + $serverSecure = $params['serversecure']; + $username = $params['username']; + $clientsDetails = $params['clientsdetails']; + $userId = $clientsDetails['userid']; + $serviceId = $params['serviceid']; + + try + { + // Create the WebsitePanel Enterprise Server Client object instance + $wsp = new websitepanel_EnterpriseServer($serverUsername, $serverPassword, $serverHost, $serverPort, $serverSecure); + + // Get the user's details from WebsitePanel - We need the userid + $user = $wsp->getUserByUsername($username); + if (empty($user)) + { + throw new Exception("User {$username} does not exist - Cannot terminate account for unknown user"); + } + + // Attempt the delete the users account + $result = $wsp->deleteUser($user['UserId']); + if ($result < 0) + { + // Something went wrong + throw new Exception('Fault: ' . websitepanel_EnterpriseServer::getFriendlyError($result), $result); + } + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $result); + + // Notify success + return 'success'; + } + catch (Exception $e) + { + // Error message to log / return + $errorMessage = "TerminateAccount Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}, Service ID: {$serviceId})"; + + // Log to WHMCS + logactivity($errorMessage, $userId); + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $e->getMessage()); + + // Notify failure - Houston we have a problem! + return $errorMessage; + } +} + +/** + * Suspends the WebsitePanel user account and package + * + * @param array $params WHMCS parameters + * @throws Exception + * @return string + */ +function websitepanel_SuspendAccount($params) +{ + // WHMCS server parameters & package parameters + $serverUsername = $params['serverusername']; + $serverPassword = $params['serverpassword']; + $serverPort = $params['configoption6']; + $serverHost = (empty($params['serverhostname']) ? $params['serverip'] : $params['serverhostname']); + $serverSecure = $params['serversecure']; + $username = $params['username']; + $clientsDetails = $params['clientsdetails']; + $userId = $clientsDetails['userid']; + $serviceId = $params['serviceid']; + + try + { + // Create the WebsitePanel Enterprise Server Client object instance + $wsp = new websitepanel_EnterpriseServer($serverUsername, $serverPassword, $serverHost, $serverPort, $serverSecure); + + // Get the user's details from WebsitePanel - We need the userid + $user = $wsp->getUserByUsername($username); + if (empty($user)) + { + throw new Exception("User {$username} does not exist - Cannot suspend account for unknown user"); + } + + // Change the user's account and package account status + $result = $wsp->changeUserStatus($user['UserId'], websitepanel_EnterpriseServer::USERSTATUS_SUSPENDED); + if ($result < 0) + { + // Something went wrong + throw new Exception('Fault: ' . websitepanel_EnterpriseServer::getFriendlyError($result), $result); + } + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $result); + + // Notify success + return 'success'; + } + catch (Exception $e) + { + // Error message to log / return + $errorMessage = "SuspendAccount Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}, Service ID: {$serviceId})"; + + // Log to WHMCS + logactivity($errorMessage, $userId); + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $e->getMessage()); + + // Notify failure - Houston we have a problem! + return $errorMessage; + } +} + +/** + * Unsuspends the WebsitePanel user account and package + * + * @param array $params WHMCS parameters + * @throws Exception + * @return string + */ +function websitepanel_UnsuspendAccount($params) +{ + // WHMCS server parameters & package parameters + $serverUsername = $params['serverusername']; + $serverPassword = $params['serverpassword']; + $serverPort = $params['configoption6']; + $serverHost = (empty($params['serverhostname']) ? $params['serverip'] : $params['serverhostname']); + $serverSecure = $params['serversecure']; + $username = $params['username']; + $clientsDetails = $params['clientsdetails']; + $userId = $clientsDetails['userid']; + $serviceId = $params['serviceid']; + + try + { + // Create the WebsitePanel Enterprise Server Client object instance + $wsp = new websitepanel_EnterpriseServer($serverUsername, $serverPassword, $serverHost, $serverPort, $serverSecure); + + // Get the user's details from WebsitePanel - We need the userid + $user = $wsp->getUserByUsername($username); + if (empty($user)) + { + throw new Exception("User {$username} does not exist - Cannot unsuspend account for unknown user"); + } + + // Change the user's account and package account status + $result = $wsp->changeUserStatus($user['UserId'], websitepanel_EnterpriseServer::USERSTATUS_ACTIVE); + if ($result < 0) + { + // Something went wrong + throw new Exception('Fault: ' . websitepanel_EnterpriseServer::getFriendlyError($result), $result); + } + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $result); + + // Notify success + return 'success'; + } + catch (Exception $e) + { + // Error message to log / return + $errorMessage = "UnsuspendAccount Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}, Service ID: {$serviceId})"; + + // Log to WHMCS + logactivity($errorMessage, $userId); + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $e->getMessage()); + + // Notify failure - Houston we have a problem! + return $errorMessage; + } +} + +/** + * Changes the WebsitePanel user account password + * + * @param array $params WHMCS parameters + * @throws Exception + * @return string + */ +function websitepanel_ChangePassword($params) +{ + // WHMCS server parameters & package parameters + $serverUsername = $params['serverusername']; + $serverPassword = $params['serverpassword']; + $serverPort = $params['configoption6']; + $serverHost = (empty($params['serverhostname']) ? $params['serverip'] : $params['serverhostname']); + $serverSecure = $params['serversecure']; + $username = $params['username']; + $password = $params['password']; + $clientsDetails = $params['clientsdetails']; + $userId = $clientsDetails['userid']; + $serviceId = $params['serviceid']; + + try + { + // Create the WebsitePanel Enterprise Server Client object instance + $wsp = new websitepanel_EnterpriseServer($serverUsername, $serverPassword, $serverHost, $serverPort, $serverSecure); + + // Get the user's details from WebsitePanel - We need the userid + $user = $wsp->getUserByUsername($username); + if (empty($user)) + { + throw new Exception("User {$username} does not exist - Cannot change account password for unknown user"); + } + + // Change the user's account password + $result = $wsp->changeUserPassword($user['UserId'], $password); + if ($result < 0) + { + // Something went wrong + throw new Exception('Fault: ' . websitepanel_EnterpriseServer::getFriendlyError($result), $result); + } + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $result); + + // Notify success + return 'success'; + } + catch (Exception $e) + { + // Error message to log / return + $errorMessage = "ChangePassword Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}, Service ID: {$serviceId})"; + + // Log to WHMCS + logactivity($errorMessage, $userId); + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $e->getMessage()); + + // Notify failure - Houston we have a problem! + return $errorMessage; + } +} + +/** + * Changes the WebsitePanel user hosting package + * + * @param array $params WHMCS parameters + * @throws Exception + * @return string + */ +function websitepanel_ChangePackage($params) +{ + // WHMCS server parameters & package parameters + $serverUsername = $params['serverusername']; + $serverPassword = $params['serverpassword']; + $serverPort = $params['configoption6']; + $serverHost = (empty($params['serverhostname']) ? $params['serverip'] : $params['serverhostname']); + $serverSecure = $params['serversecure']; + $username = $params['username']; + $clientsDetails = $params['clientsdetails']; + $userId = $clientsDetails['userid']; + $serviceId = $params['serviceid']; + + // WebsitePanel API parameters + $planId = $params['configoption4']; + $packageName = $params['configoption1']; + + try + { + // Create the WebsitePanel Enterprise Server Client object instance + $wsp = new websitepanel_EnterpriseServer($serverUsername, $serverPassword, $serverHost, $serverPort, $serverSecure); + + // Get the user's details from WebsitePanel - We need the userid + $user = $wsp->getUserByUsername($username); + if (empty($user)) + { + throw new Exception("User {$username} does not exist - Cannot change package for unknown user"); + } + + // Get the user's package details from WebsitePanel - We need the PackageId + $package = $wsp->getUserPackages($user['UserId']); + + // Update the user's WebsitePanel package + $result = $wsp->updatePackageLiteral($package['PackageId'], $package['StatusId'], $planId, $package['PurchaseDate'], $packageName, $package['PackageComments']); + if ($result < 0) + { + // Something went wrong + throw new Exception('Fault: ' . websitepanel_EnterpriseServer::getFriendlyError($result), $result); + } + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $result); + + // Notify success + return 'success'; + } + catch (Exception $e) + { + // Error message to log / return + $errorMessage = "ChangePackage Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}, Service ID: {$serviceId})"; + + // Log to WHMCS + logactivity($errorMessage, $userId); + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $e->getMessage()); + + // Notify failure - Houston we have a problem! + return $errorMessage; + } +} + +/** + * Updates the WHMCS service's usage details from WebsitePanel + * + * @param aray $params WHMCS parameters + * @throws Exception + */ +function websitepanel_UsageUpdate($params) +{ + // WHMCS server parameters & package parameters + $serverUsername = $params['serverusername']; + $serverPassword = $params['serverpassword']; + $serverHost = (empty($params['serverhostname']) ? $params['serverip'] : $params['serverhostname']); + $serverSecure = $params['serversecure']; + $serverId = $params['serverid']; + $userId = 0; + $serviceId = 0; + + // Query for WebsitePanel user accounts assigned to this server + // Only services that have packages that have "Tick to update diskpace / bandwidth in WHMCS" enabled + $result = full_query("SELECT h.id AS serviceid, h.userid AS userid, h.username AS username, h.regdate AS regdate, p.configoption2 AS configoption2, p.configoption3 AS configoption3, p.configoption6 AS configoption6 FROM `tblhosting` AS h, `tblproducts` AS p WHERE h.server = {$serverId} AND h.packageid = p.id AND p.configoption16 = 'on' AND h.domainstatus IN ('Active', 'Suspended')"); + while (($row = mysql_fetch_array($result)) != false) + { + // Start processing the users usage + $username = $row['username']; + $userId = $row['userid']; + $serviceId = $row['serviceid']; + $serverPort = $row['configoption6']; + + // Diskspace and Bandwidth limits for this package + $diskLimit = $row['configoption2']; + $bwidthLimit = $row['configoption3']; + + try + { + // Create the WebsitePanel Enterprise Server Client object instance + $wsp = new websitepanel_EnterpriseServer($serverUsername, $serverPassword, $serverHost, $serverPort, $serverSecure); + + // Get the user's details from WebsitePanel - We need the userid + $user = $wsp->getUserByUsername($username); + if (empty($user)) + { + throw new Exception("User {$username} does not exist - Cannot calculate usage for unknown user"); + } + + // Get the user's package details from WebsitePanel - We need the PackageId + $package = $wsp->getUserPackages($user['UserId']); + + // Gather the bandwidth / diskspace usage stats + $bwidthUsage = websitepanel_CalculateUsage($wsp->getPackageBandwidthUsage($package['PackageId'], websitepanel_CreateBandwidthDate($row['regdate']), date('Y-m-d', time())), websitepanel_EnterpriseServer::USAGE_BANDWIDTH); + $diskUsage = websitepanel_CalculateUsage($wsp->getPackageDiskspaceUsage($package['PackageId']), websitepanel_EnterpriseServer::USAGE_DISKSPACE); + + // Update WHMCS's service details + update_query('tblhosting', array('diskusage' => $diskUsage, 'disklimit' => $diskLimit, 'bwusage' => $bwidthUsage, 'bwlimit' => $bwidthLimit, 'lastupdate' => 'now()'), array('id' => $serviceId)); + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $package); + } + catch (Exception $e) + { + // Error message to log / return + $errorMessage = "UsageUpdate Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}, Service ID: {$serviceId})"; + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $e->getMessage()); + + // Log to WHMCS + logactivity($errorMessage, $userId); + } + } +} + +/** + * Returns the WebsitePanel one-click login link + * + * @param array $params WHMCS parameters + * @throws Exception + * @return string + */ +function websitepanel_LoginLink($params) +{ + // WHMCS does not return the full hosting account details, we will query for what we need + $result = select_query('tblhosting', 'domainstatus', array('id' => $params['serviceid'])); + $results = mysql_fetch_array($result); + $params['domainstatus'] = $results['domainstatus']; + + // Display the link only if the account is Active or Suspended + if (in_array($params['domainstatus'], array('Active', 'Suspended'))) + { + // WHMCS server parameters & package parameters + $serverUsername = $params['serverusername']; + $serverPassword = $params['serverpassword']; + $serverPort = $params['configoption6']; + $serverHost = (empty($params['serverhostname']) ? $params['serverip'] : $params['serverhostname']); + $serverSecure = $params['serversecure']; + $username = $params['username']; + $serviceId = $params['serviceid']; + $clientsDetails = $params['clientsdetails']; + $userId = $clientsDetails['userid']; + + try + { + // Create the WebsitePanel Enterprise Server Client object instance + $wsp = new websitepanel_EnterpriseServer($serverUsername, $serverPassword, $serverHost, $serverPort, $serverSecure); + + // Get the user's details from WebsitePanel - We need the userid + $user = $wsp->getUserByUsername($username); + if (empty($user)) + { + throw new Exception("User {$username} does not exist - Cannot display account link for unknown user"); + } + + // Load the client area language file + $LANG = websitepanel_LoadClientLanguage(); + + // Print the link + echo "{$LANG['websitepanel_adminarea_gotowebsitepanelaccount']}
"; + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $user); + } + catch (Exception $e) + { + // Error message to log / return + $errorMessage = "LoginLink Fault: (Code: {$e->getCode()}, Message: {$e->getMessage()}, Service ID: {$serviceId})"; + + // Log to WHMCS + logactivity($errorMessage, $userId); + + // Log the module call + websitepanel_logModuleCall(__FUNCTION__, $params, $e->getMessage()); + } + } +} + +/** + * Client Area module output for the customer's "My Services" service output + * + * @access public + * @param array $params WHMCS parameters + * @throws Exception + * @return array + */ +function websitepanel_ClientArea($params) +{ + // WHMCS server parameters & package parameters + $username = $params['username']; + $password = $params['password']; + + // Load the client area language file + websitepanel_LoadClientLanguage(); + + // Return template information + return array('templatefile' => 'clientarea', 'vars' => array('websitepanel_url' => $params['configoption8'], 'username' => $username, 'password' => $password)); +} + +/** + * Logs all module calls to the WHMCS module debug logger + * + * @access public + * @param string $function + * @param mixed $params + * @param mixed $response + */ +function websitepanel_logModuleCall($function, $params, $response) +{ + // Get the module name + $callerData = explode('_', $function); + $module = $callerData[0]; + $action = $callerData[1]; + + // Replacement variables + $replacementVars = array(''); + + // Log the call with WHMCS + logModuleCall($module, $action, $params, $response, '', $replacementVars); } \ No newline at end of file diff --git a/WebsitePanel.WHMCSModule/readme.txt b/WebsitePanel.WHMCSModule/readme.txt deleted file mode 100644 index 631f8816..00000000 --- a/WebsitePanel.WHMCSModule/readme.txt +++ /dev/null @@ -1,19 +0,0 @@ -Extract the "includes" and "modules" directories into the root of your WHMCS installation -Overwrite any files that already exists - -To enable addon automation... -1. WHMCS Admin -> Setup -> Addon Modules -> "WebsitePanel Addons Automation" -> Activate -2. Select "Configure" -3. Enter your WebsitePanel Enterprise Server details -4. WHMCS Admin -> Addons -> "WebsitePanel Addons" -5. Enter your addons here. You can get the WHMCS addon ID by clicking the edit icon on the product addon and extracting the &id=x from the URL (x being the WHMCS Addon ID) - You can retrieve your WebsitePanel addon ID by clicking the hosting addon and extracting the PlanID=x from the URL (x being the WebsitePanel Addon ID) -6. If this is a Dedicated IP address addon, check the Dedicated IP Address box to allow the module to auto-allocate an IP address. - -What does not work? -- Quantities, only a single addon => addon can be allocated -- Terminating / Suspending Addons, I've ran out of time on what I can do currently -- When an IP address is allocated WebsitePanel does not return back what IP was allocated, so WHMCS is not updated which what IP has been allocated to his / her package at this time. -- A single user => single package is the only way the WebsitePanel server module works. I have no plans on making this work any other way. - -DO NOT CONTACT WHMCS FOR SUPPORT WITH THIS MODULE - THIS IS NOT DEVELOPED BY WHMCS AND HAS NO AFFILIATION WITH WHMCS OR WHMCS.COM. \ No newline at end of file diff --git a/WebsitePanel/Database/update_db.sql b/WebsitePanel/Database/update_db.sql index a980545a..f3c9b329 100644 --- a/WebsitePanel/Database/update_db.sql +++ b/WebsitePanel/Database/update_db.sql @@ -5376,6 +5376,48 @@ AS END GO + + +-- IIS80 Provider update for SNI and CCS support +-- Add default serviceproperties for all existing IIS80 Services (if any). These properties are used as markers in the IIS70 Controls in WebPortal to know the version of the IIS Provider +declare c cursor read_only for +select ServiceID from Services where ProviderID in(select ProviderID from Providers where ProviderName='IIS80') + +declare @ServiceID int + +open c + +fetch next from c +into @ServiceID + +while @@FETCH_STATUS = 0 +begin + if not exists(select null from ServiceProperties where ServiceID = @ServiceID and PropertyName = 'sslccscommonpassword') + insert into ServiceProperties(ServiceID, PropertyName, PropertyValue) + values(@ServiceID, 'sslccscommonpassword', '') + + if not exists(select null from ServiceProperties where ServiceID = @ServiceID and PropertyName = 'sslccsuncpath') + insert into ServiceProperties(ServiceID, PropertyName, PropertyValue) + values(@ServiceID, 'sslccsuncpath', '') + + if not exists(select null from ServiceProperties where ServiceID = @ServiceID and PropertyName = 'ssluseccs') + insert into ServiceProperties(ServiceID, PropertyName, PropertyValue) + values(@ServiceID, 'ssluseccs', 'False') + + if not exists(select null from ServiceProperties where ServiceID = @ServiceID and PropertyName = 'ssluseccs') + insert into ServiceProperties(ServiceID, PropertyName, PropertyValue) + values(@ServiceID, 'sslusesni', 'False') + + fetch next from c + into @ServiceID +end + +close c + +deallocate c + +GO + -- Hyper-V 2012 R2 IF NOT EXISTS (SELECT * FROM [dbo].[Providers] WHERE [ProviderName] = 'HyperV2012R2') BEGIN diff --git a/WebsitePanel/Lib/References/Microsoft/Windows2012/Microsoft.Web.Administration.dll b/WebsitePanel/Lib/References/Microsoft/Windows2012/Microsoft.Web.Administration.dll new file mode 100644 index 00000000..7415f557 Binary files /dev/null and b/WebsitePanel/Lib/References/Microsoft/Windows2012/Microsoft.Web.Administration.dll differ diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/EnterpriseStorage/EnterpriseStorageController.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/EnterpriseStorage/EnterpriseStorageController.cs index 530f21be..919580e3 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/EnterpriseStorage/EnterpriseStorageController.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/EnterpriseStorage/EnterpriseStorageController.cs @@ -192,10 +192,10 @@ namespace WebsitePanel.EnterpriseServer try { TaskManager.StartTask("ENTERPRISE_STORAGE", taskName, org.PackageId); - + + EnterpriseStorageController.SetFRSMQuotaOnFolder(itemId, folder.Name, quota, quotaType); EnterpriseStorageController.SetDirectoryBrowseEnabled(itemId, folder.Url, directoyBrowsingEnabled); EnterpriseStorageController.SetFolderPermission(itemId, folder.Name, permissions); - EnterpriseStorageController.SetFRSMQuotaOnFolder(itemId, folder.Name, quota, quotaType); } catch (Exception ex) { diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/ExchangeServer/ExchangeServerController.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/ExchangeServer/ExchangeServerController.cs index 746d8234..2b3fef03 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/ExchangeServer/ExchangeServerController.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/ExchangeServer/ExchangeServerController.cs @@ -586,6 +586,7 @@ namespace WebsitePanel.EnterpriseServer List acceptedDomains = GetOrganizationDomains(itemId); int exchangeServiceId = GetExchangeServiceID(org.PackageId); + ExchangeServer exchange = GetExchangeServer(exchangeServiceId, org.ServiceId); bool successful = exchange.DeleteOrganization( @@ -599,6 +600,18 @@ namespace WebsitePanel.EnterpriseServer org.AddressBookPolicy, acceptedDomains.ToArray()); + // delete public folders + if (successful) + { + List folders = GetAccounts(itemId, ExchangeAccountType.PublicFolder); + folders.Sort(delegate(ExchangeAccount f1, ExchangeAccount f2) { return f2.AccountId.CompareTo(f1.AccountId);}); + + foreach(ExchangeAccount folder in folders) + DeletePublicFolder(itemId, folder.AccountId); + + exchange.DeletePublicFolder(org.OrganizationId, "\\" + org.OrganizationId); + } + return successful ? 0 : BusinessErrorCodes.ERROR_EXCHANGE_DELETE_SOME_PROBLEMS; } @@ -1782,7 +1795,9 @@ namespace WebsitePanel.EnterpriseServer //GetServiceSettings StringDictionary primSettings = ServerController.GetServiceSettings(exchangeServiceId); - string samAccount = exchange.CreateMailEnableUser(email, org.OrganizationId, org.DistinguishedName, accountType, primSettings["mailboxdatabase"], + string samAccount = exchange.CreateMailEnableUser(email, org.OrganizationId, org.DistinguishedName, + org.SecurityGroup, org.DefaultDomain, + accountType, primSettings["mailboxdatabase"], org.OfflineAddressBook, org.AddressBookPolicy, retUser.SamAccountName, @@ -5317,6 +5332,54 @@ namespace WebsitePanel.EnterpriseServer TaskManager.CompleteTask(); } } + + public static string CreateOrganizationRootPublicFolder(int itemId) + { + string res = null; + + // place log record + TaskManager.StartTask("EXCHANGE", "CREATE_ORG_PUBLIC_FOLDER", itemId); + + try + { + // load organization + Organization org = GetOrganization(itemId); + if (org == null) + return null; + + // get mailbox settings + int exchangeServiceId = GetExchangeServiceID(org.PackageId); + + if (exchangeServiceId <= 0) + return null; + + ExchangeServer exchange = GetExchangeServer(exchangeServiceId, org.ServiceId); + + if (exchange == null) + return null; + + //Create Exchange Organization + if (string.IsNullOrEmpty(org.GlobalAddressList)) + { + ExtendToExchangeOrganization(ref org); + + PackageController.UpdatePackageItem(org); + } + + res = exchange.CreateOrganizationRootPublicFolder(org.OrganizationId, org.DistinguishedName, org.SecurityGroup, org.DefaultDomain); + } + catch (Exception ex) + { + throw TaskManager.WriteError(ex); + } + finally + { + TaskManager.CompleteTask(); + } + + return res; + } + #endregion #region Private Helpers diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/HostedSolution/OrganizationController.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/HostedSolution/OrganizationController.cs index 97f29adf..2b8341ab 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/HostedSolution/OrganizationController.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/HostedSolution/OrganizationController.cs @@ -419,6 +419,9 @@ namespace WebsitePanel.EnterpriseServer }; PackageController.AddPackageItem(orgDomain); + + ExchangeServerController.CreateOrganizationRootPublicFolder(itemId); + } catch (Exception ex) { diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/IExchangeServer.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/IExchangeServer.cs index 6a69cc2b..395a295d 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/IExchangeServer.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/IExchangeServer.cs @@ -37,7 +37,9 @@ namespace WebsitePanel.Providers.HostedSolution bool CheckAccountCredentials(string username, string password); // Organizations - string CreateMailEnableUser(string upn, string organizationId, string organizationDistinguishedName, ExchangeAccountType accountType, + string CreateMailEnableUser(string upn, string organizationId, string organizationDistinguishedName, + string securityGroup, string organizationDomain, + ExchangeAccountType accountType, string mailboxDatabase, string offlineAddressBook, string addressBookPolicy, string accountName, bool enablePOP, bool enableIMAP, bool enableOWA, bool enableMAPI, bool enableActiveSync, @@ -74,6 +76,8 @@ namespace WebsitePanel.Providers.HostedSolution void SetMailboxPermissions(string organizationId, string accountName, string[] sendAsAccounts, string[] fullAccessAccounts); ExchangeMailbox GetMailboxPermissions(string organizationId, string accountName); ExchangeMailboxStatistics GetMailboxStatistics(string accountName); + string[] SetDefaultPublicFolderMailbox(string id, string organizationId, string organizationDistinguishedName); + // Contacts void CreateContact(string organizationId, string organizationDistinguishedName, string contactDisplayName, string contactAccountName, string contactEmail, string defaultOrganizationDomain); @@ -113,6 +117,8 @@ namespace WebsitePanel.Providers.HostedSolution ExchangeItemStatistics[] GetPublicFoldersStatistics(string organizationId, string[] folders); string[] GetPublicFoldersRecursive(string organizationId, string parent); long GetPublicFolderSize(string organizationId, string folder); + string CreateOrganizationRootPublicFolder(string organizationId, string organizationDistinguishedName, string securityGroup, string organizationDomain); + //ActiveSync void CreateOrganizationActiveSyncPolicy(string organizationId); diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebSite.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebSite.cs index b697b560..eb5da8d6 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebSite.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebSite.cs @@ -63,6 +63,7 @@ namespace WebsitePanel.Providers.Web private bool heliconApeInstalled; private bool heliconApeEnabled; private HeliconApeStatus heliconApeStatus; + private bool sniEnabled; public WebSite() { @@ -187,6 +188,12 @@ namespace WebsitePanel.Providers.Web get { return this.heliconApeStatus; } set { this.heliconApeStatus = value; } } + + public bool SniEnabled + { + get { return this.sniEnabled; } + set { this.sniEnabled = value; } + } } [Flags] diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Exchange2013/Exchange2013.cs b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Exchange2013/Exchange2013.cs index deb82a91..62df4ff6 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Exchange2013/Exchange2013.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Exchange2013/Exchange2013.cs @@ -1871,14 +1871,18 @@ namespace WebsitePanel.Providers.HostedSolution } - public string CreateMailEnableUser(string upn, string organizationId, string organizationDistinguishedName, ExchangeAccountType accountType, + public string CreateMailEnableUser(string upn, string organizationId, string organizationDistinguishedName, + string securityGroup, string organizationDomain, + ExchangeAccountType accountType, string mailboxDatabase, string offlineAddressBook, string addressBookPolicy, string accountName, bool enablePOP, bool enableIMAP, bool enableOWA, bool enableMAPI, bool enableActiveSync, long issueWarningKB, long prohibitSendKB, long prohibitSendReceiveKB, int keepDeletedItemsDays, int maxRecipients, int maxSendMessageSizeKB, int maxReceiveMessageSizeKB, bool hideFromAddressBook, bool IsConsumer, bool enabledLitigationHold, long recoverabelItemsSpace, long recoverabelItemsWarning) { - return CreateMailEnableUserInternal(upn, organizationId, organizationDistinguishedName, accountType, + return CreateMailEnableUserInternal(upn, organizationId, organizationDistinguishedName, + securityGroup, organizationDomain, + accountType, mailboxDatabase, offlineAddressBook, addressBookPolicy, accountName, enablePOP, enableIMAP, enableOWA, enableMAPI, enableActiveSync, @@ -1886,7 +1890,9 @@ namespace WebsitePanel.Providers.HostedSolution keepDeletedItemsDays, maxRecipients, maxSendMessageSizeKB, maxReceiveMessageSizeKB, hideFromAddressBook, IsConsumer, enabledLitigationHold, recoverabelItemsSpace, recoverabelItemsWarning); } - internal virtual string CreateMailEnableUserInternal(string upn, string organizationId, string organizationDistinguishedName, ExchangeAccountType accountType, + internal virtual string CreateMailEnableUserInternal(string upn, string organizationId, string organizationDistinguishedName, + string securityGroup, string organizationDomain, + ExchangeAccountType accountType, string mailboxDatabase, string offlineAddressBook, string addressBookPolicy, string accountName, bool enablePOP, bool enableIMAP, bool enableOWA, bool enableMAPI, bool enableActiveSync, @@ -1955,8 +1961,19 @@ namespace WebsitePanel.Providers.HostedSolution transaction.RegisterEnableMailbox(id); + // default public folder + string orgCanonicalName = ConvertADPathToCanonicalName(organizationDistinguishedName); + + //create organization public folder mailbox if required + CheckOrganizationPublicFolderMailbox(runSpace, orgCanonicalName, organizationId, organizationDomain); + + //create organization root folder if required + CheckOrganizationRootFolder(runSpace, organizationId, securityGroup, orgCanonicalName, organizationId); + string windowsEmailAddress = ObjToString(GetPSObjectProperty(result[0], "WindowsEmailAddress")); + string defaultPublicFolderMailbox = orgCanonicalName + "/" + GetPublicFolderMailboxName(organizationId); + //update mailbox cmd = new Command("Set-Mailbox"); cmd.Parameters.Add("Identity", id); @@ -1987,6 +2004,8 @@ namespace WebsitePanel.Providers.HostedSolution cmd.Parameters.Add("RecoverableItemsWarningQuota", ConvertKBToUnlimited(recoverabelItemsWarning)); } + cmd.Parameters.Add("DefaultPublicFolderMailbox", defaultPublicFolderMailbox); + ExecuteShellCommand(runSpace, cmd); //Litigation Hold @@ -4441,8 +4460,6 @@ namespace WebsitePanel.Providers.HostedSolution ExchangeLog.LogEnd("CheckOrganizationPublicFolderMailbox"); } - - private void CheckOrganizationRootFolder(Runspace runSpace, string folder, string user, string orgCanonicalName, string organizationId) { ExchangeLog.LogStart("CheckOrganizationRootFolder"); @@ -4467,6 +4484,48 @@ namespace WebsitePanel.Providers.HostedSolution ExchangeLog.LogEnd("CheckOrganizationRootFolder"); } + private void CheckOrganizationRootPublicFolderPermission(Runspace runSpace, string organizationId) + { + string rootFolder = "\\" + organizationId; + + // exchange transport needs access to create new items in order to deliver email + AddPublicFolderClientPermission(runSpace, rootFolder, "Anonymous", "CreateItems"); + } + + public string CreateOrganizationRootPublicFolder(string organizationId, string organizationDistinguishedName, string securityGroup, string organizationDomain) + { + ExchangeLog.LogStart("CreateOrganizationRootPublicFolder"); + + string res = null; + + Runspace runSpace = null; + try + { + runSpace = OpenRunspace(); + + // default public folder + string orgCanonicalName = ConvertADPathToCanonicalName(organizationDistinguishedName); + + //create organization public folder mailbox if required + CheckOrganizationPublicFolderMailbox(runSpace, orgCanonicalName, organizationId, organizationDomain); + + //create organization root folder if required + CheckOrganizationRootFolder(runSpace, organizationId, securityGroup, orgCanonicalName, organizationId); + + res = orgCanonicalName + "/" + GetPublicFolderMailboxName(organizationId); + + CheckOrganizationRootPublicFolderPermission(runSpace, organizationId); + } + finally + { + CloseRunspace(runSpace); + } + + ExchangeLog.LogEnd("CreateOrganizationRootPublicFolder"); + + return res; + } + private string AddPublicFolder(Runspace runSpace, string name, string path, string mailbox) { ExchangeLog.LogStart("CreatePublicFolder"); @@ -4697,9 +4756,7 @@ namespace WebsitePanel.Providers.HostedSolution System.Threading.Thread.Sleep(5000); } - // exchange transport needs access to create new items in order to deliver email - AddPublicFolderClientPermission(runSpace, folder, "Anonymous", "CreateItems"); - + CheckOrganizationRootPublicFolderPermission(runSpace, organizationId); } finally { @@ -5209,6 +5266,54 @@ namespace WebsitePanel.Providers.HostedSolution return size; } + public string[] SetDefaultPublicFolderMailbox(string id, string organizationId, string organizationDistinguishedName) + { + ExchangeLog.LogStart("SetDefaultPublicFolderMailbox"); + + List res = new List(); + + Runspace runSpace = null; + try + { + runSpace = OpenRunspace(); + + Command cmd = new Command("Get-Mailbox"); + cmd.Parameters.Add("Identity", id); + Collection result = ExecuteShellCommand(runSpace, cmd); + + string oldValue = ""; + + if (result != null && result.Count > 0) + { + oldValue = ObjToString(GetPSObjectProperty(result[0], "DefaultPublicFolderMailbox")); + } + + res.Add(oldValue); + + string orgCanonicalName = ConvertADPathToCanonicalName(organizationDistinguishedName); + + string newValue = orgCanonicalName + "/" + GetPublicFolderMailboxName(organizationId); + + if (newValue != oldValue) + { + cmd = new Command("Set-Mailbox"); + cmd.Parameters.Add("Identity", id); + cmd.Parameters.Add("DefaultPublicFolderMailbox", newValue); + + res.Add(newValue); + } + + } + finally + { + CloseRunspace(runSpace); + } + + ExchangeLog.LogEnd("SetDefaultPublicFolderMailbox"); + return res.ToArray(); + } + + #endregion #region Address Lists (GAL, AL, RAL, OAB, ABP) diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/Exchange2007.cs b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/Exchange2007.cs index 181d7d11..e6b49c46 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/Exchange2007.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/Exchange2007.cs @@ -1784,7 +1784,9 @@ namespace WebsitePanel.Providers.HostedSolution } - public string CreateMailEnableUser(string upn, string organizationId, string organizationDistinguishedName, ExchangeAccountType accountType, + public string CreateMailEnableUser(string upn, string organizationId, string organizationDistinguishedName, + string securityGroup, string organizationDomain, + ExchangeAccountType accountType, string mailboxDatabase, string offlineAddressBook, string addressBookPolicy, string accountName, bool enablePOP, bool enableIMAP, bool enableOWA, bool enableMAPI, bool enableActiveSync, @@ -4852,6 +4854,19 @@ namespace WebsitePanel.Providers.HostedSolution return size; } + public string CreateOrganizationRootPublicFolder(string organizationId, string organizationDistinguishedName, string securityGroup, string organizationDomain) + { + // not implemented + return null; + } + + public string[] SetDefaultPublicFolderMailbox(string id, string organizationId, string organizationDistinguishedName) + { + // not implemented + return null; + } + + #endregion #region Address Lists (GAL, AL, RAL, OAB, ABP) diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/Exchange2010SP2.cs b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/Exchange2010SP2.cs index f2ae8e76..fbb33f3a 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/Exchange2010SP2.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/Exchange2010SP2.cs @@ -325,7 +325,8 @@ namespace WebsitePanel.Providers.HostedSolution #endregion #region Mailbox - internal override string CreateMailEnableUserInternal(string upn, string organizationId, string organizationDistinguishedName, ExchangeAccountType accountType, + internal override string CreateMailEnableUserInternal(string upn, string organizationId, string organizationDistinguishedName, + ExchangeAccountType accountType, string mailboxDatabase, string offlineAddressBook, string addressBookPolicy, string accountName, bool enablePOP, bool enableIMAP, bool enableOWA, bool enableMAPI, bool enableActiveSync, diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/Common/ConfigurationModuleService.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/Common/ConfigurationModuleService.cs index c522d736..a83ca798 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/Common/ConfigurationModuleService.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/Common/ConfigurationModuleService.cs @@ -43,7 +43,7 @@ namespace WebsitePanel.Providers.Web.Iis.Common /// We'll use it in the future to implement management of web farm with shared configuration enabled /// /// - internal ServerManager GetServerManager() + protected internal ServerManager GetServerManager() { return new ServerManager(); } diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/IIs70.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/IIs70.cs index cdfbcf8c..cd3a07b5 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/IIs70.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/IIs70.cs @@ -1240,6 +1240,7 @@ namespace WebsitePanel.Providers.Web // site.SiteState = GetSiteState(srvman, siteId); // + site.SniEnabled = false; } return site; } diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/SSL/SSLModuleService.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/SSL/SSLModuleService.cs index e08dd492..91d60a3e 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/SSL/SSLModuleService.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/SSL/SSLModuleService.cs @@ -40,7 +40,7 @@ using WebsitePanel.Providers.Web.Iis.WebObjects; namespace WebsitePanel.Providers.Web.Iis { - internal sealed class SSLModuleService : ConfigurationModuleService + public class SSLModuleService : ConfigurationModuleService { public void GenerateCsr(SSLCertificate cert) { diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIs80/IIs80.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIs80/IIs80.cs index 07717566..250bf49e 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIs80/IIs80.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIs80/IIs80.cs @@ -26,18 +26,84 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +using Microsoft.Web.Administration; using Microsoft.Win32; using System; using System.Collections.Generic; -using System.Linq; -using System.Text; +using WebsitePanel.Providers.Common; +using WebsitePanel.Providers.Web.Iis; namespace WebsitePanel.Providers.Web { - public class IIs80 : IIs70, IWebServer + public class IIs80 : IIs70 { - public IIs80() : base() + private SslFlags SSLFlags { + get + { + return (UseSni ? SslFlags.Sni : SslFlags.None) | (UseCcs ? SslFlags.CentralCertStore : SslFlags.None); + } + } + + public string CCSUncPath { + get { return ProviderSettings["SSLCCSUNCPath"]; } + } + + public string CCSCommonPassword { + get { return ProviderSettings["SSLCCSCommonPassword"]; } + } + + public bool UseSni { + get + { + try + { + return Convert.ToBoolean(ProviderSettings["SSLUseSNI"]); + } + catch + { + return false; + } + } + } + + public bool UseCcs { + get + { + try + { + return Convert.ToBoolean(ProviderSettings["SSLUseCCS"]); + } + catch + { + return false; + } + } + } + + public override SettingPair[] GetProviderDefaultSettings() + { + var allSettings = new List(); + allSettings.AddRange(base.GetProviderDefaultSettings()); + + // Add these to get som default values in. These are also used a marker in the IIS70_Settings.ascx.cs to know that it is the IIS80 provider that is used + allSettings.Add(new SettingPair("SSLUseCCS", false.ToString())); + allSettings.Add(new SettingPair("SSLUseSNI", false.ToString())); + allSettings.Add(new SettingPair("SSLCCSUNCPath", "")); + allSettings.Add(new SettingPair("SSLCCSCommonPassword", "")); + + return allSettings.ToArray(); + } + + public override string[] Install() + { + var messages = new List(); + + messages.AddRange(base.Install()); + + // TODO: Setup ccs + + return messages.ToArray(); } public override bool IsIISInstalled() @@ -58,5 +124,70 @@ namespace WebsitePanel.Providers.Web { return IsIISInstalled(); } + + public override bool CheckCertificate(WebSite webSite) + { + var sslObjectService = new SSLModuleService80(SSLFlags, CCSUncPath, CCSCommonPassword); + + return sslObjectService.CheckCertificate(webSite); + } + + public override ResultObject DeleteCertificate(SSLCertificate certificate, WebSite website) + { + var sslObjectService = new SSLModuleService80(SSLFlags, CCSUncPath, CCSCommonPassword); + + return sslObjectService.DeleteCertificate(certificate, website); + } + + public override SSLCertificate installPFX(byte[] certificate, string password, WebSite website) + { + var sslObjectService = new SSLModuleService80(SSLFlags, CCSUncPath, CCSCommonPassword); + + return sslObjectService.InstallPfx(certificate, password, website); + } + + public override SSLCertificate ImportCertificate(WebSite website) + { + var sslObjectService = new SSLModuleService80(SSLFlags, CCSUncPath, CCSCommonPassword); + + return sslObjectService.ImportCertificate(website); + } + + public override byte[] exportCertificate(string serialNumber, string password) + { + var sslObjectService = new SSLModuleService80(SSLFlags, CCSUncPath, CCSCommonPassword); + + return sslObjectService.ExportPfx(serialNumber, password); + } + + public override SSLCertificate generateCSR(SSLCertificate certificate) + { + var sslObjectService = new SSLModuleService80(SSLFlags, CCSUncPath, CCSCommonPassword); + + sslObjectService.GenerateCsr(certificate); + + return certificate; + } + + public override List getServerCertificates() + { + var sslObjectService = new SSLModuleService80(SSLFlags, CCSUncPath, CCSCommonPassword); + + return sslObjectService.GetServerCertificates(); + } + + public override SSLCertificate installCertificate(SSLCertificate certificate, WebSite website) + { + var sslObjectService = new SSLModuleService80(SSLFlags, CCSUncPath, CCSCommonPassword); + + return sslObjectService.InstallCertificate(certificate, website); + } + + public override WebSite GetSite(string siteId) + { + var site = base.GetSite(siteId); + site.SniEnabled = UseSni; + return site; + } } } diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIs80/SSL/SSLModuleService80.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIs80/SSL/SSLModuleService80.cs new file mode 100644 index 00000000..01baf828 --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIs80/SSL/SSLModuleService80.cs @@ -0,0 +1,508 @@ +using System; +using System.Globalization; +using System.IO; +using CertEnrollInterop; +using WebsitePanel.Providers.Common; +using WebsitePanel.Server.Utils; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using Microsoft.Web.Administration; + +namespace WebsitePanel.Providers.Web.Iis +{ + public class SSLModuleService80 : SSLModuleService + { + private const string CertificateStoreName = "WebHosting"; + + public bool UseSNI { get; private set; } + public bool UseCCS { get; private set; } + public string CCSUncPath { get; private set; } + public string CCSCommonPassword { get; private set; } + + public SSLModuleService80(SslFlags sslFlags, string ccsUncPath, string ccsCommonPassword) + { + UseSNI = sslFlags.HasFlag(SslFlags.Sni); + UseCCS = sslFlags.HasFlag(SslFlags.CentralCertStore); + CCSUncPath = ccsUncPath; + CCSCommonPassword = ccsCommonPassword; + } + + public new SSLCertificate InstallCertificate(SSLCertificate cert, WebSite website) + { + try + { + var response = Activator.CreateInstance(Type.GetTypeFromProgID("X509Enrollment.CX509Enrollment", true)) as CX509Enrollment; + if (response == null) + { + throw new Exception("Cannot create instance of X509Enrollment.CX509Enrollment"); + } + + response.Initialize(X509CertificateEnrollmentContext.ContextMachine); + response.InstallResponse( + InstallResponseRestrictionFlags.AllowUntrustedRoot, + cert.Certificate, EncodingType.XCN_CRYPT_STRING_BASE64HEADER, + null + ); + + // At this point, certificate has been installed into "Personal" store + // We need to move it into "WebHosting" store + // Get certificate + var servercert = GetServerCertificates(StoreName.My.ToString()).Single(c => c.FriendlyName == cert.FriendlyName); + if (UseCCS) + { + // Delete existing certificate, if any. This is needed to install a new binding + if (CheckCertificate(website)) + { + DeleteCertificate(GetCurrentSiteCertificate(website), website); + } + } + + // Get certificate data - the one we just added to "Personal" store + var storeMy = new X509Store(StoreName.My, StoreLocation.LocalMachine); + storeMy.Open(OpenFlags.MaxAllowed); + X509CertificateCollection existCerts2 = storeMy.Certificates.Find(X509FindType.FindBySerialNumber, servercert.SerialNumber, false); + var certData = existCerts2[0].Export(X509ContentType.Pfx); + storeMy.Close(); + + if (UseCCS) + { + // Revert to InstallPfx to install new certificate - this also adds binding + InstallPfx(certData, string.Empty, website); + } + else + { + // Add new certificate to "WebHosting" store + var store = new X509Store(CertificateStoreName, StoreLocation.LocalMachine); + var x509Cert = new X509Certificate2(certData); + store.Open(OpenFlags.ReadWrite); + store.Add(x509Cert); + store.Close(); + } + + // Remove certificate from "Personal" store + storeMy.Open(OpenFlags.MaxAllowed); + X509CertificateCollection existCerts = storeMy.Certificates.Find(X509FindType.FindBySerialNumber, servercert.SerialNumber, false); + storeMy.Remove((X509Certificate2)existCerts[0]); + storeMy.Close(); + // Fill object with certificate data + cert.SerialNumber = servercert.SerialNumber; + cert.ValidFrom = servercert.ValidFrom; + cert.ExpiryDate = servercert.ExpiryDate; + cert.Hash = servercert.Hash; + cert.DistinguishedName = servercert.DistinguishedName; + + if (!UseCCS) + { + if (CheckCertificate(website)) + { + DeleteCertificate(GetCurrentSiteCertificate(website), website); + } + + AddBinding(cert, website); + } + } + catch (Exception ex) + { + Log.WriteError("Error adding SSL certificate", ex); + cert.Success = false; + } + + return cert; + } + + public new List GetServerCertificates() + { + // Use Web Hosting store - new for IIS 8.0 + return GetServerCertificates(CertificateStoreName); + } + + public new SSLCertificate ImportCertificate(WebSite website) + { + SSLCertificate certificate; + + try + { + certificate = GetCurrentSiteCertificate(website); + } + catch (Exception ex) + { + certificate = new SSLCertificate + { + Success = false, + Certificate = ex.ToString() + }; + } + + return certificate; + } + + public new SSLCertificate InstallPfx(byte[] certificate, string password, WebSite website) + { + SSLCertificate newcert, oldcert = null; + + // Ensure we perform operations safely and preserve the original state during all manipulations, save the oldcert if one is used + if (CheckCertificate(website)) + { + oldcert = GetCurrentSiteCertificate(website); + } + + X509Certificate2 x509Cert; + var store = new X509Store(CertificateStoreName, StoreLocation.LocalMachine); + + if (UseCCS) + { + // We need to use this constructor or we won't be able to export this certificate + x509Cert = new X509Certificate2(certificate, password, X509KeyStorageFlags.Exportable); + + var certData = x509Cert.Export(X509ContentType.Pfx); + var convertedCert = new X509Certificate2(certData, string.Empty, X509KeyStorageFlags.Exportable); + + // Attempts to move certificate to CCS UNC path + try + { + // Create a stream out of that new certificate + certData = convertedCert.Export(X509ContentType.Pfx, CCSCommonPassword); + + // Open UNC path and set path to certificate subject + var filename = (CCSUncPath.EndsWith("/") ? CCSUncPath: CCSUncPath + "/") + x509Cert.GetNameInfo(X509NameType.SimpleName, false) + ".pfx"; + var writer = new BinaryWriter(File.Open(filename, FileMode.Create)); + writer.Write(certData); + writer.Flush(); + writer.Close(); + // Certificated saved + } + catch (Exception ex) + { + // Log error + Log.WriteError("SSLModuleService could not save certificate to Centralized Certificate Store", ex); + // Re-throw + throw; + } + } + else + { + x509Cert = new X509Certificate2(certificate, password); + + // Step 1: Register X.509 certificate in the store + // Trying to keep X.509 store open as less as possible + try + { + store.Open(OpenFlags.ReadWrite); + + store.Add(x509Cert); + } + catch (Exception ex) + { + Log.WriteError(String.Format("SSLModuleService could not import PFX into X509Store('{0}', '{1}')", store.Name, store.Location), ex); + // Re-throw error + throw; + } + finally + { + store.Close(); + } + } + + // Step 2: Instantiate a copy of new X.509 certificate + try + { + store.Open(OpenFlags.ReadWrite); + newcert = GetSSLCertificateFromX509Certificate2(x509Cert); + } + catch (Exception ex) + { + if (!UseCCS) + { + // Rollback X.509 store changes + store.Remove(x509Cert); + } + // Log error + Log.WriteError("SSLModuleService could not instantiate a copy of new X.509 certificate. All previous changes have been rolled back.", ex); + // Re-throw + throw; + } + finally + { + store.Close(); + } + + if (!UseCCS) + { + // Step 3: Remove old certificate from the web site if any + try + { + store.Open(OpenFlags.ReadWrite); + // Check if certificate already exists, remove it. + if (oldcert != null) + DeleteCertificate(oldcert, website); + } + catch (Exception ex) + { + // Rollback X.509 store changes + store.Remove(x509Cert); + // Log the error + Log.WriteError( + String.Format("SSLModuleService could not remove existing certificate from '{0}' web site. All changes have been rolled back.", website.Name), ex); + // Re-throw + throw; + } + finally + { + store.Close(); + } + } + + // Step 4: Register new certificate with HTTPS binding on the web site + try + { + //if (!UseCCS) + //{ + // store.Open(OpenFlags.ReadWrite); + //} + + AddBinding(newcert, website); + } + catch (Exception ex) + { + if (!UseCCS) + { + // Install old certificate back if any + store.Open(OpenFlags.ReadWrite); + if (oldcert != null) + InstallCertificate(oldcert, website); + // Rollback X.509 store changes + store.Remove(x509Cert); + store.Close(); + } + // Log the error + Log.WriteError( + String.Format("SSLModuleService could not add new X.509 certificate to '{0}' web site. All changes have been rolled back.", website.Name), ex); + // Re-throw + throw; + } + + return newcert; + } + + public new byte[] ExportPfx(string serialNumber, string password) + { + if (UseCCS) + { + // This is not a good way to do it + // Find cert by somehow perhaps first looking in the database? There vi kan lookup the serialnumber and find the hostname needed to create the path to the cert in CCS and then we can load the certdata into a cert and do a export with new password. + // Another solution would be to look through all SSL-bindings on all sites until we found the site with the binding that has this serialNumber. But serialNumber is not good enough, we need hash that is unique and present in bindingInfo + // A third solution is to iterate over all files in CCS, load them into memory and find the one with the correct serialNumber, but that cannot be good if there are thousands of files... + foreach (var file in Directory.GetFiles(CCSUncPath)) + { + var fileStream = File.OpenRead(file); + + // Read certificate data from file + var certData = new byte[fileStream.Length]; + fileStream.Read(certData, 0, (int) fileStream.Length); + var convertedCert = new X509Certificate2(certData, CCSCommonPassword, X509KeyStorageFlags.Exportable); + + fileStream.Close(); + + if (convertedCert.SerialNumber == serialNumber) + { + return convertedCert.Export(X509ContentType.Pfx, password); + } + } + } + + var store = new X509Store(CertificateStoreName, StoreLocation.LocalMachine); + store.Open(OpenFlags.ReadOnly); + var cert = store.Certificates.Find(X509FindType.FindBySerialNumber, serialNumber, false)[0]; + var exported = cert.Export(X509ContentType.Pfx, password); + return exported; + } + + + public new void AddBinding(SSLCertificate certificate, WebSite website) + { + using (var srvman = GetServerManager()) + { + var store = new X509Store(CertificateStoreName, StoreLocation.LocalMachine); + store.Open(OpenFlags.ReadOnly); + + // Look for dedicated ip + var dedicatedIp = SiteHasBindingWithDedicatedIp(srvman, website); + + var bindingInformation = string.Format("{0}:443:{1}", website.SiteIPAddress, dedicatedIp ? "" : certificate.Hostname); + + Binding siteBinding = UseCCS ? + srvman.Sites[website.SiteId].Bindings.Add(bindingInformation, "https") : + srvman.Sites[website.SiteId].Bindings.Add(bindingInformation, certificate.Hash, store.Name); + + if (UseSNI) + { + siteBinding.SslFlags |= SslFlags.Sni; + } + if (UseCCS) + { + siteBinding.SslFlags |= SslFlags.CentralCertStore; + } + + store.Close(); + + srvman.CommitChanges(); + } + } + + public new ResultObject DeleteCertificate(SSLCertificate certificate, WebSite website) + { + var result = new ResultObject() { IsSuccess = true }; + + if (certificate == null) + { + return result; + } + + try + { + // Regardless of the CCS setting on the server, we try to find and remove the certificate from both CCS and WebHosting Store. + // This is because we don't know how this was set when the certificate was added + + if (!string.IsNullOrWhiteSpace(CCSUncPath) && Directory.Exists(CCSUncPath)) + { + // This is where it will be if CCS is used + var path = GetCCSPath(certificate.Hostname); + if (File.Exists(path)) + { + File.Delete(path); + } + } + + // Now delete all certs with the same serialnumber in WebHosting Store + var store = new X509Store(CertificateStoreName, StoreLocation.LocalMachine); + store.Open(OpenFlags.MaxAllowed); + + var certs = store.Certificates.Find(X509FindType.FindBySerialNumber, certificate.SerialNumber, false); + foreach (var cert in certs) + { + store.Remove(cert); + } + + store.Close(); + + // Remove binding from site + if (CheckCertificate(website)) + { + RemoveBinding(certificate, website); + } + } + catch (Exception ex) + { + Log.WriteError(String.Format("Unable to delete certificate for website {0}", website.Name), ex); + result.IsSuccess = false; + result.AddError("", ex); + } + + return result; + } + + public new SSLCertificate GetCurrentSiteCertificate(WebSite website) + { + using (var srvman = GetServerManager()) + { + var site = srvman.Sites[website.SiteId]; + var sslBinding = site.Bindings.First(b => b.Protocol == "https"); + + X509Certificate2 cert = null; + + // If the certificate is in the central store + if (((SslFlags)Enum.Parse(typeof(SslFlags), sslBinding["sslFlags"].ToString())).HasFlag(SslFlags.CentralCertStore)) + { + // Let's try to match binding host and certificate filename + var path = GetCCSPath(sslBinding.Host); + if (File.Exists(path)) + { + var fileStream = File.OpenRead(path); + + // Read certificate data from file + var certData = new byte[fileStream.Length]; + fileStream.Read(certData, 0, (int) fileStream.Length); + cert = new X509Certificate2(certData, CCSCommonPassword); + fileStream.Close(); + } + } + else + { + var currentHash = sslBinding.CertificateHash; + var store = new X509Store(CertificateStoreName, StoreLocation.LocalMachine); + store.Open(OpenFlags.ReadOnly); + + cert = store.Certificates.Cast().Single(c => Convert.ToBase64String(c.GetCertHash()) == Convert.ToBase64String(currentHash)); + + store.Close(); + } + + return GetSSLCertificateFromX509Certificate2(cert); + } + } + + private static List GetServerCertificates(string certificateStoreName) + { + var store = new X509Store(certificateStoreName, StoreLocation.LocalMachine); + + List certificates; + + try + { + store.Open(OpenFlags.ReadOnly); + certificates = store.Certificates.Cast().Select(GetSSLCertificateFromX509Certificate2).ToList(); + } + catch (Exception ex) + { + Log.WriteError( + String.Format("SSLModuleService is unable to get certificates from X509Store('{0}', '{1}') and complete GetServerCertificates call", store.Name, store.Location), ex); + // Re-throw exception + throw; + } + finally + { + store.Close(); + } + + return certificates; + } + + private string GetCCSPath(string bindingName) + { + return (CCSUncPath.EndsWith("/") ? CCSUncPath : CCSUncPath + "/") + bindingName + ".pfx"; + } + + private static SSLCertificate GetSSLCertificateFromX509Certificate2(X509Certificate2 cert) + { + var certificate = new SSLCertificate + { + Hostname = cert.GetNameInfo(X509NameType.SimpleName, false), + FriendlyName = cert.FriendlyName, + CSRLength = Convert.ToInt32(cert.PublicKey.Key.KeySize.ToString(CultureInfo.InvariantCulture)), + Installed = true, + DistinguishedName = cert.Subject, + Hash = cert.GetCertHash(), + SerialNumber = cert.SerialNumber, + ExpiryDate = DateTime.Parse(cert.GetExpirationDateString()), + ValidFrom = DateTime.Parse(cert.GetEffectiveDateString()), + Success = true + }; + + return certificate; + } + + private static bool SiteHasBindingWithDedicatedIp(ServerManager srvman, WebSite website) + { + try + { + var bindings = srvman.Sites[website.SiteId].Bindings; + return bindings.Any(b => string.IsNullOrEmpty(b.Host) && b.BindingInformation.Split(':')[1] != "*"); + } + catch + { + return false; + } + } + } +} diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIs80/WebsitePanel.Providers.Web.IIs80.csproj b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIs80/WebsitePanel.Providers.Web.IIs80.csproj index 8e83d0c4..dd28ae8c 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIs80/WebsitePanel.Providers.Web.IIs80.csproj +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIs80/WebsitePanel.Providers.Web.IIs80.csproj @@ -9,8 +9,9 @@ Properties WebsitePanel.Providers.Web WebsitePanel.Providers.Web.IIs80 - v3.5 + v4.0 512 + true @@ -32,11 +33,7 @@ False - ..\..\Lib\References\Microsoft\Microsoft.Web.Administration.dll - - - False - ..\..\Lib\References\Microsoft\Microsoft.Web.Management.dll + ..\..\Lib\References\Microsoft\Windows2012\Microsoft.Web.Administration.dll @@ -51,6 +48,9 @@ + + Code + @@ -65,7 +65,12 @@ {1b9dce85-c664-49fc-b6e1-86c63cab88d1} WebsitePanel.Providers.Web.IIs70 + + {e91e52f3-9555-4d00-b577-2b1dbdd87ca7} + WebsitePanel.Server.Utils + +