package Transformer; use Logging; use XPath; use XmlNode; use Dumper; use Validator; use HelpFuncs; use Error qw(:try); use Exception::XmlNode; # # Begin global variables # # Hash of client names and client XmlNode elements, Plesk format my %clientNodes; # Initialized in initQuickInfo: # Hash of client names and shallow client XmlNode elements, Plesk format my %shallowClientNodes; # Hash of Plesk client and cPanel accounts my %clients2cpAccount; # Hash of domains and its owners (clients) my %domain2client; # Hash of domains and its hosting type my %domain2hosting; my $initialized; # # End of global variables # # # Begin constants: # # Maximum significant value for the disk space / traffic limit. # Values exceeding that would be counted as 'unlimited' my $max_limit_value = 999999*1024*1024; my %limit_map = ( 'max_traffic' => 'max_traffic', 'disk_space' => 'disk_space', 'max_subdom' => 'max_subdom', 'max_addon' => 'max_site', 'max_db' => 'max_db', 'max_box' => 'max_box', 'max_ftpusers' => 'max_subftp_users'); # # End of constants # # # Begin service subs # sub initialize { # Get all accounts from Dumper # Get account' basic information, only need for getting the domain list # Should initialize %resellerNodes, %clientNodes and %domainNodes with 'undef' # unless ( $initialized ) { Dumper::initialize(); # Get accounts my @cp_accounts = Dumper::getAllAccounts(); foreach my $account ( sort @cp_accounts ) { my $cpAccountNode = Dumper::makeAccountNode( $account, undef, undef, 'shallow_mode'); if ( ref($cpAccountNode) =~ /XmlNode/ ) { # Transformation now is realized in 'one-to-one' mode. This does not preserve cPanel accounts hierarhy. my $accountNode = transformAccountNode($cpAccountNode); unless ( defined $accountNode ) { Logging::error("Account '$accountNode' transformation failed"); } } } $initialized = 1; } } sub getResellers { my @resellers; # empty return @resellers; } sub getClients { my $owner = shift; # reseller that owns the clients returned. Could be 'undef' for default reseller ('root' or 'admin') my @clients; # empty return @clients; } sub getDomains { my $owner = shift; # reseller or client that owns the domains returned. Could be 'undef' for default reseller or client ('root' or 'admin') # Should return an array of clients identifiers, that could be a number, name or guid. Should be unique through migration dump. # The current implementation of cPanel migration deals with domains only. initialize(); my @domains; unless ( defined $owner ) { foreach my $domain (sort keys %domain2client) { push @domains, $domain; } } return @domains; } # # Basic transform routine # # Works in 'shallow mode' by default # Important: dump in 'shallow_mode' is not required to be valid for plesk.xsd. # sub transformAccountNode { my ($cpAccountNode, $not_shallow_mode) = @_; if ( ref($cpAccountNode) =~ /XmlNode/ ) { if ($cpAccountNode->getName() eq 'account' ) { my $clientNode = XmlNode->new ('client'); my $cp_account_name = $cpAccountNode->getAttribute( 'name' ); my $client_name = $cp_account_name; $clientNode->setAttribute( 'name', $client_name ); $clientNode->setAttribute( 'guid', '' ); if ( $not_shallow_mode ) { $clientNode->setAttribute( 'contact', 'client ' . $client_name ); my $crDate = $cpAccountNode->getAttribute( 'date' ); $clientNode->setAttribute( 'cr-date', $crDate ) if ( defined $crDate ); $clientNode->addChild( XmlNode->new( 'preferences' )); my $clientPropertiesNode = XmlNode->new( 'properties' ); my $clientPasswordNode = getClientPassword($cpAccountNode); $clientPropertiesNode->addChild( $clientPasswordNode ) if ( defined $clientPasswordNode ); $clientPropertiesNode->addChild( getStatus($cpAccountNode) ); $clientNode->addChild( $clientPropertiesNode ); addClientLimitsAndPermissions( $clientNode, $cpAccountNode ); } my $clientIpPoolNode = XmlNode->new( 'ip_pool' ); $clientIpPoolNode->addChild( getIp($cpAccountNode) ); $clientNode->addChild( $clientIpPoolNode ); my $cpDomainNode = $cpAccountNode->getChild( 'domain' ); if ( defined ( $cpDomainNode ) ) { # 1) Transform cPanel account's domain to Plesk domain my $domainNode = XmlNode->new ('domain'); $domainNode->setAttribute( 'www', 'true' ); my $domain_name = $cpDomainNode->getAttribute( 'name' ); $domainNode->setAttribute( 'name', $domain_name ); # Plesk dump format requires guid, could be empty however, will be fixed with guid fixer before restore $domainNode->setAttribute( 'guid', '' ); my $crDate = $cpAccountNode->getAttribute( 'date' ); $domainNode->setAttribute( 'cr-date', $crDate ) if ( defined $crDate ); if ( $not_shallow_mode ) { my $domainPreferencesNode = getDomainPreferences($cpDomainNode); $domainNode->addChild( $domainPreferencesNode ); } my $domainPropertiesNode = getDomainProperties($cpAccountNode); $domainNode->addChild( $domainPropertiesNode ); my $domainPhostingNode; if ( $not_shallow_mode ) { # Call of getPhosting should be before addDomainLimitsAndPermissions because some modifications with limits are inside $domainPhostingNode = getPhosting( $domainNode, $cpAccountNode); addDomainLimitsAndPermissions( $domainNode, $cpAccountNode ); addDomainMailsystem( $domainNode, $cpAccountNode ); addDomainDatabases( $domainNode, $cpDomainNode ); addDomainMaillists( $domainNode, $cpDomainNode ); addDomainuser( $domainNode, $cpAccountNode); $domainNode->addChild( $domainPhostingNode ); } unless( $not_shallow_mode ) { $domain2hosting{$domain_name} = 'phosting'; } my $domainsNode = XmlNode->new( 'domains' ); $domainsNode->addChild( $domainNode ); $clientNode->addChild( $domainsNode ); $domain2client{$domain_name} = $client_name; if ( $not_shallow_mode ) { # Array to store 'site' nodes. Then we'll create 'sites' node if any 'site' node is created my @sites = (); # 2) Transform cPanel account's subdomains into Plesk sites my @cpSubdomainNodes = $cpDomainNode->getChildren( 'subdomain' ); if ( @cpSubdomainNodes ) { foreach my $cpSubdomainNode (sort @cpSubdomainNodes) { my $has_ftp_account = defined ( $cpSubdomainNode->getChild( 'ftpuser' ) ); my @cpAddonDomainNodes = $cpSubdomainNode->getChildren( 'addondomain' ); my $addon_domain_name ; $addon_domain_name = $cpAddonDomainNodes[0]->getAttribute('name') if ( @cpAddonDomainNodes ); if ( $addon_domain_name ) { my $domainFromSubdomainNode = XmlNode->new ('site'); $domainFromSubdomainNode->setAttribute( 'www', 'true' ); $domainFromSubdomainNode->setAttribute( 'name', $addon_domain_name ); # Plesk dump format requires guid, could be empty however, will be fixed with guid fixer before restore $domainFromSubdomainNode->setAttribute( 'guid', '' ); # Subdomains which have addondomains and have ftp account are mapped into Plesk sites with phosting # Subdomains which have addondomains but do not have ftp account are mapped into Plesk sites with shosting my $hosting_type = $has_ftp_account? 'phosting' : 'shosting' ; if ( $hosting_type eq 'phosting' ) { # Transform subdomain to site with hosting processSubdomain2Phosting($domainFromSubdomainNode, $cpSubdomainNode, $cpDomainNode, $cpAccountNode); } else { # Transform subdomain to site with shosting processSubdomain2Shosting($domainFromSubdomainNode, $cpSubdomainNode, $cpDomainNode, $cpAccountNode); } push @sites, $domainFromSubdomainNode; } } } if ( @sites ) { my $sitesNode = XmlNode->new( 'sites' ); foreach my $siteNode ( @sites ) { $sitesNode->addChild( $siteNode ); } $domainPhostingNode->addChild( $sitesNode ); } } } if ( $not_shallow_mode ) { $clientNodes{$client_name} = $clientNode; } else { $clients2cpAccount{$client_name} = $cp_account_name; $shallowClientNodes{$client_name} = $clientNode; } return $clientNode; } } return; } sub getClientNode4Domain { my $id = shift; # domain identifier from 'getDomains' result initialize(); if ( exists ( $domain2client{$id} ) ){ my $client_name = $domain2client{$id}; return $clientNodes{$client_name} if exists ( $clientNodes{$client_name} ); my $cpAccountNode = Dumper::makeAccountNode( $client_name, undef, undef); if ( Logging::getVerbosity() > 3 ) { my $cpAccountNodeDump = $cpAccountNode->serialize(); Logging::debug("-" x 16 . " begin cPanel account dump " . "-" x 16); Logging::debug($cpAccountNodeDump); Logging::debug("-" x 16 . " end of cPanel account dump " . "-" x 16); } if ( ref($cpAccountNode) =~ /XmlNode/ ) { my $error = undef; my $clientNode = undef; try { Validator::validateCpAccountNode($cpAccountNode); } catch Exception::XmlNode with { my $ex = shift; Logging::error($ex->print()); Logging::error("Domain '" . $id . "'will not be migrated due to errors above"); $error = 1; }; unless ( $error ) { $clientNode = transformAccountNode($cpAccountNode, 'not_shallow_mode'); if ( Logging::getVerbosity() > 3 ) { my $clientNodeDump = $clientNode->serialize(); Logging::debug("-" x 17 . " begin Plesk client dump " . "-" x 17); Logging::debug($clientNodeDump); Logging::debug("-" x 17 . " end of Plesk client dump " . "-" x 17); } } if ( defined ( $clientNode ) ) { $clientNodes{$client_name} = $clientNode; return $clientNode; } } return; } } # # End of service subs # # # Begin node transformation subs # sub getClientPassword { my $cpAccountNode = shift; unless ( testXmlNodeParam($cpAccountNode, 'account') ) {return;} # do nothing return; } sub addClientLimitsAndPermissions { my ($clientNode, $cpAccountNode) = @_; unless ( testXmlNodeParam($clientNode, 'client') ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account') ) {return;} # do nothing } sub getStatus { my ($cpAccountNode) = @_; my $cpSuspendedNode = $cpAccountNode->getChild( 'suspended' ); if ( defined $cpSuspendedNode) { return makeStatusDisabledBy('status', 'admin'); } return makeStatusEnabled('status'); } sub getIp { my $cpAccountNode = shift; unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my $cpIpNode = $cpAccountNode->getChild( 'ip' ); my $ipNode; if ( defined $cpIpNode) { $ipNode = XmlNode->new('ip'); my $cpDomainNode = $cpAccountNode->getChild( 'domain' ); my $allow_anon_ftp = 'false'; if (defined $cpDomainNode) { $allow_anon_ftp = $cpDomainNode->getChildAttribute( 'anonftp', 'pub' ); } # Plesk requires exclusive IP on domain to allow anon tfp access my $ipTypeNode = XmlNode->new( 'ip-type' ); $ipTypeNode->setText( $allow_anon_ftp eq 'true'? 'exclusive' : 'shared' ); $ipNode->addChild( $ipTypeNode ); my $ipAddressNode = XmlNode->new( 'ip-address' ); $ipAddressNode->setText( $cpIpNode->getText() ); $ipNode->addChild( $ipAddressNode ); } return $ipNode; } sub getDomainPreferences { my $cpDomainNode = shift; unless ( testXmlNodeParam($cpDomainNode, 'domain' ) ) {return;} my $domainPreferencesNode = XmlNode->new( 'preferences' ); # Since PPP9.x cPanel account's addondomains are transformed into Plesk domain aliases instead of domain with shosting my @cpAddondomainNodes = $cpDomainNode->getChildren( 'addondomain' ); if (@cpAddondomainNodes) { foreach my $cpAddondomainNode (sort @cpAddondomainNodes) { my $domainAliasNode = XmlNode->new( 'domain-alias' ); $domainAliasNode->setAttribute( 'name', $cpAddondomainNode->getAttribute('name') ); $domainAliasNode->setAttribute( 'mail', 'true' ); $domainAliasNode->setAttribute( 'web', 'true' ); $domainAliasNode->addChild( makeStatusEnabled() ); $domainPreferencesNode->addChild( $domainAliasNode ); } } return $domainPreferencesNode; } sub getDomainProperties { my ($cpAccountNode, $skipIpNode) = @_; unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my $domainPropertiesNode = XmlNode->new( 'properties' ); $domainPropertiesNode->addChild( getIp($cpAccountNode) ) unless $skipIpNode; if ( $skipIpNode ) { $domainPropertiesNode->addChild( getStatus($cpAccountNode) ); } else { my $cpSuspendedNode = $cpAccountNode->getChild( 'suspended' ); if ( defined $cpSuspendedNode) { $domainPropertiesNode->addChild( makeStatusDisabledBy('webspace-status', 'admin') ); $domainPropertiesNode->addChild( makeStatusDisabledBy('status', 'parent') ); } else { $domainPropertiesNode->addChild( makeStatusEnabled('webspace-status') ); $domainPropertiesNode->addChild( makeStatusEnabled('status') ); } } return $domainPropertiesNode; } sub addDomainLimitsAndPermissions { my ($domainNode, $cpAccountNode) = @_; unless ( testXmlNodeParam($domainNode, 'domain' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my $cpDomainNode = $cpAccountNode->getChild('domain'); my $mboxQuota = 0; my $quotaSub = sub { if ($_[0] > $mboxQuota) { $mboxQuota = $_[0];} }; XPath::Select $cpDomainNode, 'mail/mailname', sub { $quotaSub->( shift->getAttribute( 'quota' ) ); }; XPath::Select $cpDomainNode, 'addondomain/mail/mailname', sub { $quotaSub->( shift->getAttribute( 'quota' ) ); }; XPath::Select $cpDomainNode, 'subdomain/mail/mailname', sub { $quotaSub->( shift->getAttribute( 'quota' ) ); }; XPath::Select $cpDomainNode, 'subdomain/addondomain/mail/mailname', sub { $quotaSub->( shift->getAttribute( 'quota' ) ); }; my @limitNodes; my @cpLimitNodes = $cpAccountNode->getChildren( 'limit' ); if ( @cpLimitNodes ) { foreach my $cpLimitNode ( @cpLimitNodes ) { my $cpLimitName = $cpLimitNode->getAttribute( 'name' ); if ( exists $limit_map{$cpLimitName} ) { my $limitValue = int( $cpLimitNode->getText() || 0 ); if ( int($limitValue) > $max_limit_value ) { $limitValue = -1; } my $limitName = $limit_map{$cpLimitName}; if ( ( $limitName eq 'max_site' ) && ( $limitValue != -1 ) ){ $limitValue += 1; } my $limitNode = XmlNode->new( 'limit' ); $limitNode->setAttribute( 'name', $limitName ); $limitNode->setText( $limitValue ); push @limitNodes, $limitNode; } } } my $mboxLimitNode = XmlNode->new( 'limit' ); $mboxLimitNode->setAttribute( 'name', 'mbox_quota' ); $mboxLimitNode->setText( $mboxQuota ); push @limitNodes, $mboxLimitNode; my $limitsAndPermissionsNode = XmlNode->new( 'limits-and-permissions' ); foreach my $limitNode ( @limitNodes ) { $limitsAndPermissionsNode->addChild( $limitNode ); } $domainNode->addChild( $limitsAndPermissionsNode ); return $limitsAndPermissionsNode; } sub addDomainMailsystem { my ($domainNode, $cpAccountNode) = @_; unless ( testXmlNodeParam($domainNode, 'domain' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my $cpDomainNode = $cpAccountNode->getChild( 'domain' ); my $cpMailNode = $cpDomainNode->getChild( 'mail' ); if ( defined $cpMailNode ) { my $mailsystemNode = XmlNode->new( 'mailsystem' ); $mailsystemNode->addChild( getMailsystemProperties() ); addMailsystemMailusers( $mailsystemNode, $cpDomainNode, $cpDomainNode->getAttribute( 'name' ), $cpAccountNode, (my $preferAddonDomains = 0) ); addMailsystemPreferences( $mailsystemNode, $cpMailNode ); $domainNode->addChild( $mailsystemNode ); return $mailsystemNode; } return; } sub addSubdomainMailsystem { my ($domainNode, $cpSubdomainNode, $cpAccountNode) = @_; # cPanel subdomains are always mapped to Plesk sites since PPP10.0, so domain node here is 'site' unless ( testXmlNodeParam($domainNode, 'site' ) ) {return;} unless ( testXmlNodeParam($cpSubdomainNode, 'subdomain' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my $cpMailNode = $cpSubdomainNode->getChild( 'mail' ); if ( defined $cpMailNode ) { my $mailsystemNode = XmlNode->new( 'mailsystem' ); $mailsystemNode->addChild( getMailsystemProperties() ); my $mailDomainName = $cpSubdomainNode->getAttribute( 'name' ). "." . $cpAccountNode->getChildAttribute( 'domain', 'name' ); addMailsystemMailusers( $mailsystemNode, $cpSubdomainNode, $mailDomainName, $cpAccountNode, (my $preferAddonDomains = 1) ); addMailsystemPreferences( $mailsystemNode, $cpMailNode ); $domainNode->addChild( $mailsystemNode ); return $mailsystemNode; } return; } sub getMailsystemProperties { my $propertiesNode = XmlNode->new( 'properties' ); $propertiesNode->addChild( makeStatusEnabled() ); return $propertiesNode; } sub addMailsystemMailusers { my ($mailsystemNode, $cpDomainNode, $cpMailDomainName, $cpAccountNode, $preferAddonDomains) = @_; unless ( testXmlNodeParam($mailsystemNode, 'mailsystem' ) ) {return;} unless ( testXmlNodeParam($cpDomainNode, 'domain', 'subdomain' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my $mailusersNode = XmlNode->new( 'mailusers' ); my $cpAccountName = $cpAccountNode->getAttribute( 'name' ); my $cpDomainName = $cpAccountNode->getChildAttribute( 'domain', 'name' ); my %mailnames; my $cpDomainMailNode = $cpDomainNode->getChild( 'mail' ); if ( ref($cpDomainMailNode) =~ /XmlNode/ ) { my @cpMailnameNodes = $cpDomainMailNode->getChildren( 'mailname' ); if ( @cpMailnameNodes ) { foreach my $cpMailnameNode ( @cpMailnameNodes ) { $mailnames{ $cpMailnameNode->getAttribute('name') } = [ $cpMailDomainName, $cpMailnameNode ]; } } } my @cpAddonDomainNodes = $cpDomainNode->getChildren( 'addondomain' ); if ( @cpAddonDomainNodes ) { foreach my $cpAddonDomainNode ( @cpAddonDomainNodes ) { my $cpAddonDomainMailNode = $cpAddonDomainNode->getChild( 'mail' ); if ( ref($cpAddonDomainMailNode) =~ /XmlNode/ ) { my @cpMailnameNodes = $cpAddonDomainMailNode->getChildren( 'mailname' ); if ( @cpMailnameNodes ) { foreach my $cpMailnameNode ( @cpMailnameNodes ) { if ( exists ( $mailnames{$cpMailnameNode->getAttribute('name')} ) ){ my $mailboxMainName = $cpMailnameNode->getAttribute('name')."@".$mailnames{ $cpMailnameNode->getAttribute('name') }->[0]; my $mailboxAddonName = $cpMailnameNode->getAttribute('name')."@".$cpAddonDomainNode->getAttribute('name'); if ( $preferAddonDomains ) { Logging::warning( "Couldn't migrate mailbox '$mailboxMainName'. Mailname is used in '$mailboxAddonName'."); $mailnames{ $cpMailnameNode->getAttribute('name') } = [ $cpAddonDomainNode->getAttribute( 'name' ), $cpMailnameNode ]; } else { Logging::warning( "Couldn't migrate mailbox '$mailboxAddonName'. Mailname is used in '$mailboxMainName'."); } } else { $mailnames{ $cpMailnameNode->getAttribute('name') } = [ $cpAddonDomainNode->getAttribute( 'name' ), $cpMailnameNode ]; } } } } } } while ( my ($mailname, $opts ) = each (%mailnames) ) { my $mailDomainName = $opts->[0]; my $cpMailnameNode = $opts->[1]; my $mailuserNode = XmlNode->new( 'mailuser' ); my $cpMailnameName = $cpMailnameNode->getAttribute( 'name' ); my %mailuserMetadata; $mailuserMetadata{'mailname'} = $cpMailnameName; $mailuserMetadata{'domain'} = $mailDomainName; $mailuserMetadata{'account'} = $cpAccountName; if ( ($cpMailnameName eq $cpAccountName) && ( $mailDomainName eq $cpDomainName) ) { #Default Email Account $mailuserMetadata{'exclude'} = _getDefaultMailboxExcludes($cpDomainNode); } $mailuserNode->setMetadata(\%mailuserMetadata); $mailuserNode->setAttribute( 'name', $cpMailnameName ); # Plesk dump format requires guid, could be empty however, will be fixed with guid fixer before restore $mailuserNode->setAttribute( 'guid', '' ); my $mailboxQuota = $cpMailnameNode->getAttribute( 'quota' ); $mailuserNode->setAttribute( 'mailbox-quota', $mailboxQuota ) if ( defined ( $mailboxQuota ) ); my $mailuserPropertiesNode = XmlNode->new( 'properties' ); my $mailuserPasswordNode = XmlNode->new( 'password' ); $mailuserPasswordNode->setAttribute( 'type', 'encrypted' ); $mailuserPasswordNode->setText( $cpMailnameNode->getAttribute( 'password' ) ); $mailuserPropertiesNode->addChild( $mailuserPasswordNode ); $mailuserNode->addChild( $mailuserPropertiesNode ); my $preferencesNode = getMailuserPreferences($cpMailnameNode, $cpDomainMailNode, $cpAccountNode); $mailuserNode->addChild( $preferencesNode ); if ( $preferencesNode->getChildren( 'forwarding' ) ) { $mailuserNode->setAttribute( 'forwarding-enabled', 'true' ); } else { $mailuserNode->setAttribute( 'forwarding-enabled', 'false' ); } $mailusersNode->addChild( $mailuserNode ); } addMailusersFromForwards($mailusersNode, $cpDomainMailNode, $cpAccountNode); addMailusersFromAutoresponders($mailusersNode, $cpDomainMailNode, $cpAccountNode); if ( $mailusersNode->getChildren( 'mailuser' ) ) { $mailsystemNode->addChild( $mailusersNode ); return $mailusersNode; } return; } sub getMailuserPreferences { my ($cpMailnameNode, $cpMailNode, $cpAccountNode) = @_; unless ( testXmlNodeParam($cpMailnameNode, 'mailname') ) {return;} unless ( testXmlNodeParam($cpMailNode, 'mail' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my $mailname = $cpMailnameNode->getAttribute( 'name' ); my $mailuserPreferences = XmlNode->new( 'preferences' ); my $mailboxNode = XmlNode->new( 'mailbox' ); $mailboxNode->setAttribute( 'enabled' , 'true' ); $mailboxNode->setAttribute( 'type' , 'mdir' ); $mailuserPreferences->addChild( $mailboxNode ); my @cpForwardNodes = $cpMailNode->getChildren( 'forward' ); foreach my $cpForwardNode ( @cpForwardNodes ) { next unless ( $cpForwardNode->getAttribute( 'mailname' ) eq $mailname ); $mailuserPreferences->addChild( transformForwardNode($cpForwardNode) ); last; } my @cpAutoresponderNodes = $cpMailNode->getChildren( 'autoresponder' ); foreach my $cpAutoresponderNode ( @cpAutoresponderNodes ) { next unless ( $cpAutoresponderNode->getAttribute( 'mailname' ) eq $mailname ); my $autoresponderNode = transformAutoresponderNode($cpAutoresponderNode); my $autorespondersNode = XmlNode->new( 'autoresponders' ); $autorespondersNode->addChild( $autoresponderNode ); $mailuserPreferences->addChild( $autorespondersNode ); last; } my $cpSpamassassinNode = $cpMailnameNode->getChild( 'spamassassin' ); $cpSpamassassinNode = $cpAccountNode->getChild( 'spamassassin' ) unless ( defined ( $cpSpamassassinNode ) ); my $spamassassinNode = undef; if ( defined $cpSpamassassinNode ) { $mailuserPreferences->addChild( transformSpamassassinNode( $cpSpamassassinNode) ); } return $mailuserPreferences; } sub addMailsystemPreferences { my ($mailsystemNode, $cpMailNode) = @_; unless ( testXmlNodeParam($mailsystemNode, 'mailsystem') ) {return;} unless ( testXmlNodeParam($cpMailNode, 'mail' ) ) {return;} my $preferencesNode = XmlNode->new( 'preferences' ); my $cpMailDefaultNode = $cpMailNode->getChild( 'default' ); if ( defined ( $cpMailDefaultNode ) ) { my $cpTargetAttr = $cpMailDefaultNode->getAttribute( 'target' ); my $target = ''; if ( $cpTargetAttr eq 'fail' ) { $target .= 'bounce:'; } if ($cpTargetAttr eq 'ignore') { $target .= 'reject'; } else { $target .= $cpMailDefaultNode->getText(); } my $catchAllNode = XmlNode->new( 'catch-all' ); $catchAllNode->setText( $target ); $preferencesNode->addChild( $catchAllNode ); } my $webmailNode = XmlNode->new( 'web-mail' ); $webmailNode->setText( 'horde' ); $preferencesNode->addChild( $webmailNode ); $mailsystemNode->addChild( $preferencesNode ); return $preferencesNode; } sub transformSpamassassinNode { my $cpSpamassassinNode = shift; unless ( testXmlNodeParam($cpSpamassassinNode, 'spamassassin') ) {return;} # cPanel spamassassin element format is compatible with Plesk's one my $spamassassinNode = $cpSpamassassinNode->copy(); return $spamassassinNode; } sub transformForwardNode { my $cpForwardNode = shift; unless ( testXmlNodeParam($cpForwardNode, 'forward') ) {return;} my $redirectNode = XmlNode->new( 'forwarding' ); $redirectNode->setText( $cpForwardNode->getAttribute( 'redirect' ) ); return $redirectNode; } sub transformAutoresponderNode { my $cpAutoresponderNode = shift; unless ( testXmlNodeParam($cpAutoresponderNode, 'autoresponder') ) {return;} my $autoresponderNode = XmlNode->new( 'autoresponder' ); $autoresponderNode->setAttribute( 'status' , 'on' ); my $from = $cpAutoresponderNode->getAttribute( 'from' ); $autoresponderNode->setAttribute( 'replyto', $from ) if defined $from; my $subject = $cpAutoresponderNode->getAttribute( 'subject' ); $autoresponderNode->setAttribute( 'subject', $subject ) if defined $subject; my $type = $cpAutoresponderNode->getAttribute( 'type' ); if ( $type eq 'html' ) { $autoresponderNode->setAttribute( 'content-type', 'text/html' ); } my $autoresponderTextNode = XmlNode->new( 'text' ); my $charset = $cpAutoresponderNode->getAttribute( 'charset' ); $autoresponderTextNode->setAttribute( 'charset', $charset ) if defined $charset; $autoresponderTextNode->setText( $cpAutoresponderNode->getText() ); $autoresponderNode->addChild( $autoresponderTextNode ); return $autoresponderNode; } sub addMailusersFromAutoresponders { my ($mailusersNode, $cpMailNode, $cpAccountNode) = @_; unless ( testXmlNodeParam($mailusersNode, 'mailusers') ) {return;} unless ( testXmlNodeParam($cpMailNode, 'mail' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my $cpAccountName = $cpAccountNode->getAttribute( 'name' ); my $cpDomainName = $cpAccountNode->getChildAttribute( 'domain', 'name' ); my %mailuserNames = (); my @mailuserNodes = $mailusersNode->getChildren( 'mailuser' ); foreach my $mailuserNode ( @mailuserNodes ) { $mailuserNames{$mailuserNode->getAttribute( 'name' )} = $mailuserNode; } my %mailnameNames = (); my @cpMailnameNodes = $cpMailNode->getChildren( 'mailname' ); foreach my $cpMailnameNode ( @cpMailnameNodes ) { $mailnameNames{$cpMailnameNode->getAttribute( 'name' )} = 1; } my @cpAutoresponderNodes = $cpMailNode->getChildren( 'autoresponder' ); foreach my $cpAutoresponderNode ( @cpAutoresponderNodes ) { my $mailname = $cpAutoresponderNode->getAttribute('mailname'); # skip mailnames processed in 'getMailuserPreferences' next if ( exists ($mailnameNames{$mailname}) ); my $mailuserNode; my $newnode; if ( exists ( $mailuserNames{$mailname} ) ) { $mailuserNode = $mailuserNames{$mailname}; } else { $mailuserNode = XmlNode->new( 'mailuser' ); $newnode = 1; } if ( !$mailuserNode->getMetadata() ) { my %mailuserMetadata; $mailuserMetadata{'mailname'} = $cpAutoresponderNode->getAttribute('mailname'); $mailuserMetadata{'domain'} = $cpDomainName; $mailuserMetadata{'account'} = $cpAccountName; $mailuserNode->setMetadata(\%mailuserMetadata); } if ( $newnode ) { $mailuserNode->setAttribute( 'name', $mailname ); $mailuserNode->setAttribute( 'forwarding-enabled', 'false' ); # Plesk dump format requires guid, could be empty however, will be fixed with guid fixer before restore $mailuserNode->setAttribute( 'guid', '' ); $mailuserNode->addChild( XmlNode->new( 'properties' ) ); } my $preferencesNode = $mailuserNode->getChild( 'preferences', 1 ); my $autorespondersNode = XmlNode->new( 'autoresponders' ); $autorespondersNode->addChild( transformAutoresponderNode( $cpAutoresponderNode ) ); $preferencesNode->addChild( $autorespondersNode ); $mailusersNode->addChild( $mailuserNode ) if $newnode; } return; } sub addMailusersFromForwards { my ($mailusersNode, $cpMailNode, $cpAccountNode) = @_; unless ( testXmlNodeParam($mailusersNode, 'mailusers') ) {return;} unless ( testXmlNodeParam($cpMailNode, 'mail' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my $cpAccountName = $cpAccountNode->getAttribute( 'name' ); my $cpDomainName = $cpAccountNode->getChildAttribute( 'domain', 'name' ); my %mailuserNames = (); my @mailuserNodes = $mailusersNode->getChildren( 'mailuser' ); foreach my $mailuserNode ( @mailuserNodes ) { $mailuserNames{$mailuserNode->getAttribute( 'name' )} = $mailuserNode; } my %mailnameNames = (); my @cpMailnameNodes = $cpMailNode->getChildren( 'mailname' ); foreach my $cpMailnameNode ( @cpMailnameNodes ) { $mailnameNames{$cpMailnameNode->getAttribute( 'name' )} = 1; } my @cpForwardNodes = $cpMailNode->getChildren( 'forward' ); foreach my $cpForwardNode ( @cpForwardNodes ) { my $mailname = $cpForwardNode->getAttribute('mailname'); # skip mailnames processed in 'getMailuserPreferences' next if ( exists ($mailnameNames{$mailname}) ); my $mailuserNode; my $newnode; if ( exists ( $mailuserNames{$mailname} ) ) { $mailuserNode = $mailuserNames{$mailname}; } else { $mailuserNode = XmlNode->new( 'mailuser' ); $newnode = 1; } if ( !$mailuserNode->getMetadata() ) { my %mailuserMetadata; $mailuserMetadata{'mailname'} = $mailname; $mailuserMetadata{'domain'} = $cpDomainName; $mailuserMetadata{'account'} = $cpAccountName; $mailuserNode->setMetadata(\%mailuserMetadata); } if ( $newnode ) { $mailuserNode->setAttribute( 'name', $mailname ); # Plesk dump format requires guid, could be empty however, will be fixed with guid fixer before restore $mailuserNode->setAttribute( 'guid', '' ); $mailuserNode->addChild( XmlNode->new( 'properties' ) ); } $mailuserNode->setAttribute( 'forwarding-enabled', 'true' ); my $preferencesNode = $mailuserNode->getChild( 'preferences', 1 ); $preferencesNode->addChild( transformForwardNode( $cpForwardNode ) ); if ( $newnode ) { $mailusersNode->addChild( $mailuserNode ); $mailuserNames{$mailname} = $mailuserNode; } } return $mailusersNode; } sub addDomainMaillists { my ($domainNode, $cpDomainNode) = @_; unless ( testXmlNodeParam($domainNode, 'domain') ) {return;} unless ( testXmlNodeParam($cpDomainNode, 'domain') ) {return;} my $cpMaillistsNode = $cpDomainNode->getChild( 'maillists' ); if ( defined ( $cpMaillistsNode ) ) { my @cpMaillistNodes = $cpMaillistsNode->getChildren( 'maillist' ); if ( @cpMaillistNodes ) { my $maillistsNode = XmlNode->new( 'maillists' ); my $propertiesNode = XmlNode->new( 'properties' ); $propertiesNode->addChild( makeStatusEnabled() ); $maillistsNode->addChild( $propertiesNode ); foreach my $cpMaillistNode ( @cpMaillistNodes ) { my $maillistNode = XmlNode->new( 'maillist' ); my $domainName = $cpDomainNode->getAttribute( 'name' ); my $listname = $cpMaillistNode->getAttribute( 'name' ) . "_" . $domainName; my %maillistMetadata; $maillistMetadata{'domain'} = $domainName; $maillistMetadata{'listname'} = $cpMaillistNode->getAttribute( 'name' ); $maillistNode->setMetadata(\%maillistMetadata); $maillistNode->setAttribute( 'name', $cpMaillistNode->getAttribute( 'name' ) ); $maillistNode->addChild( makeStatusEnabled() ); my @cpOwnerNodes = $cpMaillistNode->getChildren( 'owner' ); foreach my $cpOwnerNode ( @cpOwnerNodes ) { # 'owner' format is the same, just copy element $maillistNode->addChild($cpOwnerNode->copy()); } my $cpPasswordNode = $cpMaillistNode->getChild( 'password' ); if ( defined ( $cpPasswordNode ) ) { my $passwordNode = XmlNode->new( 'password' ); $passwordNode->setAttribute( 'type', $cpPasswordNode->getAttribute( 'type' ) ); $passwordNode->setText( $cpPasswordNode->getText() ); $maillistNode->addChild($passwordNode); } my @cpRecipientNodes = $cpMaillistNode->getChildren( 'recipient' ); foreach my $cpRecipientNode ( @cpRecipientNodes ) { # 'recipient' format is the same, just copy element $maillistNode->addChild($cpRecipientNode->copy()); } $maillistsNode->addChild( $maillistNode ); } $domainNode->addChild( $maillistsNode ); } } return $domainNode; } sub addDomainDatabases { my ($domainNode, $cpDomainNode) = @_; unless ( testXmlNodeParam($domainNode, 'domain') ) {return;} unless ( testXmlNodeParam($cpDomainNode, 'domain') ) {return;} my @cpDatabaseNodes = $cpDomainNode->getChildren( 'database' ); if (@cpDatabaseNodes) { my @databaseNodes = []; foreach my $cpDatabaseNode (@cpDatabaseNodes) { my $databaseNode = XmlNode->new( 'database' ); $databaseNode->setAttribute( 'name', $cpDatabaseNode->getAttribute( 'name' ) ); $databaseNode->setAttribute( 'type', $cpDatabaseNode->getAttribute( 'type' ) ); # Plesk dump format requires guid, could be empty however, will be fixed with guid fixer before restore $databaseNode->setAttribute( 'guid', '' ); my $version = $cpDatabaseNode->getAttribute( 'version' ); $databaseNode->setAttribute( 'version', $version ) if defined $version; my @cpDbuserNodes = $cpDatabaseNode->getChildren( 'dbuser' ); if (@cpDbuserNodes) { my @dbuserNodes = []; foreach my $cpDbuserNode (@cpDbuserNodes) { my $dbuserNode = XmlNode->new( 'dbuser' ); $dbuserNode->setAttribute( 'name', $cpDbuserNode->getAttribute( 'name' ) ); my $cpDbuserPassword = $cpDbuserNode->getChild( 'password' ); my $dbuserPassword = XmlNode->new( 'password' ); # cPanel password type is 'encrypted' or 'empty'. Both are allowed to be Plesk' password type. No token conversion required. $dbuserPassword->setAttribute( 'type', $cpDbuserPassword->getAttribute( 'type') ); $dbuserPassword->setText( $cpDbuserPassword->getText() ); $dbuserNode->addChild( $dbuserPassword ); my @cpAccesshostNodes = $cpDbuserNode->getChildren( 'accesshost' ); if (@cpAccesshostNodes) { foreach my $cpAccesshostNode (@cpAccesshostNodes) { my $accesshostNode = XmlNode->new( 'accesshost' ); $accesshostNode->setText( $cpAccesshostNode->getText() ); $dbuserNode->addChild( $accesshostNode ); } } $databaseNode->addChild( $dbuserNode ); } } push @databaseNodes, $databaseNode; } if (@databaseNodes) { my $databasesNode = XmlNode->new( 'databases' ); my %databasesMetadata; $databasesMetadata{'domain'} = $cpDomainNode->getAttribute( 'name' ); $databasesNode->setMetadata(\%databasesMetadata); foreach my $databaseNode (@databaseNodes) { $databasesNode->addChild( $databaseNode ); } $domainNode->addChild( $databasesNode ); return $databasesNode; } } return; } sub addDomainuser { my ($domainNode, $cpAccountNode) = @_; unless ( testXmlNodeParam($domainNode, 'domain' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account') ) {return;} # cPanel account (not reseller) that belongs to reseller account should be mapped into Plesk domain user. # So far until only cPanel domains are migrated, no domain users mapping will be performed. return; } sub getPhosting { my ($domainNode, $cpAccountNode) = @_; unless ( testXmlNodeParam($domainNode, 'domain' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account') ) {return;} my $quota; my @cpLimitNodes = $cpAccountNode->getChildren( 'limit' ); if (@cpLimitNodes) { foreach my $cpLimitNode (@cpLimitNodes) { if ( $cpLimitNode->getAttribute( 'name' ) eq 'disk_space' ) { $quota = $cpLimitNode->getText(); last; } } } my $cpDomainNode = $cpAccountNode->getChild( 'domain' ); my $phostingNode = makePhostingAttrs(); $phostingNode->setAttribute( 'www-root', getWwwRootAttribute( $cpDomainNode->getAttribute( 'www_root' ), $cpAccountNode->getAttribute( 'home' )) ); my $cgi_bin_mode = getCgiBinModeAttribute( $cpDomainNode->getAttribute( 'cgi_root' ), $cpDomainNode->getAttribute( 'www_root' ), $cpAccountNode->getAttribute( 'home' )); $phostingNode->setAttribute( 'cgi_bin_mode', $cgi_bin_mode ); my %phostingMetadata; $phostingMetadata{'domain'} = $cpDomainNode->getAttribute( 'name' ); $phostingMetadata{'account'} = $cpAccountNode->getAttribute( 'name' ); $phostingMetadata{'www_root'} = $cpDomainNode->getAttribute( 'www_root' ); $phostingMetadata{'cgi_root'} = $cpDomainNode->getAttribute( 'cgi_root' ); $phostingMetadata{'cgi_bin_mode'} = $cgi_bin_mode; $phostingNode->setMetadata(\%phostingMetadata); my $phostingPreferencesNode = getPhostingPreferences( $cpDomainNode, $cpAccountNode, (my $allowSysUser = 1)); $phostingNode->addChild( $phostingPreferencesNode ); addPhostingLimitsAndPermissions( $phostingNode); addPhostingWebusersAndFtpusers( $phostingNode, $cpDomainNode, $cpAccountNode); addPhostingSubdomains( $phostingNode, $cpDomainNode, $cpAccountNode); return $phostingNode; } sub getPhostingPreferences { my ($cpDomainNode, $cpAccountNode, $allowSysUser) = @_; unless ( testXmlNodeParam($cpDomainNode, 'domain', 'subdomain' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my $account = $cpAccountNode->getAttribute( 'name' ); my $preferencesNode = XmlNode->new( 'preferences' ); my $sysuserNode; if ( $allowSysUser ) { my @cpFtpuserNodes = $cpDomainNode->getChildren( 'ftpuser' ); if (@cpFtpuserNodes) { foreach my $cpFtpuserNode (@cpFtpuserNodes) { next if ( $cpFtpuserNode->getAttribute( 'name' ) ne $account ); $sysuserNode = XmlNode->new( 'sysuser' ); $sysuserNode->setAttribute( 'name', $account ); $sysuserNode->setAttribute( 'quota', $cpFtpuserNode->getAttribute( 'quota' ) ) if ( defined ( $cpFtpuserNode->getAttribute( 'quota' ) ) ); if ( defined ( my $shell = $cpFtpuserNode->getAttribute( 'shell' ) ) ) { if ( $shell eq '/usr/local/cpanel/bin/noshell' ) { $shell = '/bin/false'; } $sysuserNode->setAttribute( 'shell', $shell ); } # sysuser password isn't migrated because of unsupported encryption last; } } unless ( defined ( $sysuserNode ) ) { Logging::error("Unable get ftp user account for domain '" . $cpDomainNode->getAttribute( 'name' ) . "'"); $sysuserNode = XmlNode->new( 'sysuser' ); $sysuserNode->setAttribute( 'name', $account ); } $preferencesNode->addChild( $sysuserNode ); } my $cpAnonftpNode = $cpDomainNode->getChild( 'anonftp' ); if ( defined ( $cpAnonftpNode ) ) { my $anonftpNode = XmlNode->new( 'anonftp' ); if ( defined ($cpAnonftpNode->getAttribute( 'pub' )) and $cpAnonftpNode->getAttribute( 'pub' ) eq 'true' ) { $anonftpNode->setAttribute( 'pub', 'true' ); my $permissionNode = XmlNode->new( 'anonftp-permission' ); $permissionNode->setAttribute( 'name', 'incoming-download' ); $anonftpNode->addChild( $permissionNode ); } if ( defined ($cpAnonftpNode->getAttribute( 'incoming' )) and $cpAnonftpNode->getAttribute( 'incoming' ) eq 'true' ) { $anonftpNode->setAttribute( 'incoming', 'true' ); my $permissionNode = XmlNode->new( 'anonftp-permission' ); $permissionNode->setAttribute( 'name', 'incoming-mkdir' ); $anonftpNode->addChild( $permissionNode ); } $preferencesNode->addChild( $anonftpNode ); } addPhostingPreferencesPdirs( $preferencesNode, $cpDomainNode, $cpAccountNode ); return $preferencesNode; } sub addPhostingLimitsAndPermissions { my ($phostingNode) = @_; unless ( testXmlNodeParam($phostingNode, 'phosting') ) {return;} my $limitsAndPermissionsNode = XmlNode->new( 'limits-and-permissions' ); my $scriptingNode = makeScriptingAll(); $limitsAndPermissionsNode->addChild( $scriptingNode ); $phostingNode->addChild( $limitsAndPermissionsNode ); return $limitsAndPermissionsNode; } sub addPhostingWebusersAndFtpusers { my ($phostingNode, $cpDomainNode, $cpAccountNode) = @_; unless ( testXmlNodeParam($phostingNode, 'phosting' ) ) {return;} unless ( testXmlNodeParam($cpDomainNode, 'domain' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my $account = $cpAccountNode->getAttribute( 'name' ); my @cpFtpuserNodes = $cpDomainNode->getChildren( 'ftpuser' ); my @cpSubdomainNodes = $cpDomainNode->getChildren( 'subdomain' ); if (@cpSubdomainNodes) { foreach my $cpSubdomainNode (@cpSubdomainNodes) { my @cpSubdomFtpuserNodes = $cpSubdomainNode->getChildren( 'ftpuser' ); if ( @cpSubdomFtpuserNodes ) { my @cpLimitNodes = $cpAccountNode->getChildren( 'limit' ); if (@cpLimitNodes) { foreach my $cpLimitNode (@cpLimitNodes) { if ( $cpLimitNode->getAttribute( 'name' ) eq 'max_ftpusers' ) { $cpLimitNode->setText($cpLimitNode->getText() + scalar(@cpSubdomFtpuserNodes)); last; } } } push @cpFtpuserNodes, @cpSubdomFtpuserNodes; } } } if (@cpFtpuserNodes) { my @sysuserNodes; foreach my $cpFtpuserNode (@cpFtpuserNodes) { next if ( $cpFtpuserNode->getAttribute( 'name' ) eq $account ); my $sysuserNode = XmlNode->new( 'sysuser' ); $sysuserNode->setAttribute( 'name', $cpFtpuserNode->getAttribute( 'name' ) ); $sysuserNode->setAttribute( 'home', $cpFtpuserNode->getAttribute( 'directory' ) ) if ( defined ( $cpFtpuserNode->getAttribute( 'directory' ) ) ); $sysuserNode->setAttribute( 'quota', $cpFtpuserNode->getAttribute( 'quota' ) ) if ( defined ( $cpFtpuserNode->getAttribute( 'quota' ) ) ); $sysuserNode->setAttribute( 'shell', $cpFtpuserNode->getAttribute( 'shell' ) ) if ( defined ( $cpFtpuserNode->getAttribute( 'shell' ) ) ); # sysuser password isn't migrated because of unsupported encryption push @sysuserNodes, $sysuserNode; } if ( @sysuserNodes ) { my $ftpusersNode = XmlNode->new( 'ftpusers' ); foreach my $sysuserNode ( @sysuserNodes ) { my $ftpuserNode = XmlNode->new( 'ftpuser' ); $ftpuserNode->setAttribute( 'name', $sysuserNode->getAttribute( 'name' ) ); $ftpuserNode->addChild( $sysuserNode ); $ftpusersNode->addChild( $ftpuserNode ); } $phostingNode->addChild( $ftpusersNode ); } } return $phostingNode; } sub addPhostingSubdomains { my ($phostingNode, $cpDomainNode, $cpAccountNode) = @_; unless ( testXmlNodeParam($phostingNode, 'phosting') ) {return;} unless ( testXmlNodeParam($cpDomainNode, 'domain' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my @cpSubdomainNodes = $cpDomainNode->getChildren( 'subdomain' ); if (@cpSubdomainNodes) { my @subdomainNodes; foreach my $cpSubdomainNode ( @cpSubdomainNodes ) { my @cpAddonDomainNodes = $cpSubdomainNode->getChildren( 'addondomain' ); my $cpFtpuserNode = $cpSubdomainNode->getChild( 'ftpuser' ); if ( ( !defined $cpFtpuserNode ) || ( !@cpAddonDomainNodes ) ) { # Convert cPanel subdomains without addon domains and ftpusers to Plesk subdomains my $subdomainNode = XmlNode->new( 'subdomain' ); $subdomainNode->setAttribute( 'name', $cpSubdomainNode->getAttribute( 'name' ) ); $subdomainNode->setAttribute( 'guid', '' ); $subdomainNode->setAttribute( 'shared-content', 'true' ); $subdomainNode->setAttribute( 'https', 'true'); $subdomainNode->setAttribute( 'www-root', getWwwRootAttribute( $cpSubdomainNode->getAttribute( 'www_root' ), $cpAccountNode->getAttribute( 'home' )) ); my %subdomainMetadata; $subdomainMetadata{'www_root'} = $cpSubdomainNode->getAttribute( 'www_root' ); $subdomainMetadata{'cgi_root'} = $cpSubdomainNode->getAttribute( 'cgi_root' ); $subdomainMetadata{'cgi_bin_mode'} = getCgiBinModeAttribute( $cpSubdomainNode->getAttribute( 'cgi_root' ), $cpSubdomainNode->getAttribute( 'www_root' ), $cpAccountNode->getAttribute( 'home' )); $subdomainNode->setMetadata(\%subdomainMetadata); $subdomainNode->addChild( makeScriptingAll() ); push @subdomainNodes, $subdomainNode; } } if ( @subdomainNodes ) { my $subdomainsNode = XmlNode->new( 'subdomains' ); foreach my $subdomainNode ( @subdomainNodes ) { $subdomainsNode->addChild( $subdomainNode ); } $phostingNode->addChild( $subdomainsNode ); return $subdomainsNode; } } return; } sub addPhostingPreferencesPdirs { my ($preferencesNode, $cpDomainNode, $cpAccountNode) = @_; unless ( testXmlNodeParam($preferencesNode, 'preferences' ) ) {return;} unless ( testXmlNodeParam($cpDomainNode, 'domain', 'subdomain' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my $cpAccountDomainNode = $cpAccountNode->getChild( 'domain' ); my $accountHome = $cpAccountNode->getAttribute( 'home' ); my @cpPdirNodes = $cpAccountDomainNode->getChildren( 'pdir' ); if (@cpPdirNodes) { foreach my $cpPdirNode (@cpPdirNodes) { my $path = $cpPdirNode->getAttribute( 'name' ); my $name; my $type; my $www_relative = HelpFuncs::getRelativePath( $cpDomainNode->getAttribute( 'www_root' ), $accountHome ); if ( defined $www_relative ) { if ( $path eq $www_relative ) { $name = '/'; } else { $name = HelpFuncs::getRelativePath( $path, $www_relative ); } } if ( defined $name ) { $type = 'nonssl'; } else { my $cgi_relative = HelpFuncs::getRelativePath( $cpDomainNode->getAttribute( 'cgi_root' ), $accountHome ); if ( defined $cgi_relative) { if ( $path eq $cgi_relative ) { $name = '/'; } else { $name = HelpFuncs::getRelativePath( $path, $cgi_relative ); } if ( defined $name ) { $type = 'cgi'; } } } if ( defined $name ) { my $pdirNode = XmlNode->new( 'pdir' ); $pdirNode->setAttribute( 'name', $name ); my $title = $cpPdirNode->getAttribute( 'title' ); $pdirNode->setAttribute( 'title', $title ) if ( defined $title ); $pdirNode->setAttribute( $type, 'true' ); my @cpPduserNodes = $cpPdirNode->getChildren( 'pduser' ); if (@cpPduserNodes) { foreach my $cpPduserNode (@cpPduserNodes) { my $pduserNode = XmlNode->new( 'pduser' ); $pduserNode->setAttribute( 'name', $cpPduserNode->getAttribute( 'name' ) ); my $password = $cpPduserNode->getAttribute( 'password' ); if ( defined ($password) ) { my $passwordNode = XmlNode->new( 'password' ); $passwordNode->setAttribute( 'type', 'encrypted' ); my $encoding = $cpPduserNode->getAttribute( 'encoding' ); $passwordNode->setAttribute( 'encoding', $encoding ) if defined ( $encoding ); $passwordNode->setText( $password ); $pduserNode->addChild( $passwordNode ); } $pdirNode->addChild( $pduserNode ); } } $preferencesNode->addChild( $pdirNode ); } } } return $preferencesNode; } sub getWwwRootAttribute { my ($wwwRootDir, $homeDir) = @_; my $wwwRootAttribute = HelpFuncs::getRelativePath( $wwwRootDir, $homeDir ); if ( defined $wwwRootAttribute ) { return $wwwRootAttribute; } else { Logging::warning("Couldn't get 'www-root' attribute for domain where docroot dir '$wwwRootDir' is out of user webspace. ". "Domain's docroot will be migrated into '$wwwRootDir' directory under webspace."); return $wwwRootDir; } } sub getCgiBinModeAttribute { my ($scriptAliasDir, $wwwRootDir, $homeDir) = @_; if ( $scriptAliasDir =~ /^($wwwRootDir)\/*cgi-bin$/ ) { return 'www-root'; } if ( $scriptAliasDir =~ /^($homeDir)\/*cgi-bin$/ ) { return 'webspace'; } else { Logging::warning("Couldn't get 'cgi_bin_mode' attribute for domain where cgi-bin dir is '$scriptAliasDir' and docroot dir is '$wwwRootDir'. ". "Domain will be migrated in that way as if its cgi-bin directory was located under docroot."); return 'www-root'; } } sub processSubdomain2Phosting { my ($domainFromSubdomainNode, $cpSubdomainNode, $cpDomainNode, $cpAccountNode) = @_; unless ( testXmlNodeParam($domainFromSubdomainNode, 'site' ) ) {return;} unless ( testXmlNodeParam($cpSubdomainNode, 'subdomain') ) {return;} unless ( testXmlNodeParam($cpDomainNode, 'domain' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my $domainName = $domainFromSubdomainNode->getAttribute( 'name' ); # Get domain preferences (aliases only) my $domainPreferencesNode = XmlNode->new( 'preferences' ); my @aliases; my @cpSubdomainAddondomainNodes = $cpSubdomainNode->getChildren( 'addondomain' ); # At least one addondomain should always exist, because addondomain is required for subdomain-to-domain conversion foreach my $cpSubdomainAddondomainNode ( @cpSubdomainAddondomainNodes ) { next if ( $cpSubdomainAddondomainNode->getAttribute('name') eq $domainName ); push @aliases, $cpSubdomainAddondomainNode->getAttribute('name'); } my $subdomainName = ($cpSubdomainNode->getAttribute( 'name' )).'.'.($cpDomainNode->getAttribute( 'name' )); push @aliases, $subdomainName; for my $alias ( @aliases ) { my $domainAliasNode = XmlNode->new( 'domain-alias' ); $domainAliasNode->setAttribute( 'name', $alias ); $domainAliasNode->setAttribute( 'mail', 'true'); $domainAliasNode->setAttribute( 'web', 'true'); $domainAliasNode->addChild( makeStatusEnabled() ); $domainPreferencesNode->addChild( $domainAliasNode ); } $domainFromSubdomainNode->addChild( $domainPreferencesNode ); # Get domain properties (ip and status only) my $domainPropertiesNode = getDomainProperties($cpAccountNode, 'skipIpNode' ); $domainFromSubdomainNode->addChild( $domainPropertiesNode ); addSubdomainMailsystem( $domainFromSubdomainNode, $cpSubdomainNode, $cpAccountNode ); my $phostingNode = makePhostingAttrs(); $phostingNode->setAttribute( 'www-root' , getWwwRootAttribute($cpSubdomainNode->getAttribute( 'www_root' ), $cpAccountNode->getAttribute( 'home' ) ) ); my $cgi_bin_mode = getCgiBinModeAttribute( $cpSubdomainNode->getAttribute( 'cgi_root' ), $cpSubdomainNode->getAttribute( 'www_root' ), $cpAccountNode->getAttribute( 'home' )); $phostingNode->setAttribute( 'cgi_bin_mode', $cgi_bin_mode ); my %phostingMetadata; $phostingMetadata{'domain'} = $cpDomainNode->getAttribute( 'name' ); $phostingMetadata{'account'} = $cpAccountNode->getAttribute( 'name' ); $phostingMetadata{'from_subdomain'} = $cpSubdomainNode->getAttribute( 'name' ); $phostingMetadata{'to_domain'} = $domainName; $phostingMetadata{'www_root'} = $cpSubdomainNode->getAttribute( 'www_root' ); $phostingMetadata{'cgi_root'} = $cpSubdomainNode->getAttribute( 'cgi_root' ); $phostingMetadata{'cgi_bin_mode'} = $cgi_bin_mode; $phostingNode->setMetadata(\%phostingMetadata); my $preferencesNode = getPhostingPreferences( $cpSubdomainNode, $cpAccountNode, (my $allowSysUser = 0) ); $phostingNode->addChild( $preferencesNode ); addPhostingLimitsAndPermissions($phostingNode); $domainFromSubdomainNode->addChild( $phostingNode ); return $phostingNode; } sub processSubdomain2Shosting { my ($domainFromSubdomainNode, $cpSubdomainNode, $cpDomainNode, $cpAccountNode) = @_; unless ( testXmlNodeParam($domainFromSubdomainNode, 'site' ) ) {return;} unless ( testXmlNodeParam($cpSubdomainNode, 'subdomain') ) {return;} unless ( testXmlNodeParam($cpDomainNode, 'domain' ) ) {return;} unless ( testXmlNodeParam($cpAccountNode, 'account' ) ) {return;} my $domainName = $cpDomainNode->getAttribute( 'name' ); my $domainPreferencesNode = XmlNode->new( 'preferences' ); $domainFromSubdomainNode->addChild( $domainPreferencesNode ); # Get domain properties (ip and status only) my $domainPropertiesNode = getDomainProperties($cpAccountNode, 'skipIpNode'); $domainFromSubdomainNode->addChild( $domainPropertiesNode ); $domainFromSubdomainNode->addChild( makeZeroDomainLimitsAndPermissions() ); my $shostingNode = XmlNode->new( 'shosting' ); my $urlNode = XmlNode->new( 'url' ); my $subdomainName = $cpSubdomainNode->getAttribute( 'name' ); $urlNode->setText( $subdomainName.".".$domainName); $shostingNode->addChild( $urlNode ); $domainFromSubdomainNode->addChild( $shostingNode ); $domainFromSubdomainNode->addChild( $shostingNode ); return $shostingNode; } # # End of node transformation subs # sub _convertMailnameToExcludeName { my ( $mailname, $domain ) = @_; $domain =~ tr/\./_/; return ".$mailname@".$domain; } sub _addDefaultMailboxExcludesFromMail { my ( $cpMailNode, $excludesPtr ) = @_; unless ( testXmlNodeParam($cpMailNode, 'mail' ) ) {return;} unless ( ref($excludesPtr) =~ /ARRAY/ ) {return;} my @cpMailnameNodes = $cpMailNode->getChildren( 'mailname' ); if ( @cpMailnameNodes ) { foreach my $cpMailnameNode ( @cpMailnameNodes ) { push @{$excludesPtr}, _convertMailnameToExcludeName( $cpMailnameNode->getAttribute('name'), $cpMailnameNode->getAttribute('domainname')); } } } sub _addDefaultMailboxExcludesFromAddon { my ( $cpAddonDomainNode, $excludesPtr ) = @_; unless ( testXmlNodeParam($cpAddonDomainNode, 'addondomain' ) ) {return;} unless ( ref($excludesPtr) =~ /ARRAY/ ) {return;} my $addondomainName = $cpAddonDomainNode->getAttribute( 'name' ); push @{$excludesPtr}, $addondomainName; my $cpMailNode = $cpAddonDomainNode->getChild( 'mail' ); if ( $cpMailNode ) { _addDefaultMailboxExcludesFromMail( $cpMailNode, $excludesPtr); } } sub _addDefaultMailboxExcludesFromSubdom { my ( $cpDomainName, $cpSubdomainNode, $excludesPtr ) = @_; unless ( testXmlNodeParam($cpSubdomainNode, 'subdomain' ) ) {return;} unless ( ref($excludesPtr) =~ /ARRAY/ ) {return;} my $subdomainName = $cpSubdomainNode->getAttribute( 'name' ); push @{$excludesPtr}, "$subdomainName.$cpDomainName"; my @cpAddonDomainNodes = $cpSubdomainNode->getChildren( 'addondomain' ); if( @cpAddonDomainNodes ) { foreach my $cpAddonDomainNode ( @cpAddonDomainNodes ) { _addDefaultMailboxExcludesFromAddon( $cpAddonDomainNode, $excludesPtr); } } my $cpMailNode = $cpSubdomainNode->getChild( 'mail' ); if ( $cpMailNode ) { _addDefaultMailboxExcludesFromMail( $cpMailNode, $excludesPtr); } } sub _getDefaultMailboxExcludes { my ( $cpDomainNode ) = @_; unless ( testXmlNodeParam($cpDomainNode, 'domain' ) ) {return;} my $domainName = $cpDomainNode->getAttribute( 'name' ); my @excludes; push @excludes, $domainName; my @cpSubdomainNodes = $cpDomainNode->getChildren( 'subdomain' ); if( @cpSubdomainNodes ) { foreach my $cpSubdomainNode ( @cpSubdomainNodes ) { _addDefaultMailboxExcludesFromSubdom( $domainName, $cpSubdomainNode, \@excludes ); } } my @cpAddonDomainNodes = $cpDomainNode->getChildren( 'addondomain' ); if( @cpAddonDomainNodes ) { foreach my $cpAddonDomainNode ( @cpAddonDomainNodes ) { _addDefaultMailboxExcludesFromAddon( $cpAddonDomainNode, \@excludes); } } my $cpMailNode = $cpDomainNode->getChild( 'mail' ); if ( $cpMailNode ) { _addDefaultMailboxExcludesFromMail( $cpMailNode, \@excludes); } return \@excludes; } # # Begin static content getters # sub makeStatusEnabled { my $nodeName = shift || 'status'; my $statusEnabledNode = XmlNode->new( $nodeName ); $statusEnabledNode->addChild( XmlNode->new( 'enabled' ) ); return $statusEnabledNode; } sub makeStatusDisabledBy { my $nodeName = shift || 'status'; my $name = shift || 'admin'; my $statusNode = XmlNode->new( $nodeName ); $statusNode->addChild( XmlNode->new( 'disabled-by', 'attributes' => { 'name' => $name } ) ); return $statusNode; } sub makeScriptingAll { my $scriptingNode = XmlNode->new( 'scripting' ); $scriptingNode->setAttribute( 'ssi', 'true' ); $scriptingNode->setAttribute( 'php', 'true' ); $scriptingNode->setAttribute( 'cgi', 'true' ); $scriptingNode->setAttribute( 'perl', 'true' ); $scriptingNode->setAttribute( 'python', 'true' ); return $scriptingNode; } sub makePhostingAttrs { my $phostingNode = XmlNode->new( 'phosting' ); $phostingNode->setAttribute( 'wu_script', 'true' ); $phostingNode->setAttribute( 'guid', '' ); $phostingNode->setAttribute( 'https', 'true' ); $phostingNode->setAttribute( 'fp', 'true' ); $phostingNode->setAttribute( 'fpssl', 'true' ); $phostingNode->setAttribute( 'fpauth', 'true' ); $phostingNode->setAttribute( 'webstat', 'true' ); $phostingNode->setAttribute( 'errdocs', 'true' ); $phostingNode->setAttribute( 'shared-content', 'true' ); return $phostingNode; } sub makeZeroDomainLimitsAndPermissions { my $limitsAndPermissionsNode = XmlNode->new( 'limits-and-permissions' ); $limitsAndPermissionsNode->addChild( 'limit', 'content' => '0', 'attributes' => { 'name' => 'max_traffic' } ); $limitsAndPermissionsNode->addChild( 'limit', 'content' => '0', 'attributes' => { 'name' => 'max_maillists' } ); $limitsAndPermissionsNode->addChild( 'limit', 'content' => '0', 'attributes' => { 'name' => 'max_box' } ); $limitsAndPermissionsNode->addChild( 'limit', 'content' => '0', 'attributes' => { 'name' => 'max_db' } ); $limitsAndPermissionsNode->addChild( 'limit', 'content' => '0', 'attributes' => { 'name' => 'max_subdom' } ); $limitsAndPermissionsNode->addChild( 'limit', 'content' => '51200', 'attributes' => { 'name' => 'disk_space' } ); $limitsAndPermissionsNode->addChild( 'limit', 'content' => '0', 'attributes' => { 'name' => 'max_wu' } ); return $limitsAndPermissionsNode; } # # End of static content getters # # # Begin miscellanneous subs # sub testXmlNodeParam { my $param = shift; my @testarray = @_; my @caller = caller(1); unless ( ref($param) =~ /XmlNode/ ) { Logging::error('XmlNode instance is required, got \''. ( defined (ref($param))? ref($param) : 'undef' ). '\' in '. $caller[3] .' called at '. $caller[1] .' ,line '. $caller[2] ); return; } my $name = $param->getName(); foreach my $testname ( @testarray ) { if( $name eq $testname ) { return 1; } } Logging::error( 'One of \'' . "@testarray" . '\' XmlNode is required, got \'' . $name . '\' in '. $caller[3] .' called at '. $caller[1] .' ,line '. $caller[2] ); return; } # # End of miscellanneous subs # 1;