# Copyright 1999-2017. Plesk International GmbH. All rights reserved.
package Packer;
use strict;
use warnings;
use Status;
use HelpFuncs;
use Storage::FileNameCreator;
use ArchiveContent::ArchiveContent;
use CommonPacker;
use Mailman;
use Logging;
use PerlMD5;
use XPath;
use File::Temp;
use File::Basename qw(dirname);
use IPC::Run qw(run);
use Fcntl qw< S_IROTH S_IWOTH S_ISDIR S_ISLNK >;
use vars qw|@ISA|;
my $DEBUG = undef;
### Common function ###
sub new {
my $self = {};
bless( $self, shift );
$self->_init(@_);
return $self;
}
sub _init {
my ( $self, $version, $storagePolicy ) = @_;
XmlNode::resetCompatibilityProcs();
$self->{storage} = $storagePolicy;
$self->{version} = $version;
$self->{base64} = HelpFuncs::makeMIMEBase64();
$self->{fnamecreator} = Storage::FileNameCreator->new();
$self->setBackupProfileFileName( 'backup' );
$self->{ownerGuid} = '';
$self->{ownerType} = '';
$self->{roots} = [];
$self->{content_transport_type} = 'archive';
$self->{content_transport} = ArchiveContent::ArchiveContent->new( $self->{storage}, $self );
$self->{decrypt_full_dump} = 0;
$self->{apache_user} = AgentConfig::getApacheUserInfo();
$self->{mailman_user} = AgentConfig::getMailmanUserInfo();
$self->{incrementalCreationDate} = undef;
$self->{lastIndexPath} = undef;
$self->{lastIncrementFile} = undef;
$self->{excludePatternsFile} = undef;
$self->{relatedDumps} = ();
$self->flushDumpStatistics();
}
sub flushDumpStatistics {
my ($self) = @_;
$self->{stat} = ();
$self->{stat}{vhostDumpsCount} = 0;
$self->{stat}{vhostSizeOnFS} = 0;
$self->{stat}{vhostSizeDumped} = 0;
$self->{stat}{dbDumpsCount} = 0;
$self->{stat}{dbSizeOnFS} = 0;
$self->{stat}{dbSizeDumped} = 0;
$self->{stat}{mailDumpsCount} = 0;
$self->{stat}{mailSizeOnFS} = 0;
$self->{stat}{mailSizeDumped} = 0;
}
sub setContentTransport {
my ($self) = @_;
$self->{content_transport} = ArchiveContent::ArchiveContent->new($self->{storage}, $self);
}
sub getContentTransport {
my ($self) = @_;
return $self->{content_transport};
}
sub setBackupProfileFileName{
my ($self, $profileName, $profileId ) = @_;
$self->{backupname} = $self->{fnamecreator}->normalize_long_string( $profileName, $profileId );
$profileId = '' if not defined $profileId;
Logging::debug( "Set backup file name '$self->{backupname}' (profile '$profileName', id='$profileId')\n" );
$self->{backupPrefix} = $profileName;
}
sub setIncrementalCreationDate{
my ($self, $incrementalCreationDate) = @_;
$self->{fnamecreator}->setIncrementalCreationDate($incrementalCreationDate);
$self->{incrementalCreationDate} = $incrementalCreationDate;
}
sub getIncrementalCreationDate {
my ($self) = @_;
return $self->{incrementalCreationDate};
}
sub getCreationDate {
my ($self) = @_;
return $self->{fnamecreator}->getCreationDate();
}
sub setLastIndexPath{
my ($self, $lastIndexPath) = @_;
$self->{lastIndexPath} = $lastIndexPath;
}
sub setLastIncrementFile {
my ($self, $lastIncrementFile) = @_;
$self->{lastIncrementFile} = $lastIncrementFile;
}
sub setExcludePatternsFile {
my ($self, $excludePatternsFile) = @_;
$self->{excludePatternsFile} = $excludePatternsFile;
}
sub setBackupOwnerGuid{
my ($self, $ownerGuid, $ownertype ) = @_;
$ownerGuid = '' if not $ownerGuid;
$self->{ownerGuid} = $ownerGuid;
$ownertype = '' if not $ownertype;
$self->{ownerType} = $ownertype;
Logging::debug( "Set backup owner guid '$ownerGuid', type '$ownertype'\n" );
}
sub getBackupOwnerGuid{
my ($self) = @_;
return $self->{ownerGuid};
}
sub startCollectStorageStatistics {
my $self = shift;
$self->{storage}->startCollectStatistics();
}
sub getStorageStatistics {
my $self = shift;
return $self->{storage}->getStatistics();
}
sub setRoot {
my ( $self, $description, $content, $dumpformat, $adminGuid, $embeddedInfo ) = @_;
$self->{root} = XmlNode->new( 'migration-dump',
'attributes' =>
{ 'agent-name' => 'PleskX', 'dump-version' => $self->{version}, 'dump-original-version' => $self->{version} } );
$self->{root}->setAttribute( 'content-included', $content ? 'true' : 'false' ) if defined $content;
$self->{root}->setAttribute( 'dump-format', $dumpformat ) if defined $dumpformat;
my $dumpinfo = $self->{root}->getChild( 'dump-info', 1 );
if ($description) {
$dumpinfo->addChild( XmlNode->new( 'description', 'content' => $description ) );
}
my $osDescriptionNode = XmlNode->new('os-description');
$osDescriptionNode->setAttribute('type', 'unix');
if (my $apacheUid = getpwnam($self->{apache_user}{'user'})) {
$osDescriptionNode->setAttribute('apache-uid', $apacheUid);
}
if (my $apacheGid = getgrnam($self->{apache_user}{'group'})) {
$osDescriptionNode->setAttribute('apache-gid', $apacheGid);
}
if (my $mailmanUid = getpwnam($self->{mailman_user}{'user'})) {
$osDescriptionNode->setAttribute('mailman-uid', $mailmanUid);
}
if (my $mailmanGid = getgrnam($self->{mailman_user}{'group'})) {
$osDescriptionNode->setAttribute('mailman-gid', $mailmanGid);
}
$dumpinfo->addChild($osDescriptionNode);
my $cpDescriptionNode = XmlNode->new('cp-description');
my $componentsInstalledNode = XmlNode->new('components-installed');
my %packages = %{DAL::getSoftwarePackages()};
while (my ($name, $version) = each(%packages)) {
my $componentNode = XmlNode->new('component');
$componentNode->setAttribute('name', $name);
$componentsInstalledNode->addChild($componentNode);
}
$cpDescriptionNode->addChild($componentsInstalledNode);
if (defined($embeddedInfo->{'services'})) {
my ($services) = @{$embeddedInfo->{'services'}};
$self->addEmbeddedInfo($cpDescriptionNode, 'services', $services);
}
$dumpinfo->addChild($cpDescriptionNode);
my $contentTransportDescriptionNode = $self->{content_transport}->getContentTransportDescription();
if ( defined $contentTransportDescriptionNode ) {
my $contentTransportNode = XmlNode->new( 'content-transport' );
$contentTransportNode->addChild( $contentTransportDescriptionNode );
$dumpinfo->addChild ( $contentTransportNode );
}
if ($adminGuid) {
$dumpinfo->addChild(XmlNode->new('server-id', 'content' => $adminGuid));
}
}
sub setMarkers{
my ($self, @markers) = @_;
my $dumpinfo = $self->{root}->getChild('dump-info', 0);
foreach my $marker (@markers) {
$dumpinfo->addChild(XmlNode->new('dump-marker', 'content' => $marker));
}
}
sub _getRootForStorageFinish {
my ($self, $dumpDirPath) = @_;
my $dumpinfo = $self->{root}->getChild('dump-info', 0);
$dumpinfo->removeChildren('related-dumps');
if (exists $self->{relatedDumps}->{$dumpDirPath}) {
my $relatedDumpsNode = XmlNode->new('related-dumps');
$dumpinfo->addChild($relatedDumpsNode);
foreach my $relatedDump ( @{$self->{relatedDumps}->{$dumpDirPath}} ) {
$relatedDumpsNode->addChild(XmlNode->new('related-dump', 'content' => $relatedDump));
}
}
return $self->{root};
}
sub setDecryptFullDump {
my ($self) = @_;
$self->{decrypt_full_dump} = 1;
Logging::debug( "Set to decrypt full dump" );
}
sub turnOffContent{
my ($self) = @_;
$self->{skip_content} = 1;
Logging::debug( "The dump of content is switched off" );
}
sub isRootNode{
my ($self, $node) = @_;
foreach my $root( @{$self->{roots}} ){
return 1 if $root==$node;
}
return 0;
}
sub finishChild{
my ($self, $node, $path, $fileName ) = @_;
my $ret;
if(scalar( @{$self->{roots}} )==1 && $self->isRootNode($node) ) {
$ret = $self->{storage}->finish( $self->_getRootForStorageFinish($path), $path, $fileName );
die "Cannot create main dump file!" if $ret!=0;
$ret = $self->{storage}->getMainDumpXmlRelativePath();
}
else {
$ret = $self->{storage}->finishChild( $self->_getRootForStorageFinish($path), $node, $path, $fileName );
}
return $ret;
}
sub finishDomains {
my ($self, $fileName, $fh, $usersContentSize, $infoxml) = @_;
if ( exists $self->{domainNodes} ) {
my ( $id, $node, $path );
while ( ($id, $node ) = each( %{$self->{domainNodes}} ) ){
$path = $self->getDomainsBackupPath( $id );
Logging::debug( "Save domain dump $path" );
XmlNode::setStartSavePath( $path );
print $fh "" . $path . "/" .$self->getDomainsBackupPath( $id, $fileName, 1 ) . ".xml" . "\n";
my $fileid = $self->finishChild( $node, $path, $self->getDomainsBackupPath( $id, $fileName, 1 ) );
my $contentSize = $self->getContentSize($node);
@{$infoxml->{$fileid}} = ( $contentSize, $self->getDomainObjectId( $id ), $node->getAttribute('guid') );
$self->{storage}->createRepositoryIndex( $node->getAttribute('guid') . '_' . $self->getDomainObjectId( $id ) );
#Keep total domain content size for each client
my $clientId = PleskStructure::getClientIdForDomainId( $id );
$usersContentSize->{$clientId} = (exists $usersContentSize->{$clientId}) ? $usersContentSize->{$clientId} + $contentSize : $contentSize;
}
}
}
sub finishClients {
my ($self, $fileName, $fh, $selectResellers, $usersContentSize, $infoxml) = @_;
if( exists $self->{clientNodes} ){
my ( $id, $node, $path );
while( ($id, $node ) = each( %{$self->{clientNodes}} ) ){
my $fname;
if (exists $self->{resellersNodes}->{$id}) {
next if !$selectResellers;
$path = $self->getResellersBackupPath( $id );
$fname = $self->getResellersBackupPath( $id, $fileName, 1 );
Logging::debug( "Save reseller dump $path" );
} else {
next if $selectResellers;
$path = $self->getClientsBackupPath( $id );
$fname = $self->getClientsBackupPath( $id, $fileName, 1 );
Logging::debug( "Save client dump $path" );
}
XmlNode::setStartSavePath( $path );
print $fh "" . $path . "/" . $fname. ".xml" . "\n";
# Calculate current client size
$usersContentSize->{$id} = (exists $usersContentSize->{$id})
? $usersContentSize->{$id} + $self->getContentSize($node)
: $self->getContentSize($node);
# Add current client size to the parent (reseller or admin) total content size
my $parentId = PleskStructure::getClientParentId(PleskStructure::getClientNameFromId($id));
$usersContentSize->{$parentId} = (exists $usersContentSize->{$parentId})
? $usersContentSize->{$parentId} + $usersContentSize->{$id}
: $usersContentSize->{$id};
my $fileid = $self->finishChild( $node, $path, $fname );
@{$infoxml->{$fileid}} = ( $usersContentSize->{$id}, $self->getClientObjectId( $id ), $node->getAttribute('guid') );
$self->{storage}->createRepositoryIndex( $node->getAttribute('guid') . '_' . $self->getClientObjectId( $id ) );
}
}
}
sub finishCustomers {
my ($self, $fileName, $fh, $usersContentSize, $infoxml) = @_;
$self->finishClients($fileName, $fh, 0, $usersContentSize, $infoxml);
}
sub finishResellers {
my ($self, $fileName, $fh, $usersContentSize, $infoxml) = @_;
$self->finishClients($fileName, $fh, 1, $usersContentSize, $infoxml);
}
sub finish {
my ($self) = @_;
my %infoxml;
my $ret = 0;
my $fileName;
my $mainDumpXmlFile;
if(scalar( @{$self->{roots}} )!=1 ){
XmlNode::setStartSavePath( '' );
$fileName = $self->{fnamecreator}->getFileName( '', $self->{backupname}, '', 'info' );
$ret = $self->{storage}->finish( $self->_getRootForStorageFinish(''), '', $fileName );
die "Cannot create main dump file!" if $ret!=0;
$mainDumpXmlFile = $self->{storage}->getMainDumpXmlRelativePath();
@{$infoxml{$mainDumpXmlFile}} = ( $self->getContentSize( $self->{root} ), $self->getAdminObjectId(), ( exists $self->{admin} ? $self->{admin}->getAttribute('guid') : $self->{ownerGuid} ) );
$self->{storage}->createRepositoryIndex( ( exists $self->{admin} ? $self->{admin}->getAttribute('guid') : '' ) . '_' . $self->getAdminObjectId() );
}
$fileName = 'info';
my ($fh, $targetFile);
($fh, $targetFile ) = File::Temp::tempfile( AgentConfig::getBackupTmpDir() . "/pmm-xmlFilesList-XXXXXX", UNLINK => 1 );
print $fh "{storage}->getFullOutputPath()."\">\n";
print $fh "" . $self->{storage}->getMainDumpXmlFile() . "\n" if $self->{storage}->getMainDumpXmlFile();
my %usersContentSize; # Summary size of each customer, reseller and admin content
$self->finishDomains($fileName, $fh, \%usersContentSize, \%infoxml);
$self->finishCustomers($fileName, $fh, \%usersContentSize, \%infoxml);
$self->finishResellers($fileName, $fh, \%usersContentSize, \%infoxml);
if (exists $infoxml{$mainDumpXmlFile}) {
my $adminId = PleskStructure::getAdminId();
@{$infoxml{$mainDumpXmlFile}}[0] += $usersContentSize{$adminId} if exists $usersContentSize{$adminId};
}
print $fh "";
close $fh;
if ($self->{decrypt_full_dump}) {
$self->_decryptDump($targetFile);
} else {
$self->_encryptDump($targetFile);
}
my $path;
#Create discovered files
foreach my $fileid( keys( %infoxml ) ){
my $idx = rindex( $fileid, '/' );
$path = $fileid;
$path = substr( $path, 0, $idx ) if $idx>0;
my $xmlsize = 0;
my $files;
foreach my $id( keys( %infoxml ) ){
if( $idx<0 || index( $id, $path )==0 ){
$files = $self->{storage}->getFilesFromId( $id );
foreach my $filedata( @{$files} ) {
$xmlsize += $filedata->[1];
}
}
}
$files = $self->{storage}->getFilesFromId( $fileid );
if( scalar( @{$files} )==1 ){
my $xmlfiledata = $files->[0];
$xmlsize += @{$infoxml{$fileid}}[0];
my $objId = @{$infoxml{$fileid}}[1];
my $objGuid = @{$infoxml{$fileid}}[2];
$self->{storage}->writeDiscovered( $self->{storage}->getFilePathFromId( $fileid ), $xmlfiledata->[0], $xmlsize, $self->{ownerGuid}, $self->{ownerType}, $objGuid, $objId );
}
}
return 0;
}
sub _decryptDump {
my ($self, $targetFile) = @_;
eval {
my $encryptCmd = AgentConfig::getEncryptUtil();
push(@{$encryptCmd}, '--decrypt-by-plesk', '-backup-files-map', $targetFile);
Logging::debug("Execute: @{$encryptCmd}");
my $stderr;
IPC::Run::run($encryptCmd, '2>', \$stderr) or die($stderr);
};
if ($@) {
Logging::error("Cannot decrypt dump file (this is not fatal error!): $@", 'UtilityError');
}
}
sub _encryptDump {
my ($self, $targetFile) = @_;
my $cryptKey = $ENV{'PLESK_BACKUP_CRYPT_KEY'};
delete $ENV{'PLESK_BACKUP_CRYPT_KEY'} if ($cryptKey);
my $password = $ENV{'PLESK_BACKUP_PASSWORD'};
delete $ENV{'PLESK_BACKUP_PASSWORD'} if ($password);
eval {
my $encryptCmd = AgentConfig::getEncryptUtil();
push(@{$encryptCmd}, '--encrypt-by-plesk', '-backup-files-map', $targetFile);
Logging::debug("Execute: @{$encryptCmd}");
my $stderr;
IPC::Run::run($encryptCmd, '2>', \$stderr) or die($stderr);
};
if ($@) {
Logging::error("Cannot encrypt dump file (this is not fatal error!): $@", 'UtilityError');
}
$ENV{'PLESK_BACKUP_CRYPT_KEY'} = $cryptKey if ($cryptKey);
$ENV{'PLESK_BACKUP_PASSWORD'} = $password if ($password);
}
sub getContentSize{
my ($self, $node) = @_;
my $size = 0;
foreach my $child ( $node->getChildren() ) {
if( $child ) {
my $childName = $child->getName();
if( $childName && $childName eq 'cid' ){
if( !defined($child->getAttribute('referrer')) ) {
foreach my $cid ( $child->getChildren() ){
if ($cid->isAttributeExist('size')) {
$size += $cid->getAttribute('size');
}
}
}
}
else {
$size += $self->getContentSize($child);
}
}
}
return $size;
}
### Server functions ###
sub setServerSettings {
my ( $self ) = @_;
my $serverNode = XmlNode->new('server');
$self->{serverNode} = $serverNode;
}
sub addServerNodeToDump {
my ( $self ) = @_;
my $root = $self->{root};
unless (defined $root)
{
Logging::warning("Root node is not set", 'PackerStructure');
return;
}
if ( ref ($self->{serverNode}) =~ /XmlNode/ ) {
$root->addChild($self->{serverNode});
}
}
sub addPanelCertificate {
my ($self) = @_;
my $serverNode = $self->{serverNode};
my $path = AgentConfig::get('PRODUCT_ROOT_D') . "/admin/conf";
my $httpsdFilename = 'httpsd.pem';
if ( -e "$path/$httpsdFilename") {
my $certNode = XmlNode->new('panel-certificate');
my $content = undef;
open HTTPSDFILE, $path . "/" . $httpsdFilename;
binmode(HTTPSDFILE);
while () {
$content .= $_;
}
close HTTPSDFILE;
$certNode->addChild(XmlNode->new('cp-certificate', 'content' => $self->{base64}->{'ENCODE'}->($content) ));
my $rootchainFilename = 'rootchain.pem';
if ( -e "$path/$rootchainFilename") {
my $content = undef;
open ROOTCHAINFILE, $path . "/" . $rootchainFilename;
binmode(ROOTCHAINFILE);
while () {
$content .= $_;
}
close ROOTCHAINFILE;
$certNode->addChild(XmlNode->new('cp-rootchain', 'content' => $self->{base64}->{'ENCODE'}->($content) ));
}
$serverNode->getChild( 'certificates', 1 )->addChild($certNode);
}
}
sub addServerSiteIsolationConfig {
my ($self) = @_;
my $root = $self->{serverNode};
my $path = AgentConfig::get('PRODUCT_ROOT_D') . "/admin/conf";
my $file = 'site_isolation_settings.ini';
if ( -e "$path/$file") {
my $siteIsolationNode = XmlNode->new('site-isolation');
my $configText = undef;
open CONFIGFILE, $path . "/" . $file;
binmode(CONFIGFILE);
while () {
$configText .= $_;
}
close CONFIGFILE;
$siteIsolationNode->addChild(XmlNode->new('config', 'content' => $self->{base64}->{'ENCODE'}->($configText) ));
$root->addChild($siteIsolationNode);
}
}
sub setServerEventHandler {
my ($self, $embeddedInfo) = @_;
return unless defined($embeddedInfo->{'events'});
my ($events) = @{$embeddedInfo->{'events'}};
return unless ref($events) =~ /HASH/;
my $eventsNode = XmlNode->new('events');
my ($rotation) = @{$events->{'rotation'}};
$self->addEmbeddedInfo($eventsNode, 'rotation', $rotation);
if (defined($events->{'event'})) {
foreach my $event (@{$events->{'event'}}) {
$self->addEmbeddedInfo($eventsNode, 'event', $event);
}
}
$self->{serverNode}->addChild($eventsNode);
}
sub addServerNotifications {
my ( $self, $expirationWarnDays, $ptrNotifications, $ptrNotes ) = @_;
my $root = $self->{serverNode};
my @notifications = @{$ptrNotifications};
my %notes = %{$ptrNotes};
my $notificationsNode = XmlNode->new('notifications');
$notificationsNode->setAttribute( 'expiration-warning-days', $expirationWarnDays);
foreach my $notification (@notifications) {
my $notificationNode = XmlNode->new( 'notification' );
$notificationNode->setAttribute( 'id', $notification->{'id'} );
$notificationNode->setAttribute( 'send2admin', $notification->{'send2admin'} ? 'true' : 'false' );
$notificationNode->setAttribute( 'send2reseller', $notification->{'send2reseller'} ? 'true' : 'false' );
$notificationNode->setAttribute( 'send2client', $notification->{'send2client'} ? 'true' : 'false' );
$notificationNode->setAttribute( 'send2email', $notification->{'send2email'} ? 'true' : 'false' );
$notificationNode->setAttribute( 'email', $notification->{'email'} ) if defined $notification->{'email'};
$notificationNode->setAttribute( 'subj', $notification->{'subj'} ) if defined $notification->{'subj'};
my $noteText = (exists $notes{$notification->{'note_id'}}) ? $notes{$notification->{'note_id'}} : '';
$notificationNode->addChild( XmlNode->new( 'notice-text', 'content' => $noteText ) );
$notificationsNode->addChild( $notificationNode );
}
$root->addChild($notificationsNode);
}
sub addServerCustomButton {
my ( $self, $id, $optionsPtr, $customButtonsDir, $icon ) = @_;
my $parent = $self->{serverNode};
if ( !defined($parent) ) {
Logging::warning('Unable to dump custom buttons settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $node = $self->makeCustomButtonNode( 'admin', undef, $id, $optionsPtr, $customButtonsDir, $icon );
$parent->getChild( 'interface-preferences', 1 )->addChild($node);
}
my %dumpedSystemIps;
sub addServerIp {
my ( $self, $ip ) = @_;
$self->setServerSettings() unless defined $self->{serverNode};
if ( ! $dumpedSystemIps{$ip->{'ip_address'}} ) {
$self->makeSystemIpNode( $self->{serverNode}, $ip );
$dumpedSystemIps{$ip->{'ip_address'}} = 1;
}
}
sub setServerDefaultIp {
my ( $self, $ip ) = @_;
my $parent = $self->{serverNode};
if ( !defined($parent) ) {
Logging::warning('Unable to dump server default IP, because of dump XML structure is not full', 'PackerStructure');
return;
}
$parent->getChild( 'properties', 1 )->addChild( XmlNode->new( 'default-ip', 'content' => $ip ) );
}
sub setServerHostname {
my ( $self, $hostname ) = @_;
my $parent = $self->{serverNode};
if ( !defined($parent) ) {
Logging::warning('Unable to dump server host name, because of dump XML structure is not full', 'PackerStructure');
return;
}
$parent->getChild( 'properties', 1 )->addChild( XmlNode->new( 'hostname', 'content' => $hostname ) );
}
sub setServerAdminInfo {
my ( $self, $ptrAdmin, $passwd, $max_btn_len, $send_announce, $external_id, $cron, $descriptions ) = @_;
my $parent = $self->{admin};
if ( !defined($parent) ) {
Logging::warning('Unable to dump server admin user information, because of dump XML structure is not full', 'PackerStructure');
return;
}
$parent->setAttribute( 'max-button-length', $max_btn_len ) if $max_btn_len;
$parent->setAttribute( 'send-announce', $send_announce ) if $send_announce;
$parent->setAttribute( 'external-id', $external_id ) if defined $external_id and $external_id ne '';
my %adminInfo = (
'cname' => 'company',
'phone' => 'phone',
'fax' => 'fax',
'address' => 'address',
'city' => 'city',
'state' => 'state',
'pcode' => 'zip',
'country' => 'country',
'email' => 'email',
'pname' => 'name',
'locale' => 'locale',
);
my $pref = $parent->getChild( 'preferences', 1 );
while ( my ( $name, $value ) = each( %{$ptrAdmin} ) ) {
#Attributes transformation. Bug 97408
$name =~ s/^admin_//g;
next if not defined $adminInfo{$name};
$pref->addChild( XmlNode->new( 'pinfo', 'attributes' => { 'name' => $adminInfo{$name} }, 'content' => $value ) );
}
if (defined $cron) {
$self->addEmbeddedInfo($pref, 'scheduled-tasks', $cron);
}
$self->makeDescriptionsNode( $pref, $descriptions );
}
sub addServerDb {
my ( $self, $dbServerPtr, $passwd, $default ) = @_;
my %dbServer = %{$dbServerPtr};
my $parent = $self->{serverNode};
if ( !defined($parent) ) {
Logging::warning('Unable to dump server database, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $dbServerNode = $self->makeDbServerNodeWithoutCredentials(\%dbServer);
if ( $default ) {
$dbServerNode->setAttribute( 'default', 'true' );
}
if ( ($dbServer{'admin_login'}) and ($dbServer{'admin_login'} ne '')) {
my $adminNode =
XmlNode->new( 'db-admin',
"attributes" => { "name" => "$dbServer{'admin_login'}" } );
if ( $dbServer{'type'} eq 'mysql'
&& $dbServer{'host'} eq 'localhost' )
{
$dbServer{'admin_password'} = $passwd;
}
my $passwordNode =
CommonPacker::makePasswordNode( $dbServer{'admin_password'}, 'plain' )
; # password type for dbservers is always plain
$adminNode->addChild($passwordNode);
$dbServerNode->addChild($adminNode);
}
$parent->getChild( 'db-servers', 1 )->addChild($dbServerNode);
}
sub makeDbServerNodeWithoutCredentials {
my ($self, $dbServer) = @_;
my $dbServerNode = XmlNode->new('db-server');
$dbServerNode->setAttribute( 'type', $dbServer->{'type'} );
$dbServerNode->addChild( XmlNode->new( 'host', 'content' => "$dbServer->{'host'}" ) );
$dbServerNode->addChild( XmlNode->new( 'port', 'content' => "$dbServer->{'port'}" ) );
return $dbServerNode;
}
sub makeDatabaseUserRemoteAccessRulesNode {
my ($self, $dbUser, $dbId) = @_;
Logging::debug("Backing up remote access rules for db user " . $dbUser->{'login'});
my @rules = @{DAL::DatabaseUserRemoteAccessRules($dbUser->{'login'}, $dbId)};
if ( @rules ) {
my $rulesNode = XmlNode->new('remote-access-rules');
for my $ptrRow ( @rules ) {
my $ruleItemNode = XmlNode->new( 'rule-item' );
$ruleItemNode->setAttribute( 'type', $ptrRow->[0] );
$ruleItemNode->setAttribute( 'ip-address', $ptrRow->[1] );
$ruleItemNode->setAttribute( 'ip-subnet-mask', $ptrRow->[2] );
$rulesNode->addChild( $ruleItemNode );
}
return $rulesNode;
}
return;
}
sub addServerKey {
my ( $self, $keyId, $keyName, $keyDir, $additional, $instance ) = @_;
my $parent = $self->{serverNode};
if ( !defined($parent) ) {
Logging::warning('Unable to dump server license key, because of dump XML structure is not full', 'PackerStructure');
return;
}
if ( -e "$keyDir/$keyName" ) {
my $keyNode =
XmlNode->new( 'key',
'attributes' => { 'additional' => $additional } );
$keyNode->setAttribute('instance-id', $instance) if $instance ne '';
my $cid = $self->{content_transport}->addAdminContent(
'key',
undef,
"$keyId.key",
"directory" => $keyDir,
"include" => [$keyName]
);
$keyNode->getChild( 'content', 1, 1 )->addChild($cid) if $cid;
$parent->getChild( 'keys', 1 )->addChild($keyNode);
}
}
sub setServerMail {
my ( $self, $letterSize, $paramsPtr, $mailSettingsPtr, $blackListPtr, $whiteListPtr, $ipAddressesPtr, $externalWebmailsPtr, $mailCertificate ) = @_;
my %params = %{$paramsPtr};
my %mailSettings = %{$mailSettingsPtr};
my @blackList = @{$blackListPtr};
my %whiteList = %{$whiteListPtr};
my @externalWebmails = @{$externalWebmailsPtr};
my $parent = $self->{serverNode};
if ( !defined($parent) ) {
Logging::warning('Unable to dump server mail settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $mailNode = XmlNode->new(
'mail-settings',
'attributes' => {
'relay' => $mailSettings{'relay'},
'use-vocabulary' => (defined($params{'use_vocabulary'}) and ($params{'use_vocabulary'} eq 'true'))
? 'true'
: 'false',
'short-pop3-names' => (defined($params{'allow_short_pop3_names'}) and ($params{'allow_short_pop3_names'})) eq 'enabled'
? 'true'
: 'false',
'message-submission' => (defined($mailSettings{'message_submission'}) and ($mailSettings{'message_submission'} eq 'true'))
? 'true'
: 'false',
'sign-outgoing-mail' => (defined($mailSettings{'domain_keys_sign'}) and ($mailSettings{'domain_keys_sign'} eq 'true'))
? 'true'
: 'false',
'verify-incoming-mail' => (defined($mailSettings{'domain_keys_verify'}) and ($mailSettings{'domain_keys_verify'} eq 'true'))
? 'true'
: 'false',
}
);
if (defined $letterSize) {
$mailNode->setAttribute('max-letter-size', $letterSize);
}
if (defined $mailSettings{'courier_max_connections'}) {
$mailNode->setAttribute('courier-max-connections', $mailSettings{'courier_max_connections'});
}
if (defined $mailSettings{'courier_max_connections_per_ip'}) {
$mailNode->setAttribute('courier-max-connections-per-ip', $mailSettings{'courier_max_connections_per_ip'});
}
if (defined $mailSettings{'dovecot_max_connections'}) {
$mailNode->setAttribute('dovecot-max-connections', $mailSettings{'dovecot_max_connections'});
}
if (defined $mailSettings{'dovecot_max_connections_per_ip'}) {
$mailNode->setAttribute('dovecot-max-connections-per-ip', $mailSettings{'dovecot_max_connections_per_ip'});
}
if (defined $mailSettings{'dmarc_policy'}) {
$mailNode->setAttribute('dmarc-enabled', $mailSettings{'dmarc_policy'} eq 'true' ? 'true' : 'false');
}
$mailNode->setAttribute('certificate', $mailCertificate) if defined $mailCertificate;
my $spfNode = XmlNode->new(
'spf',
'attributes' => {
'status' => (exists $mailSettings{'spf_enabled'} and $mailSettings{'spf_enabled'} eq 'true') ? 'true' : 'false'
}
);
$spfNode->setAttribute('spf-behavior', (exists $mailSettings{'spf_behavior'} and "$mailSettings{'spf_behavior'}" ne '' ) ? $mailSettings{'spf_behavior'} : 1);
if (exists $mailSettings{'spf_dnserrignore'}) {
$spfNode->setAttribute('spf-ignore-dns-error', $mailSettings{'spf_dnserrignore'} eq 'true' ? 'true' : 'false');
}
$spfNode->addChild( XmlNode->new( 'spf-rules', 'content' => exists $mailSettings{'spf_rules'} ? $mailSettings{'spf_rules'} : '' ) );
$spfNode->addChild( XmlNode->new( 'spf-guess', 'content' => exists $mailSettings{'spf_guess'} ? $mailSettings{'spf_guess'} : '' ) );
$spfNode->addChild( XmlNode->new( 'spf-exp', 'content' => exists $mailSettings{'spf_exp'} ? $mailSettings{'spf_exp'} : '' ) );
$mailNode->addChild($spfNode);
my $rblNode = XmlNode->new(
'rbl',
'attributes' => {
'status' => ( exists $mailSettings{'rbl'} and $mailSettings{'rbl'} eq 'true' )
? 'true'
: 'false'
}
);
$rblNode->addChild( XmlNode->new( 'rbl-server', 'content' => exists $mailSettings{'rbl_server'} ? $mailSettings{'rbl_server'} : '' ) );
$mailNode->addChild($rblNode);
if ( $mailSettings{'relay'} eq 'auth' ) {
$mailNode->setAttribute( 'pop-auth', my $disable_pop_auth = (exists $mailSettings{'disable_pop_auth'} and $mailSettings{'disable_pop_auth'} ? 'false' : 'true') );
$mailNode->setAttribute( 'smtp-auth', (exists $mailSettings{'disable_smtp_auth'} and $mailSettings{'disable_smtp_auth'} ? 'false' : 'true') );
$mailNode->setAttribute( 'poplock-time', $mailSettings{'poplock_time'} ) if ('false' eq $disable_pop_auth);
}
# black list
my $listNode = XmlNode->new('black-list');
for my $listItem (@blackList) {
$listNode->addChild( XmlNode->new( 'list-item', 'content' => $listItem ) );
}
$mailNode->addChild($listNode);
# white list
$listNode = XmlNode->new('white-list');
for my $key (keys %whiteList) {
$listNode->addChild(
XmlNode->new(
'list-item', 'content' => $key . '/' . $whiteList{$key}
)
);
}
$mailNode->addChild($listNode);
$parent->addChild($mailNode);
if (@externalWebmails) {
$self->_makeExternalWebmails(\@externalWebmails);
}
for my $key (keys %mailSettings) {
if ($key =~ /^outgoing_messages_/) {
$self->_makeServerOutgoingMessagesParameter($key, $mailSettings{$key});
}
}
$self->_makeSeverOutgoingEmailMode($mailSettingsPtr, $ipAddressesPtr);
}
sub setServerDNS {
my ( $self, $paramsPtr, $recordsPtr ) = @_;
my @records = @{$recordsPtr};
my %params = %{$paramsPtr};
my $parent = $self->{serverNode};
if ( !defined($parent) ) {
Logging::warning('Unable to dump server DNS settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
# dump dns
my $dnsSettingsAttributes = {};
if (defined $params{'dns_recursion'} and ($params{'dns_recursion'} eq 'any' or $params{'dns_recursion'} eq 'localnets' or $params{'dns_recursion'} eq 'localhost')) {
$dnsSettingsAttributes = {
'recursion' => $params{'dns_recursion'}
}
}
my $dnsNode = XmlNode->new(
'dns-settings',
'attributes' => $dnsSettingsAttributes
);
my $dnsZone = XmlNode->new(
'dns-zone',
'attributes' =>
{ 'email' => 'root@localhost.localdomain', 'type' => 'master' },
'children' =>
[ Status::make( (not exists $params{'dns_zone_status'} or $params{'dns_zone_status'} ne 'false') ? 0 : 16 ) ]
);
$dnsZone->setAttribute( 'serial-format', $params{'soa_serial_format'} ) if exists $params{'soa_serial_format'};
my %zone_params = (
'ttl' => 1 * 86400,
'refresh' => 3 * 3600,
'retry' => 1 * 3600,
'expire' => 7 * 86400,
'minimum' => 3 * 3600
);
my %zone_units = (
'ttl' => 86400,
'refresh' => 3600,
'retry' => 3600,
'expire' => 86400,
'minimum' => 3600
);
foreach my $zone_param ( keys %zone_params ) {
my $soa_param = 'soa_' . $zone_param;
$dnsZone->addChild(
$self->makeDnsZoneParam(
$zone_param,
exists $params{ $soa_param . '_unit' }
? $params{ $soa_param . '_unit' }
: $zone_units{$zone_param},
exists $params{$soa_param} ? $params{$soa_param}
: $zone_params{$zone_param},
)
);
}
# dns records
for my $ptrHash (@records) {
my $dnsrec = $self->makeDnsRecord($ptrHash);
if ($dnsrec) {
$dnsZone->addChild($dnsrec);
}
}
$dnsNode->addChild($dnsZone);
# dump common acl for dns zone
my $aclNode = XmlNode->new('common-acl');
foreach my $param ( keys %params ) {
if ( $param =~ /^DNS_Allow_Transfer/ ) {
$aclNode->addChild( XmlNode->new( 'list-item', 'content' => $params{$param} ) );
}
}
$dnsNode->addChild($aclNode);
my $subdomainOwnZone = 'false';
if (exists($params{'subdomain_own_zones'})) {
$subdomainOwnZone = $params{'subdomain_own_zones'} eq 'false' ? 'false' : 'true';
}else {
$subdomainOwnZone = 'false';
}
$dnsNode->addChild( XmlNode->new( 'subdomain-own-zones', 'content' => $subdomainOwnZone ) );
$parent->addChild($dnsNode);
}
sub setServerWebSettings {
my ($self, $embeddedInfo) = @_;
if (defined($embeddedInfo->{'web-settings'})) {
my ($webSettings) = @{$embeddedInfo->{'web-settings'}};
$self->addEmbeddedInfo($self->{serverNode}, 'web-settings', $webSettings);
}
}
sub addEmbeddedInfo {
my ($self, $parentNode, $embeddedNodeName, $embeddedInfo) = @_;
eval {require XML::Simple; 1;};
my $xs = XML::Simple->new(ForceArray => 1);
my $embeddedInfoXml = $xs->XMLout($embeddedInfo, RootName => $embeddedNodeName);
$embeddedInfoXml = Encode::encode('UTF-8', $embeddedInfoXml); # workaround for UTF8 symbols
$parentNode->addChild(XmlNode->new(undef, 'raw' => $embeddedInfoXml));
}
sub addServerCertificate {
my ( $self, $name, $cert, $csr, $ca_cert, $pvt_key, $default) = @_;
my $parent = $self->{serverNode};
if ( !defined($parent) ) {
Logging::warning('Unable to dump server certificate, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $root = XmlNode->new('certificate');
addUrlDecodedTextNode( $root, 'certificate-data', $cert ) if defined($cert);
addUrlDecodedTextNode( $root, 'signing-request', $csr ) if defined($csr);
addUrlDecodedTextNode( $root, 'ca-certificate', $ca_cert ) if defined($ca_cert);
addUrlDecodedTextNode( $root, 'private-key', $pvt_key ) if defined($pvt_key);
$root->setAttribute( 'name', $name );
if ($default) {
$root->setAttribute('default', 'true');
}
$parent->getChild( 'certificates', 1 )->addChild($root);
}
sub addTemplateToServer {
my ( $self, $templateType, $templateName, $dataPtr ) = @_;
my %templates = (
'reseller' => 'reseller-template',
'domain' => 'domain-template',
'domain_addon' => 'domain-template'
);
unless ( exists( $templates{$templateType} ) ){
return;
}
$self->setServerSettings() unless defined $self->{serverNode};
my $root = $self->{serverNode};
my $node = $self->makeTemplateNode($templates{$templateType}, $templateName, $dataPtr);
$root->getChild( 'account-templates', 1 )->addChild($node);
}
sub makePlanItemNode {
my ( $self, $planItemPtr, $planItemPropsPtr, $customButtonsDir ) = @_;
return unless ( ref($planItemPtr) =~ /HASH/ );
return unless ( ref($planItemPropsPtr) =~ /HASH/ );
return unless ( exists( $planItemPtr->{'name'}) && exists( $planItemPtr->{'classname'}) && exists( $planItemPtr->{'uuid'}) );
my $planItemNode = XmlNode->new('plan-item');
$planItemNode->setAttribute( 'name', $planItemPtr->{'name'} );
$planItemNode->setAttribute( 'type', $planItemPtr->{'classname'} );
$planItemNode->setAttribute( 'guid', $planItemPtr->{'uuid'} );
$planItemNode->setAttribute( 'visible', ($planItemPtr->{'isVisible'})? 'true' : 'false' );
if ( ( $planItemPtr->{'classname'} eq 'Plan_Item_Custom') && ( defined $planItemPropsPtr->{'file'} ) ) {
my $file = $planItemPropsPtr->{'file'};
my $filename = "$customButtonsDir/$file";
if( -f $filename) {
my $cid = $self->{content_transport}->addAdminContent('icon', undef, 'icon_planitem'.$planItemPtr->{'id'}, 'directory' => $customButtonsDir, 'include' => [$file]);
$planItemNode->getChild('content', 1, 1)->addChild($cid) if $cid;
}
}
my $applicableNode = XmlNode->new( 'applicable' );
$applicableNode->addChild( XmlNode->new( 'applicable-to-subscription' ) ) if ( $planItemPtr->{'applicableToSubscription'} == 1 );
$applicableNode->addChild( XmlNode->new( 'applicable-to-site' ) ) if ( $planItemPtr->{'applicableToSite' } == 1 );
$applicableNode->addChild( XmlNode->new( 'applicable-to-email' ) ) if ( $planItemPtr->{'applicableToEmail' } == 1 );
$planItemNode->addChild( $applicableNode );
my $propertiesNode = XmlNode->new( 'properties' );
while ( my ($name,$value) = each( %{$planItemPropsPtr} ) ) {
next if ($name eq '');
my $planItemPropertyNode = XmlNode->new( 'plan-item-property' );
$planItemPropertyNode->setAttribute( 'name', $name);
if ( $value ne '' ) {
$planItemPropertyNode->setText( $value );
}
$propertiesNode->addChild( $planItemPropertyNode );
}
$planItemNode->addChild( $propertiesNode );
return $planItemNode;
}
sub addPlanItemToServer {
my ( $self, $planItemPtr, $planItemPropsPtr, $customButtonsDir ) = @_;
my $root = $self->{serverNode};
my $node = $self->makePlanItemNode( $planItemPtr, $planItemPropsPtr, $customButtonsDir );
$root->getChild( 'account-templates', 1 )->addChild($node) if defined $node;
}
sub setServerAppVault {
my ( $self ) = @_;
my $root = $self->{serverNode};
return $root->getChild('application-vault', 1);
}
sub setServerPackagesPool {
my ( $self ) = @_;
my $appVaultNode = $self->setServerAppVault();
return $appVaultNode->getChild('sapp-packages-pool', 1);
}
my %dumpedApplications;
sub addServerAppPackage {
my ($self, $name, $version, $release, $distrib_path, $file_name, $is_uploaded, $is_visible, $applicationPackage) = @_;
my $fullname = $name."-".$version."-".$release;
if (exists $dumpedApplications{$fullname}) {
return;
}
$dumpedApplications{$fullname} = 1;
my $appPackagesPoolNode = $self->setServerPackagesPool();
my $packageNode = XmlNode->new('sapp-package');
if ( defined $applicationPackage and $applicationPackage->getSappPackageId() ) {
$packageNode->addChild( XmlNode->new( 'sapp-package-id', 'content' => $applicationPackage->getSappPackageId() ) );
}
$packageNode->addChild( XmlNode->new( 'sapp-name', 'content' => $name ) );
$packageNode->addChild( XmlNode->new( 'sapp-version', 'content' => $version ) ) if ( $version );
$packageNode->addChild( XmlNode->new( 'sapp-release', 'content' => $release ) ) if ( $release );
$packageNode->addChild( XmlNode->new( 'sapp-uploaded' )) if ( defined $is_uploaded && $is_uploaded ne "0" );
$packageNode->addChild( XmlNode->new( 'sapp-visible' )) if ( defined $is_visible && $is_visible ne "0" );
if( $distrib_path && $file_name )
{
my $real_path = $distrib_path . "/" . $file_name;
if ( -e $real_path ) {
my $cid = $self->{content_transport}->addAdminContent(
'sapp-distrib',
undef,
"sapp-distrib." . HelpFuncs::generateProcessId(),
"directory" => $distrib_path,
"include" => [$file_name]
);
$packageNode->getChild( 'content', 1, 1 )->addChild( $cid ) if $cid;
}
else { return; }
if ( defined $applicationPackage ) {
my $settings = $applicationPackage->getSettings();
if ( $settings ) {
my $settingsNode = XmlNode->new('sapp-settings');
foreach my $setting ( keys %{$settings} ) {
my $settingNode = XmlNode->new('setting');
$settingNode->addChild( XmlNode->new( 'name', 'content' => $setting ) );
if (ref($settings->{$setting}) =~ /ARRAY/) {
foreach my $value ( @{$settings->{$setting}}) {
$settingNode->addChild( XmlNode->new( 'value', 'content' => $value ) );
}
} else {
$settingNode->addChild( XmlNode->new( 'value', 'content' => $settings->{$setting} ) );
}
$settingsNode->addChild($settingNode);
}
$packageNode->addChild($settingsNode);
}
}
$appPackagesPoolNode->addChild($packageNode);
}
}
sub setServerAppItemsPool {
my ( $self ) = @_;
my $appVaultNode = $self->setServerAppVault();
return $appVaultNode->getChild('sapp-items-pool',1);
}
sub addServerAppItem {
my ($self, $paramsPtr) = @_;
my %params = %{$paramsPtr};
my $appItemsPoolNode = $self->setServerAppItemsPool();
my $appItemNode = XmlNode->new('sapp-item');
$appItemNode->setAttribute( 'enabled',
( $params{'disabled'} eq 'true' ) ? 'false' : 'true' )
if defined $params{'disabled'};
my $appSpecNode = XmlNode->new('sapp-spec');
$appSpecNode->addChild(
XmlNode->new( 'sapp-name', 'content' => $params{'sapp_name'} ) );
$appSpecNode->addChild(
XmlNode->new(
'sapp-version', 'content' => $params{'sapp_version'}
)
) if defined $params{'sapp_version'};
$appSpecNode->addChild(
XmlNode->new(
'sapp-release', 'content' => $params{'sapp_release'}
)
) if defined $params{'sapp_release'};
$appItemNode->addChild($appSpecNode);
$appItemNode->addChild(
XmlNode->new(
'license-type',
'content' => defined( $params{'license_type_id'} )
? $params{'license_type_id'}
: "0"
)
);
$appItemNode->addChild(
XmlNode->new( 'shared', 'content' => $params{'shared'} ) )
if defined $params{'shared'};
$appItemNode->addChild(
XmlNode->new( 'description', 'content' => $params{'description'} )
) if defined $params{'description'};
$appItemNode->addChild(
XmlNode->new(
'instances-limit', 'content' => $params{'instances_limit'}
)
) if defined $params{'instances_limit'};
$appItemsPoolNode->addChild($appItemNode);
}
sub setServerAppLicensesPool {
my ( $self ) = @_;
my $appVaultNode = $self->setServerAppVault();
return $appVaultNode->getChild('sapp-licenses-pool',1);
}
sub addServerAppLicense {
my ($self, $keyNumber, $licenseType, $licenseText) = @_;
my $licensePoolNode = $self->setServerAppLicensesPool();
my $licenseNode = XmlNode->new(
'sapp-license',
'children' => [
XmlNode->new( 'key-number', 'content' => $keyNumber ),
XmlNode->new( 'license-type', 'content' => $licenseType ),
XmlNode->new( 'license-text', 'content' => $licenseText )
]
);
$licensePoolNode->addChild($licenseNode);
}
sub setServerSBConfig {
my ( $self, $configPtr ) = @_;
my @config = @{$configPtr};
my $serverNode = $self->{serverNode};
my $sbNode = XmlNode->new('sb-config');
for my $ptrHash (@config) {
$sbNode->addChild(
XmlNode->new(
'sb-param',
'children' => [
XmlNode->new(
'sb-param-name', 'content' => $ptrHash->{'param_name'}
),
XmlNode->new(
'sb-param-value', 'content' => $ptrHash->{'param_value'}
)
]
)
);
}
$serverNode->addChild($sbNode);
}
sub setGLServerSettings {
my ( $self, $paramsPtr) = @_;
my %params = %{$paramsPtr};
my $serverNode = $self->{serverNode};
my $glNode = XmlNode->new('grey-listing');
$glNode->setAttribute('grey-interval', $params{'greyInterval'}) if defined $params{'greyInterval'};
$glNode->setAttribute('expire-interval', $params{'expireInterval'}) if defined $params{'expireInterval'};
$glNode->setAttribute('penalty-enabled', $params{'penaltyEnabled'}) if defined $params{'penaltyEnabled'};
$glNode->setAttribute('penalty-interval', $params{'penaltyInterval'}) if defined $params{'penaltyInterval'};
$glNode->setAttribute('enabled', $params{'enabled'}) if defined $params{'enabled'};
$glNode->setAttribute('personal-conf', $params{'personal-conf'}) if defined $params{'personal-conf'};
my $wlNode = XmlNode->new('white-list');
foreach my $wdomain (@{$params{'white_domains'}}) {
$wlNode->addChild(XmlNode->new('list-item', 'content' => $wdomain));
}
$glNode->addChild($wlNode);
my $blNode = XmlNode->new('black-list');
foreach my $bdomain (@{$params{'black_domains'}}) {
$blNode->addChild(XmlNode->new('list-item', 'content' => $bdomain));
}
$glNode->addChild($blNode);
$serverNode->addChild($glNode);
}
sub setControlsVisibility {
my ( $self, $paramsPtr ) = @_;
my %params = %{$paramsPtr};
my $serverNode = $self->{serverNode};
my $controlsVisibilityNode = XmlNode->new('controls-visibility');
$controlsVisibilityNode->addChild( XmlNode->new( 'hide-domain-registration-buttons', 'content' => HelpFuncs::negation(HelpFuncs::checkValue($params{'domain_registration'},'true','false')) ) );
$controlsVisibilityNode->addChild( XmlNode->new( 'hide-certificate-purchasing-buttons', 'content' => HelpFuncs::negation(HelpFuncs::checkValue($params{'cert_purchasing'},'true','false')) ) );
$controlsVisibilityNode->addChild( XmlNode->new( 'hide-extra-services-buttons', 'content' => HelpFuncs::negation(HelpFuncs::checkValue($params{'extras'},'true','false')) ) );
$controlsVisibilityNode->addChild( XmlNode->new( 'hide-mail-bouncing-controls', 'content' => HelpFuncs::negation(HelpFuncs::checkValue($params{'mail_bounce'},'true','false')) ) );
$controlsVisibilityNode->addChild( XmlNode->new( 'domain-registration-url', 'content' => $params{'domain_registration_url'})) if defined $params{'domain_registration_url'};
$controlsVisibilityNode->addChild( XmlNode->new( 'domain-management-url', 'content' => $params{'domain_management_url'})) if defined $params{'domain_management_url'};
$controlsVisibilityNode->addChild( XmlNode->new( 'cert-purchasing-url', 'content' => $params{'cert_purchasing_url'})) if defined $params{'cert_purchasing_url'};
$controlsVisibilityNode->addChild( XmlNode->new( 'mpc-portal-url', 'content' => $params{'mpc_portal_url'})) if defined $params{'mpc_portal_url'};
$serverNode->getChild( 'interface-preferences', 1 )->addChild($controlsVisibilityNode);
}
sub setServerBackupSettings {
my ( $self, $paramsPtr ) = @_;
my %params = %{$paramsPtr};
my $serverNode = $self->{serverNode};
my ($lowPriority,$doNotCompress,$maxProcesses);
$lowPriority = $params{'bu_nice'};
$doNotCompress = $params{'bu_nozip'};
$maxProcesses = $params{'max_bu_proc_number'};
if ( defined $lowPriority or defined $doNotCompress or defined $maxProcesses ) {
my $serverBackupSettingsNode = XmlNode->new('backup-settings');
$serverBackupSettingsNode->setAttribute( 'low-priority', $lowPriority)
if defined $lowPriority and $lowPriority eq 'true';
$serverBackupSettingsNode->setAttribute( 'do-not-compress', $doNotCompress)
if defined $doNotCompress and $doNotCompress eq 'true';
$serverBackupSettingsNode->setAttribute( 'max-processes', $maxProcesses)
if defined $maxProcesses;
$serverNode->addChild($serverBackupSettingsNode);
}
}
sub addServerPreferences {
my ( $self, $paramsPtr ) = @_;
my %params = %{$paramsPtr};
my $serverNode = $self->{serverNode};
my $serverPrefsNode = XmlNode->new('server-preferences');
if ( defined $params{'forbid_create_dns_subzone'} ) {
$serverPrefsNode->addChild(
XmlNode->new(
'forbid-create-dns-subzone',
'content' => $params{'forbid_create_dns_subzone'}
)
);
}
if ( defined $params{'force_db_user_prefix'} ) {
$serverPrefsNode->addChild(
XmlNode->new(
'force-db-user-prefix',
'content' => $params{'force_db_user_prefix'}
)
);
}
if ( defined $params{'db_user_length'} ) {
$serverPrefsNode->addChild(
XmlNode->new(
'db-user-length', 'content' => $params{'db_user_length'}
)
);
}
if ( defined $params{'hide_top_advertisement'} ) {
$serverPrefsNode->addChild(
XmlNode->new(
'hide-top-advertisement',
'attributes' => { 'hide' => $params{'hide_top_advertisement'} }
)
);
}
if ( defined $params{'traffic_accounting'} ) {
my $val = $params{'traffic_accounting'};
if ( $val == 1 ) { $val = 'in'; }
elsif ( $val == 2 ) { $val = 'out'; }
else { $val = 'both'; }
$serverPrefsNode->addChild(
XmlNode->new(
'traffic-direction', 'attributes' => { 'traffic' => $val }
)
);
}
if ( defined $params{'restart_apache_interval'} ) {
$serverPrefsNode->addChild(
XmlNode->new(
'restart-apache', 'content' => $params{'restart_apache_interval'}
)
);
}
if ( defined $params{'stat_ttl'} ) {
$serverPrefsNode->addChild(
XmlNode->new( 'stat-keep', 'content' => $params{'stat_ttl'} ) );
}
if ( defined $params{'size_count_type'} ) {
$serverPrefsNode->addChild(
XmlNode->new(
'disk-space-count-type',
'attributes' => {
'count-type' => $params{'size_count_type'} eq 'byte'
? 'byte'
: 'block'
}
)
);
}
my $duNode = XmlNode->new('disk-usage');
$serverPrefsNode->addChild($duNode);
$duNode->addChild( XmlNode->new('include-logs') )
if defined $params{'include_logs'}
and $params{'include_logs'} eq 'true';
$duNode->addChild( XmlNode->new('include-databases') )
if defined $params{'include_databases'}
and $params{'include_databases'} eq 'true';
$duNode->addChild( XmlNode->new('include-mailboxes') )
if defined $params{'include_mailboxes'}
and $params{'include_mailboxes'} eq 'true';
$duNode->addChild( XmlNode->new('include-maillists') )
if defined $params{'include_maillists'}
and $params{'include_maillists'} eq 'true';
$duNode->addChild( XmlNode->new('include-domaindumps') )
if defined $params{'include_domaindumps'}
and $params{'include_domaindumps'} eq 'true';
$duNode->addChild( XmlNode->new('include-admindumps') )
if defined $params{'include_admindumps'}
and $params{'include_admindumps'} eq 'true';
$serverPrefsNode->addChild( XmlNode->new( 'force-db-prefix', 'content' => $params{'force_db_prefix'} ) ) if defined $params{'force_db_prefix'};
$serverPrefsNode->addChild( XmlNode->new( 'multiple-session', 'content' => $params{'multiply_login'} ) ) if defined $params{'multiply_login'};
$serverPrefsNode->addChild( XmlNode->new( 'lock-screen', 'content' => ($params{'disable_lock_screen'} eq 'true' ? 'false' : 'true' ) ) ) if defined $params{'disable_lock_screen'};
$serverPrefsNode->addChild( XmlNode->new( 'aps-catalog-url', 'content' => $params{'apscatalog_url'} ) ) if defined $params{'apscatalog_url'};
$serverPrefsNode->addChild( XmlNode->new( 'mode', 'content' => (defined($params{'power_user_panel'}) and $params{'power_user_panel'} eq 'true') ? 'poweruser' : 'standard'));
$serverNode->addChild($serverPrefsNode);
}
sub addServerMailmanConfiguration {
my ($self) = @_;
unless ( defined Mailman::version() ) {
Logging::debug("Unable to found Mailman installation");
return;
}
if (Mailman::isMailmanNotConfigured() eq '1') {
Logging::debug("Mailman is not configured. Nothing to backup");
return;
}
my $adminPassword = Mailman::getListPassword('mailman');
my @owners = Mailman::getListOwners('mailman');
if (defined $adminPassword and defined $owners[0]) {
my $root = $self->{serverNode};
my $mailmanNode = XmlNode->new('mailman');
$mailmanNode->setAttribute('owner', $owners[0]);
$mailmanNode->setAttribute('password', $adminPassword);
$root->addChild($mailmanNode);
}
}
sub addDisableMailUiOption {
my ($self, $state) = @_;
my $serverNode = $self->{serverNode};
my $serverPrefNode = $serverNode->getChild( 'server-preferences', 1 );
my $disableUiNode = XmlNode->new('disable-mail-ui', 'content' => $state);
$serverPrefNode->addChild($disableUiNode);
}
sub _makeExternalWebmails {
my ($self, $webmailsPtr) = @_;
my $serverNode = $self->{serverNode};
my $mailPrefNode = $serverNode->getChild( 'mail-settings', 1 );
my @webmails = @{$webmailsPtr};
foreach my $webmail (@webmails) {
my $extWebMailNode = XmlNode->new('external-webmail');
$extWebMailNode->addChild( XmlNode->new('name', 'content' => $webmail->{'name'}) );
$extWebMailNode->addChild( XmlNode->new('url', 'content' => $webmail->{'url'}) );
$extWebMailNode->addChild( XmlNode->new('enabled') ) if $webmail->{'enabled'} == 1;
$mailPrefNode->addChild($extWebMailNode);
}
}
sub addRestrictionItem {
my ( $self, $type, $ip, $mask ) = @_;
$ip = '' unless defined $ip;
$mask = '' unless defined $mask;
my $serverNode = $self->{serverNode};
my $serverPrefNode = $serverNode->getChild( 'server-preferences', 1 );
my $adminAccessRestrictionsNode = $serverPrefNode->getChild( 'admin-access-restrictions', 1 );
my $restrictionItemNode = XmlNode->new( 'restriction-item' );
$restrictionItemNode->setAttribute( 'type', $type eq 'allow'? 'allow' : 'deny' );
$restrictionItemNode->setAttribute( 'ip-address', $ip );
$restrictionItemNode->setAttribute( 'ip-subnet-mask', $mask );
$adminAccessRestrictionsNode->addChild( $restrictionItemNode );
}
sub addRootAdmin {
my ( $self, $id, $guid ) = @_;
return if defined $self->{admin};
my $rootNode = $self->{root};
if ( !defined($rootNode) ) {
Logging::warning('Unable to dump Panel admin user, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $root = XmlNode->new( 'admin' );
$self->{admin} = $root;
$root->setAttribute( 'id', $id ) if $id;
$root->setAttribute( 'guid', $guid ) if $guid;
$rootNode->addChild($root);
}
### Client functions ##
sub addRootClient {
my ( $self, $clientId, $clientPtr, $passwdPtr, $status ) = @_;
my $rootNode = $self->{root};
if ( !defined($rootNode) ) {
Logging::warning('Unable to dump root client user, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $root = $self->makeClientNode($clientId, $clientPtr, $passwdPtr, $status, 1);
$rootNode->addChild($root);
push @{$self->{roots}}, $root;
}
sub addRootReseller{
my ( $self, $clientId, $clientPtr, $passwdPtr, $status ) = @_;
my $rootNode = $self->{root};
if ( !defined($rootNode) ) {
Logging::warning('Unable to dump reseller, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $root = $self->makeResellerNode($clientId, $clientPtr, $passwdPtr, $status, 1);
$rootNode->addChild($root);
push @{$self->{roots}}, $root;
}
sub addResellerClient {
my ( $self, $resellerId, $clientId, $clientPtr, $passwdPtr, $status ) = @_;
my %client = %{$clientPtr};
my %passwd = %{$passwdPtr};
my $resellerNode = $self->{resellersNodes}->{$resellerId};
if (!defined($resellerNode))
{
Logging::warning('Unable to dump reseller\'s client, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $root = $self->makeClientNode($clientId, \%client, \%passwd, $status, 0);
$resellerNode->getChild( 'clients', 1 )->addChild($root);
$self->regClientObjectBackupPath( $self->getResellersBackupPath( $resellerId ), $clientId, $clientPtr->{'login'} );
if (exists $self->{resellersShortNodes}->{$resellerId}) {
$self->{resellersShortNodes}->{$resellerId}->addChild($self->{clientsShortNodes}->{$clientId});
}
}
sub addAdminClient {
my ( $self, $clientId, $clientPtr, $passwdPtr, $status ) = @_;
my %client = %{$clientPtr};
my %passwd = %{$passwdPtr};
my $admin = $self->{admin};
if (!defined($admin))
{
Logging::warning('Unable to dump admin\'s client, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $root = $self->makeClientNode($clientId, \%client, \%passwd, $status, 0);
$admin->getChild( 'clients', 1 )->addChild($root);
$self->regClientObjectBackupPath( $self->getAdminBackupPath(), $clientId, $clientPtr->{'login'} );
}
sub addAdminReseller {
my ( $self, $clientId, $clientPtr, $passwdPtr, $status ) = @_;
my $admin = $self->{admin};
if (!defined($admin))
{
Logging::warning('Unable to dump admin\'s reseller, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $root = $self->makeResellerNode($clientId, $clientPtr, $passwdPtr, $status, 0);
$admin->getChild( 'resellers', 1 )->addChild($root);
$self->regResellersObjectBackupPath( $self->getAdminBackupPath(), $clientId, $clientPtr->{'login'} );
}
sub makeResellerNode{
my ( $self, $clientId, $clientPtr, $passwdPtr, $status, $needFullInfo ) = @_;
my $root = $self->processClientNode( $clientId, $clientPtr, $passwdPtr, $status, 1, $needFullInfo );
return $root;
}
sub makeClientNode {
my ( $self, $clientId, $clientPtr, $passwdPtr, $status, $needFullInfo ) = @_;
my $root = $self->processClientNode( $clientId, $clientPtr, $passwdPtr, $status, 0, $needFullInfo );
return $root;
}
sub processClientNode {
my ( $self, $clientId, $clientPtr, $passwdPtr, $status, $is_reseller, $needFullInfo ) = @_;
my $root = XmlNode->new( $is_reseller ? 'reseller' : 'client');
$root->getChild( 'preferences', 1 );
$root->getChild( 'properties', 1 );
my %client = %{$clientPtr};
my %passwd = %{$passwdPtr};
$root->setAttribute( 'id', $clientId );
if ( defined $client{'uid'} ) {
$root->setAttribute( 'uid', $client{'uid'} );
$root->setAttribute( 'ownership', $client{'ownership'} eq 'true' ? 'true' : 'false' );
}
$root->setAttribute( 'guid', $client{'guid'} ) if ( defined $client{'guid'} );
$root->setAttribute( 'external-id', $client{'external_id'} ) if ( defined $client{'external_id'} and $client{'external_id'} ne '');
$root->setAttribute( 'vendor-guid', $client{'vendor-guid'} ) if ( defined $client{'vendor-guid'} );
$root->setAttribute( 'vendor-login', $client{'vendor-login'} ) if ( defined $client{'vendor-login'} );
$root->setAttribute( 'owner-guid', $client{'owner-guid'} ) if ( defined $client{'owner-guid'} and not $is_reseller );
if ( exists $client{'login'} ) {
$root->setAttribute( 'name', ( defined $client{'login'} )? $client{'login'}:'' );
}
if ( exists $client{'pname'} ) {
$root->setAttribute( 'contact', ( defined $client{'pname'} )? $client{'pname'}:'' );
}
if ( exists $client{'cr_date'} ) {
$root->setAttribute( 'cr-date', ( defined $client{'cr_date'} )? $client{'cr_date'}:'' );
}
if ( exists $client{'owner-name'} and not $is_reseller ) {
$root->setAttribute( 'owner-name', $client{'owner-name'} );
}
my $item;
my $props = $root->getChild( 'properties', 1 );
$item = CommonPacker::makePasswordNode( $passwd{'password'}, CommonPacker::normalizePasswordType( $passwd{'type'} ) );
$props->addChild($item);
$props->addChild( Status::make($status) );
$self->{clientNodes}->{$clientId} = $root;
$self->{resellersNodes}->{$clientId} = $root if $is_reseller;
if ($needFullInfo) {
return $root;
} else {
my $shortInfoNodeName = ($is_reseller ? 'reseller' : 'client') . '-info';
my $shortInfoNode = XmlNode->new($shortInfoNodeName);
$shortInfoNode->setAttribute('name', ( defined $client{'login'} )? $client{'login'}:'');
$shortInfoNode->setAttribute( 'guid', $client{'guid'} ) if defined $client{'guid'};
if ($is_reseller) {
$self->{resellersShortNodes}->{$clientId} = $shortInfoNode;
} else {
$self->{clientsShortNodes}->{$clientId} = $shortInfoNode;
}
return $shortInfoNode;
}
}
sub finishClient {
my ( $self, $clientId ) = @_;
my $root = $self->{clientNodes}->{$clientId};
if ( !defined($root) ) {
Logging::warning('Unable to finish client node, because of dump XML structure is not full', 'PackerStructure');
return;
}
#TODO: uncomment
#$root->ReleaseCode();
}
sub setClientPinfo {
my ( $self, $clientId, $clientPtr ) = @_;
my %client = %{$clientPtr};
my $root = $self->{clientNodes}->{$clientId};
if ( !defined($root) ) {
Logging::warning('Unable to dump client personal information, because of dump XML structure is not full', 'PackerStructure');
return;
}
my ( $field, $name );
my %clientsInfo = (
'company' => 'cname',
'phone' => 'phone',
'fax' => 'fax',
'address' => 'address',
'city' => 'city',
'state' => 'state',
'zip' => 'pcode',
'country' => 'country',
'email' => 'email',
);
my $prefs = $root->getChild( 'preferences', 1 );
while ( ( $name, $field ) = each(%clientsInfo) ) {
if ( exists( $client{$field} ) && $client{$field} ) {
$prefs->addChild(
XmlNode->new(
'pinfo',
'content' => $client{$field},
'attributes' => { 'name' => $name }
)
);
}
}
}
sub setClientLocale {
my ( $self, $clientId, $locale ) = @_;
my $root = $self->{clientNodes}->{$clientId};
if ( !defined($root) ) {
Logging::warning('Unable to dump client locale, because of dump XML structure is not full', 'PackerStructure');
return;
}
$root->getChild( 'preferences', 1 )->addChild(
XmlNode->new(
'pinfo',
'content' => $locale,
'attributes' => { 'name' => 'locale' }
)
);
}
sub addClientLimit {
my ( $self, $clientId, $name, $value ) = @_;
my $root = $self->{clientNodes}->{$clientId};
if ( !defined($root) ) {
Logging::warning('Unable to dump client limits, because of dump XML structure is not full', 'PackerStructure');
return;
}
$self->insertLimitNode( $root, $name, $value );
}
sub addClientPermission {
my ( $self, $clientId, $name, $value ) = @_;
my $root = $self->{clientNodes}->{$clientId};
if ( !defined($root) ) {
Logging::warning('Unable to dump client permissions, because of dump XML structure is not full', 'PackerStructure');
return;
}
$self->makePermissionNode( $root->getChild( 'limits-and-permissions', 1 ), $name, $value );
}
sub addClientDomainSkeleton {
my ( $self, $clientId, $path, $arc_path ) = @_;
my $root = $self->{clientNodes}->{$clientId};
if ( !defined($root) ) {
Logging::warning('Unable to dump client\'s domain skeleton, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $dumpFile = $self->{content_transport}->addClientContent( 'skeleton', $clientId, $arc_path, 'directory' => $path );
$root->getChild( 'content', 1, 1 )->addChild( $dumpFile) if $dumpFile;
}
sub addServerSkeleton {
my ( $self, $path, $arc_path) = @_;
my $root = $self->{serverNode};
my $dumpFile = $self->{content_transport}->addAdminContent('skeleton', undef, $arc_path, 'directory' => $path);
$root->getChild('content', 1, 1)->addChild($dumpFile) if $dumpFile;
}
sub addSmbDbDump {
my ($self, $options) = @_;
my $root = $self->{serverNode};
$options->{utf8names} = 1;
my $cid = $self->{content_transport}->addDbContent('smb-sqldump', $self->getAdminBackupPath('smbdb'), %{$options});
$root->getChild('content', 1, 1)->addChild($cid) if $cid;
}
sub addApsCache {
my ($self, $path) = @_;
my $root = $self->{serverNode};
my $dumpFile = $self->{content_transport}->addAdminContent('aps-cache', undef, 'aps_cache', 'directory' => $path, 'checkEmptyDir' => 1 );
$root->getChild('content', 1, 1)->addChild($dumpFile) if $dumpFile;
}
sub addResellerDomainsClientsNodes {
my ( $self, $clientId ) = @_;
my $root = $self->{clientNodes}->{$clientId};
if ( !defined($root) ) {
Logging::warning('Unable to dump reseller\'s clients and domains, because of dump XML structure is not full', 'PackerStructure');
return;
}
$root->addChild( XmlNode->new('domains') );
$root->addChild( XmlNode->new('clients') );
}
sub removeSiteNode {
my ( $self, $domainId, $siteName ) = @_;
my $domainNode = $self->{domainNodes}->{$domainId};
my $sitesNode = $domainNode->getChild( 'phosting' )->getChild( 'sites' );
if ( defined $sitesNode ) {
$sitesNode->removeChildByAttribute( 'site', 'name', $siteName );
}
}
sub removeDatabaseNode {
my ( $self, $domainId, $db ) = @_;
my $domainNode = $self->{domainNodes}->{$domainId};
my $dbNode = $domainNode->getChild( 'databases' );
if ( defined $dbNode ) {
$dbNode->removeChildByAttribute( 'database', 'id', $db->{'id'} );
}
}
sub removeServerNode {
my ( $self ) = @_;
$self->{serverNode} = undef;
}
sub removeMailuserNode {
my ( $self, $domainId, $mail ) = @_;
my $domainNode = $self->{domainNodes}->{$domainId};
my $mailSystemNode = $domainNode->getChild( 'mailsystem' );
my $mailUsersNode = $mailSystemNode->getChild( 'mailusers' );
if ( defined $mailUsersNode ) {
$mailUsersNode->removeChildByAttribute( 'mailuser', 'id', $mail->{'id'} );
}
}
sub removeMailSystemNode {
my ( $self, $domainId ) = @_;
my $domainNode = $self->{domainNodes}->{$domainId};
$domainNode->removeChildren( 'mailsystem' );
}
sub removeHostingNode {
my ( $self, $domainId, $hostingType ) = @_;
my $domainNode = $self->{domainNodes}->{$domainId};
my $hostingNodeName;
if ( $hostingType eq 'vrt_hst' ) {
$hostingNodeName = 'phosting';
} elsif ( $hostingType eq 'std_fwd' ) {
$hostingNodeName = 'shosting';
} elsif ( $hostingType eq 'frm_fwd' ) {
$hostingNodeName = 'fhosting';
}
$domainNode->removeChildren( $hostingNodeName );
}
sub addClientIps {
my ( $self, $clientId, $ipsPtr ) = @_;
my %ips = %{$ipsPtr};
my $root = $self->{clientNodes}->{$clientId};
if ( !defined($root) ) {
Logging::warning('Unable to dump client\'s IP settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $ip_pool = XmlNode->new('ip_pool');
$root->addChild($ip_pool);
while( my($ip,$iptype) = each(%ips) ){
$ip_pool->addChild( $self->makeIpNode($ip, $iptype) );
}
}
sub setClientTraffic{
my ( $self, $clientId, $trafficValue ) = @_;
my $parent = $self->{clientNodes}->{$clientId};
if ( !defined($parent) ) {
Logging::warning('Unable to dump client traffic, because of dump XML structure is not full', 'PackerStructure');
return;
}
$parent->addChild( XmlNode->new( 'traffic', 'content' => $trafficValue ) );
}
sub addResellerDomainTemplate {
my $self = shift;
$self->addClientDomainTemplate( @_ );
}
sub addClientDomainTemplate {
my ( $self, $clientId, $templateName, $dataPtr ) = @_;
my $root = $self->{clientNodes}->{$clientId};
my $node = $self->makeTemplateNode('domain-template', $templateName, $dataPtr);
$root->getChild( 'preferences', 1 )->addChild($node);
}
sub addClientCustomButton {
my ( $self, $clientId, $id, $optionsPtr, $customButtonsDir, $icon ) = @_;
my $parent = $self->{clientNodes}->{$clientId};
if ( !defined($parent) ) {
Logging::warning('Unable to dump client\'s custom buttons settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $node = $self->makeCustomButtonNode( 'clients', $clientId, $id, $optionsPtr, $customButtonsDir,
$icon );
$parent->getChild( 'preferences', 1 )->addChild($node);
}
sub setPpbConnection {
my ($self, $clientParams) = @_;
my $ppbUrl = undef;
my $apiVersion = undef;
my $parent;
$parent = $self->{serverNode};
$ppbUrl = $clientParams->{'ppb-url'} if exists $clientParams->{'ppb-url'};
if (defined $ppbUrl && defined $apiVersion) {
my $ppbConnectionNode = XmlNode->new('ppb-connection');
$ppbConnectionNode->addChild(XmlNode->new('ppb-url', 'content' => $ppbUrl));
$parent->getChild( 'properties', 1)->addChild($ppbConnectionNode);
}
}
### Domain functions ##
my @_rootDomains;
sub addRootDomain {
my ( $self, $domainId, $domainName, $domainAsciiName, $domainPtr, $ownerGuid ) = @_;
$domainAsciiName = $domainName if not $domainAsciiName;
my $root = $self->makeDomainNode($domainId, $domainName, $domainPtr, 0, 1);
push @_rootDomains, $root;
}
sub addRootDomains {
my $self = shift;
my $rootNode = $self->{root};
if ( !defined($rootNode) ) {
Logging::warning('Unable to dump root domains, because of dump XML structure is not full', 'PackerStructure');
return;
}
for my $domainNode ( @_rootDomains ) {
$rootNode->addChild($domainNode);
push @{$self->{roots}}, $domainNode;
}
}
sub addAdminDomain {
my ( $self, $domainId, $domainName, $domainAsciiName, $domainPtr ) = @_;
$domainAsciiName = $domainName if not $domainAsciiName;
my $admin = $self->{admin};
if ( !defined($admin) ) {
Logging::warning('Unable to dump admin\'s domain, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $root = $self->makeDomainNode($domainId, $domainName, $domainPtr, 0, 0);
$admin->getChild( 'domains', 1 )->addChild($root);
$self->regDomainObjectBackupPath( $self->getAdminBackupPath(), $domainId, $domainAsciiName );
}
sub addResellerDomain {
my ( $self, $resellerId, $domainId, $domainName, $domainAsciiName, $domainPtr ) = @_;
$domainAsciiName = $domainName if not $domainAsciiName;
my $resellerNode = $self->getCashedClientNode($resellerId);
return unless defined $resellerNode;
my $root = $self->makeDomainNode($domainId, $domainName, $domainPtr, 0, 0);
$resellerNode->getChild( 'domains', 1 )->addChild($root);
$self->regDomainObjectBackupPath( $self->getResellersBackupPath( $resellerId ), $domainId, $domainAsciiName );
if (exists $self->{resellersShortNodes}->{$resellerId}) {
$self->{resellersShortNodes}->{$resellerId}->addChild($self->{domainShortNodes}->{$domainId});
}
}
sub addClientDomain {
my ( $self, $clientId, $domainId, $domainName, $domainAsciiName, $domainPtr ) = @_;
$domainAsciiName = $domainName if not $domainAsciiName;
my $clientNode = $self->getCashedClientNode($clientId);
return unless defined $clientNode;
my $root = $self->makeDomainNode($domainId, $domainName, $domainPtr, 0, 0);
$clientNode->getChild( 'domains', 1 )->addChild($root);
$self->regDomainObjectBackupPath( $self->getClientsBackupPath( $clientId ), $domainId, $domainAsciiName );
if (exists $self->{clientsShortNodes}->{$clientId}) {
$self->{clientsShortNodes}->{$clientId}->addChild($self->{domainShortNodes}->{$domainId});
}
}
my %_rootUsers;
my %_rootRoles;
sub addDomainSite {
my ( $self, $domainId, $siteId, $siteAsciiName, $siteName, $sitePtr ) = @_;
my $domainNode = $self->{domainNodes}->{$domainId};
if ( !defined($domainNode) ) {
Logging::warning('Unable to dump domain site, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $siteNode = $self->makeDomainNode($siteId, $siteName, $sitePtr, 1, 1);
my $phostingNode = $domainNode->getChild( 'phosting', 1 );
$phostingNode->getChild( 'sites', 1 )->addChild($siteNode);
$self->regSiteObjectBackupPath( $self->getDomainsBackupPath( $domainId ), $siteId, $siteAsciiName );
}
sub addAdminUser {
my ( $self, $userName, $userPtr ) = @_;
my $adminNode = $self->{admin};
if ( !defined($adminNode) ) {
Logging::warning('Unable to dump admin user, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $userNode = $self->makeUserNode($userName, $userPtr);
$adminNode->getChild( 'users', 1 )->addChild($userNode) if defined $userNode;
}
sub removeAdminUser {
my ( $self, $userName ) = @_;
my $adminNode = $self->{admin};
my $usersNode = $adminNode->getChild( 'users' );
if ( defined $usersNode ) {
$usersNode->removeChildByAttribute( 'user', 'name', $userName );
}
}
sub addAdminPermission {
my ( $self, $name, $value ) = @_;
my $adminNode = $self->{admin};
if ( !defined($adminNode) ) {
Logging::warning('Unable to dump admin permissions, because of dump XML structure is not full', 'PackerStructure');
return;
}
$self->makePermissionNode( $adminNode->getChild( 'limits-and-permissions', 1 ), $name, $value );
}
sub addClientUser {
my ( $self, $ownerId, $userName, $userPtr ) = @_;
my $clientNode = $self->getCashedClientNode($ownerId);
return unless defined $clientNode;
my $userNode = $self->makeUserNode($userName, $userPtr);
$clientNode->getChild( 'users', 1 )->addChild($userNode) if defined $userNode;
}
sub removeClientUser {
my ( $self, $ownerId, $userName ) = @_;
my $clientNode = $self->getCashedClientNode($ownerId);
my $usersNode = $clientNode->getChild( 'users' );
if ( defined $usersNode ) {
$usersNode->removeChildByAttribute( 'user', 'name', $userName );
}
}
sub addRootUser {
my ( $self, $userName, $userPtr ) = @_;
if (!exists $_rootUsers{$userName}) {
my $userNode = $self->makeUserNode($userName, $userPtr);
$_rootUsers{$userName} = $userNode if defined $userNode;
}
}
sub removeRootUser {
my ( $self, $userName ) = @_;
if ( exists $_rootUsers{$userName} ) {
delete $_rootUsers{$userName};
}
}
sub addRootUsers {
my ( $self ) = @_;
my $rootNode = $self->{root};
if ( !defined($rootNode) ) {
Logging::warning('Unable to dump root users, because of dump XML structure is not full', 'PackerStructure');
return;
}
if (%_rootUsers) {
foreach my $userName (keys %_rootUsers) {
$rootNode->addChild($_rootUsers{$userName});
}
}
}
sub addRoleToRoles {
my ( $self, $roleNode, $rolesNode ) = @_;
my @roles = $rolesNode->getChildren( 'role' );
foreach my $role ( @roles ) {
return if $role->getAttribute('name') eq $roleNode->getAttribute('name');
}
$rolesNode->addChild( $roleNode );
}
sub addAdminRole {
my ( $self, $roleName, $isBuiltIn, $permsPtr, $servicePermissions ) = @_;
my $adminNode = $self->{admin};
if ( !defined($adminNode) ) {
Logging::warning('Unable to dump admin role, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $roleNode = $self->makeRoleNode($roleName, $isBuiltIn, $permsPtr, $servicePermissions);
$self->addRoleToRoles( $roleNode, $adminNode->getChild( 'roles', 1 ) );
}
sub removeAdminRole {
my ( $self, $roleName ) = @_;
my $adminNode = $self->{admin};
my $rolesNode = $adminNode->getChild( 'roles' );
if ( defined $rolesNode ) {
$rolesNode->removeChildByAttribute( 'role', 'name', $roleName );
}
}
sub addClientRole {
my ( $self, $ownerId, $roleName, $isBuiltIn, $permsPtr, $servicePermissions ) = @_;
my $clientNode = $self->getCashedClientNode($ownerId);
return unless defined $clientNode;
my $roleNode = $self->makeRoleNode($roleName, $isBuiltIn, $permsPtr, $servicePermissions);
$self->addRoleToRoles( $roleNode, $clientNode->getChild( 'roles', 1 ) );
}
sub removeClientRole {
my ( $self, $ownerId, $roleName ) = @_;
my $clientNode = $self->getCashedClientNode($ownerId);
my $rolesNode = $clientNode->getChild( 'roles' );
if ( defined $rolesNode ) {
$rolesNode->removeChildByAttribute( 'role', 'name', $roleName );
}
}
sub addRootRole {
my ( $self, $roleName, $isBuiltIn, $permsPtr, $servicePermissions ) = @_;
if (!exists $_rootRoles{$roleName}) {
my $roleNode = $self->makeRoleNode($roleName, $isBuiltIn, $permsPtr, $servicePermissions);
$_rootRoles{$roleName} = $roleNode if defined $roleNode;
}
}
sub removeRootRole {
my ( $self, $roleName ) = @_;
if ( exists $_rootRoles{$roleName} ) {
delete $_rootRoles{$roleName};
}
}
sub addRootRoles {
my ( $self ) = @_;
my $rootNode = $self->{root};
if ( !defined($rootNode) ) {
Logging::warning('Unable to dump root roles, because of dump XML structure is not full', 'PackerStructure');
return;
}
if (%_rootRoles) {
foreach my $roleName (keys %_rootRoles) {
$self->addRoleToRoles( $_rootRoles{$roleName}, $rootNode );
}
}
}
sub getCashedClientNode {
my ($self, $clientId) = @_;
my $root = $self->{resellersNodes}->{$clientId};
unless ( defined($root) ) {
$root = $self->{clientNodes}->{$clientId};
}
return $root if defined($root);
my $caller = (caller(1))[3];
if (defined $caller) {
Logging::warning("Error in $caller : empty client parent node for id ($clientId)", 'PackerStructure');
}
else {
Logging::warning('Unable to dump client settings, because of dump XML structure is not full', 'PackerStructure');
}
return;
}
my %_requiredLimits = (
domain => ['max_subdom', 'max_dom_aliases', 'disk_space', 'max_traffic', 'max_wu', 'max_db',
'max_box', 'mbox_quota', 'max_maillists', 'expiration', 'max_site'],
client => ['max_dom', 'max_subdom', 'max_dom_aliases', 'disk_space', 'max_traffic', 'max_wu',
'max_db', 'max_box', 'mbox_quota', 'max_maillists', 'expiration'],
reseller => ['max_cl', 'max_dom', 'max_subdom', 'max_dom_aliases', 'disk_space', 'max_traffic', 'max_wu',
'max_db', 'max_box', 'mbox_quota', 'max_maillists', 'expiration']
);
sub fixDefaultLimits {
my ($self, $type, $id) = @_;
my $node;
my $requiredLimits;
if ( ($type eq 'client') || ($type eq 'reseller') ) {
$node = $self->getCashedClientNode($id);
}
elsif ($type eq 'domain') {
$node = $self->getCashedDomainNode($id);
}
return unless defined $node;
$requiredLimits = $_requiredLimits{$type};
my %usedLimits;
XPath::Select $node, 'limits-and-permissions/limit', sub {
$usedLimits{ shift->getAttribute( 'name' ) } = 1;
};
for my $name ( @{$requiredLimits} ) {
if ( !exists( $usedLimits{$name} ) ) {
my $value = ( $name eq 'max_site' ) ? '1' : '-1';
$self->insertLimitNode( $node, $name, $value );
}
}
}
my %smbUserPinfo = (
'phone' => 'phone',
'phoneType' => 'phone-type',
'phone2' => 'phone2',
'phone2Type' => 'phone2-type',
'phone3' => 'phone3',
'phone3Type' => 'phone3-type',
'imNumber' => 'im',
'imType' => 'im-type',
'additionalInfo' => 'comment',
'email' => 'email',
'companyName' => 'company',
'fax' => 'fax',
'address' => 'address',
'city' => 'city',
'state' => 'state',
'zip' => 'zip',
'country' => 'country'
);
sub makeUserNode {
my ( $self, $userName, $userPtr ) = @_;
my %user = %{$userPtr};
my $userNode = XmlNode->new( 'user' );
$userNode->setAttribute( 'name', $userName );
if (defined $user{'contactName'}) {
$userNode->setAttribute( 'contact', $user{'contactName'} );
}else {
$userNode->setAttribute( 'contact', $userName );
}
$userNode->setAttribute( 'guid', $user{'uuid'}) if defined $user{'uuid'};
$userNode->setAttribute( 'email', $user{'email'} ) if defined $user{'email'};
$userNode->setAttribute( 'is-built-in', $user{'isBuiltIn'} ? 'true' : 'false' ) if exists $user{'isBuiltIn'};
$userNode->setAttribute( 'cr-date', $user{'creationDate'} ) if exists $user{'creationDate'};
$userNode->setAttribute( 'external-id', $user{'externalId'} ) if defined $user{'externalId'};
if (defined $user{'subscriptionDomainId'} and $user{'subscriptionDomainId'} != 0) {
my $subscriptionName = PleskStructure::getDomainNameFromId($user{'subscriptionDomainId'});
if ($subscriptionName) {
$userNode->setAttribute( 'subscription-name', $subscriptionName );
}else{
$userNode->setAttribute( 'subscription-name', 'removed');
}
}
$userNode->setAttribute( 'is-domain-admin', (defined $user{'isDomainAdmin'} and ( $user{'isDomainAdmin'} eq '1' ) )? 'true' : 'false' );
$userNode->setAttribute( 'is-legacy-user', (defined $user{'isLegacyUser'} and ( $user{'isLegacyUser'} eq '1' ) ) ? 'true' : 'false' );
$userNode->setAttribute( 'file-sharing-id', $user{'fileSharingId'} ) if defined $user{'fileSharingId'};
$userNode->setAttribute( 'external-email', 'true' ) if not defined $user{'mailId'};
my $propsNode = XmlNode->new('properties');
my $passwordNode = CommonPacker::makePasswordNode($userPtr->{'password'}, (defined $userPtr->{'passwordType'})? $userPtr->{'passwordType'} : 'plain', (defined $userPtr->{'isBase64'} and $userPtr->{'isBase64'} eq '0') ? undef : 'base64');
$propsNode->addChild($passwordNode);
my $status = $userPtr->{'isLocked'} ? $Status::ADMIN : $Status::ENABLED;
$propsNode->addChild(Status::make($status));
$userNode->addChild($propsNode);
my $lpNode = $userNode->getChild('limits-and-permissions', 1);
$lpNode->addChild(XmlNode->new('role-ref', 'content' => $userPtr->{'SmbRoleName'}));
foreach my $app (@{$user{'assignedApplications'}}) {
$lpNode->addChild(XmlNode->new('assigned-application', 'content' => $app));
}
my $prefsNode = XmlNode->new('preferences');
my @usersPhones;
foreach my $pinfo (keys %user) {
next unless defined $smbUserPinfo{$pinfo};
if ( defined $user{$pinfo} and $user{$pinfo} ne '' ) {
next if ( $smbUserPinfo{$pinfo} =~ /phone(\d?)-type/);
if ($smbUserPinfo{$pinfo} =~ /^phone(\d?)$/) {
push @usersPhones, $user{$pinfo};
next;
}
$prefsNode->addChild(XmlNode->new('pinfo',
'attributes' => {'name' => $smbUserPinfo{$pinfo} },
'content' => $user{$pinfo}
)
);
}
}
if (@usersPhones) {
$prefsNode->addChild( XmlNode->new('pinfo',
'attributes' => { 'name' => 'phone' },
'content' => join(',', @usersPhones)
)
);
}
$userNode->addChild($prefsNode);
return $userNode;
}
sub makeRoleNode {
my ( $self, $roleName, $isBuiltIn, $permsPtr, $servicePermissions ) = @_;
my $roleNode = XmlNode->new( 'role' );
$roleNode->setAttribute( 'name', $roleName );
$roleNode->setAttribute( 'is-built-in', $isBuiltIn? 'true' : 'false' );
my $limitsAndPermsNode = XmlNode->new( 'limits-and-permissions' );
$roleNode->addChild($limitsAndPermsNode);
while ( my ( $name, $value ) = each( %{$permsPtr} ) ) {
my $permNode = XmlNode->new( 'permission', 'attributes' => {
'name' => $name,
'value' => $value? 'true' : 'false' }
);
$limitsAndPermsNode->addChild( $permNode );
}
for my $perm (@$servicePermissions) {
if ($perm->{classname} == "Smb_Service_Provider_Aps") {
my $permNode = XmlNode->new('service-permission', 'attributes' => {
'classname' => $perm->{'classname'},
'description' => $perm->{'description'},
'externalId' => $perm->{'externalId'},
'permissionCode' => $perm->{'permissionCode'},
'class' => $perm->{'class'},
'value' => 'true',
});
$limitsAndPermsNode->addChild( $permNode );
}
}
return $roleNode;
}
sub makeDomainNode {
my ( $self, $domainId, $domainName, $domainPtr, $issite, $needFullInfo ) = @_;
unless ( ref($domainPtr) =~ /HASH/ ) {
Logging::warning("Unable to backup domain $domainName");
return;
}
my %domain = %{$domainPtr};
my $nodeName = ($issite? 'site' : 'domain');
my $root = XmlNode->new( $nodeName, 'attributes' => {
'name' => $domainName,
'id' => $domainId }
);
$root->getChild( 'preferences', 1 );
$root->getChild( 'properties', 1 );
$root->getChild( 'limits-and-permissions', 1 ) unless $issite;
$root->setAttribute( 'cr-date', $domain{'cr_date'} ) if exists $domain{'cr_date'};
$root->setAttribute( 'guid', $domain{'guid'} ) if defined $domain{'guid'};
$root->setAttribute( 'external-id', $domain{'external_id'} ) if ( defined $domain{'external_id'} and $domain{'external_id'} ne '');
$root->setAttribute( 'vendor-guid', $domain{'vendor-guid'} ) if ( not $issite and defined $domain{'vendor-guid'} );
$root->setAttribute( 'owner-guid', $domain{'owner-guid'} ) if ( not $issite and defined $domain{'owner-guid'} );
$root->setAttribute( 'owner-name', $domain{'owner-name'} ) if ( not $issite and defined $domain{'owner-name'} );
$root->setAttribute( 'parent-domain-name', $domain{'parentDomainName'} ) if ( $issite and defined $domain{'parentDomainName'} );
$root->setAttribute( 'vendor-login', $domain{'vendor-login'} ) if ( not $issite and defined $domain{'vendor-login'} );
if($issite) {
$self->{siteNodes}->{$domainId} = $root;
}
else {
$self->{domainNodes}->{$domainId} = $root;
}
if ($needFullInfo) {
return $root;
} else {
my $shortInfoNode = XmlNode->new('domain-info');
$shortInfoNode->setAttribute('name', $domainName);
$shortInfoNode->setAttribute('guid', $domain{'guid'}) if defined $domain{'guid'};
unless($issite) {
$self->{domainShortNodes}->{$domainId} = $shortInfoNode;
}
return $shortInfoNode;
}
}
sub getCashedDomainNode {
my ($self, $domainId) = @_;
my $root = $self->{domainNodes}->{$domainId};
unless ( defined($root) ) {
$root = $self->{siteNodes}->{$domainId};
}
return $root if defined($root);
my $caller = (caller(1))[3];
if (defined $caller) {
Logging::warning("Error in $caller : empty domain parent node for id ($domainId)", 'PackerStructure');
}
else {
Logging::warning('Error: empty domain parent node', 'PackerStructure');
}
return;
}
sub finishDomain {
my ( $self, $domainId) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
#TODO: uncomment
#$root->ReleaseCode();
}
sub setDomainWwwStatus {
my ( $self, $domainId, $status ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
$root->setAttribute( 'www', $status );
}
sub setDomainIP {
my ( $self, $domainId, $ip, $iptype ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
$root->getChild( 'properties', 1 )->addChild( $self->makeIpNode( $ip, $iptype ), 1 );
}
sub setDomainStatus {
my ( $self, $domainId, $status ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
$root->getChild( 'properties', 1 )->addChild( Status::make($status) );
}
sub setWebspaceStatus {
my ( $self, $domainId, $status, $siteStatus ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
if (not defined $siteStatus) {
$root->getChild( 'properties', 1 )->addChild( Status::make($status, 'webspace-status') );
$root->getChild( 'properties', 1 )->addChild( Status::make($status) );
} else {
$root->getChild( 'properties', 1 )->addChild( Status::make($status, 'webspace-status') );
$root->getChild( 'properties', 1 )->addChild( Status::make($siteStatus) );
}
}
sub getDomainARecordIp {
my ( $self, $domainId ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $name = PleskStructure::getDomainNameFromId($domainId);
my $aRecordIp;
XPath::Select $root, 'properties/dns-zone/dnsrec', sub {
my $rec = shift;
if (($rec->getAttribute('type') eq 'A') or ($rec->getAttribute('type') eq 'AAAA') and ($rec->getAttribute('src') eq "$name.") ) {
$aRecordIp = $rec->getAttribute('dst');
}
};
return $aRecordIp;
}
sub addDomainDatabase {
my ( $self, $dbId, $dbServerId, $domainId, $dbName, $dbType, $optionalPtr, $dbServerPtr, $dbUsersPtr, $contentDescriptionPtr, $skipContent ) = @_;
$self->regDatabaseObjectBackupPath( $self->getDomainsBackupPath( $domainId ), $dbId, $dbName, $dbServerId );
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $node = $self->makeDatabaseNode( $dbId, $dbName, $dbType, 'domain', $domainId, $optionalPtr,
$dbServerPtr, $dbUsersPtr, $contentDescriptionPtr, $skipContent );
my $parentGuid = $root->getAttribute('guid');
$node->setAttribute( 'guid', $self->getDatabaseGuid( $parentGuid, $dbId ) ) if $parentGuid;
$node->setAttribute( 'owner-guid', $parentGuid ) if $parentGuid;
$root->getChild( 'databases', 1 )->addChild($node);
}
sub setDomainDefault {
my ( $self, $domainId ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
$root->getChild( 'preferences', 1 )->addChild( XmlNode->new('default-domain') );
}
sub addDomainLimit {
my ( $self, $domainId, $name, $value ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
$self->insertLimitNode( $root, $name, $value );
}
sub setDomainMailService {
my ( $self, $domainId, $status, $ips ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $mailServiceStatus = Status::make($status);
my $rootMail = XmlNode->new('mailsystem');
my $properties = $rootMail->getChild( 'properties', 1 );
$properties->addChild($mailServiceStatus);
foreach my $ip (keys %{$ips}) {
my $ipNode = $self->makeIpNode($ip, $ips->{$ip});
$properties->addChild($ipNode);
}
$root->addChild($rootMail);
}
sub addDomainCustomButton {
my ( $self, $domainId, $id, $optionsPtr, $customButtonsDir, $icon ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $node = $self->makeCustomButtonNode( 'domains', $domainId, $id, $optionsPtr, $customButtonsDir, $icon );
$root->getChild( 'preferences', 1 )->addChild( $node);
}
sub addToPreferences {
my ( $self, $objectType, $objectId, $node ) = @_;
my $parent;
if ($objectType eq 'domain') {
$parent = $self->getCashedDomainNode($objectId);
}
elsif($objectType eq 'client') {
$parent = $self->{clientNodes}->{$objectId};
}
if ( !defined($parent) ) {
Logging::warning('Error: addToPreferences: empty parent node', 'PackerStructure');
return;
}
$parent->getChild( 'preferences', 1 )->addChild( $node);
}
sub setDomainCatchMail {
my ( $self, $domainId, $catchAllAddr ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $mailService = $root->getChild('mailsystem');
unless (defined $mailService ) {
Logging::warning("Error: setDomainCatchMail: there are no node 'mailsystem'", 'PackerStructure');
return;
}
$mailService->getChild( 'preferences', 1 )->addChild(XmlNode->new( 'catch-all', 'content' => $catchAllAddr ) );
}
sub setDomainKeysDomainSupport {
my ( $self, $domainId, $domainName, $state, $privateKeyPath, $publickKey ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $mailService = $root->getChild('mailsystem');
unless ( defined $mailService ) {
Logging::warning("Error: setDomainKeysDomainSupport: there are no node 'mailsystem'", 'PackerStructure');
return;
}
my $domainKeysNode = XmlNode->new( 'domain-keys',
'attributes' => { 'state' => $state } );
if ($state) {
my $privateKey = $self->{content_transport}->addDomainContent( 'key', $domainId,
"privatekey",
'directory' => $privateKeyPath,
'include' => ['default']
);
$domainKeysNode->getChild( 'content', 1, 1 )->addChild( $privateKey ) if $privateKey;
$domainKeysNode->setAttribute( 'public-key', $publickKey ) if ( defined($publickKey) && $publickKey );
}
$mailService->getChild( 'preferences', 1 )->addChild($domainKeysNode);
}
sub setDomainWebMail{
my ( $self, $domainId, $webmail, $cert ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $mailService = $root->getChild('mailsystem');
if ( not $mailService ) {
Logging::warning("Unable to dump domain webmail preferences, because of dump XML structure is not full", 'PackerStructure');
return;
}
my $node = XmlNode->new( 'web-mail' );
$node->setText( $webmail );
$node->setAttribute('certificate', $cert) if defined $cert;
$mailService->getChild( 'preferences', 1 )->addChild( $node );
}
sub setDomainGLSupport {
my ( $self, $domainId, $state ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $mailsystem = $root->getChild('mailsystem');
my $node = XmlNode->new( 'grey-listing' );
$node->setText($state);
$mailsystem->getChild('preferences', 1)->addChild($node);
}
sub setDomainDnsZone {
my ( $self, $domainId, $paramsPtr, $recordsPtr ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
$self->makeDnsZone($root->getChild( 'properties', 1 ), $paramsPtr, $recordsPtr);
}
sub removeDomainDnsZone {
my ( $self, $domainId ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $propertiesNode = $root->getChild( 'properties');
if ( $propertiesNode ) {
$propertiesNode->removeChildren('dns-zone');
}
}
sub setDomainDnsOld {
my ( $self, $domainId, $enabled, $type, $masterIp, $recordsPtr ) = @_;
my @records = @{$recordsPtr};
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $properties = $root->getChild( 'properties', 1 );
if ( !defined($properties) ) {
Logging::warning("Error: setDomainDnsOld: empty 'properties' node", 'PackerStructure');
return;
}
my $dnsNode = XmlNode->new('dns-zone');
$dnsNode->setAttribute(
'type',
( !$type || ( $type eq 'master' ) ) ? 'master' : 'slave'
);
$dnsNode->addChild(Status::make( $enabled eq 'true' ? 0 : 16 ));
for my $hash (@records) {
my $dnsrec = $self->makeDnsRecord($hash);
if ($dnsrec) {
$dnsNode->addChild($dnsrec);
}
$hash = undef;
}
if ( defined($masterIp) ) {
$dnsNode->addChild( makeOldMasterRec($masterIp) );
}
$properties->addChild($dnsNode);
}
sub addDomainAlias {
my ( $self, $domainId, $aliasPtr, $dnsParamsPtr, $dnsRecordsPtr) = @_;
my %alias = %{$aliasPtr};
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $dnsSync = defined $alias{'dns'} ? $alias{'dns'} : 'false';
my $aliasNode = XmlNode->new(
'domain-alias',
'attributes' => {
'name' => $alias{'displayName'},
'mail' => $alias{'mail'},
'web' => $alias{'web'},
'dns' => $dnsSync
},
'children' => [ Status::make( $alias{'status'} ) ]
);
$aliasNode->setAttribute('seo-redirect', defined $alias{'seoRedirect'} ? $alias{'seoRedirect'} : 'false');
$aliasNode->setAttribute('external-id', $alias{'external_id'}) if defined $alias{'external_id'} and $alias{'external_id'} ne '';
# DNS zone
if ( $alias{'dns_zone_id'} != 0 ) {
$self->makeDnsZone( $aliasNode, $dnsParamsPtr, $dnsRecordsPtr, $dnsSync );
}
$root->getChild( 'preferences', 1 )->addChild($aliasNode);
}
sub setDomainMailLists {
my ( $self, $domainId, $status, $ips) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $mlNode = XmlNode->new('maillists');
my $propertiesNode = $mlNode->getChild( 'properties', 1 );
$propertiesNode->addChild( Status::make( $status ) );
foreach my $ip (keys %{$ips}) {
my $ipNode = $self->makeIpNode($ip, $ips->{$ip});
$propertiesNode->addChild($ipNode);
}
$root->addChild($mlNode);
}
sub addDomainMailList {
my ($self, $domainId, $name, $passwd, $state, $ownersPtr, $membersPtr) = @_;
my @owners = @{$ownersPtr};
my %members = %{$membersPtr};
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my @mailListServs = $root->getChildren('maillists');
if ( scalar(@mailListServs) < 1 ) {
Logging::warning('Unable to dump domain maillist, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $mailListService = $mailListServs[0];
my $node = XmlNode->new(
'maillist',
'attributes' => { 'name', $name },
'children' => [ Status::make($state) ]
);
for my $listOwner (@owners) {
$node->addChild( XmlNode->new( 'owner', 'content' => $listOwner ) );
}
$node->addChild( CommonPacker::makePasswordNode( $passwd, 'encrypted') );
for my $memberEmail ( keys %members ) {
my $member = XmlNode->new( 'recipient', 'content' => $memberEmail );
if ( $members{$memberEmail} ne "" ) {
$member->setAttribute( 'fullname', $members{$memberEmail} );
}
$node->addChild($member);
}
$mailListService->addChild($node);
}
sub setDomainTraffic {
my ( $self, $domainId, $trafficValue) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
$root->addChild( XmlNode->new( 'traffic', 'content' => $trafficValue ) );
}
sub addDomainCertificate {
my ( $self, $domainId, $name, $cert, $csr, $ca_cert, $pvt_key, $default) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $certNode = XmlNode->new('certificate');
addUrlDecodedTextNode( $certNode, 'certificate-data', $cert ) if defined($cert);
addUrlDecodedTextNode( $certNode, 'signing-request', $csr ) if defined($csr);
addUrlDecodedTextNode( $certNode, 'ca-certificate', $ca_cert ) if defined($ca_cert);
addUrlDecodedTextNode( $certNode, 'private-key', $pvt_key ) if defined($pvt_key);
$certNode->setAttribute( 'name', $name );
$certNode->setAttribute( 'default', 'true' ) if ( defined $default && $default == 1 );
$root->getChild('certificates', 1 )->addChild($certNode);
}
sub addDomainPersonalPermission {
my ( $self, $domainId, $name, $value ) = @_;
my $root = $self->getCashedDomainNode($domainId);
if ( !defined($root) ) {
Logging::warning('Unable to dump domain personal permissions, because of dump XML structure is not full', 'PackerStructure');
return;
}
$self->makePermissionNode( $root->getChild( 'limits-and-permissions', 1 ), $name, $value );
}
sub setDomainPhostingEmpty {
my ( $self, $domainId, $sysuserPtr, $ips ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $phostingNode = XmlNode->new('phosting');
my $preferencesNode = XmlNode->new('preferences');
$phostingNode->addChild( $preferencesNode );
if (defined $sysuserPtr) {
$preferencesNode->addChild($self->makeSysUser($sysuserPtr));
}
my $propertiesNode = $phostingNode->getChild( 'properties', 1 );
foreach my $ip (keys %{$ips}) {
my $ipNode = $self->makeIpNode($ip, $ips->{$ip});
$propertiesNode->addChild($ipNode);
}
$root->addChild($phostingNode);
$self->regPhostingObjectBackupPath( $self->getDomainsBackupPath( $domainId ), $domainId );
$self->{phostingNodes}->{$domainId} = $phostingNode;
}
sub setDomainPhosting {
my ( $self, $domainId, $paramsPtr, $sysuserPtr, $scriptingPtr, $ips, $phpSettingsPtr ) = @_;
my %params = %{$paramsPtr};
my %scripting = %{$scriptingPtr};
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $phostingNode = XmlNode->new('phosting');
my $parentGuid = $root->getAttribute('guid');
if ( $parentGuid ) {
$phostingNode->setAttribute( 'guid', $self->getPhostingGuid( $parentGuid , $domainId ) );
$phostingNode->setAttribute( 'owner-guid', $parentGuid );
}
## %params ##
my %hostingAttribute = (
'https' => 'ssl',
'webstat' => 'webstat',
);
$phostingNode->setAttribute( 'shared-content', $params{'shared-content'} ) if defined($params{'shared-content'});
while ( my ( $xmlName, $fieldName ) = each(%hostingAttribute) ) {
# MySQL allows 'true', 'false' and '' in enums
if ( defined( $params{$fieldName} )
and $params{$fieldName} eq "true" )
{
$phostingNode->setAttribute( $xmlName, 'true' );
}
}
if ( defined( $params{'webstat'} ) and $params{'webstat'} ) {
$phostingNode->setAttribute( 'webstat', $params{'webstat'} );
}
if ( defined( $params{'https'} ) and $params{'https'} ) {
$phostingNode->setAttribute( 'https', $params{'https'} );
}
if ( defined( $params{'sslRedirect'} ) and $params{'sslRedirect'} ) {
$phostingNode->setAttribute( 'sslRedirect', $params{'sslRedirect'} );
}
if ( defined($params{'errdocs'} ) ) {
$phostingNode->setAttribute( 'errdocs', 'true' );
}
if ( defined( $params{'www-root'} ) ) {
$phostingNode->setAttribute( 'www-root', $params{'www-root'} );
}
if ( defined( $params{'cgi_bin_mode'} ) ) {
$phostingNode->setAttribute( 'cgi_bin_mode', $params{'cgi_bin_mode'} );
}
if ( defined( $params{'sitebuilder-site-id'} ) ) {
$phostingNode->setAttribute( 'sitebuilder-site-id', $params{'sitebuilder-site-id'} );
}
if ( defined( $params{'sitebuilder-site-published'} ) ) {
$phostingNode->setAttribute( 'sitebuilder-site-published', $params{'sitebuilder-site-published'} );
}
if ( defined( $params{'wu_script'} ) ) {
$phostingNode->setAttribute( 'wu_script', $params{'wu_script'} );
}
if ( defined( $params{'certificate_ref'} ) ) {
$phostingNode->setAttribute( 'certificate', $params{'certificate_ref'} );
}
if ( defined( $params{'original-conf-directory'} ) ) {
$phostingNode->setAttribute( 'original-conf-directory', $params{'original-conf-directory'} );
}
## %sysuser ##
my $prefs = $phostingNode->getChild( 'preferences', 1 );
if (defined $sysuserPtr) {
my $sysUserNode = $self->makeSysUser($sysuserPtr);
$prefs->addChild($sysUserNode);
}
## properties ##
my $propertiesNode = $phostingNode->getChild( 'properties', 1);
foreach my $ip (keys %{$ips}) {
my $ipNode = $self->makeIpNode($ip, $ips->{$ip});
$propertiesNode->addChild($ipNode);
}
## %scripting ##
my $scripringItem = XmlNode->new('scripting');
while ( my ( $scriptXmlName, $value ) = each(%scripting) ) {
$scripringItem->setAttribute( $scriptXmlName, $value ) if defined $value;
}
$phostingNode->getChild( 'limits-and-permissions', 1 )->addChild($scripringItem);
if (defined $phpSettingsPtr and (scalar keys %{$phpSettingsPtr} != 0)) {
$phostingNode->addChild($self->makePhpSettingsNode($phpSettingsPtr));
}
$root->addChild($phostingNode);
$self->regPhostingObjectBackupPath( $self->getDomainsBackupPath( $domainId ), $domainId );
$self->{phostingNodes}->{$domainId} = $phostingNode;
}
sub setDomainUserDataContent {
my ( $self, $domainId, $domainName, $path, $optPtr) = @_;
if (!$self->getContentTransport()->directoryExists("$path")) {
Logging::debug("Domain $domainName. Skip backup of non-existent directory $path");
return;
}
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $phostings = $root->getChild('phosting');
my ($fhApache, $tmpApache) = File::Temp::tempfile( AgentConfig::getBackupTmpDir() . "/pmm-dudc-incApacheFiles-XXXXXX", UNLINK => 1 );
my ($fhUser, $tmpUserData) = File::Temp::tempfile( AgentConfig::getBackupTmpDir() . "/pmm-dudc-incUserData-XXXXXX", UNLINK => 1 );
chown scalar(getpwnam('root')), scalar(getgrnam('root')), $tmpApache, $tmpUserData;
chmod 0600, $tmpApache, $tmpUserData;
my %excludes = map { $_ => 1 } @{$optPtr->{'exclude'}};
Logging::debug("List files in " . $path);
$self->_listApacheAndUserFilesInFolder($path, $fhUser, $fhApache, $optPtr->{'include'}, \%excludes);
close $fhUser;
close $fhApache;
my $userDataSize = $self->_setDomainContentIncrementally($domainId, $path, $optPtr, $tmpUserData, $phostings, 'user-data', $optPtr->{'sysuser'});
if (defined($userDataSize)) {
my $apacheSize = $self->_setDomainContentIncrementally($domainId, $path, $optPtr, $tmpApache, $phostings, 'apache-files', $self->{apache_user}{'user'});
if (defined($apacheSize)) {
$self->{stat}{vhostDumpsCount}++;
$self->{stat}{vhostSizeDumped} += $userDataSize + $apacheSize;
return;
}
}
my @apacheFiles;
my $cmd = "find $path \\( \\( -type d -user $self->{apache_user}{user} -group $self->{apache_user}{group} ! -perm -o+rw -prune \\) -o \\( ! -type d -user $self->{apache_user}{user} -group $self->{apache_user}{group} ! -perm -o+rw \\) \\) -printf \"%P\n\"";
my $findCmd = `$cmd`;
if ($? eq '0') {
@apacheFiles = split "\n", $findCmd;
}
my @exclude = (@apacheFiles) ? (@apacheFiles, @{$optPtr->{'exclude'}}) : @{$optPtr->{'exclude'}};
my $cidUserData = $self->{content_transport}->addDomainContent( 'user-data', $domainId,
'user-data',
'directory' => $path,
'sysuser' => $optPtr->{'sysuser'},
'exclude' => \@exclude
);
$phostings->getChild( 'content', 1, 1 )->addChild( $cidUserData ) if $cidUserData;
@{$self->{domainVhost}->{$domainId}} = ( 'user-data', $cidUserData, $path ) if $cidUserData;
my $cidApache;
if (@apacheFiles) {
$cidApache = $self->{content_transport}->addDomainContent( 'apache-files', $domainId,
'apache-files',
'directory' => $path,
'sysuser' => $self->{apache_user}{'user'},
'include' => \@apacheFiles
);
$phostings->getChild( 'content', 1, 1 )->addChild( $cidApache ) if $cidApache;
@{$self->{domainVhost}->{$domainId}} = ( 'apache-files', $cidApache, $path ) if $cidApache;
}
$self->{stat}{vhostDumpsCount}++;
$self->{stat}{vhostSizeDumped} += $self->_getContentSizeFromCidNode($cidUserData) + $self->_getContentSizeFromCidNode($cidApache);
}
sub _setDomainContentIncrementally {
my ($self, $domainId, $srcDirPath, $optPtr, $listingFile, $contentOwner, $cidType, $sysuser, $refferedContentType) = @_;
$refferedContentType = 'domainVhost' unless defined $refferedContentType;
my $cidSize = undef;
my $changesFile = HelpFuncs::mktemp(AgentConfig::getBackupTmpDir() . "/pmm-dci-chn-XXXXXXXX");
my $indexFile = HelpFuncs::mktemp(AgentConfig::getBackupTmpDir() . "/pmm-dci-idx-XXXXXXXX");
my $dependenciesFile = HelpFuncs::mktemp(AgentConfig::getBackupTmpDir() . "/pmm-dci-dep-XXXXXXXX");
my $oldMask = umask(0077);
for my $outFile ( ($changesFile, $indexFile, $dependenciesFile) ) {
open(my $outFileHandle, '>', $outFile);
close($outFileHandle);
}
umask($oldMask);
my $cmd = [
AgentConfig::pmmRasBin(), '--get-diff',
'--listing-file', $listingFile,
'--backup-file', $self->{storage}->{output_dir}."/".$self->getDomainsBackupPath($domainId, $cidType).".tgz",
'--changes-file', $changesFile,
'--index-file', $indexFile,
'--dependencies-file', $dependenciesFile
];
my $cidPostfix = '';
if ($cidType eq 'domainmail') {
push (@{$cmd}, '--id');
push (@{$cmd}, $domainId);
$cidPostfix = '_' . $domainId;
}
if ($self->{lastIndexPath}) {
push (@{$cmd}, '--last-index-path');
push (@{$cmd}, $self->{lastIndexPath});
}
if ($self->{lastIncrementFile}) {
push (@{$cmd}, '--last-increment-file');
push (@{$cmd}, $self->{lastIncrementFile});
}
if ($self->{excludePatternsFile}) {
push (@{$cmd}, '--exclude-patterns-file');
push (@{$cmd}, $self->{excludePatternsFile});
}
if (defined($self->{storage}->{ftpsettings})) {
push (@{$cmd}, '--use-ftp-passive-mode') if $self->{storage}->{passive_mode};
$ENV{'DUMP_STORAGE_PASSWD'} = $self->{storage}->{ftpsettings}->{password};
}
if (Logging::getVerbosity() >= Logging::LOG_LEVEL_DEBUG) {
push (@{$cmd}, '--debug');
}
if (Logging::getVerbosity() >= Logging::LOG_LEVEL_TRACE) {
push (@{$cmd}, '--verbose');
}
Logging::debug("Execute: ".join(' ', @{$cmd}));
my($err);
run $cmd, '>&', \$err;
if ($?) {
Logging::debug("Unable to calculate file diff, full dump will be performed instead. Error (".$?.") ".$err, "IncrementalBackup");
} else {
my $dumpXmlRelativePath = $self->getDomainsBackupPath($domainId, 'info', 0);
my $posNameBegin = rindex( $dumpXmlRelativePath, '/' ) + 1;
my $dumpName = substr($dumpXmlRelativePath, $posNameBegin);
my $dumpDirPath = ($posNameBegin > 0) ? substr($dumpXmlRelativePath, 0, $posNameBegin - 1) : "";
my $indexDirPath = $dumpDirPath;
if (!$self->{domainNodes}->{$domainId}) {
my $posSitesBegin = rindex($indexDirPath, '/sites/');
if ($posSitesBegin > 0) {
$indexDirPath = substr($indexDirPath, 0, $posSitesBegin);
}
}
my $cid_content = $self->{content_transport}->addDomainContent( $cidType, $domainId,
$cidType,
'directory' => $srcDirPath,
'sysuser' => $sysuser,
'includes-file' => $changesFile,
'exclude' => \@{$optPtr->{'exclude'}},
'no_recursion' => 1,
'indexed' => 1
);
if ($cid_content) {
$self->{storage}->moveFileToDiscovered($indexFile, "cid_".$cidType.$cidPostfix, $indexDirPath, $dumpName);
$contentOwner->getChild('content', 1, 1)->addChild($cid_content);
@{$self->{$refferedContentType}->{$domainId}} = ($cidType, $cid_content, $srcDirPath);
$cidSize = $self->_getContentSizeFromCidNode($cid_content);
}
$self->_keepRelatedDumps($dumpDirPath, $dependenciesFile);
}
unlink($changesFile) if -e $changesFile;
unlink($indexFile) if -e $indexFile;
unlink($dependenciesFile) if -e $dependenciesFile;
return $cidSize;
}
sub _getContentSizeFromCidNode {
my ($self, $cidNode) = @_;
my $size = 0;
if ($cidNode) {
foreach my $contentFileNode ( $cidNode->getChildren('content-file') ) {
if ($contentFileNode) {
$size += $contentFileNode->getAttribute('size');
}
}
}
return $size;
}
sub _keepRelatedDumps {
my ($self, $pathToDumpFolder, $relatedDumpsFile) = @_;
my @relatedDumps = HelpFuncs::loadArrayFromFile($relatedDumpsFile);
return unless (@relatedDumps);
@relatedDumps = sort(@relatedDumps);
$self->_keepRelatedDumpsTo($pathToDumpFolder, \@relatedDumps);
}
sub _keepRelatedDumpsTo {
my ($self, $pathToDumpFolder, $relatedDumps) = @_;
if (exists $self->{relatedDumps}->{$pathToDumpFolder}) {
my @diff = HelpFuncs::arrayDifference($relatedDumps, $self->{relatedDumps}->{$pathToDumpFolder});
my @merged = (@{$self->{relatedDumps}->{$pathToDumpFolder}}, @diff);
@{$self->{relatedDumps}->{$pathToDumpFolder}} = sort(@merged);
} else {
@{$self->{relatedDumps}->{$pathToDumpFolder}} = @{$relatedDumps};
}
return if ($pathToDumpFolder eq '');
my $pathToParentDumpFolder = dirname(dirname($pathToDumpFolder));
$pathToParentDumpFolder = "" if ($pathToParentDumpFolder eq '.');
$self->_keepRelatedDumpsTo($pathToParentDumpFolder, $relatedDumps);
}
sub _listApacheAndUserFilesInFolder {
my ($self, $srcDirPath, $outUserFiles, $outApacheFiles, $includes, $excludes, $isApacheBranch, $szPathTrim, $usersCache, $groupsCache, $orderNumber) = @_;
return if !opendir(my $dh, $srcDirPath);
$szPathTrim = length($srcDirPath) + 1 if (not defined $szPathTrim or $szPathTrim == 0);
$$orderNumber = 0 if not defined($orderNumber);
my @entriesInfo;
while (my $entry = readdir($dh)) {
next if ($entry eq "." || $entry eq "..");
my $entryFullPath = $srcDirPath."/".$entry;
my $entryRelPath = substr $entryFullPath, $szPathTrim;
next unless $self->_isEntryIncluded($entryRelPath, $includes, $excludes);
my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = lstat($entryFullPath) or next;
push @entriesInfo, join("\t", HelpFuncs::encodePath($entry), ++$$orderNumber, $mode, $uid, $gid, $size, $mtime, $ctime);
}
closedir($dh);
@entriesInfo = sort(@entriesInfo);
foreach my $entryInfo (@entriesInfo) {
my ($entry, $entryOrderNumber, $mode, $uid, $gid, $size, $mtime, $ctime) = split("\t", $entryInfo);
my $entryFullPath = $srcDirPath . "/" . HelpFuncs::decodePath($entry);
my $entryRelPath = substr $entryFullPath, $szPathTrim;
my $addToApacheListing = $outApacheFiles && ($isApacheBranch || ($uid == $self->{apache_user}{uid} && $gid == $self->{apache_user}{gid} && !($mode & Fcntl::S_IROTH && $mode & Fcntl::S_IWOTH)));
my $ftype = (Fcntl::S_ISDIR($mode) && !Fcntl::S_ISLNK($mode)) ? 'd' : 'f';
my $fsize = ($ftype eq 'd') ? "0" : "$size";
$mode = sprintf '%04o', $mode & 07777;
$mtime = HelpFuncs::Max($mtime, $ctime);
$usersCache->{$uid} = getpwuid($uid) if (not exists $usersCache->{$uid});
$groupsCache->{$gid} = getgrgid($gid) if (not exists $groupsCache->{$gid});
my $outFile = ($addToApacheListing) ? $outApacheFiles : $outUserFiles;
print $outFile join("\t", HelpFuncs::encodePath($entryRelPath), $ftype, $fsize, $mtime, $entryOrderNumber, $usersCache->{$uid}, $groupsCache->{$gid}, $mode) . "\n";
if ($ftype eq 'd') {
$self->_listApacheAndUserFilesInFolder($entryFullPath, $outUserFiles, $outApacheFiles, $includes, $excludes, $addToApacheListing, $szPathTrim, $usersCache, $groupsCache, $orderNumber);
}
}
}
sub _isEntryIncluded {
my ($self, $entryRelPath, $includes, $excludes) = @_;
my $isEntryIncluded = 0;
foreach my $include (@{$includes}) {
if (length($include) > length($entryRelPath)) {
$isEntryIncluded = index($include, $entryRelPath) == 0 ? 1 : 0;
} else {
$isEntryIncluded = index($entryRelPath, $include) == 0 ? 1 : 0;
}
last if $isEntryIncluded;
}
return 0 unless $isEntryIncluded;
return exists($excludes->{$entryRelPath}) ? 0 : 1;
}
sub setDomainPhostingFullContent {
my ( $self, $domainId, $domainName, $path, $optPtr) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $phostings = $root->getChild('phosting');
my $cid_content = $self->{content_transport}->addDomainContent( 'vhost', $domainId,
'vhost',
'directory' => $path,
'sysuser' => $optPtr->{'sysuser'},
'exclude' => $optPtr->{'exclude'},
);
$phostings->getChild( 'content', 1, 1 )->addChild( $cid_content ) if $cid_content;
@{$self->{domainVhost}->{$domainId}} = ( 'vhost', $cid_content, $path ) if $cid_content;
}
sub setDomainMailNamesContent{
my ( $self, $domainId, $domainAsciiName, $path, $sysuser ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my %options;
$options{'directory'} = $path;
$options{'sysuser'} = $sysuser;
my ($fhApache, $tmpApache) = File::Temp::tempfile( AgentConfig::getBackupTmpDir() . "/pmm-dmnc-incApacheFiles-XXXXXX", UNLINK => 1 );
my ($fhUser, $tmpUserData) = File::Temp::tempfile( AgentConfig::getBackupTmpDir() . "/pmm-dmnc-incUserData-XXXXXX", UNLINK => 1 );
chown scalar(getpwnam('root')), scalar(getgrnam('root')), $tmpApache, $tmpUserData;
chmod 0600, $tmpApache, $tmpUserData;
my $optPtr = \%options;
my %excludes = map { $_ => 1 } @{$optPtr->{'exclude'}};
Logging::debug("List files in " . $path);
$self->_listApacheAndUserFilesInFolder($path, $fhUser, $fhApache, [''], \%excludes);
close $fhUser;
close $fhApache;
my $mailsystem = $root->getChild('mailsystem');
my $mailContentSize = $self->_setDomainContentIncrementally(
$domainId, $path, $optPtr, $tmpUserData, $mailsystem, 'domainmail', $sysuser, 'domainMailContent');
$self->{stat}{mailSizeDumped} += $mailContentSize;
$self->{stat}{mailDumpsCount}++;
}
sub setDomainMailListContent{
my ( $self, $domainId, $domainAsciiName, $path, $optPtr ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $mailContent = $self->{content_transport}->addDomainContent( 'domainmaillist', $domainId,
'ml',
'directory' => $path,
'include' => $optPtr->{'include'},
'follow_symlinks' => $optPtr->{'follow_symlinks'},
'sysuser' => $optPtr->{'sysuser'}
);
$root->getChild( 'maillists' )->getChild( 'content', 1, 1 )->addChild( $mailContent ) if $mailContent;
@{$self->{domainMailListContent}->{$domainId}} = ( 'domainmaillist', $mailContent, $path ) if $mailContent;
}
sub setDomainPhostingContentCommon {
my ( $self, $domainId, $domainName, $path, $contentType ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my @phostings = $root->getChildren('phosting');
if ( scalar(@phostings) < 1 ) {
Logging::warning('Unable to dump domain phosting content, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $cid_content = $self->{content_transport}->addDomainContent( $contentType, $domainId,
$contentType,
'directory' => $path
);
$phostings[0]->getChild( 'content', 1, 1 )->addChild( $cid_content ) if $cid_content;
return $cid_content;
}
sub setDomainPhostingProtectedDirContent {
my ( $self, $domainId, $domainName, $path ) = @_;
$self->setDomainPhostingContentCommon($domainId, $domainName, $path, 'pd');
}
sub setDomainPhostingStatisticsContent {
my ( $self, $domainId, $domainName, $path, $optPtr ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my @phostings = $root->getChildren('phosting');
if ( scalar(@phostings) < 1 ) {
Logging::warning('Unable to dump domain phosting statistics, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $cid_content = $self->{content_transport}->addDomainContent( 'statistics', $domainId,
'statistics',
'directory' => $path
);
$phostings[0]->getChild( 'content', 1, 1 )->addChild( $cid_content ) if $cid_content;
@{$self->{domainStatistics}->{$domainId}} = ( 'statistics', $cid_content, $path ) if $cid_content;
}
sub setDomainPhostingWebstatContent {
my ( $self, $domainId, $domainName, $path ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my @phostings = $root->getChildren('phosting');
if ( scalar(@phostings) < 1 ) {
Logging::warning('Unable to dump domain phosting webstat content, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $cid_webstat = $self->{content_transport}->addDomainContent( 'webstat', $domainId,
'webstat',
'directory' => $path
);
$phostings[0]->getChild( 'content', 1, 1 )->addChild( $cid_webstat ) if $cid_webstat;
}
sub setDomainPhostingWebstatSslContent {
my ( $self, $domainId, $domainName, $path ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my @phostings = $root->getChildren('phosting');
if ( scalar(@phostings) < 1 ) {
Logging::warning('Error: setDomainPhostingWebstatSslContent: there are no node "phosting"', 'PackerStructure');
return;
}
my $cid_webstat_ssl = $self->{content_transport}->addDomainContent( 'webstat_ssl', $domainId,
'webstat-ssl',
'directory' => $path
);
$phostings[0]->getChild( 'content', 1, 1 )->addChild( $cid_webstat_ssl ) if $cid_webstat_ssl;
}
sub setDomainPhostingFtpstatContent {
my ( $self, $domainId, $domainName, $path ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my @phostings = $root->getChildren('phosting');
if ( scalar(@phostings) < 1 ) {
Logging::warning('Unable to dump domain phosting ftpstat content, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $cid_ftpstat = $self->{content_transport}->addDomainContent( 'ftp_stat', $domainId,
'ftpstat',
'directory' => $path
);
$phostings[0]->getChild( 'content', 1, 1 )->addChild( $cid_ftpstat ) if $cid_ftpstat;
}
sub setDomainPhostingLogsContent {
my ( $self, $domainId, $domainName, $path ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my @phostings = $root->getChildren('phosting');
if ( scalar(@phostings) < 1 ) {
Logging::warning('Error: setDomainPhostingLogsContent: there are no node "phosting"', 'PackerStructure');
return;
}
if ($self->{excludePatternsFile} and -e $self->{excludePatternsFile} and -s $self->{excludePatternsFile}) {
# Prepare logs directory listing
my ($fhListing, $listingFile) = File::Temp::tempfile(AgentConfig::getBackupTmpDir() . "/pmm-dplc-lst-XXXXXX", UNLINK => 1);
chown scalar(getpwnam('root')), scalar(getgrnam('root')), $listingFile;
chmod 0600, $listingFile;
Logging::debug("List files in " . $path);
$self->_listApacheAndUserFilesInFolder($path, $fhListing, undef, ['']);
close($fhListing);
# Prepare temporary files for pmm-ras
my ($fhChages, $changesFile) = File::Temp::tempfile(AgentConfig::getBackupTmpDir() . "/pmm-dplc-ch-XXXXXX", UNLINK => 1);
my ($fhIndex, $indexFile) = File::Temp::tempfile(AgentConfig::getBackupTmpDir() . "/pmm-dplc-id-XXXXXX", UNLINK => 1);
my ($fhExcludes, $excludesFile) = File::Temp::tempfile(AgentConfig::getBackupTmpDir() . "/pmm-dplc-ex-XXXXXX", UNLINK => 1);
close($fhChages);
close($fhIndex);
close($fhExcludes);
# Prepare excludes for logs directory
my $res = HelpFuncs::replaceLinesInFile($self->{excludePatternsFile}, $excludesFile, '^\/logs\/|^logs\/', '');
if ($res == 0) {
my $cmd = [
AgentConfig::pmmRasBin(), '--get-diff',
'--listing-file', $listingFile,
'--backup-file', $self->{storage}->{output_dir}."/".$self->getDomainsBackupPath($domainId, 'logs').".tgz",
'--changes-file', $changesFile,
'--index-file', $indexFile,
'--exclude-patterns-file', $excludesFile
];
if (Logging::getVerbosity() >= Logging::LOG_LEVEL_DEBUG) {
push (@{$cmd}, '--debug');
}
if (Logging::getVerbosity() >= Logging::LOG_LEVEL_TRACE) {
push (@{$cmd}, '--verbose');
}
Logging::debug("Execute: ".join(' ', @{$cmd}));
my($err);
run $cmd, '>&', \$err;
my $dumpSucceed = 0;
if ($?) {
Logging::debug("Unable to apply exclusion pattern to log files, all log files will be dumped. Error (".$?.") ".$err, "LogsBackup");
} else {
my $cid_logs = $self->{content_transport}->addDomainContent( 'logs', $domainId,
'logs',
'directory' => $path,
'includes-file' => $changesFile,
'no_recursion' => 1
);
$phostings[0]->getChild( 'content', 1, 1 )->addChild( $cid_logs ) if $cid_logs;
$dumpSucceed = 1;
}
return if ($dumpSucceed);
}
}
my $cid_logs = $self->{content_transport}->addDomainContent( 'logs', $domainId,
'logs',
'directory' => $path
);
$phostings[0]->getChild( 'content', 1, 1 )->addChild( $cid_logs ) if $cid_logs;
}
sub setDomainPhostingAnonFtpstatContent {
my ( $self, $domainId, $domainName, $path ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my @phostings = $root->getChildren('phosting');
if ( scalar(@phostings) < 1 ) {
Logging::warning('Error: setDomainPhostingAnonFtpstatContent: there are no node "phosting"', 'PackerStructure');
return;
}
my $cid_anon_ftpstat = $self->{content_transport}->addDomainContent( 'anon_ftpstat', $domainId,
'anon-ftpstat',
'directory' => $path
);
$phostings[0]->getChild( 'content', 1, 1 )->addChild( $cid_anon_ftpstat ) if $cid_anon_ftpstat;
}
sub setDomainPhostingConfContent {
my ( $self, $domainId, $domainName, $path, $optPtr ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my @phostings = $root->getChildren('phosting');
if ( scalar(@phostings) < 1 ) {
Logging::warning('Error: setDomainPhostingConfContent: there are no node "phosting"', 'PackerStructure');
return;
}
my $cid_conf;
$cid_conf = $self->{content_transport}->addDomainContent( 'conf', $domainId,
'conf',
'directory' => $path,
'exclude' => $optPtr->{'exclude'}
);
$phostings[0]->getChild( 'content', 1, 1 )->addChild( $cid_conf ) if $cid_conf;
}
sub setDomainLogrotation {
my ( $self, $domainId, $logRotationPtr) = @_;
my %logRotation = %{$logRotationPtr};
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $phosting = $root->getChild('phosting');
if ( not $phosting ) {
Logging::warning('Unable to dump domain log rotation settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $node;
if (keys %logRotation) {
$self->makeLogrotationNode( $phosting->getChild( 'preferences', 1 ), \%logRotation );
}
}
sub setDomainAnonFtp {
my ( $self, $domainId, $domainName, $propsPtr, $pub_path, $incoming_path, $optPtr ) = @_;
my %props = %{$propsPtr};
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $phosting = $root->getChild('phosting');
if ( not $phosting ) {
Logging::warning('Error: setDomainAnonFtp: there are no node "phosting"', 'PackerStructure');
return;
}
my $anonRoot = XmlNode->new('anonftp');
if ( $props{'status'} =~ /true/ ) {
$anonRoot->setAttribute( 'pub', 'true' );
}
if ( $props{'incoming'} =~ /true/ ) {
$anonRoot->setAttribute( 'incoming', 'true' );
}
if ( defined( $props{'max_conn'} ) ) {
makeAnonftpLimitNode( $anonRoot, 'max-connections',
$props{'max_conn'} );
}
if ( defined( $props{'bandwidth'} ) ) {
makeAnonftpLimitNode( $anonRoot, 'bandwidth',
$props{'bandwidth'} );
}
if ( defined( $props{'quota'} ) ) {
makeAnonftpLimitNode( $anonRoot, 'incoming-disk-quota',
$props{'quota'} );
}
if ( defined( $props{'display_login'} ) ) {
$anonRoot->setAttribute( 'display-login', $props{'display_login'} );
}
if ( $props{'incoming_readable'} =~ /true/ ) {
makeAnonftpPermissionNode( $anonRoot, 'incoming-download' );
}
if ( $props{'incoming_subdirs'} =~ /true/ ) {
makeAnonftpPermissionNode( $anonRoot, 'incoming-mkdir' );
}
if ( defined( $props{'login_text'} ) ) {
my $loginMessageNode =
XmlNode->new( 'login-message',
'content' => $props{'login_text'} );
$anonRoot->addChild($loginMessageNode);
}
$phosting->getChild( 'preferences', 1 )->addChild($anonRoot);
}
sub addDomainProtectedDir {
my ( $self, $domainId, $pdirPath, $pdirTitle, $pdirNonSSL, $pdirSSL, $pdirCGI, $pdirUsersPtr) = @_;
my @pdirUsers = @{$pdirUsersPtr};
my $parent = $self->getCashedDomainNode($domainId);
return unless defined $parent;
my $phostingNode = $parent->getChild('phosting');
unless ( defined $phostingNode ) {
Logging::warning('Error: addDomainProtectedDir: there are no node "phosting"', 'PackerStructure');
return;
}
my $pdirNode = XmlNode->new('pdir');
# workaround of CLI inabliity to create '' directory.
if ( $pdirPath eq '' ) {
$pdirPath = '/';
}
$pdirNode->setAttribute( 'name', $pdirPath );
if ($pdirTitle) {
$pdirNode->setAttribute( 'title', $pdirTitle );
}
if ($pdirNonSSL) {
$pdirNode->setAttribute( 'nonssl', $pdirNonSSL );
}
if ($pdirSSL) {
$pdirNode->setAttribute( 'ssl', $pdirSSL );
}
if ($pdirCGI) {
$pdirNode->setAttribute( 'cgi', $pdirCGI );
}
my $userNode;
my $item;
for my $user (@pdirUsers) {
$userNode = XmlNode->new('pduser');
$pdirNode->addChild($userNode);
$userNode->setAttribute( 'name', $user->{'login'} );
$item = CommonPacker::makePasswordNode( $user->{'passwd'}, CommonPacker::normalizePasswordType( $user->{'passwdType'} ) );
$userNode->addChild($item);
}
$phostingNode->getChild( 'preferences', 1 )->addChild($pdirNode);
}
sub addDomainSubFtpUser {
my ( $self, $domainId, $domainName, $sysuserPtr, $ptrFtpUser) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $phostingNode = $root->getChild('phosting');
my $ftpuserNode = XmlNode->new('ftpuser');
$ftpuserNode->setAttribute('name', $sysuserPtr->{'login'});
$ftpuserNode->setAttribute('external-id', $ptrFtpUser->{'external_id'}) if defined $ptrFtpUser->{'external_id'} and $ptrFtpUser->{'external_id'} ne '';
$ftpuserNode->addChild($self->makeSysUser($sysuserPtr));
$phostingNode->getChild( 'ftpusers', 1 )->addChild($ftpuserNode);
}
sub setEmptySubFtpUsersNode {
my ($self, $domainId) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $phostingNode = $root->getChild('phosting', 1);
$phostingNode->getChild('ftpusers', 1);
}
sub removeResellerChildNodeIfEmpty {
my ( $self, $clientId, $nodeName ) = @_;
my $root = $self->getCashedClientNode( $clientId );
return unless defined $root;
my $containerNode = $root->getChild( $nodeName );
if ( defined $containerNode && not $containerNode->getChildren() ) {
$root->removeChildren( $nodeName );
}
}
sub removePhostingChildNodeIfEmpty {
my ( $self, $domainId, $nodeName ) = @_;
my $root = $self->getCashedDomainNode( $domainId );
return unless defined $root;
my $phostingNode = $root->getChild( 'phosting', 1 );
my $containerNode = $phostingNode->getChild( $nodeName . 's' );
if ( defined $containerNode && not $containerNode->getChildren( $nodeName ) ) {
$phostingNode->removeChildren( $nodeName . 's' );
}
}
sub removeMailSystemChildNodeIfEmpty {
my ( $self, $domainId, $nodeName ) = @_;
my $root = $self->getCashedDomainNode( $domainId );
return unless defined $root;
my $mailsystemNode = $root->getChild( 'mailsystem' );
my $containerNode = $mailsystemNode->getChild( $nodeName . 's' );
if ( defined $containerNode && not $containerNode->getChildren( $nodeName ) ) {
$mailsystemNode->removeChildren( $nodeName . 's' );
}
}
sub addDomainWebUser {
my ( $self, $domainId, $domainName, $sysuserPtr, $scriptingPtr, $webUserHome, $privatePath ) = @_;
my %sysuser = %{$sysuserPtr};
my %scripting = %{$scriptingPtr};
my $parent = $self->getCashedDomainNode($domainId);
return unless defined $parent;
my $phostingNode = $parent->getChild('phosting');
unless( defined $phostingNode ) {
Logging::warning('Unable to dump domain webuser preferences, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $webuserNode = XmlNode->new('webuser');
$webuserNode->addChild($self->makeSysUser(\%sysuser));
my $userName = $sysuser{'login'};
$webuserNode->setAttribute( 'name', $userName );
my %webUserScripting = (
'ssi' => 'ssi',
'php' => 'php',
'cgi' => 'cgi',
'perl' => 'perl',
'asp' => 'asp',
'python' => 'python',
'asp_dot_net' => 'asp_dot_net',
'fastcgi' => 'fastcgi',
);
my $item = XmlNode->new('scripting');
while ( my ( $xmlName, $fieldName ) = each(%webUserScripting) ) {
if ( defined $scripting{$fieldName}
and ( $scripting{$fieldName} eq 'true' or $scripting{$fieldName} eq 'false' ) )
{
$item->setAttribute( $xmlName, $scripting{$fieldName} );
}
}
if (exists $scripting{'write_modify'} && defined $scripting{'write_modify'}) {
$item->setAttribute('write_modify', $scripting{'write_modify'}) ;
}
$webuserNode->addChild($item);
$phostingNode->getChild( 'webusers', 1 )->addChild($webuserNode);
}
sub setDomainWebalizer {
my ( $self, $domainId, $directRef, $hiddenRefsPtr, $groupRefsPtr) = @_;
my @hiddenRefs = @{$hiddenRefsPtr};
my @groupRefs = @{$groupRefsPtr};
my $parent = $self->getCashedDomainNode($domainId);
return unless defined $parent;
my $phostingNode = $parent->getChild('phosting');
unless( defined $phostingNode ) {
Logging::warning('Unable to dump domain webalizer settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $webalizerNode = XmlNode->new("webalizer");
if ($directRef)
{
$webalizerNode->setAttribute( 'hide-direct-referrer', 'true' );
}
for my $ref (@hiddenRefs) {
$webalizerNode->addChild(
XmlNode->new(
"webalizer-hidden-referrer", 'content' => $ref
)
);
}
for my $groupRef (@groupRefs ) {
$webalizerNode->addChild(
XmlNode->new(
'webalizer-group-referrer',
'content' => $groupRef->{'ref'},
'attributes' => { 'group-name' => $groupRef->{'name'} }
)
);
}
$phostingNode->getChild( 'preferences', 1 )->addChild($webalizerNode);
}
sub setComposerInstances {
my ($self, $domainId, $embeddedInfo) = @_;
return unless defined($embeddedInfo->{'composer-instances'});
my $domainNode = $self->getCashedDomainNode($domainId);
return unless defined $domainNode;
my ($composerInstances) = @{$embeddedInfo->{'composer-instances'}};
$self->addEmbeddedInfo($domainNode, 'composer-instances', $composerInstances);
}
sub setDomainPerfomance {
my ( $self, $domainId, $max_connection, $traffic_bandwidth) = @_;
my $parent = $self->getCashedDomainNode($domainId);
return unless defined $parent;
my $phostingNode = $parent->getChild('phosting');
unless ( defined $phostingNode ) {
Logging::warning('Unable to dump domain performance settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $perfomanceNode = XmlNode->new('perfomance');
$perfomanceNode->addChild(
XmlNode->new(
'max-connections', 'content' => $max_connection
)
);
$perfomanceNode->addChild(
XmlNode->new(
'traffic-bandwidth', 'content' => $traffic_bandwidth
)
);
$phostingNode->getChild( 'preferences', 1 )->addChild( $perfomanceNode );
}
sub appendNodeToPhosting {
my ( $self, $domainId, $rawXml ) = @_;
my $parent = $self->getCashedDomainNode($domainId);
return unless defined $parent;
my $phostingNode = $parent->getChild('phosting');
unless ( defined $phostingNode ) {
Logging::warning('Error: appendNodeToPhosting: there are no node "phosting"', 'PackerStructure');
return;
}
$phostingNode->addChild(XmlNode->new(undef, 'raw' => $rawXml));
}
sub setIisAppPool {
my ( $self, $domainId, $info ) = @_;
my $parent = $self->getCashedDomainNode($domainId);
return unless defined $parent;
my $phostingNode = $parent->getChild('phosting');
unless ( defined $phostingNode ) {
Logging::warning('Error: setIisAppPool: there are no node "phosting"', 'PackerStructure');
return;
}
my $phostingPreferencesNode = $phostingNode->getChild('preferences');
unless ( defined $phostingPreferencesNode ) {
Logging::warning('Error: setIisAppPool: there are no node "phosting/preferences"', 'PackerStructure');
return;
}
$phostingPreferencesNode->addChild(XmlNode->new(undef, 'raw' => $info));
}
sub setDomainWebStat{
my ( $self, $domainId, $stat_ttl) = @_;
my $parent = $self->getCashedDomainNode($domainId);
return unless defined $parent;
my $phostingNode = $parent->getChild('phosting');
unless( defined $phostingNode ) {
Logging::warning('Error: setDomainWebStat: there are no node "phosting"', 'PackerStructure');
return;
}
my $webstatNode = XmlNode->new('web-stat');
$webstatNode->setAttribute( 'stat-ttl', $stat_ttl ) if $stat_ttl;
$phostingNode->getChild( 'preferences', 1 )->addChild( $webstatNode );
}
sub setDomainShosting {
my ( $self, $domainId, $forward, $ips) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $shostingNode = XmlNode->new( 'shosting');
$shostingNode->addChild(XmlNode->new('url', 'content' => $forward->{'redirect'}));
my $propertiesNode = $shostingNode->getChild('properties', 1);
foreach my $ip (keys %{$ips}) {
my $ipNode = $self->makeIpNode($ip, $ips->{$ip});
$propertiesNode->addChild($ipNode);
}
if (defined ($forward->{'http_code'})) {
my $httpcodeNode = XmlNode->new('httpcode', 'content' => $forward->{'http_code'});
$shostingNode->addChild($httpcodeNode);
}
$root->addChild($shostingNode);
}
sub setDomainFhosting {
my ( $self, $domainId, $forward, $ips) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $fhostingNode = XmlNode->new( 'fhosting');
$fhostingNode->addChild(XmlNode->new('url', 'content' => $forward));
my $propertiesNode = $fhostingNode->getChild('properties', 1);
foreach my $ip (keys %{$ips}) {
my $ipNode = $self->makeIpNode($ip, $ips->{$ip});
$propertiesNode->addChild($ipNode);
}
$root->addChild($fhostingNode);
}
sub addSite {
my ( $self, $domainId, $sitePtr) = @_;
my $parent = $self->getCashedDomainNode($domainId);
return unless defined $parent;
my $phostingNode = $parent->getChild('phosting');
unless ( defined $phostingNode ) {
Logging::warning('Error: addSite: there are no node "phosting"', 'PackerStructure');
return;
}
my $siteNode = XmlNode->new( 'site' );
$phostingNode->getChild( 'sites', 1 )->addChild($siteNode);
}
###### SubDomain functions ######
sub addSubDomain {
my ( $self, $domainId, $ptrSubDomain, $subDomainName, $subAsciiDomainName, $https, $shared_content, $sysuserPtr, $scriptingPtr) = @_;
$subAsciiDomainName = $subDomainName if not $subAsciiDomainName;
my $subDomainId = $ptrSubDomain->{'id'};
$self->regSubdomainObjectBackupPath( $self->getPhostingBackupPath( $domainId ), $subDomainId, $subAsciiDomainName, $domainId );
my %sysuser = %{$sysuserPtr};
my %scripting = %{$scriptingPtr};
my $parent = $self->getCashedDomainNode($domainId);
return unless defined $parent;
my $phosting = $parent->getChild('phosting');
if ( not $phosting ) {
Logging::warning('Error: addSubdomain: there are no node "phosting"', 'PackerStructure');
return;
}
my $root = XmlNode->new('subdomain', 'attributes' => {'id' => $subDomainId});
$self->{subDomainNodes}->{$subDomainId} = $root;
my $parentGuid = $parent->getAttribute('guid');
$root->setAttribute( "guid", $self->getSubdomainGuid( $parentGuid, $subDomainId ) ) if $parentGuid;
my $phostingGuid = $phosting->getAttribute('guid');
$root->setAttribute( 'owner-guid', $phostingGuid ) if $phostingGuid;
$root->setAttribute( 'name', $subDomainName );
if ( 'true' eq $https ) {
$root->setAttribute( 'https', 'true' );
}
if ( $shared_content ne '' ) {
$root->setAttribute( 'shared-content', $shared_content );
}
if ( exists $ptrSubDomain->{'www-root'} ) {
$root->setAttribute( 'www-root', $ptrSubDomain->{'www-root'} );
}
if ( exists $ptrSubDomain->{'certificate_ref'} ) {
$root->setAttribute( 'certificate', $ptrSubDomain->{'certificate_ref'});
}
if ( exists $ptrSubDomain->{'original-conf-directory'} ) {
$root->setAttribute('original-conf-directory', $ptrSubDomain->{'original-conf-directory'});
}
## %sysuser ##
if (%sysuser)
{
$root->addChild($self->makeSysUser(\%sysuser));
}
## %scripting ##
my $scripringItem = XmlNode->new('scripting');
while ( my ( $xmlName, $value ) = each(%scripting) ) {
$scripringItem->setAttribute( $xmlName, $value );
}
$root->addChild($scripringItem);
$phosting->getChild( 'subdomains', 1 )->addChild($root);
}
sub setSubDomainHttpdocsContent {
my ( $self, $subDomainId, $path, $exclude_httpdocs_files_ptr, $webspaceId ) = @_;
my @exclude_httpdocs_files = @{$exclude_httpdocs_files_ptr};
my $root = $self->{subDomainNodes}->{$subDomainId};
my $cid_docroot = $self->{content_transport}->addSubDomainPhostingContent( 'docroot', $subDomainId, $webspaceId,
"httpdocs",
"directory" => $path,
"exclude" => \@exclude_httpdocs_files
);
$root->getChild( 'content', 1, 1 )->addChild( $cid_docroot ) if $cid_docroot;
}
sub setSubDomainHttpsdocsContent {
my ( $self, $subDomainId, $path, $exclude_httpsdocs_files_ptr ) = @_;
my @exclude_httpsdocs_files = @{$exclude_httpsdocs_files_ptr};
my $root = $self->{subDomainNodes}->{$subDomainId};
my $cid_docroot_ssl = $self->{content_transport}->addSubDomainPhostingContent('docroot_ssl', $subDomainId, undef,
"httpsdocs",
"directory" => $path,
"exclude" => \@exclude_httpsdocs_files
);
$root->getChild( 'content', 1, 1 )->addChild( $cid_docroot_ssl ) if $cid_docroot_ssl;
}
sub setSubDomainErrorDocsContent {
my ( $self, $subDomainId, $path ) = @_;
my $subdomainNode = $self->{subDomainNodes}->{$subDomainId};
my $cid_conf = $self->{content_transport}->addSubDomainPhostingContent( 'error_docs', $subDomainId, undef,
"error-docs",
"directory" => $path
);
$subdomainNode->getChild( 'content', 1, 1 )->addChild( $cid_conf ) if $cid_conf;
}
sub setSubDomainConfContent {
my ( $self, $subDomainId, $path ) = @_;
my $root = $self->{subDomainNodes}->{$subDomainId};
my $cid_conf = $self->{content_transport}->addSubDomainPhostingContent( 'conf', $subDomainId, undef,
"conf",
"directory" => $path
);
$root->getChild( 'content', 1, 1 )->addChild( $cid_conf ) if $cid_conf;
}
###### End SubDomain functions ######
####### Mail functions #######
sub addMail {
my ( $self, $domainId, $mailId, $mailName, $passwd, $typePasswd, $userUid, $cpAccessDefault ) = @_;
$self->regMailnameObjectBackupPath( $self->getDomainsBackupPath( $domainId ), $mailId, $mailName, $domainId );
my $parent = $self->getCashedDomainNode($domainId);
return unless defined $parent;
my $mailService = $parent->getChild('mailsystem');
if ( not $mailService ) {
Logging::warning("Error: Packer.addMail: there are no node 'mailsystem'", 'PackerStructure');
return;
}
my $root = XmlNode->new( 'mailuser', 'attributes' => {
'id' => $mailId,
'name' => $mailName
} );
if (defined $userUid) {
$root->setAttribute('user-guid', $userUid);
}
if (defined $cpAccessDefault) {
$root->setAttribute('cp-access-default', $cpAccessDefault);
}
my $parentGuid = $parent->getAttribute('guid');
$root->setAttribute( 'guid', $self->getMailnameGuid( $parentGuid, $mailId ) ) if $parentGuid;
$root->setAttribute( 'owner-guid', $parentGuid ) if $parentGuid;
my $props = $root->getChild( 'properties', 1 );
$root->getChild( 'preferences', 1 );
my $item;
if ( defined($passwd) && $passwd ) {
if ( $passwd =~ /NULL/ ) {
$item = CommonPacker::makePasswordNode( '', 'plain' );
}
else {
$item = CommonPacker::makePasswordNode( $passwd, $typePasswd );
}
$props->addChild( $item );
}
$self->{mailNodes}->{$mailId} = $root;
$mailService->getChild( 'mailusers', 1 )->addChild($root);
}
sub setMailBoxQuota {
my ( $self, $mailId, $mbox_quota ) = @_;
my $root = $self->{mailNodes}->{$mailId};
$root->setAttribute( 'mailbox-quota', $mbox_quota );
}
sub setMailBox {
my ( $self, $mailId, $mailName, $domainAsciiName, $enabled, $path ) = @_;
my $root = $self->{mailNodes}->{$mailId};
if ( !defined($root) ) {
Logging::warning('Unable to dump $mailName mailbox settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $item = XmlNode->new( 'mailbox', 'attributes' => { 'type' => 'mdir' } );
$root->getChild( 'preferences', 1 )->addChild($item);
$item->setAttribute( 'enabled', $enabled );
my $cid = $self->{content_transport}->addMailnameContent( 'mailbox', $mailId, "mdir",
'directory' => $path, 'include_hidden_files' => 1 );
$item->getChild( 'content', 1, 1 )->addChild( $cid ) if $cid;
}
sub addMailAliase {
my ( $self, $mailId, $name ) = @_;
my $root = $self->{mailNodes}->{$mailId};
if ( !defined($root) ) {
Logging::warning('Unable to dump $name mail alias settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $item = XmlNode->new( 'alias', 'content' => $name );
$root->getChild( 'preferences', 1 )->addChild($item);
}
sub setMailForwarding {
my ( $self, $mailId, $enabled, $membersPtr ) = @_;
unless ( ref($membersPtr) =~ /ARRAY/ ) {
Logging::warning("Error: setMailForwarding: membersPtr is not ref array",'assert');
return;
}
my @members = @{$membersPtr};
my $root = $self->{mailNodes}->{$mailId};
if ( !defined($root) ) {
Logging::warning('Unable to dump mail forwarding settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
$root->setAttribute( 'forwarding-enabled', $enabled? 'true': 'false' );
my $item;
foreach my $member (@members) {
$item = XmlNode->new( 'forwarding', 'content' => $member );
$root->getChild( 'preferences', 1 )->addChild($item);
}
}
sub setMailAutoresponders {
my ( $self, $mailId, $mailName, $domainAsciiName, $dir, $enabled, $autorespondersPtr, $attachesPtr ) = @_;
unless ( ref($autorespondersPtr) =~ /ARRAY/ ) {
Logging::warning("Error: setMailAutoresponders: autorespondersPtr is not ref array",'assert');
return;
}
my @autoresponders = @{$autorespondersPtr};
unless ( ref($attachesPtr) =~ /ARRAY/ ) {
Logging::warning("Error: setMailAutoresponders: attachesPtr is not ref array",'assert');
return;
}
my @attaches = @{$attachesPtr};
my $root = $self->{mailNodes}->{$mailId};
if ( !defined($root) ) {
Logging::warning('Error: setMailAutoresponders: empty parent node', 'PackerStructure');
return;
}
my $autorespondersNode = XmlNode->new( 'autoresponders' );
my $cid = $self->{content_transport}->addMailnameContent( 'attaches', $mailId, "attach",
"directory" => $dir, 'checkEmptyDir' => 1 );
$autorespondersNode->getChild( 'content', 1, 1 )->addChild( $cid ) if $cid;
foreach my $file (@attaches) {
$autorespondersNode->addChild(
XmlNode->new( 'attach', 'attributes' => { 'file' => $file } ) );
}
foreach my $autoresponder (@autoresponders) {
my $node = $self->makeAutoresponderNode ($enabled, $autoresponder, $mailName);
$autorespondersNode->addChild($node);
}
$root->getChild( 'preferences', 1 )->addChild($autorespondersNode);
}
sub setMailAddressbook {
my ( $self, $mailId, $paramsPtr, $turbaVersion ) = @_;
my @params = @{$paramsPtr};
my $parent = $self->{mailNodes}->{$mailId};
if ( !defined($parent) ) {
Logging::warning('Unable to dump mailbox addressbook, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $node = XmlNode->new('addressbook');
my %objectFields = (
'id' => 'id',
'name' => 'name',
'alias' => 'alias',
'email' => 'email',
'title' => 'title',
'company' => 'company',
'home-phone' => 'homephone',
'work-phone' => 'workphone',
'mobile-phone' => 'cellphone',
'fax' => 'fax',
'home-address' => 'homeaddress',
'work-address' => 'workaddress',
'notes' => 'notes'
);
if ($turbaVersion->{'majorVersion'} = 2 && $turbaVersion->{'minorVersion'} > 2 ) {
$objectFields{'name'} = 'lastname';
$objectFields{'home-address'} = 'homestreet';
$objectFields{'work-address'} = 'workstreet';
$objectFields{'first-name'} = 'firstname';
$objectFields{'middle-names'} = 'middlenames';
}
foreach my $ptrHash (@params) {
if ( $ptrHash->{'object_type'} eq 'Group' ) {
my $group =
XmlNode->new( 'addressbook-group',
'attributes' => { 'id' => $ptrHash->{'object_id'} } );
my $members = $ptrHash->{'object_members'};
while ( $members =~ /"(.*?)"/g ) {
my $member = $1;
chomp $member;
$group->addChild(
XmlNode->new(
'addressbook-member', 'attributes' => { 'id' => $member }
)
);
}
$node->addChild($group);
}
else {
my $user = XmlNode->new('addressbook-contact');
my ( $field, $attr );
while ( ( $field, $attr ) = each %objectFields ) {
if ( defined $ptrHash->{ 'object_' . $attr } ) {
# Here 'encoded' attribute means there is no meaning to
# convert data to UTF as it was already converted manually
my $value = $ptrHash->{ 'object_' . $attr };
$value = $self->{base64}->{'ENCODE'}->($value) if $attr ne 'id';
$user->setAttribute( $field, $value );
}
}
$node->addChild($user);
}
}
$parent->getChild( 'preferences', 1 )->addChild($node);
}
sub setMailSpamSettings {
my ( $self, $mailId, $mailName, $domainAsciiName, $status, $server_conf,
$action, $requiredScore, $modify_subj, $subj_text,
$blackListPtr, $whiteListPtr, $unblackListPtr, $unwhiteListPtr, $path, $server ) = @_;
my @blackList = @{$blackListPtr};
my @whiteList = @{$whiteListPtr};
my @unblackList = @{$unblackListPtr};
my @unwhiteList = @{$unwhiteListPtr};
my $parent;
if (defined($mailId)) {
$parent = $self->{mailNodes}->{$mailId};
}elsif (defined($server)) {
$parent = $self->{serverNode};
}
if ( !defined($parent) ) {
Logging::warning('Unable to dump SPAM filter settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $item = XmlNode->new( 'spamassassin' );
$item->setAttribute( 'status', $status ) if defined($status);
$item->setAttribute( 'action', $action ) if ( defined($action) && $action );
$item->setAttribute( 'server-conf', $server_conf )
if ( defined($server_conf) && $server_conf );
$item->setAttribute( 'hits', $requiredScore )
if ( defined($requiredScore) && $requiredScore );
$item->setAttribute( 'modify-subj', $modify_subj )
if ( defined($modify_subj) && $modify_subj );
$item->setAttribute( 'subj-text', $subj_text )
if ( defined($subj_text) && $subj_text );
$item->setAttribute( 'max-spam-threads', $server->{'spamfilter_max_children'})
if ( defined($server->{'spamfilter_max_children'}) && $server->{'spamfilter_max_children'});
foreach my $blMail (@blackList) {
$item->addChild( XmlNode->new( 'blacklist-member', 'content' => $blMail ) );
}
foreach my $wtMail (@whiteList) {
$item->addChild( XmlNode->new( 'whitelist-member', 'content' => $wtMail ) );
}
foreach my $ublMail (@unblackList) {
$item->addChild(
XmlNode->new( 'unblacklist-member', 'content' => $ublMail ) );
}
foreach my $uwtMail (@unwhiteList) {
$item->addChild(
XmlNode->new( 'unwhitelist-member', 'content' => $uwtMail ) );
}
if (defined($mailId) && -d "$path") {
my $cid = $self->{content_transport}->addMailnameContent( 'spam-assasin', $mailId, "sa", "directory" => $path );
$item->getChild( 'content', 1, 1 )->addChild( $cid ) if $cid;
}
if (defined($mailId)) {
$parent->getChild( 'preferences', 1 )->addChild($item);
}elsif(defined($server)) {
$parent->addChild($item);
}
}
sub setMailVirusSettings {
my ( $self, $mailId, $state ) = @_;
my $parent = $self->{mailNodes}->{$mailId};
if ( !defined($parent) ) {
Logging::warning('Unable to dump virus protection settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $item = XmlNode->new('virusfilter');
$item->setAttribute( 'state', $state );
$parent->getChild( 'preferences', 1 )->addChild($item);
}
sub addMailCustomButton {
my ( $self, $mailId, $id, $optionsPtr, $customButtonsDir, $icon ) = @_;
my $parent = $self->{mailNodes}->{$mailId};
if ( !defined($parent) ) {
Logging::warning('Unable to dump mail custom buttons settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $node = $self->makeCustomButtonNode( 'mails', $mailId, $id, $optionsPtr, $customButtonsDir, $icon );
$parent->getChild( 'preferences', 1 )->addChild($node);
}
####### End Mail functions #######
####### Siteapps functions #######
sub addDomainSapp {
my ( $self, $domainId, $sappId, $sapp, $licenseType ) = @_;
my $parent = $self->getCashedDomainNode($domainId);
return unless defined $parent;
my $phosting = $parent->getChild('phosting');
if ( not $phosting ) {
Logging::warning('Unable to dump domain site applications, because of dump XML structure is not full','assert');
return;
}
my $sapp_installed = $self->makeSappNode($sappId, $sapp, $licenseType);
$self->{sappNodes}->{$sappId} = $sapp_installed;
$phosting->getChild( 'applications', 1 )->addChild($sapp_installed);
}
sub addSubDomainSapp {
my ( $self, $subDomainId, $sappId, $sapp, $licenseType ) = @_;
my $root = $self->{subDomainNodes}->{$subDomainId};
my $sapp_installed = $self->makeSappNode( $sappId, $sapp, $licenseType );
$self->{sappNodes}->{$sappId} = $sapp_installed;
$root->getChild( 'applications', 1 )->addChild($sapp_installed);
}
sub setSappParams {
my ( $self, $sappId, $sapp ) = @_;
my $paramsPtr = $sapp->getParams();
my %params = %{$paramsPtr};
my $sapp_installed = $self->{sappNodes}->{$sappId};
while ( my ( $param_name, $param_value ) = each %params )
{
my $name;
my $value;
if ( $sapp->encodedParams() ) {
$name = $param_name;
$value = $param_value;
}
else {
$name = $self->{base64}->{'ENCODE'}->($param_name);
$value = $self->{base64}->{'ENCODE'}->($param_value);
}
$sapp_installed->addChild(
XmlNode->new(
'sapp-param',
'children' => [
XmlNode->new(
'sapp-param-name',
'attributes' => { 'encoding' => 'base64' },
'content' => $name
),
XmlNode->new(
'sapp-param-value',
'attributes' => { 'encoding' => 'base64' },
'content' => $value
)
]
)
);
}
}
sub setSappSettings {
my ( $self, $sappId, $sapp ) = @_;
my $settingsPtr = $sapp->getSettings();
if (scalar keys %{$settingsPtr} > 0) {
my %settings = %{$settingsPtr};
my $sappInstalledNode = $self->{sappNodes}->{$sappId};
my $sappSettingsNode = XmlNode->new('sapp-settings');
while ( my ( $setting_name, $setting_value ) = each %settings )
{
$sappSettingsNode->addChild(
XmlNode->new(
'setting',
'children' => [
XmlNode->new(
'name',
'content' => $setting_name
),
XmlNode->new(
'value',
'content' => $setting_value
)
]
)
);
}
$sappInstalledNode->addChild($sappSettingsNode);
}
}
sub setSappEntryPoints {
my ( $self, $sappId, $sapp ) = @_;
my $sapp_installed = $self->{sappNodes}->{$sappId};
my @ep = $sapp->getEntryPoints();
foreach my $node (@ep) {
my $epNode = XmlNode->new('sapp-entry-point');
$epNode->addChild(XmlNode->new('label', 'content' => $node->{'label'}));
$epNode->addChild(XmlNode->new('description', 'content' => $node->{'description'}));
$epNode->addChild(XmlNode->new('hidden', 'content' => $node->{'hidden'}));
$epNode->addChild(XmlNode->new('http', 'content' => $node->{'http'}));
$epNode->addChild(XmlNode->new('icon', 'content' => $node->{'icon'})) if defined $node->{'icon'};
my $permissionsNode = XmlNode->new('limits-and-permissions');
$permissionsNode->addChild(
XmlNode->new('permission', 'attributes' => {'name' => $node->{'permission-name'} , 'class' => $node->{'permission-class'}})
);
$epNode->addChild($permissionsNode);
$sapp_installed->addChild($epNode);
}
}
sub setDomainSappBackupArchiveContent {
my ( $self, $domainId, $sappId, $path, $include, $webspaceId ) = @_;
my $sapp_installed = $self->{sappNodes}->{$sappId};
my $cid = $self->{content_transport}->addPhostingContent( 'sapp-apsc', $domainId, $webspaceId,
"sapp-apsc." . $sappId,
"directory" => $path,
"include" => [$include]
);
$sapp_installed->getChild( 'content', 1, 1 )->addChild( $cid ) if $cid;
}
sub setSubDomainSappBackupArchiveContent {
my ( $self, $subdomainId, $sappId, $path, $include, $webspaceId ) = @_;
my $sapp_installed = $self->{sappNodes}->{$sappId};
my $cid = $self->{content_transport}->addSubDomainPhostingContent( 'sapp-apsc', $subdomainId, $webspaceId,
"sapp-apsc." . $sappId,
"directory" => $path,
"include" => [$include]
);
$sapp_installed->getChild( 'content', 1, 1 )->addChild( $cid ) if $cid;
}
sub addDomainSappDatabase {
my ( $self, $dbId, $dbServerId, $domainId, $sappId, $dbName, $dbType, $optionalPtr, $dbServerPtr, $dbUsersPtr, $contentDescriptionPtr, $skipContent ) = @_;
$self->regDatabaseObjectBackupPath( $self->getDomainsBackupPath( $domainId ), $dbId, $dbName, $dbServerId );
my $parent = $self->{sappNodes}->{$sappId};
my $domain = $self->getCashedDomainNode($domainId);
my $node = $self->makeDatabaseNode( $dbId, $dbName, $dbType, 'domain', $domainId, $optionalPtr,
$dbServerPtr, $dbUsersPtr, $contentDescriptionPtr, $skipContent );
my $domainGuid = $domain->getAttribute('guid');
$node->setAttribute( 'guid', $self->getDatabaseGuid( $domainGuid, $dbId ) ) if $domainGuid;
$node->setAttribute( 'owner-guid', $domainGuid ) if $domainGuid;
$node->setAttribute( 'aps-registry-id', $optionalPtr->{'aps-registry-id'}) if $optionalPtr->{'aps-registry-id'};
$parent->addChild($node);
}
sub addSubDomainSappDatabase {
my ( $self, $dbId, $dbServerId, $subdomainId, $sappId, $dbName, $dbType, $optionalPtr, $dbServerPtr, $dbUsersPtr, $contentDescriptionPtr, $skipContent ) = @_;
$self->regDatabaseObjectBackupPath( $self->getSubdomainsBackupPath( $subdomainId ), $dbId, $dbName, $dbServerId );
my $subdomain = $self->{subDomainNodes}->{$subdomainId};
my $parent = $self->{sappNodes}->{$sappId};
my $node = $self->makeDatabaseNode( $dbId, $dbName, $dbType, 'subdomain', $subdomainId, $optionalPtr,
$dbServerPtr, $dbUsersPtr, $contentDescriptionPtr, $skipContent );
my $subDomainGuid = $subdomain->getAttribute('guid');
$node->setAttribute( 'guid', $self->getDatabaseGuid( $subDomainGuid, $dbId ) ) if $subDomainGuid;
$node->setAttribute( 'owner-guid', $subDomainGuid ) if $subDomainGuid;
$node->setAttribute( 'aps-registry-id', $optionalPtr->{'aps-registry-id'}) if $optionalPtr->{'aps-registry-id'};
$parent->addChild($node);
}
sub addDomainSappCustomButton {
my $self = shift;
$self->addSappCustomButton( 'domains', @_ );
}
sub addSubDomainSappCustomButton {
my $self = shift;
$self->addSappCustomButton( 'subdom', @_ );
}
sub addSappCustomButton {
my ( $self, $parentType, $parentid, $sappId, $id, $optionsPtr, $customButtonsDir, $icon ) = @_;
my $parent = $self->{sappNodes}->{$sappId};
if ( !defined($parent) ) {
Logging::warning('Unable to dump site applications custom buttons settings, because of dump XML structure is not full', 'PackerStructure');
return;
}
my $node = $self->makeCustomButtonNode( $parentType, $parentid, $id, $optionsPtr, $customButtonsDir, $icon );
$parent->addChild($node);
}
sub setSappApscNode {
my ( $self, $sappId, $content) = @_;
my $parent = $self->{sappNodes}->{$sappId};
my $sappApscNode = XmlNode->new('sapp-apsc', 'content' => $self->{base64}->{'ENCODE'}->($content));
$parent->addChild($sappApscNode);
}
####### End Siteapps functions #######
sub insertLimitNode {
my ( $self, $node, $name, $value ) = @_;
my $limits = $node->getChild( 'limits-and-permissions', 1 );
$limits->addChild( XmlNode->new( "limit",
"attributes" => { "name" => $name },
"content" => $value ) );
}
sub makePermissionNode {
my ($self, $parent, $name, $allowed) = @_;
#[Bug 111477] Value "-1" for attribute allowed of permission is not among the enumerated set
if ($allowed =~ /-1/) {
$allowed = 'false';
}
$parent->addChild( XmlNode->new('permission', 'attributes' => { 'name' => $name, 'value' => $allowed}) );
}
###### Backup content structure ######
sub getPhostingGuid{
my ( $self, $ownerguid, $id ) = @_;
return "$ownerguid\_ph_$id";
}
sub getDatabaseGuid{
my ( $self, $ownerguid, $id ) = @_;
return "$ownerguid\_db_$id";
}
sub getSubdomainGuid{
my ( $self, $ownerguid, $id ) = @_;
return "$ownerguid\_sb_$id";
}
sub getMailnameGuid{
my ( $self, $ownerguid, $id ) = @_;
return "$ownerguid\_mn_$id";
}
sub regObjectBackupPath{
my( $self, $basePath, $group, $key, $objectId, $parentId ) = @_;
$basePath .= '/' if $basePath;
my $path = "$basePath$group";
$path = $basePath if $group eq 'admin';
$self->{backupPath}->{"$group\_$key"} = $path;
$self->{objectId}->{"$group\_$key"} = $objectId;
$self->{parentId}->{"$group\_$key"} = $parentId;
return $self->getBackupPath( $group, $key, undef, 0 );
}
sub regAdminObjectBackupPath{
my( $self, $basePath ) = @_;
return $self->regObjectBackupPath( $basePath, 'admin', 'admin', '' );
}
sub regResellersObjectBackupPath{
my( $self, $basePath, $key, $resellerLogin ) = @_;
return $self->regObjectBackupPath( $basePath, 'resellers', $key, $self->{fnamecreator}->normalize_short_string( $resellerLogin, $key ) );
}
sub regClientObjectBackupPath{
my( $self, $basePath, $key, $clientLogin ) = @_;
return $self->regObjectBackupPath( $basePath, 'clients', $key, $self->{fnamecreator}->normalize_short_string( $clientLogin, $key ) );
}
sub regDomainObjectBackupPath{
my( $self, $basePath, $key, $domainAscName ) = @_;
return $self->regObjectBackupPath( $basePath, 'domains', $key, $self->{fnamecreator}->normalize_long_string( $domainAscName, $key ) );
}
sub regSiteObjectBackupPath{
my( $self, $basePath, $key, $siteName ) = @_;
return $self->regObjectBackupPath( $basePath, 'sites', $key, $self->{fnamecreator}->normalize_long_string( $siteName, $key ) );
}
sub regMailnameObjectBackupPath{
my( $self, $basePath, $key, $mailName, $domainId ) = @_;
return $self->regObjectBackupPath( $basePath, 'mailnames', $key, $self->{fnamecreator}->normalize_short_string( $mailName, $key ), $domainId );
}
sub regDatabaseObjectBackupPath{
my( $self, $basePath, $key, $databaseName, $dbServerId ) = @_;
return $self->regObjectBackupPath( $basePath, 'databases', $key, $self->{fnamecreator}->normalize_short_string( "$databaseName\_$dbServerId", $key ) );
}
sub regSubdomainObjectBackupPath{
my( $self, $basePath, $key, $subdomainName, $domainId ) = @_;
return $self->regObjectBackupPath( $basePath, 'subdomains', $key, $self->{fnamecreator}->normalize_short_string( $subdomainName, $key ), $domainId );
}
sub regPhostingObjectBackupPath{
my( $self, $basePath, $key ) = @_;
return $self->regObjectBackupPath( $basePath, 'phosting', $key, '' );
}
sub getObjectId{
my( $self, $group, $key ) = @_;
$key = "$group\_$key";
return 'phosting' if $group eq 'phosting';
return 'admin' if $group eq 'admin';
return $self->{objectId}->{$key};
}
sub getParentId{
my( $self, $group, $key ) = @_;
$key = "$group\_$key";
return $self->{parentId}->{$key} if exists $self->{parentId} && exists $self->{parentId}->{$key};
return;
}
sub getPhostingParentId{
my( $self, $key ) = @_;
return $key;
}
sub getSubdomainParentId{
my( $self, $key ) = @_;
return $self->getParentId( "subdomains", $key );
}
sub getMailNameParentId{
my( $self, $key ) = @_;
return $self->getParentId( "mailnames", $key );
}
sub getBackupPath{
my( $self, $group, $key, $fileName, $onlyFileName ) = @_;
$key = "$group\_$key";
my $res = '';
if( not $onlyFileName ) {
$res .= $self->{backupPath}->{$key};
$res .= '/' . $self->{objectId}->{$key} if $group ne 'phosting' and $group ne 'admin';
}
$res = $self->{fnamecreator}->getFileName( $res, $self->{backupname}, $self->{objectId}->{$key}, $fileName ) if defined $fileName;
return $res;
}
sub getAdminBackupPath{
my( $self, $fileName, $onlyFileName ) = @_;
return $self->getBackupPath( 'admin', 'admin', $fileName, $onlyFileName );
}
sub getResellersBackupPath{
my( $self, $key, $fileName, $onlyFileName ) = @_;
return $self->getBackupPath( 'resellers', $key, $fileName, $onlyFileName );
}
sub getClientsBackupPath{
my $self = shift;
my $key = shift;
return $self->getBackupPath( 'clients', $key, @_ ) if exists $self->{objectId}->{"clients_$key"};
return $self->getResellersBackupPath( $key, @_ );
}
sub getDomainsBackupPath{
my( $self, $key, $fileName, $onlyFileName ) = @_;
if ( defined $self->{domainNodes}->{$key} ) {
return $self->getBackupPath( 'domains', $key, $fileName, $onlyFileName );
}
return $self->getBackupPath( 'sites', $key, $fileName, $onlyFileName );
}
sub getSitesBackupPath{
my $self = shift;
return $self->getBackupPath( 'sites', @_ );
}
sub getPhostingBackupPath{
my $self = shift;
return $self->getBackupPath( 'phosting', @_ );
}
sub getDatabasesBackupPath{
my $self = shift;
return $self->getBackupPath( 'databases', @_ );
}
sub getMailnamesBackupPath{
my $self = shift;
return $self->getBackupPath( 'mailnames', @_ );
}
sub getSubdomainsBackupPath{
my $self = shift;
return $self->getBackupPath( 'subdomains', @_ );
}
sub getAdminObjectId{
my( $self ) = @_;
return $self->getObjectId( 'admin', 'admin' );
}
sub getResellerObjectId{
my( $self, $key ) = @_;
return $self->getObjectId( 'resellers', $key );
}
sub getClientObjectId{
my( $self, $key ) = @_;
return $self->getResellerObjectId( $key ) if exists $self->{objectId}->{"resellers_$key"};
return $self->getObjectId( 'clients', $key );
}
sub getDomainObjectId{
my( $self, $key ) = @_;
return $self->getObjectId( 'domains', $key );
}
sub getPhostingObjectId{
my( $self, $key ) = @_;
return $self->getObjectId( 'phosting', $key );
}
sub getDatabaseObjectId{
my( $self, $key ) = @_;
return $self->getObjectId( 'databases', $key );
}
sub getMailnameObjectId{
my( $self, $key ) = @_;
return $self->getObjectId( 'mailnames', $key );
}
sub getSubdomainObjectId{
my( $self, $key ) = @_;
return $self->getObjectId( 'subdomains', $key );
}
###### End Backup content structure ######
sub addTemplateItem {
my ( $self, $node, $name, $value ) = @_;
$node->addChild( XmlNode->new( "template-item",
"attributes" => { "name" => $name },
"content" => $value ) );
}
sub makeTemplatePlanItem {
my ( $self, $name, $value ) = @_;
my $templatePlanItemNode = XmlNode->new( "template-plan-item",
"attributes" => { "name" => $name },
"content" => $value );
return $templatePlanItemNode;
}
sub addTemplatePlanItem {
my ( $self, $node, $name, $value ) = @_;
my $templatePlanItemNode = $self->makeTemplatePlanItem( $name, $value );
$node->addChild( $templatePlanItemNode ) if defined $templatePlanItemNode;
}
sub makeLogrotationNode {
my ( $self, $parent, $logRotationPtr ) = @_;
my %logRotation = %{$logRotationPtr};
my $item = XmlNode->new( 'logrotation', 'attributes' => {
'max-number-of-logfiles' => $logRotation{'max_number_of_logfiles'},
'compress' => $logRotation{'compress_enable'}
} );
$item->setAttribute( 'email', $logRotation{'email'} ) unless $logRotation{'email'} eq '';
$item->setAttribute( 'enabled', $logRotation{'turned_on'} );
my $rottype;
if ( $logRotation{'period_type'} eq 'by_time' ) {
$rottype = XmlNode->new( 'logrotation-period',
'attributes' => { 'period' => $logRotation{'period'} } );
}
else {
$rottype = XmlNode->new( 'logrotation-maxsize',
'content' => $logRotation{'period'} );
}
$item->addChild($rottype);
$parent->addChild($item);
}
sub makeDatabaseNode {
my ( $self, $dbId, $dbName, $dbType, $parent, $parentId, $optionalPtr, $dbServerPtr, $dbUsersPtr, $contentDescriptionPtr, $skipContent ) = @_;
my %optional = %{$optionalPtr};
my %dbServer = %{$dbServerPtr};
my @dbUsers = @{$dbUsersPtr};
my %contentDescription = %{$contentDescriptionPtr};
my $root = XmlNode->new( 'database', 'attributes' => {
'name' => $dbName,
'type' => $dbType,
'id' => $dbId
} );
$root->setAttribute( 'version', $optional{'version'} )
if $optional{'version'};
$root->setAttribute( 'charset', $optional{'charset'} )
if $optional{'charset'};
$root->setAttribute( 'version', $optional{'version'} )
if $optional{'version'};
$root->setAttribute( 'db-existent', $optional{'db-existent'} )
if $optional{'db-existent'};
$root->setAttribute( 'prefix', $optional{'prefix'} )
if $optional{'prefix'};
$root->setAttribute( 'collation', $optional{'collation'} )
if $optional{'collation'};
$root->setAttribute( 'external-id', $optional{'external_id'} )
if defined $optional{'external_id'} and $optional{'external_id'} ne '';
$root->setAttribute( 'custom-host', $optional{'custom-host'} )
if (defined($optional{'custom-host'}));
if (%dbServer) {
my $dbServerNode = XmlNode->new('db-server');
$dbServerNode->setAttribute( 'type', $dbServer{'type'} );
$dbServerNode->addChild( XmlNode->new( 'host', 'content' => $dbServer{'host'} ) );
$dbServerNode->addChild( XmlNode->new( 'port', 'content' => $dbServer{'port'} ) );
$root->addChild($dbServerNode);
}
$self->makeDatabaseUsersNodes($root, \@dbUsers, $dbId);
if (defined($optional{'related-sites'})) {
$self->makeRelatedSitesNode($root, $optional{'related-sites'});
}
if (%contentDescription and !$skipContent) {
if (exists $self->{databaseCids}{$dbId}) {
$root->getChild('content', 1, 1)->addChild($self->{databaseCids}{$dbId});
} else {
my $cid;
if ($parent eq 'subdomain') {
$cid = $self->{content_transport}->addSubdomainDbContent('sqldump', $parentId, $dbId, %contentDescription);
}
else {
$cid = $self->{content_transport}->addDbContent('sqldump', $dbId, %contentDescription);
}
if ($cid) {
$root->getChild('content', 1, 1)->addChild($cid);
$self->{stat}{dbSizeDumped} += $self->_getContentSizeFromCidNode($cid);
$self->{databaseCids}->{$dbId} = $cid;
}
}
}
return $root;
}
sub makeDbUsersToAnyDatabasesNode {
my ( $self, $domainId, $dbUsersPtr ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $rootNode = $root->getChild( 'databases', 1 );
my $globalDbUsersNode = XmlNode->new('dbusers');
$self->makeDatabaseUsersNodes($globalDbUsersNode, $dbUsersPtr);
$rootNode->addChild($globalDbUsersNode);
}
sub makeDatabaseUsersNodes {
my ( $self, $parentNode, $dbUsersPtr, $dbId ) = @_;
$dbId ||= 0;
my @dbUsers = @{$dbUsersPtr};
my $item;
foreach my $user (@dbUsers) {
my $dbUserRoot = XmlNode->new( 'dbuser',
'attributes' => { 'name' => $user->{'login'}, 'id' => $user->{'id'} } );
$dbUserRoot->setAttribute( 'default', ( defined( $user->{'default'} ) ) ? 'true' : 'false' );
$dbUserRoot->setAttribute('aps-registry-id', $user->{'aps-registry-id'}) if $user->{'aps-registry-id'};
$dbUserRoot->setAttribute('db-user-existent', $user->{'db-user-existent'}) if $user->{'db-user-existent'};
$dbUserRoot->setAttribute('external-id', $user->{'external_id'}) if defined $user->{'external_id'} and $user->{'external_id'} ne '';
$item = CommonPacker::makePasswordNode( $user->{'password'}, CommonPacker::normalizePasswordType( $user->{'type'} ) );
$dbUserRoot->addChild($item);
if ($user->{'host'}) {
my %dbServer;
$dbServer{'host'} = $user->{'host'};
$dbServer{'port'} = $user->{'port'};
$dbServer{'type'} = $user->{'dbservertype'};
my $dbServerNode = $self->makeDbServerNodeWithoutCredentials(\%dbServer);
$dbUserRoot->addChild($dbServerNode);
}
my $databaseUserRemoteAccessRulesNode = $self->makeDatabaseUserRemoteAccessRulesNode($user, $dbId);
if ($databaseUserRemoteAccessRulesNode) {
$dbUserRoot->addChild($databaseUserRemoteAccessRulesNode);
}
if ( exists $user->{'acl'} ) {
my $aclNode = XmlNode->new( 'acl' );
foreach my $acl ( @{$user->{'acl'}} ) {
$aclNode->addChild( XmlNode->new( 'allowed-host', 'content' => $acl ) );
}
$dbUserRoot->addChild( $aclNode );
}
if (exists($user->{'privileges'})) {
my $privilegesNode = XmlNode->new('privileges');
foreach my $privilege (@{$user->{'privileges'}}) {
$privilegesNode->addChild(XmlNode->new('privilege', 'attributes' => $privilege));
}
$dbUserRoot->addChild($privilegesNode);
}
$parentNode->addChild($dbUserRoot);
}
}
sub makeRelatedSitesNode {
my ($self, $parentNode, $relatedSites) = @_;
my $relatedSitesNode = XmlNode->new('related-sites');
foreach my $relatedSiteName (@{$relatedSites}) {
my $relatedSiteNode = XmlNode->new('related-site');
$relatedSiteNode->setAttribute('name', $relatedSiteName);
$relatedSitesNode->addChild($relatedSiteNode);
}
$parentNode->addChild($relatedSitesNode);
}
sub makeAutoresponderNode {
my ( $self, $enabled, $autoPtr, $mailName ) = @_;
my %auto = %{$autoPtr};
my $root = XmlNode->new('autoresponder');
my $value = $self->{base64}->{'ENCODE'}->( $auto{'text'} );
my $item = XmlNode->new( 'text', 'content' => $value );
if ( exists $auto{'charset'} && $auto{'charset'} ne '' ) {
$item->setAttribute( 'charset', $auto{'charset'} );
}
$root->addChild($item);
if ( exists $auto{'content_type'} && $auto{'content_type'} ) {
$root->setAttribute( 'content-type', $auto{'content_type'} );
}
$root->setAttribute( 'status', ($enabled eq 'true' && $auto{'resp_on'} eq 'true') ? 'on' : 'off' );
if ( $auto{'subject'} ) {
$value = $self->{base64}->{'ENCODE'}->( $auto{'subject'} );
chomp $value;
$root->setAttribute( 'subject', $value );
}
#
# forward
#
if ( $auto{'redirect'} ) {
$root->setAttribute( 'redirect', $auto{'redirect'} );
}
#
# end forward
#
if (exists($auto{'ans_freq'})) {
$root->addChild( XmlNode->new( 'autoresponder-limit',
'content' => $auto{'ans_freq'},
'attributes' => { 'name' => 'ans-freq' } ) );
}
if (exists($auto{'endDate'})) {
$root->addChild( XmlNode->new( 'autoresponder-limit',
'content' => $auto{'endDate'},
'attributes' => { 'name' => 'end-date' } ) );
}
my @attach = @{$auto{'attach'}};
if ( @attach ) {
foreach my $file (@attach) {
$root->addChild( XmlNode->new( 'attach', 'attributes' => { 'file' => $file } ) );
}
}
return $root;
}
sub parseCustomButtonOptions {
my ( $node, $options ) = @_;
#CUSTOM_BUTTON_PUBLIC
$node->setAttribute( 'visible-to-sublogins', $options & 128 ? 'true' : 'false' );
#CUSTOM_BUTTON_INTERNAL
$node->setAttribute( 'open-in-same-frame', $options & 256 ? 'true' : 'false' );
$node->setAttribute( 'no-frame', $options & 64 ? 'true' : 'false' );
my %options = (
"domain-id" => 1, #CUSTOM_BUTTON_DOM_ID
"domain-name" => 32, #CUSTOM_BUTTON_DOM_NAME
"ftp-login" => 512, #CUSTOM_BUTTON_FTP_USER
"ftp-password" => 1024, #CUSTOM_BUTTON_FTP_PASS
"client-id" => 2, #CUSTOM_BUTTON_CL_ID
"client-company-name" => 4, #CUSTOM_BUTTON_CNAME
"client-contact-name" => 8, #CUSTOM_BUTTON_PNAME
"client-email" => 16, #CUSTOM_BUTTON_EMAIL
);
while ( my ( $optname, $optmask ) = each %options ) {
if ( $options & $optmask ) {
$node->addChild(
XmlNode->new( "url-option", "attributes" => { "name" => $optname } )
);
}
}
}
sub addAdminContentProxy{
my $self = shift;
$self->{content_transport}->addAdminContent(@_);
}
sub addClientContentProxy{
my $self = shift;
$self->{content_transport}->addClientContent(@_);
}
sub addDomainContentProxy{
my $self = shift;
$self->{content_transport}->addDomainContent(@_);
}
sub addMailnameContentProxy{
my $self = shift;
$self->{content_transport}->addMailnameContent(@_);
}
sub addCustomButtonNode {
my ( $self, $optionsPtr) = @_;
my %options = %{$optionsPtr};
my $node = XmlNode->new('custom-button');
my %attributes = (
'url' => 'url',
'text' => 'text',
'sort_key' => 'sort-priority',
'place' => 'interface-place',
'conhelp' => 'conhelp' );
foreach my $key (keys %attributes) {
$node->setAttribute( $attributes{$key}, $options{$key} ) if defined $options{$key};
}
return $node;
}
sub makeCustomButtonNode65 {
my ( $self, $optionsPtr ) = @_;
my $node = $self->addCustomButtonNode($optionsPtr);
## 128 == CUSTOM_BUTTON_PUBLIC
parseCustomButtonOptions( $node, $optionsPtr->{'options'} | 128 );
return $node;
}
sub makeCustomButtonNode {
my ( $self, $parentType, $parentId, $id, $optionsPtr, $customButtonsDir, $icon ) = @_;
my $node = $self->addCustomButtonNode($optionsPtr);
my %options = %{$optionsPtr};
if ( -e $customButtonsDir . "/" . $icon ) {
if ($icon) {
my $proc;
if( $parentType eq 'admin' ) { $proc = \&addAdminContentProxy; }
elsif( $parentType eq 'clients' ) { $proc = \&addClientContentProxy; }
elsif( $parentType eq 'domains' ) { $proc = \&addDomainContentProxy; }
elsif( $parentType eq 'mails' ) { $proc = \&addMailnameContentProxy; }
else{
Logging::warning( "Error: makeCustomButtonNode: unsupported parent type '$parentType' ",'assert');
}
if( $proc ) {
my $cid_icon =
( AgentConfig::tarVersionMoreThan15() )
? $self->$proc(
'icon',
$parentId,
$icon . "." . $id,
"directory" => $customButtonsDir,
"add_file" => $icon
)
: $self->$proc(
'icon',
$parentId,
$icon . "." . $id,
"directory" => $customButtonsDir,
"include" => [$icon]
);
$node->getChild( 'content', 1, 1 )->addChild( $cid_icon ) if $cid_icon;
}
}
}
parseCustomButtonOptions( $node, $options{'options'} );
# exists $options{'plan_item_name'} <=> (PleskVersion::atLeast( 10, 1, 0))
if ( defined $options{'plan_item_name'} && ( '' ne $options{'plan_item_name'} ) ) {
my $templatePlanItemNode = $self->makeTemplatePlanItem( $options{'plan_item_name'}, '' );
$node->addChild( $templatePlanItemNode );
}
return $node;
}
sub makeDnsZoneParam {
my ( $self, $name, $db_unit, $db_value ) = @_;
my $dnsZoneParam =
XmlNode->new( 'dns-zone-param',
'attributes' => { 'name' => $name, 'value' => $db_value } );
my %units = (
'second' => 1,
'minutes' => 60,
'hours' => 3600,
'days' => 86400,
'weeks' => 604800
);
my $string_unit;
foreach my $quant ( keys %units ) {
if ( $units{$quant} == $db_unit ) {
$string_unit = $quant;
last;
}
}
$dnsZoneParam->setAttribute( 'unit', $string_unit );
return $dnsZoneParam;
}
sub makeDnsZone {
my ( $self, $parent, $paramsPtr, $recordsPtr, $syncWithParent ) = @_;
my %params = %{$paramsPtr};
my @records = @{$recordsPtr};
my $email;
if ( defined($params{'email'}) and (length( $params{'email'} ) != 0) ) {
$email = $params{'email'};
}
else {
# should assume some default email or something...
$email = 'root@localhost.localdomain';
}
my $dnsZone = XmlNode->new( 'dns-zone',
'attributes' => {
'email' => $email,
'type' => $params{'type'},
'rnameType' => $params{'rnameType'},
'serial-format' => $params{'serial_format'}
},
'children' => [ Status::make( $params{'status'} ) ] );
if ( defined $syncWithParent ) {
$dnsZone->setAttribute( 'sync-with-parent', $syncWithParent );
}
$dnsZone->setAttribute('external-id', $params{'external_id'}) if defined $params{'external_id'} and $params{'external_id'} ne '';
foreach my $zoneParam ( 'ttl', 'refresh', 'retry', 'expire', 'minimum' ) {
$dnsZone->addChild(
$self->makeDnsZoneParam(
$zoneParam, $params{ $zoneParam . '_unit' },
$params{$zoneParam}
)
);
}
# dns records
for my $hash (@records) {
my $dnsrec = $self->makeDnsRecord( $hash );
if ($dnsrec) {
$dnsZone->addChild($dnsrec);
}
}
$parent->addChild($dnsZone);
}
sub makeDnsRecord {
my ( $self, $hashPtr ) = @_;
unless (ref($hashPtr) =~ /HASH/)
{
Logging::warning('Error: makeDnsRecord: hashPtr is not hash ptr', 'assert');
return;
}
my %hash = %{$hashPtr};
return unless $hash{'type'} =~ /^A|AAAA|NS|MX|CNAME|PTR|TXT|master|SRV|AXFR|DS|CAA$/;
my $host =
defined $hash{'displayHost'}
? $hash{'displayHost'}
: $hash{'host'};
my $val =
defined $hash{'displayVal'}
? $hash{'displayVal'}
: $hash{'val'};
if ( $hash{'type'} eq 'SRV' ) {
$host =~ s/\.$//;
$val =~ s/\.$//;
}
my ($item) =
XmlNode->new( 'dnsrec',
'attributes' => { 'type' => $hash{'type'}, 'src' => $host } );
$item->setAttribute( 'dst', $val ) if ($val);
$item->setAttribute( 'opt', $hash{'opt'} ) if ( defined $hash{'opt'} );
$item->setAttribute( 'status', $hash{'status'} ) if (defined $hash{'status'});
$item->setAttribute('external-id', $hash{'external_id'}) if defined $hash{'external_id'} and $hash{'external_id'} ne '';
return $item;
}
#
# Creates node representing pre-8.0 DNS master record
#
sub makeOldMasterRec {
my ($ipAddress) = @_;
return XmlNode->new(
"dnsrec",
"attributes" => {
"src" => $ipAddress,
"type" => "master"
}
);
}
sub addUrlDecodedTextNode {
my ( $parent, $name, $value ) = @_;
$parent->addChild( XmlNode->new( $name, "content" => HelpFuncs::urlDecode($value) ) )
if $value;
}
sub makeSysUser {
my ( $self, $sysuserPtr ) = @_;
my %sysuser = %{$sysuserPtr};
#
# attributes
#
my $root =
XmlNode->new( 'sysuser',
'attributes' => { 'name' => lc( $sysuser{'login'} ) } );
$root->setAttribute( 'shell', $sysuser{'shell'} ) if $sysuser{'shell'} and $sysuser{'shell'} ne '/bin/false';
my $quota;
if ( $sysuser{'quota'} ) {
$quota = $sysuser{'quota'};
$root->setAttribute( 'quota', $quota ) if $quota;
}
if ( $sysuser{'home'} ) {
my $home = $sysuser{'home'};
if (exists $sysuser{'relative_path'}) {
if (substr($home,0, length($sysuser{'relative_path'})) eq $sysuser{'relative_path'} ) {
$home = substr($home, length($sysuser{'relative_path'}));
}
}
$root->setAttribute( 'home', $home) if $home;
}
#
# end attributes
#
$root->addChild( CommonPacker::makePasswordNode( $sysuser{'passwd'}, $sysuser{'passwdType'} ) );
if (defined($sysuser{'scheduled-tasks'})) {
$self->addEmbeddedInfo($root, 'scheduled-tasks', $sysuser{'scheduled-tasks'});
} elsif ( $sysuser{'cron'} ) {
my $cronNode = XmlNode->new( 'cron', 'content' => $sysuser{'cron'} );
if ( $sysuser{'cron-encoding'} ) {
$cronNode->setAttribute( 'encoding', $sysuser{'cron-encoding'} );
}
$root->addChild( $cronNode );
}
return $root;
}
sub makeSappNode {
my ( $self, $sappId, $sapp, $licenseType ) = @_;
my $name = $sapp->getName();
my $version = $sapp->getVersion();
my $release = $sapp->getRelease();
my $description = $sapp->getDescription();
my $isCommercial = $sapp->isCommercial();
my $isIntegrated = $sapp->isIntegrated();
my $prefix = $sapp->getInstallPrefix();
my $isSsl = $sapp->isSsl();
my $packageId = $sapp->getSappPackageId();
my $sapp_installed = XmlNode->new('sapp-installed');
#-----------------------------------------------------------------
# sapp-spec
#-----------------------------------------------------------------
my $sapp_spec = XmlNode->new('sapp-spec');
if ( $packageId ) {
$sapp_spec->addChild(
XmlNode->new( 'sapp-package-id', 'content' => $packageId ) );
}
$sapp_spec->addChild( XmlNode->new( 'sapp-name', 'content' => $name ) );
if ( $version ) {
$sapp_spec->addChild(
XmlNode->new( 'sapp-version', 'content' => $version ) );
}
if ( $release ) {
$sapp_spec->addChild(
XmlNode->new( 'sapp-release', 'content' => $release ) );
}
if ( $description ) {
my $desc = $self->{base64}->{'ENCODE'}->( $description );
$sapp_spec->addChild(
XmlNode->new(
'sapp-description',
'attributes' => { 'encoding' => 'base64' },
'content' => $desc
)
);
}
if ( $isCommercial ) {
$sapp_spec->addChild( XmlNode->new('sapp-commercial') );
}
if ( $isIntegrated ) {
$sapp_spec->addChild( XmlNode->new('sapp-integrated') );
}
$sapp_installed->addChild($sapp_spec);
if ( defined($licenseType) ) {
$sapp_installed->addChild(
XmlNode->new(
'sapp-installed-license-type',
'content' => $licenseType
)
);
}
return $sapp_installed;
}
sub makeSiteAppInstalled{
my ( $self, $sappId, $prefix, $isSsl, $apsRegistryId ) = @_;
my $sapp_installed = $self->{sappNodes}->{$sappId};
# sapp-installdir
my $sapp_installdir =
XmlNode->new( 'sapp-installdir',
'children' => [ XmlNode->new( 'sapp-prefix', 'content' => $prefix ) ] );
if ( $isSsl ) {
$sapp_installdir->addChild( XmlNode->new('sapp-ssl') );
}
if ($apsRegistryId) {
$sapp_installdir->addChild( XmlNode->new( 'aps-registry-id', 'content' => $apsRegistryId ));
}
$sapp_installed->addChild($sapp_installdir);
}
sub setSappApsControllerInfo {
my ( $self, $sappId, $sapp ) = @_;
my $sapp_installed = $self->{sappNodes}->{$sappId};
if ( $sapp->getContext() ) {
$sapp_installed->addChild( XmlNode->new( 'context', 'attributes' => { "type" => $sapp->getContext() } ) );
}
if ( $sapp->getApplicationApsRegistryId() ) {
$sapp_installed->addChild( XmlNode->new( 'aps-registry-id', 'content' => $sapp->getApplicationApsRegistryId() ) );
}
}
sub setSappApsLicense {
my ( $self, $sappId, $sapp ) = @_;
my $sapp_installed = $self->{sappNodes}->{$sappId};
if ( $sapp->isContainLicense() ) {
my $licenseNode = XmlNode->new('sapp-license');
$licenseNode->addChild( XmlNode->new('aps-registry-id', 'content' => $sapp->getLicenseApsRegistryId())) if $sapp->getLicenseApsRegistryId();
$licenseNode->addChild( XmlNode->new('license-type', 'content' => $sapp->getLicenseType()));
$licenseNode->addChild( XmlNode->new('activation-code', 'content' => $sapp->getActivationCode()));
$licenseNode->addChild( XmlNode->new('use-stub', 'content' => $sapp->getUseStub()));
$sapp_installed->addChild($licenseNode);
}
}
sub makeAnonftpPermissionNode {
my ( $parent, $name ) = @_;
$parent->addChild(
XmlNode->new( 'anonftp-permission', "attributes" => { "name" => $name } ) );
}
sub makeAnonftpLimitNode {
my ( $parent, $name, $value ) = @_;
if ( $value != 0 ) {
$parent->addChild(
XmlNode->new(
"anonftp-limit",
"attributes" => { "name" => $name },
"content" => $value
)
);
}
}
sub makeSystemIpNode {
my ( $self, $parent, $ptrIp ) = @_;
my $correctMask = HelpFuncs::blockToNum( $ptrIp->{'mask'} );
my $md5 = PerlMD5->new();
$md5->add(HelpFuncs::urlDecode($ptrIp->{'pvtkey'}));
$parent->getChild( 'properties', 1 )->addChild(
XmlNode->new(
'system-ip',
'attributes' => { 'certificate' => $md5->hexdigest() },
'children' => [
XmlNode->new(
'ip',
'children' => [
XmlNode->new( 'ip-type', 'content' => "$ptrIp->{'type'}" ),
XmlNode->new(
'ip-address', 'content' => $ptrIp->{'ip_address'}
)
]
),
XmlNode->new( 'ip-netmask', 'content' => "$correctMask" ),
XmlNode->new( 'ip-interface', 'content' => "$ptrIp->{'iface'}" )
]
)
);
}
sub makeTemplateNode {
my ( $self, $nodeName, $templateName, $data ) = @_;
my ( $templateAttrs, $templatePtr, $planItemsPtr, $apsBundleFilterItemsPtr, $filterType, $phpSettingsPtr, $defaultDbServersPtr );
$templateAttrs = $data->{'attributes'};
$templatePtr = $data->{'data'};
$planItemsPtr = $data->{'items'};
$apsBundleFilterItemsPtr = $data->{'aps-filter-items'};
$filterType = $data->{'aps-filter-type'};
$phpSettingsPtr = $data->{'php-settings'};
$defaultDbServersPtr = $data->{'default-db-servers'};
my %logRotation = %{$data->{'log-rotation'}};
my %ipPool = %{$data->{'ip-pool'}};
my $node =
XmlNode->new( $nodeName,
'attributes' => { 'name' => $templateName } );
for my $ptrRowAttrs ( @{$templateAttrs} ) {
my ($attrName, $attrValue ) = @{$ptrRowAttrs};
$node->setAttribute( $attrName, $attrValue );
}
for my $ptrRow ( @{$templatePtr} ) {
my ( $element, $value ) = @{$ptrRow};
$self->addTemplateItem( $node, $element, $value );
}
while ( my ($itemName, $itemValue) = each ( %{$planItemsPtr} ) ) {
$self->addTemplatePlanItem( $node, $itemName, $itemValue );
}
if (keys %logRotation){
$self->makeLogrotationNode( $node, \%logRotation );
}
if (%ipPool and scalar(keys %ipPool) > 0){
my $ipPoolNode = XmlNode->new( 'ip_pool' );
for my $ip ( keys %ipPool ) {
$ipPoolNode->addChild(
$self->makeIpNode($ip, $ipPool{$ip} )
);
}
$node->addChild($ipPoolNode);
}
if (@{$apsBundleFilterItemsPtr}) {
$self->makeApsBundleFilterNode(undef, undef, $filterType, $apsBundleFilterItemsPtr, $node);
}
if (defined $phpSettingsPtr and $nodeName ne 'reseller-template') {
$node->addChild($self->makePhpSettingsNode($phpSettingsPtr));
}
if (defined $defaultDbServersPtr and $nodeName eq 'domain-template') {
$node->addChild($self->makeDefaultDbServersNode($defaultDbServersPtr));
}
return $node;
}
sub makeDomainDefaultDbServersNode {
my ($self, $domainId, $defaultDbServersPtr) = @_;
my $parent = $self->getCashedDomainNode($domainId);
$parent->getChild( 'preferences', 1 )->addChild($self->makeDefaultDbServersNode($defaultDbServersPtr));
}
sub makeDefaultDbServersNode {
my ($self, $defaultDbServersPtr) = @_;
my $defaulDbServersNode = XmlNode->new('default-db-servers');
foreach my $dbServer (@{$defaultDbServersPtr}) {
$defaulDbServersNode->addChild($self->makeDbServerNodeWithoutCredentials($dbServer));
}
return $defaulDbServersNode;
}
sub setDomainPhpSettingsNode {
my ($self, $domainId, $phpSettingsPtr) = @_;
my $parent = $self->getCashedDomainNode($domainId);
return unless defined $parent;
if (defined $phpSettingsPtr) {
$parent->addChild($self->makePhpSettingsNode($phpSettingsPtr));
}
}
sub makePhpSettingsNode {
my ($self, $phpSettingsPtr) = @_;
return unless (defined $phpSettingsPtr and (scalar keys %{$phpSettingsPtr} != 0));
my $node = XmlNode->new('php-settings');
if (exists $phpSettingsPtr->{'notice'}) {
$node->addChild(XmlNode->new('notice-text', 'content' => $phpSettingsPtr->{'notice'}));
delete $phpSettingsPtr->{'notice'};
}
foreach my $key (keys %{$phpSettingsPtr}) {
my $settingNode = XmlNode->new('setting');
$settingNode->addChild(XmlNode->new('name', 'content' => $key));
$settingNode->addChild(XmlNode->new('value', 'content' => $phpSettingsPtr->{$key}));
$node->addChild($settingNode);
}
return $node;
}
sub makeIpNode {
my ($self, $ip, $iptype) = @_;
return XmlNode->new(
'ip',
'children' => [
XmlNode->new( 'ip-type', content => $iptype ),
XmlNode->new( 'ip-address', content => $ip )
]
);
}
sub addServerVirusfilter {
my ($self, $virusfilter) = @_;
my $root = $self->{serverNode};
my $content = defined($virusfilter) ? $virusfilter : 'none';
my $virusfilterNode = XmlNode->new('virusfilter', 'content' => $content);
$virusfilterNode->setAttribute( 'state', defined($virusfilter) ? 'inout' : 'none' );
$root->addChild($virusfilterNode);
return $virusfilterNode;
}
sub getSb5SitePublished {
my ($self, $name) = @_;
my $sb5SitePublishedUtil = AgentConfig::sb5SitePublishedUtil();
my $cmd = $sb5SitePublishedUtil . " --is-site-builder-site-published " . $name;
Logging::debug("Exec: $cmd");
my $result = `$cmd`;
chomp($result);
my $retCode = $? >> 8;
if( $retCode != 0 ) {
Logging::warning( "Unable to backup Site Builder publishing status on site $name (ErrorCode: $retCode, STDOUT:$result).", 'UtilityError' );
return;
}
return ($result eq 'true')? 'true' : 'false';
}
sub setSb5ServerContent {
my ($self) = @_;
my $root = $self->{serverNode};
my $sb5backupUtil = AgentConfig::sb5BackupUtil();
unless (defined $sb5backupUtil)
{
Logging::debug("Unable to find SiteBuilder backup utility to create server content backup.");
return;
}
my $dstFile = HelpFuncs::mktemp("pmm-sb5-sc-XXXXXXXX");
my $cmd = "$sb5backupUtil --backup --target=server_settings --log=stdout --file=$dstFile";
my $result = `$cmd`;
my $retCode = $? >> 8;
Logging::debug("Backing up sitebuilder server settings:");
Logging::debug($cmd);
Logging::debug($result);
if( $retCode == 0 ) {
if( -e "$dstFile.zip") {
my $cid = $self->{content_transport}->addAdminContent('sb5-server', undef, 'sb_server', "directory" => ".", "include" => [$dstFile.".zip"]);
$root->getChild('content', 1, 1)->addChild($cid) if $cid;
}
else {
Logging::warning( "Sitebuilder backup was not created.", 'UtilityError' );
}
}
else {
Logging::warning( "Return code of sitebuilder bru utility: ".$retCode.". Some errors occured during sitebuilder backup. Please see psadump.log file for more information", 'UtilityError' );
}
unlink "$dstFile.zip" if( -e "$dstFile.zip");
}
sub setSb5DomainContent {
my ($self, $domainId, $domainName, $uuid) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $sb5backupUtil = AgentConfig::sb5BackupUtil();
unless (defined $sb5backupUtil)
{
Logging::debug("Unable to find SiteBuilder backup utility to create domain content backup.");
return;
}
my $dstFile = HelpFuncs::mktemp("pmm-sb5-dc-XXXXXXXX");
my $cmd = "$sb5backupUtil --backup --target=site --uuid=$uuid --log=stdout --file=$dstFile";
my $result = `$cmd`;
my $retCode = $? >> 8;
Logging::debug("Backing up sitebuilder settings for site $domainName:");
Logging::debug($cmd);
Logging::debug($result);
if( $retCode==0 ){
if( -e "$dstFile.zip") {
my $cid = $self->{content_transport}->addDomainContent('sb5-site', $domainId, 'sb_site', "directory" => ".", "include" => [$dstFile.".zip"]);
if ( $cid ) {
my @phostings = $root->getChildren('phosting');
if ( @phostings ) {
$phostings[0]->getChild('content', 1, 1)->addChild($cid);
}
else {
Logging::warning('Error: setSb5DomainContent: there are no node "phosting"', 'PackerStructure');
}
}
}
else {
Logging::warning( "Sitebuilder backup was not created." , 'UtilityError' );
}
}
else {
Logging::warning( "Return code of sitebuilder bru utility: ".$retCode.". Some errors occured during sitebuilder backup. Please see psadump.log file for more information", 'UtilityError' );
}
unlink "$dstFile.zip" if( -e "$dstFile.zip");
}
sub setSmbSiteEditorDomainContent {
my ($self, $domainId, $domainName ) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $backupUtil = AgentConfig::sbbackupBin();
my $dstFile = HelpFuncs::mktemp("pmm-siteeditor-XXXXXXXX");
my $cmd = "$backupUtil --target=site --name=$domainName --log=stdout --file=$dstFile";
my $result = `$cmd`;
my $retCode = $? >> 8;
Logging::debug("Backing up siteeditor settings for site $domainName:");
Logging::debug($cmd);
Logging::debug($result);
if( $retCode==0 ){
if( -e "$dstFile.zip") {
my $cid = $self->{content_transport}->addDomainContent('sb-dump', $domainId, 'sb_dump', "directory" => ".", "include" => [$dstFile.".zip"]);
if ( $cid ) {
my @phostings = $root->getChildren('phosting');
if ( @phostings ) {
$phostings[0]->getChild('preferences', 1)->getChild('sb-domain', 1)->getChild('content', 1, 1)->addChild($cid);
}
else {
Logging::warning('Error: setSmbSiteEditorDomainContent: there are no node "phosting"', 'PackerStructure');
}
}
}
else {
Logging::warning( "SiteEditor backup was not created." , 'UtilityError' );
}
}
else {
Logging::warning( "Return code of SiteEditor sbbackup utility: ".$retCode.". Some errors occured during SiteEditor backup. Please see psadump.log file for more information", 'UtilityError' );
}
unlink "$dstFile.zip" if( -e "$dstFile.zip");
}
sub addFileSharingContent {
my ($self, $path) = @_;
my $root = $self->{serverNode};
my $cid = $self->{content_transport}->addAdminContent('file-sharing', undef, 'file_sharing', 'directory' => $path, 'checkEmptyDir' => 1, 'exclude' => ['unlisted']);
$root->getChild('content', 1, 1)->addChild($cid) if $cid;
}
sub addFileSharingPasswd {
my ($self, $path) = @_;
my $root = $self->{serverNode};
my $cid = $self->{content_transport}->addAdminContent('file-sharing-passwd', undef, 'file_sharing_passwd', 'directory' => $path, 'checkEmptyDir' => 1 );
$root->getChild('content', 1, 1)->addChild($cid) if $cid;
}
sub addServerCustomApacheTemplates {
my ($self, $path) = @_;
my $root = $self->{serverNode};
my $dumpFile = $self->{content_transport}->addAdminContent('custom-apache-templates', undef, 'custom_apache_templates', 'directory' => $path);
$root->getChild('content', 1, 1)->addChild($dumpFile) if $dumpFile;
}
sub addServerCustomHealthConfig {
my ($self) = @_;
my $root = $self->{serverNode};
my $path = AgentConfig::get('PRODUCT_ROOT_D') . "/var";
my $file = 'custom-health-config.xml';
if ( -e "$path/$file") {
my $dumpFile = $self->{content_transport}->addAdminContent('drilldowns-config', undef, 'dd_conf', 'directory' => $path, 'include' => [$file]);
$root->getChild('content', 1, 1)->addChild($dumpFile) if $dumpFile;
}
}
sub addCustomizationConfig {
my ($self) = @_;
my $root = $self->{serverNode};
my $path = AgentConfig::get('PRODUCT_ROOT_D') . "/admin/conf";
my $file = 'customizations.conf';
if ( -e "$path/$file") {
my $customizationNode = XmlNode->new('customization');
my $configText = undef;
open CONFIGFILE, $path . "/" . $file;
binmode(CONFIGFILE);
while () {
$configText .= $_;
}
close CONFIGFILE;
$customizationNode->addChild(XmlNode->new('config', 'content' => $self->{base64}->{'ENCODE'}->($configText) ));
$root->addChild($customizationNode);
}
}
sub addRestrictedDomains {
my ($self) = @_;
my $root = $self->{serverNode};
my @restrictedDomains = @{DAL::getRestrictedDomains()};
if ( @restrictedDomains ) {
my $restrictedDomainNode = XmlNode->new('restricted-domains');
foreach my $domain (@restrictedDomains) {
$restrictedDomainNode->addChild(XmlNode->new('hostname', 'content' => $domain->{'name'}));
}
$root->addChild($restrictedDomainNode);
}
}
sub addFail2ban {
my ($self) = @_;
my %packages = %{DAL::getSoftwarePackages()};
if (!exists($packages{'fail2ban'})) {
return;
}
my $fail2banNode = XmlNode->new('fail2ban');
$fail2banNode->setAttribute('version', $packages{'fail2ban'});
my $fail2banDir = '/etc/fail2ban';
my @includeList = ('action.d/', 'filter.d/', 'jail.d/', 'jail.conf');
for my $localConfig ( ('jail.local', 'fail2ban.local') ) {
if (-e "$fail2banDir/$localConfig") {
push(@includeList, $localConfig);
}
}
my $cid = $self->{content_transport}->addAdminContent(
'fail2ban',
undef,
'fail2ban',
'directory' => $fail2banDir,
'include' => \@includeList,
'skip_content' => 0,
);
$fail2banNode->getChild('content', 1, 1)->addChild($cid) if $cid;
$self->{serverNode}->addChild($fail2banNode);
}
sub addModSecurityContent {
my ($self, $rulesBaseDir, @ruleSetDirs) = @_;
my $cid = $self->{content_transport}->addAdminContent(
'modsecurity',
undef,
'modsecurity',
'directory' => $rulesBaseDir,
'include' => \@ruleSetDirs,
'skip_content' => 0
);
$self->{serverNode}->getChild('content', 1, 1)->addChild($cid) if $cid;
}
sub dumpUnityMobileIntegration {
my ($self, $domainId, $ptrDomParams) = @_;
my %domParams = %{$ptrDomParams};
if ( defined $domParams{'unity_mobile_site_dns_target'}
and defined $domParams{'unity_mobile_site_key'}
and defined $domParams{'unity_mobile_site_prefix'}
) {
my $root = $self->getCashedDomainNode($domainId);
my $umNode = XmlNode->new('unity-mobile-integration');
my $siteNode = XmlNode->new('mobile-site');
$siteNode->addChild(XmlNode->new('dns-target', 'content' => $domParams{'unity_mobile_site_dns_target'}));
$siteNode->addChild(XmlNode->new('key', 'content' => $domParams{'unity_mobile_site_key'}));
$siteNode->addChild(XmlNode->new('prefix', 'content' => $domParams{'unity_mobile_site_prefix'}));
$umNode->addChild($siteNode);
$root->getChild( 'preferences', 1 )->addChild($umNode);
}
}
sub makeApsBundleFilterNode {
my ($self, $parentId, $parentType, $filterType, $filterItems, $parentNode) = @_;
my $apsBundleNode = XmlNode->new('aps-bundle');
my $filterNode = XmlNode->new('filter', 'attributes' => { 'type' => $filterType});
$apsBundleNode->addChild($filterNode);
foreach my $itemHash (@{$filterItems}) {
my ($name, $value) = each %{$itemHash};
my $itemNode = XmlNode->new('item');
$itemNode->addChild(XmlNode->new('name', 'content' => $name));
$itemNode->addChild(XmlNode->new('value', 'content' => $value));
$filterNode->addChild($itemNode);
}
if (!defined($parentNode)) {
if ($parentType eq 'client') {
$parentNode = $self->getCashedClientNode($parentId);
}elsif ($parentType eq 'domain') {
$parentNode = $self->getCashedDomainNode($parentId);
}
$parentNode->getChild('preferences', 1)->addChild($apsBundleNode);
}else{
$parentNode->addChild($apsBundleNode);
}
}
sub makeSkinNode {
my ($self, $skinName, $login, $id) = @_;
$self->makeBrandingCid($id, $login, "-name " . $skinName, "theme-skin") if $skinName ne '';
}
sub makeBrandingCid {
my ($self, $id, $login, $cmdArgs, $cidType) = @_;
my $parentNode;
if (defined $id) {
$parentNode = $self->{resellersNodes}->{$id};
}else {
$parentNode = $self->{serverNode};
}
my $command = AgentConfig::brandingUtil();
my $dstFile = HelpFuncs::mktemp("pmm-brandtheme-XXXXXXXX");
if (defined $command) {
my $cmd = $command . " --pack " . $cmdArgs . " -destination " . $dstFile;
Logging::debug("Exec: $cmd");
my $ret = `$cmd`;
my $retCode = $? >> 8;
if( $retCode!=0 and $retCode != 13){
Logging::warning( "Cannot pack theme for vendor " . $login . "STDOUT:" . $ret,'UtilityError');
return;
}
if ( -e $dstFile) {
my $cid = undef;
if (defined $id) {
$cid = $self->{content_transport}->addClientContent($cidType, $id, 'branding', 'directory' => '.', 'include' => [$dstFile]);
}else{
$cid = $self->{content_transport}->addAdminContent($cidType, undef, 'branding', 'directory' => '.', 'include' => [$dstFile]);
}
if ($cid) {
$parentNode->getChild('content', 1, 1)->addChild($cid);
}
}
} else {
Logging::warning( "Utility for dumping branding theme is unavailable ", 'UtilityError');
unlink $dstFile if ( -e $dstFile);
return;
}
unlink $dstFile if ( -e $dstFile);
}
sub addCrontabSecureSettings {
my ($self, $params) = @_;
my $serverNode = $self->{serverNode};
my $serverPrefNode = $serverNode->getChild( 'server-preferences', 1 );
$serverPrefNode->addChild(XmlNode->new('crontab-secure-shell', 'content' => $params->{'crontab_secure_shell'})) if defined $params->{'crontab_secure_shell'};
$serverPrefNode->addChild(XmlNode->new('crontab-secure-shell-compatibility-mode', 'content' => $params->{'crontab_secure_shell_compatibility_mode'} eq 'true' ? 'true' : 'false')) if defined $params->{'crontab_secure_shell_compatibility_mode'};
}
sub addKavSettingsParam {
my ($self, $kavSettingsNode, $param, $value) = @_;
my %allowedParams = (
'Check' => 1,
'AddXHeaders' => 1,
'AdminAddress' => 1,
'QuarantinePath' => 1,
'FilterByName' => 1,
'FilterByMIME' => 1,
'SkipByName' => 1,
'SkipByMIME' => 1,
'Quarantine' => 1,
'AdminNotify' => 1,
'AdminAction' => 1,
'SenderNotify' => 1,
'RecipientNotify' => 1,
'RecipientAttachReport' => 1,
'RecipientAction' => 1,
'CuredAdminAction' => 1,
'CuredRecipientAction' => 1,
'InfectedAdminAction' => 1,
'SuspiciousAdminAction' => 1,
'InfectedRecipientAction' => 1,
'SuspiciousRecipientAction' => 1,
'FilteredRecipientAction' => 1,
'FilteredQuarantine' => 1
);
if ( $allowedParams{$param} ) {
$kavSettingsNode->addChild( XmlNode->new( 'param', 'content' => $value, 'attributes' => { 'name' => $param } ) );
}
return;
}
sub makeSubscriptionNode {
my ($self, $locked, $synchronized, $custom, $externalId) = @_;
my $subscriptionNode = XmlNode->new( 'subscription' );
if (defined $locked) {
$subscriptionNode->setAttribute('locked', $locked);
}
if (defined $custom) {
$subscriptionNode->setAttribute('custom', $custom);
}
if (defined $externalId and $externalId ne '') {
$subscriptionNode->setAttribute('external-id', $externalId);
}
if (defined $synchronized) {
$subscriptionNode->setAttribute('synchronized', $synchronized);
}
return $subscriptionNode;
}
sub addSubscriptionPlan {
my ($self, $subscriptionNode, $quantity, $plan_guid, $is_addon) = @_;
return unless ( ( defined $quantity ) && ( defined $plan_guid ) );
my $planNode = XmlNode->new( 'plan' );
$planNode->setAttribute('quantity', $quantity);
$planNode->setAttribute('plan-guid', $plan_guid);
if ( defined $is_addon) {
$planNode->setAttribute('is-addon', $is_addon);
}
$subscriptionNode->addChild($planNode);
return;
}
sub dumpFileSharingServerSettings {
my ($self, $settingsPtr) = @_;
my %settings = %{$settingsPtr};
my $fsNode = XmlNode->new('file-sharing-settings');
my $parentNode = $self->{serverNode};
foreach my $key (keys %settings) {
$fsNode->addChild(XmlNode->new('setting','attributes' =>
{ 'name' => $key, 'value' => $settings{$key}} ) );
}
$parentNode->addChild($fsNode);
}
sub dumpFileSharingUnlistedFiles {
my ($self, $unlistedFiles) = @_;
my $unlistedFilesNode = XmlNode->new('file-sharing-unlisted-files');
foreach my $unlistedFile (@{$unlistedFiles}) {
$unlistedFilesNode->addChild(XmlNode->new('file-sharing-unlisted-file','attributes' => {
'creation-date' => $unlistedFile->{'creationDate'},
, 'salt' => $unlistedFile->{'salt'}
, 'name' => $unlistedFile->{'name'}
, 'path' => $unlistedFile->{'path'}
, 'expiration' => $unlistedFile->{'expiration'}
}));
}
$self->{serverNode}->addChild($unlistedFilesNode);
}
sub dumpUiMode {
my ($self, $paramsPtr) = @_;
my %params = %{$paramsPtr};
my $parent = $self->{serverNode};
my $uiMode = undef;
if (!defined($params{'power_user_panel'}) || $params{'power_user_panel'} ne 'true') {
$uiMode = 'classic';
} else {
if (defined $params{'simple_panel'} && $params{'simple_panel'} eq 'true') {
$uiMode = (defined $params{'simple_panel_lock'} && $params{'simple_panel_lock'} eq 'true') ? 'simple-lock' : 'simple';
} else {
$uiMode = 'normal';
}
}
if (defined $uiMode) {
$parent->getChild( 'interface-preferences', 1 )->addChild(XmlNode->new('ui-mode', 'content' => $uiMode));
}
}
sub addTechnicalPreviewDomainNode {
my ($self, $domainName) = @_;
my $serverNode = $self->{serverNode};
my $serverPrefNode = $serverNode->getChild( 'server-preferences', 1 );
$serverPrefNode->addChild(XmlNode->new('technical-domain', 'content' => $domainName));
}
sub addUpdateSettings {
my ($self, $autoUpdatesValue, $autoUpgradeToStable, $autoUpgradeBranch) = @_;
my $serverNode = $self->{serverNode};
my $serverPrefNode = $serverNode->getChild( 'server-preferences', 1 );
my $updateSettingsNode = XmlNode->new('update-settings');
$updateSettingsNode->addChild(XmlNode->new('autoupdates', 'content' => $autoUpdatesValue));
$updateSettingsNode->addChild(XmlNode->new('autoupgrade-stable', 'content' => $autoUpgradeToStable));
$updateSettingsNode->addChild(XmlNode->new('release-tier', 'content' => $autoUpgradeBranch));
$serverPrefNode->addChild($updateSettingsNode);
}
sub addFtpOverSslSettings {
my ($self, $value) = @_;
my $serverNode = $self->{serverNode};
my $serverPrefNode = $serverNode->getChild( 'server-preferences', 1 );
$serverPrefNode->addChild(XmlNode->new('ftp-over-ssl', 'content' => $value));
}
sub setMiscParameters {
my ($self, $paramsPtr) = @_;
my $serverNode = $self->{serverNode};
my %params = %{$paramsPtr};
my $miscNode = $serverNode->getChild( 'misc', 1 );
foreach my $name (keys %params) {
my $paramNode = XmlNode->new('param');
$paramNode->addChild(XmlNode->new('name', 'content' => $name));
$paramNode->addChild(XmlNode->new('value', 'content' => $params{$name}));
$miscNode->addChild($paramNode);
}
}
sub _getChildNodeName {
my ($self, $parentNodeName) = @_;
my %nodesMapping = (
'components' => 'component'
, 'resource-usage' => 'resource'
, 'miscellaneous' => 'setting'
, 'apache-modules' => 'module'
);
return $nodesMapping{$parentNodeName};
}
sub _makeNameValueNode {
my ($self, $nodeName, $name, $value) = @_;
my $node = XmlNode->new($nodeName);
my $nameNode = XmlNode->new('name', 'content' => $name);
my $valueNode = XmlNode->new('value', 'content' => $value);
$node->addChild($nameNode);
$node->addChild($valueNode);
return $node;
}
sub makeDomainParamsNode {
my ($self, $domainId, $domainParams) = @_;
my $root = $self->getCashedDomainNode($domainId);
return unless defined $root;
my $properties = $root->getChild( 'properties', 1 );
my $domParam = XmlNode->new('dom-param');
foreach my $key (keys %{$domainParams}) {
$domParam->addChild($self->_makeNameValueNode('param', $key, $self->{base64}->{'ENCODE'}->($domainParams->{$key})));
}
$properties->addChild($domParam);
}
sub makeSubscriptionPropertiesNode {
my ($self, $parentNode, $subscriptionProperties) = @_;
my $propertiesNode = XmlNode->new('properties');
foreach my $key (keys %{$subscriptionProperties}) {
$propertiesNode->addChild($self->_makeNameValueNode('property', $key, $self->{base64}->{'ENCODE'}->($subscriptionProperties->{$key})));
}
$parentNode->addChild($propertiesNode);
}
sub assignApplicationInfoToMailUser {
my ($self, $applicationApsRegistryId, $resourceInfo) = @_;
my $mailUserNode = $self->{mailNodes}->{$resourceInfo->{'id'}};
return unless defined $mailUserNode;
my $apsServices = $mailUserNode->getChild('aps-services', 1);
my $apsService = XmlNode->new('aps-service');
$apsService->addChild(XmlNode->new('application-registry-id', 'content' => $applicationApsRegistryId));
$apsService->addChild(XmlNode->new('resource-registry-id', 'content' => $resourceInfo->{'apsRegistryId'}));
$apsServices->addChild($apsService);
}
sub makeDomainDescriptionsNode {
my ( $self, $domainId, $description ) = @_;
my $domainNode = $self->getCashedDomainNode( $domainId );
my $prefs = $domainNode->getChild( 'preferences', 1 );
$self->makeDescriptionsNode( $prefs, [{ 'description' => $description }] );
}
sub makeMailUserDescriptionNode {
my ( $self, $mailUserId, $description ) = @_;
my $mailUserNode = $self->{mailNodes}->{$mailUserId};
my $prefs = $mailUserNode->getChild( 'preferences', 1 );
$self->makeDescriptionsNode( $prefs, [{ 'description' => $description }] );
}
sub makeResellerDescriptionsNode {
my ( $self, $resellerId, $descriptions ) = @_;
my $resellerNode = $self->{resellersNodes}->{$resellerId};
my $prefs = $resellerNode->getChild( 'preferences', 1 );
$self->makeDescriptionsNode( $prefs, $descriptions );
}
sub makeDescriptionsNode {
my ( $self, $parentNode, $descriptions ) = @_;
if ( scalar @{$descriptions} > 0 ) {
my $descriptionsNode = XmlNode->new( 'descriptions' );
foreach my $description ( @{$descriptions} ) {
my $descriptionNode = XmlNode->new( 'description', 'content' => $description->{'description'} );
$descriptionNode->setAttribute( 'object-name', $description->{'name'}) if $description->{'name'} and $description->{'name'} ne '';
$descriptionNode->setAttribute( 'object-type', $description->{'type'}) if $description->{'type'} and $description->{'type'} ne '';
$descriptionsNode->addChild( $descriptionNode );
}
$parentNode->addChild( $descriptionsNode );
}
}
sub makeOutgoingMessagesParameter {
my ($self, $objectType, $objectDbId, $paramName, $paramValue) = @_;
my $object = $self->_getObject($objectType, $objectDbId);
$object->getChild('preferences', 1)->getChild('outgoing-messages', 1)->addChild(XmlNode->new('parameter', 'children' => [
XmlNode->new('name', 'content' => $paramName),
XmlNode->new('value', 'content' => $paramValue),
]));
}
sub _makeSeverOutgoingEmailMode {
my ($self, $mailSettingsPtr, $ipAddressesPtr) = @_;
my %mailSettings = %{$mailSettingsPtr};
my %ipAddresses = %{$ipAddressesPtr};
if (!defined($mailSettings{'outgoing_email_mode'})) {
return;
}
my $outgoingEmailMode = $mailSettings{'outgoing_email_mode'};
Logging::debug("outgoing_email_mode found: $outgoingEmailMode");
if ($outgoingEmailMode eq 'domain-ip' || $outgoingEmailMode eq 'domain-name') {
$self->{serverNode}->getChild('mail-settings', 1)->addChild(XmlNode->new('outgoing-email-mode', 'children' => [
XmlNode->new($outgoingEmailMode)
]));
} elsif ($outgoingEmailMode == 'explicit-ip') {
my @ips;
for my $param ('outgoing_email_mode_explicit_ip_v4', 'outgoing_email_mode_explicit_ip_v6') {
if (defined($mailSettings{$param}) && $mailSettings{$param} ne ''
&& defined($ipAddresses{$mailSettings{$param}})) {
push @ips, XmlNode->new('ip-address', 'content' => $ipAddresses{$mailSettings{$param}}->{'ip_address'});
}
}
$self->{serverNode}->getChild('mail-settings', 1)->addChild(XmlNode->new('outgoing-email-mode', 'children' => [
XmlNode->new($outgoingEmailMode, 'children' => \@ips)
]));
}
}
sub _makeServerOutgoingMessagesParameter {
my ($self, $paramName, $paramValue) = @_;
$self->{serverNode}->getChild('mail-settings', 1)->getChild('outgoing-messages', 1)->addChild(
XmlNode->new('parameter', 'children' => [
XmlNode->new('name', 'content' => $paramName),
XmlNode->new('value', 'content' => $paramValue),
]
));
}
# Method return object by their types and id
# returns XmlNode | undef
sub _getObject{
my ($self, $objectType, $objectDbId) = @_;
if ($objectType eq 'admin') {
return $self->{admin};
} elsif ($objectType eq 'server') {
return $self->{serverNode};
} elsif ($objectType eq 'reseller') {
return $self->{resellersNodes}->{$objectDbId};
} elsif ($objectType eq 'client' or $objectType eq 'customer') {
return $self->{clientNodes}->{$objectDbId};
} elsif ($objectType eq 'domain' or $objectType eq 'subscription' or $objectType eq 'site' ) {
return $self->getCashedDomainNode($objectDbId);
} elsif ($objectType eq 'mailsystem') {
return $self->getCashedDomainNode($objectDbId)->getChild('mailsystem', 1);
} elsif ($objectType eq 'mailuser') {
return $self->{mailNodes}->{$objectDbId};
} else {
Logging::error("Object type \"$objectType\" is not supported by Packer::_getObject");
}
return undef;
}
sub makeClParamNode {
my ( $self, $clientId, $clientType, $params ) = @_;
my $parentNode = $self->_getObject($clientType, $clientId)->getChild('properties', 1)->getChild('cl-param', 1);
foreach my $param ( keys( %{$params} ) ) {
my $paramNode = XmlNode->new( 'param' );
$paramNode->addChild( XmlNode->new( 'name', 'content' => $param ) );
$paramNode->addChild( XmlNode->new( 'value', 'content' => $self->{base64}->{'ENCODE'}->( $params->{$param} ) ) );
$parentNode->addChild( $paramNode );
}
}
sub makeExtensionNode {
my ($self, $objectType, $objectId) = @_;
Logging::debug("makeExtensionNode $objectType, $objectId");
$objectType = 'customer' if $objectType eq 'client';
$objectType = 'subscription' if $objectType eq 'domain';
my $extensionsHooks = PleskStructure::getExtensionsHooks();
foreach my $extId (keys %{$extensionsHooks}) {
Logging::debug("Check extension $extId");
next if $extensionsHooks->{$extId}->{$objectType} ne 'true';
my $xml = DAL::backupExtension( $extId, $objectType, $objectId );
return if not defined $xml;
my $extName = $xml->{'name'};
my $extension = XmlNode->new( 'extension',
'attributes' => {
'name' => $extName,
'version' => $xml->{'version'},
'release' => $xml->{'release'},
}
);
if (exists $xml->{'config'}) {
$extension->addChild(XmlNode->new('config', 'content' => $xml->{'config'}[0]));
}
if (exists $xml->{'enabled'}) {
$extension->setAttribute('enabled', $xml->{'enabled'});
}
if (exists $xml->{'settings'} and ref($xml->{'settings'}[0]) eq "HASH") {
foreach my $setting (@{$xml->{'settings'}[0]->{'setting'}})
{
$extension->getChild( 'settings', 1 )->addChild( XmlNode->new( 'setting', 'children' => [
XmlNode->new( 'name', 'content' => $setting->{'name'}[0] ),
XmlNode->new( 'value', 'content' => $setting->{'value'}[0] ),
] ) );
}
}
if (exists $xml->{'content'}) {
my @include;
my @exclude;
my $packageFile;
if (ref($xml->{'content'}) eq "HASH") {
foreach my $item (@{$xml->{'content'}->{'include'}}) {
$item =~ s/^[\\\/]*//;
push @include, $item;
}
foreach my $item (@{$xml->{'content'}->{'exclude'}}) {
$item =~ s/^[\\\/]*//;
push @exclude, $item;
}
foreach my $item (@{$xml->{'content'}->{'webspace'}}) {
$extension->getChild( 'webspace-paths', 1 )->addChild(XmlNode->new('path', 'content' => $item));
}
if (exists $xml->{'content'}->{'package'}) {
$packageFile = $xml->{'content'}->{'package'}[0];
}
}
if (scalar(@include) > 0) {
if ("." ~~ @include) {
@include = ();
}
my $proc;
if ($objectType eq 'admin' or $objectType eq 'server') { $proc = \&addAdminContentProxy; }
elsif ($objectType eq 'customer' or $objectType eq 'reseller') { $proc = \&addClientContentProxy; }
elsif ($objectType eq 'subscription' or $objectType eq 'site') { $proc = \&addDomainContentProxy; }
else {
Logging::warning( "Error: makeExtensionNode: unsupported parent type '$objectType' ", 'assert' );
}
if ($proc) {
my $cid = $self->$proc(
'extension',
$objectId,
'ext_'.$extName,
"directory" => AgentConfig::get( 'PRODUCT_ROOT_D' )."/var/modules/$extName",
"include" => \@include,
"exclude" => \@exclude,
"include_hidden_files" => 1
);
$extension->getChild( 'content', 1, 1 )->addChild( $cid ) if $cid;
}
}
if (defined $packageFile && -e $packageFile) {
my $cid = $self->addAdminContentProxy(
'extension_dist',
$objectId,
'ext_dist_'.$extName,
"directory" => dirname($packageFile),
);
$extension->getChild( 'content', 1, 1 )->addChild( $cid ) if $cid;
eval {
File::Path::rmtree(dirname($packageFile));
};
Logging::debug('Unable to remove temporary directory with extension archive. ' . $@) if $@;
}
}
$self->_getObject( $objectType, $objectId )->getChild( 'extensions', 1 )->addChild( $extension );
if ($extensionsHooks->{$extId}->{"$objectType-post-backup"} eq 'true') {
DAL::postBackupExtension( $extId, $objectType, $objectId );
}
}
}
1;