#!/usr/bin/perl
# cpanel12 - register_transfer                    Copyright(c) 2008 cPanel, Inc.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
# $Desc: v3.0.0-274-g545221d$

BEGIN {
    unshift @INC, '/usr/local/cpanel', '/scripts';
}

use strict;
use warnings;

use Cwd 'getcwd';
use Carp 'carp', 'croak';
use Cpanel::AcctUtils ();
use Cpanel::FileUtils ();
use Getopt::Long;
use Cpanel::CPAN::Net::FTP::Recursive;
use Expect;

use constant {
    HOST         => 0,
    SSH_PORT     => 1,
    LOGIN_USER   => 2,
    FTP_PORT     => 3,
    REMOTE_USER  => 4,
    LOCAL_USER   => 5,
    DEDICATED_IP => 6,
    DOMAIN_NAME  => 7,
    PASSWD       => 8,
    PACKAGE      => 9,
    OWNER        => 10,
    CUSTOMIP     => 11,
    ZAP          => 12,
};

my $lock_file = '/var/cpanel/register_transfer.lock';

local $SIG{'__DIE__'} = sub {
    remove_lockfile($lock_file);
};

my $file;
my $verbose = 0;
GetOptions( 'f|file=s', \$file, "verbose|v" => \$verbose );

my $accounts = accounts($file);

lock_process($lock_file);

foreach my $account ( @{$accounts} ) {
    my $host         = $account->[HOST];
    my $port         = $account->[SSH_PORT] || $account->[FTP_PORT];
    my $login_user   = $account->[LOGIN_USER];
    my $remote_user  = $account->[REMOTE_USER] || $login_user;
    my $local_user   = $account->[LOCAL_USER] || $remote_user;
    my $dedecated_ip = ( $account->[DEDICATED_IP] ) ? 'y' : 'n';
    my $dns          = $account->[DOMAIN_NAME];
    my $passwd       = $account->[PASSWD];
    my $package      = $account->[PACKAGE] || 'Professional';
    my $owner        = $account->[OWNER] || 'emadmin';
    my $customip     = $account->[CUSTOMIP] || undef;
    my $zap          = $account->[ZAP] || 0;

    if ( Cpanel::AcctUtils::accountexists($local_user) ) {
        warn "Sorry, the user '$local_user' already exists on this system.\n" if $verbose;
        next;
    }

    print 'Copying user: ' . $local_user . "\n" if $verbose;
    if ( $account->[SSH_PORT] ) {
        fork_code( { 'code' => \&scp, 'wait' => 1, verbose => $verbose, args => [ $host, $port, $login_user, $remote_user, $local_user, $dedecated_ip, $dns, $passwd, $package, $owner, $customip, $zap ] } );
    }
    elsif ( $account->[FTP_PORT] ) {
        fork_code( { 'code' => \&ftp, 'wait' => 1, verbose => $verbose, args => [ $host, $port, $login_user, $remote_user, $local_user, $dedecated_ip, $dns, $passwd, $package, $owner, $customip, $zap ] } );
    }
    print 'Done.' . "\n" if $verbose;
    sleep 2;

}

remove_lockfile($lock_file);

### subs

sub ftp {
    my ( $host, $port, $loginuser, $remote_user, $local_user, $dedecated_ip, $dns, $passwd, $package, $owner, $customip, $zap ) = @_;

    $customip = "--with-customip=$customip" if $customip;

    my $local_dir = "/home/$local_user" . '.' . $$ . '/';
    my $ftp = Cpanel::CPAN::Net::FTP::Recursive->new( $host, Passive => 1, Debug => 0 );
    $ftp->login( $loginuser, $passwd );

    my $pwd = getcwd();
    mkdir($local_dir);
    chdir($local_dir);

    $ftp->rget('public');

    chdir($pwd);

    if ( -e $local_dir ) {

        if ($zap) {
            system( '/scripts/killacct', $local_user, 'y' );
        }

        local $ENV{'PKGRESTORE'} = 1;
        system( '/scripts/wwwacct', $customip, $dns, $local_user, $passwd, '0', 'x3', $dedecated_ip, 'y', 'y', 'n', 'n', 'n', 'n', 'n', '0', 'y', $owner, $package, '0', '0', $package );
        sleep 2;

        system( 'chown', '-R', $local_user . ':' . $local_user, $local_dir );
        system( 'chmod', '-R', '644', $local_dir );
        chdir($local_dir);
        system("tar -c . | tar -C /home/$local_user/public_html -x");
        system( 'chmod', '-R', '644', "/home/$local_user/public_html" );
        system( 'rm', '-rf', $local_dir ) if -e $local_dir;
    }
    else {
        carp 'Downloaded public directory not found';
        exit(1);
    }

}

sub scp {
    my ( $host, $port, $loginuser, $remote_user, $local_user, $dedecated_ip, $dns, $passwd, $package, $owner, $customip, $zap ) = @_;

    $customip = "--with-customip=$customip" if $customip;

    my $remote = $loginuser . '@' . $host . ':/public';
    my $local  = "/home/$local_user" . '.' . $$;

    my $exp = Expect->spawn( '/usr/bin/scp', '-r', $remote, $local )
      or die "Cannot spawn /usr/bin/scp: $!\n";

    $exp->expect(
        300,
        [
            qr/\(yes\/no\)\?/ => sub {
                my $exp = shift;
                $exp->send("yes\n");
                exp_continue;
              }
        ],
        [
            qr/password:/ => sub {
                my $exp = shift;
                $exp->send("$passwd\n");
              }
        ],
    );

    $exp->soft_close();

    if ( -e $local ) {
        if ($zap) {
            system( '/scripts/killacct', $local_user, 'y' );
        }

        local $ENV{'PKGRESTORE'} = 1;
        system( '/scripts/wwwacct', $customip, $dns, $local_user, $passwd, '0', 'x3', $dedecated_ip, 'y', 'y', 'n', 'n', 'n', 'n', 'n', '0', 'y', $owner, $package, '0', '0', $package );
        sleep 2;

        system( 'chown', '-R', $local_user . ':' . $local_user, $local );
        system( 'chmod', '-R', '644', $local );
        chdir($local);
        system("tar -c . | tar -C /home/$local_user/public_html -x");
        system( 'chmod', '-R', '644', "/home/$local_user/public_html" );
        system( 'rm', '-rf', $local ) if -e $local;
    }
    else {
        carp 'Downloaded public directory not found';
        exit(1);
    }
}

sub accounts {
    my $csv_file = shift || '/var/cpanel/transfer.csv';

    if ( -e $csv_file ) {

        my @accounts;
        if ( open( my $csv_h, '<', $csv_file ) ) {
            while ( my $line = <$csv_h> ) {
                chomp $line;
                next if !$line;
                next if $line =~ /^#/;
                my @items = split ',', $line;
                push @accounts, \@items;
            }
            close $csv_h;
        }
        chomp @accounts;
        return \@accounts;
    }
    else {
        croak 'File not found: ' . $csv_file . "\n";
    }
}

sub lock_process {
    my ($lockfile) = @_;
    if ( -e $lockfile ) {
        carp 'Process already running' . "\n";
        exit(1);
    }
    else {
        Cpanel::FileUtils::touchfile($lockfile);
    }
}

sub remove_lockfile {
    my ($lockfile) = @_;
    if ( -e $lockfile ) {
        system( 'rm', $lockfile );
    }
}

sub fork_code {
    my ($args) = @_;
    if ( ref( $args->{'code'} ) ne 'CODE' ) {
        print 'Argument not a code ref' . "\n";
        exit(1);
    }

    if ( ( exists $args->{'args'} ) && ( ref $args->{'args'} ne 'ARRAY' ) ) {
        print 'args must be an array ref.' . "\n";
        exit(1);
    }

    my $code    = $args->{'code'};
    my $verbose = $args->{'verbose'};
    my $wait    = $args->{'wait'} == 1 ? 1 : 0;
    my @args    = exists $args->{'args'} ? @{ $args->{'args'} } : ();

    my $pid;
    if ( $pid = fork() ) {
        my $dotcount = 5;
        if ($wait) {
            while ( waitpid( $pid, 1 ) != -1 ) {
                if ( $dotcount % 5 == 0 ) {
                    print "\t" . ".........\n" if $verbose;
                }
                sleep(1);
                $dotcount++;
            }
        }
    }
    else {
        open( STDIN,  '<', '/dev/null' );
        open( STDOUT, '>', '/dev/null' );
        open( STDERR, '>', '/dev/null' );

        $code->(@args);
        exit;
    }
}

=pod

=head1 SCRIPT OPTIONS:

=over 4

=item -f full path to csv file

=item -v output during transfer

=back

=head1 CSV FILE LOCATION:

    The default is /var/cpanel/transfer.csv
    but it can be specified by the -f option

=head1 CSV FILE FORMAT:

    HOST,SSH_PORT,LOGIN_USER,FTP_PORT,REMOTE_USER,LOCAL_USER,DEDICATED_IP,DOMAIN_NAME,PASSWORD,PACKAGE,OWNER,CUSTOMIP,ZAP

=over 4

=item HOST: required, the remote host

=item SSH_PORT: optional, default 22

=item LOGIN_USER: required, the user that will be used to login to the SSH/FTP account

=item FTP_PORT: optional, default 21

=item REMOTE_USER: optional, the use that to be transferred, default LOGIN_USER

=item LOCAL_USER: optional, the name of the cpanel user to be created, default LOGIN_USER

=item DEDICATED_IP: required, 1 or 0

=item DOMAIN_NAME: required

=item PASSWORD: required

=item PACKAGE: required, default 'Professional'

=item OWNER: required, default 'emadmin'

=item CUSTOMIP: optional

=item ZAP: optional, default 0

=back

=cut
