#!/usr/bin/perl -w
# This script (sophomorix-transfer) is maintained by Rüdiger Beck
# It is Free Software (License GPLv3)
# If you find errors, contact the author
# jeffbeck@web.de  or  jeffbeck@linuxmuster.net

# modules
use strict;
#use Quota;
use Getopt::Long;
Getopt::Long::Configure ("bundling");
use Sophomorix::SophomorixConfig;
use List::MoreUtils qw(uniq);
use String::Approx 'amatch';
use String::Approx 'adist';
use Net::LDAP;
use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Useqq = 1;
$Data::Dumper::Terse = 1; 
use JSON;
use File::Temp qw/ tempdir /;
use File::Basename qw( basename
                       dirname
                     ); 
use Text::Iconv;
use Sophomorix::SophomorixBase qw(
                                 print_line
                                 print_title
                                 unlock_sophomorix
                                 lock_sophomorix
                                 log_script_start
                                 log_script_end
                                 log_script_exit
                                 result_sophomorix_add_log
                                 backup_auk_file
                                 get_passwd_charlist
                                 get_plain_password
                                 check_options
                                 config_sophomorix_read
                                 result_sophomorix_init
                                 result_sophomorix_add
                                 result_sophomorix_check_exit
                                 result_sophomorix_print
                                 filelist_fetch
                                 remove_whitespace
                                 json_dump
                                 recode_utf8_to_ascii
                                 remove_from_list
                                 smbclient_dirlist
                                 );
use Sophomorix::SophomorixSambaAD qw(
                                 AD_get_unicodepwd
                                 AD_set_unicodepwd
                                 AD_school_create
                                 AD_bind_admin
                                 AD_unbind_admin
                                 AD_session_manage
                                 AD_user_create
                                 AD_user_kill
                                 AD_group_create
                                 AD_group_addmember
                                 AD_group_update
                                 AD_get_schoolname
                                 AD_get_name_tokened
                                 AD_dn_fetch_multivalue
                                 AD_get_sessions
                                 AD_get_user
                                 AD_dns_get
                                 AD_object_search
                                 AD_get_passwd
                                    );

my @arguments = @ARGV;

# option vars
$Conf::log_level=1;

my $debug_level=0; # for smbclient --debuglevel=$debug_level

my $help=0;
my $info=0;
my $json=0;

my $scopy=0;
my $move=0;
my $from_path="";
my $to_path="";
my $to_path_addon="";
my $no_target_directory=0;
my $keep_source_directory=0;

my $from_unix_path="";
my $to_user="";
my $subdir;

# collect
my $collect_copy=0;
my $collect_move=0;
my $from_user="";
my $file_list="";

my $collect_copy_exam="";
my $copy_account_data=0;

my $clean_transfer_dir="";
my $clean_home_dir="";
my $list_home_dir="";

# Parsen der Optionen
my $testopt=GetOptions(
           "help|h" => \$help,
           "info|i" => \$info,
           "json|j+" => \$json,
           "from-unix-path=s" => \$from_unix_path,
           "scopy" => \$scopy,
           "move" => \$move,
           "from-path=s" => \$from_path,
           "to-path=s" => \$to_path,
           "to-path-addon=s" => \$to_path_addon,
           "to-user=s" => \$to_user,
           "from-user=s" => \$from_user,
           "subdir=s" => \$subdir,
           "no-target-directory|T" => \$no_target_directory,
           "keep-source-directory" => \$keep_source_directory,
           "file-list=s" => \$file_list,
           "collect-copy" => \$collect_copy,
           "collect-move" => \$collect_move,
           "collect-copy-exam=s" => \$collect_copy_exam,
           "copy-account-data" => \$copy_account_data,
           "clean-transfer-dir=s" => \$clean_transfer_dir,
           "clean-home-dir=s" => \$clean_home_dir,
           "list-home-dir=s" => \$list_home_dir,
           "debug-level" => \$debug_level,
           "verbose|v+" => \$Conf::log_level,
          );


if ($to_path_addon eq "" or
    $to_path_addon eq "login" or
    $to_path_addon eq "fullinfo" or
    $to_path_addon eq "fullinfo-utf8" 
#    $to_path_addon eq "fullinfo-utf8-alt"
    ) {
    # OK
} else {
    print "\nERROR: Unknown option: --to-path-addon $to_path_addon\n\n";
    exit;
}

my %sophomorix_result=&result_sophomorix_init("sophomorix-transfer");
# Prüfen, ob Optionen erkannt wurden, sonst Abbruch
&check_options($testopt,\%sophomorix_result,$json);

# Reading Configuration
my ($ldap,$root_dse) = &AD_bind_admin(\@arguments,\%sophomorix_result,$json);
my $root_dns=&AD_dns_get($root_dse);
my %sophomorix_config=&config_sophomorix_read($ldap,$root_dse,\%sophomorix_result);
my ($smb_admin_pass)=&AD_get_passwd($DevelConf::sophomorix_file_admin,
                                     $DevelConf::secret_file_sophomorix_file_admin);

# --help
if ($help==1) {
   # Scriptname ermitteln
   my @list = split(/\//,$0);
   my $scriptname = pop @list;
   # Befehlsbeschreibung
   print('
sophomorix-transfer copies/moves files from/to school-shares

Options:
  -h  / --help
  -v  / --verbose
  -vv / --verbose --verbose
  -i  / --info
  --debug-level  (debug level for smbclient)


# serverside copy (universal recursive cp command)
  # overwrite dirs/files as the unix cp command would do (parent dirs are created like: mkdir -p)
    sophomorix-transfer --scopy --from-user <from1>,... --from-path <fpath> --to-user <to2>,... --to-path <tpath>
    sophomorix-transfer --move  --from-user <from1>,... --from-path <fpath> --to-user <to2>,... --to-path <tpath>
  
    if <to2> ends with a /, i.e. "dir/" the source is copied INTO "dir"
    if <to2> ends not with a /, i.e. "file" the source (must be a file) is copied OVER/TO "file"

  # modifiers
    --no-target-directory   (cp contents of source directory only, but not directory itself)
    --keep-source-directory (do NOT delete source directory, when recursively moving a directory)
    --to-path-addon login|fullinfo|fullinfo-utf8

# share data
  sophomorix-transfer --from-unix-path /srv/upload/... --to-user <user1>,<user2>-exam, ... --subdir <dir>


# collect data

  # collect some files
  sophomorix-transfer --collect-copy --from-user <user1> --to-user <user2> --file transfer/<file1>,transfer/<dir1>
  sophomorix-transfer --collect-move --from-user <user1> --to-user <user2> --file transfer/<file1>,transfer/<dir1>

  # collect transfer directory
  sophomorix-transfer --collect-copy --from-user <user1> --to-user <user2> --file transfer
  sophomorix-transfer --collect-move --from-user <user1> --to-user <user2> --file transfer

  # collect from exam-account regularly
  sophomorix-transfer --collect-copy-exam <user-exam> --subdir <transfer/session-name>
  (--subdir is the relative path in the homedirectory of sophomorixExam user)
  (--subdir is optional, if omitted <date>-nosession is used)


# list data
  sophomorix-transfer --list-home-dir <user1>,<user2>-exam, ... --subdir <dir>


# clean data
  sophomorix-transfer --clean-home-dir <user1>,<user2>-exam, ...
  sophomorix-transfer --clean-transfer-dir <user1>,<user2>-exam, ...

 
Please see the sophomorix-transfer(8) man pages for full documentation
');
   print "\n";
   exit;
}

# --info
if ($info==1) {
    print "\nNothing yet to be done\n\n";

}



&result_sophomorix_check_exit(\%sophomorix_result,\%sophomorix_config,$json);
################################################################################
# Start
################################################################################
&log_script_start(\@arguments,\%sophomorix_result,\%sophomorix_config);



# --scopy --from-user <user1> --from-path <fpath> --to-user <user2> --to-path <tpath>
if (($scopy==1 or $move==1) and $from_user ne "" and $to_user ne ""){
    &print_title("Copying/Moving ...");
    print "   * From user:     $from_user    $from_path \n";
    print "   * To user:       $to_user      $to_path\n";
    print "   * To user addon: $to_path_addon\n";

    &smbclient_scopy_recurse({ldap=>$ldap,
                             root_dse=>$root_dse,
                             root_dns=>$root_dns,
                             scopy=>$scopy,
                             move=>$move,
                             smb_admin_pass=>$smb_admin_pass,
                             from_user=>$from_user,
                             from_path=>$from_path,
                             to_user=>$to_user,
                             to_path=>$to_path,
                             to_path_addon=>$to_path_addon,
                             json=>$json,
                             arguments=>\@arguments,
                             sophomorix_config=>\%sophomorix_config,
                             sophomorix_result=>\%sophomorix_result,
                           });
    exit;
}



# --from-unix-path /srv/upload/... --to-user <user1>,<user2>-exam, ...
if ($from_unix_path ne "" and $to_user ne ""){
    &print_title("Copying ...");
    print "   * From:     $from_unix_path\n";
    print "   * To users: $to_user\n";
    # create mput commands
    my $transfer=$sophomorix_config{'INI'}{'LANG.FILESYSTEM'}{'TRANSFER_DIR_HOME_'.
                 $sophomorix_config{'GLOBAL'}{'LANG'}};
    my $subdir_mput;
    if (defined $subdir){
        $subdir_mput=$subdir;
    } else {
        $subdir_mput=$transfer;
    }

    &smbclient_mput_recurse({ldap=>$ldap,
                             root_dse=>$root_dse,
                             root_dns=>$root_dns,
                             smb_admin_pass=>$smb_admin_pass,
                             localdir=>$from_unix_path,
                             target_subdir=>$subdir_mput,
                             userstring=>$to_user,
                             json=>$json,
                             sophomorix_config=>\%sophomorix_config,
                             sophomorix_result=>\%sophomorix_result,
                           });
    exit;
} 



# --clean-transfer-dir
if ($clean_transfer_dir ne ""){
    &print_title("Cleaning transfer dir of $clean_transfer_dir");
    &clean_transfer_dir({ldap=>$ldap,
                         root_dse=>$root_dse,
                         root_dns=>$root_dns,
                         smb_admin_pass=>$smb_admin_pass,
                         userstring=>$clean_transfer_dir,
                         json=>$json,
                         sophomorix_config=>\%sophomorix_config,
                         sophomorix_result=>\%sophomorix_result,
                       });
    exit;
}



# --clean-home-dir
if ($clean_home_dir ne ""){
    if (defined $subdir){
        &print_title("Cleaning homedir of $clean_home_dir (subdir $subdir)");
    } else {
        &print_title("Cleaning homedir of $clean_home_dir");
    }
    &clean_home_without_transfer({ldap=>$ldap,
                                  root_dse=>$root_dse,
                                  root_dns=>$root_dns,
                                  smb_admin_pass=>$smb_admin_pass,
                                  userstring=>$clean_home_dir,
                                  subdir=>$subdir,
                                  json=>$json,
                                  sophomorix_config=>\%sophomorix_config,
                                  sophomorix_result=>\%sophomorix_result,
                                });
    &clean_transfer_dir({ldap=>$ldap,
                         root_dse=>$root_dse,
                         root_dns=>$root_dns,
                         smb_admin_pass=>$smb_admin_pass,
                         userstring=>$clean_home_dir,
                         json=>$json,
                         sophomorix_config=>\%sophomorix_config,
                         sophomorix_result=>\%sophomorix_result,
                       });
    exit;
}


# --list-home-dir
if ($list_home_dir ne ""){
    my %dirlist=();
    my $ref_dirlist=\%dirlist;
    #my $ref_dirlist;
    my @users=split(/,/,$list_home_dir);

    my $parallel=0; # switch parallel listing on=1/off=0
    if ($parallel==0){
        foreach my $user (@users){
            if (defined $subdir){
                &print_title("Listing homedir of $user (subdir $subdir)");
            } else {
                &print_title("Listing homedir of $user");
            }

            my ($firstname_utf8_AD,$lastname_utf8_AD,$adminclass_AD,$existing_AD,$exammode_AD,$role_AD,
                $home_directory_AD,$user_account_control_AD,$toleration_date_AD,
                $deactivation_date_AD,$school_AD,$status_AD,$firstpassword_AD,$unid_AD)=
                &Sophomorix::SophomorixSambaAD::AD_get_user({ldap=>$ldap,
                                                             root_dse=>$root_dse,
                                                             root_dns=>$root_dns,
                                                             user=>$user,
                                                            });

            my $ref_tree=&smbclient_dirlist({sharename=>$school_AD,
                                             smb_admin_pass=>$smb_admin_pass,
                                             user=>$user,
                                             home_dir=>$home_directory_AD,
                                             home_subdir=>$subdir,
                                             json=>$json,
                                             sophomorix_config=>\%sophomorix_config,
                                             sophomorix_result=>\%sophomorix_result,
                                             });

            # append result to dirlist
            $ref_dirlist->{'sAMAccountName'}{$user}=$ref_tree;
        }
    } else {
	# collect user data
        my $ref_user;
        foreach my $user (@users) {
            $ref_user = &Sophomorix::SophomorixSambaAD::AD_get_user_return_hash({
	        ldap=>$ldap,
                root_dse=>$root_dse,
                root_dns=>$root_dns,
	        user=>$user,
	        hash_ref=>$ref_user,
                });
        }

	# run the parallel processes
	use Parallel::ForkManager;
	my $pm = Parallel::ForkManager->new(30);

        $pm -> run_on_finish ( # called BEFORE the first call to start()
            sub {
                my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_;
                if (not defined $ident){
	            $ident="";
                }
                #print Dumper ($data_structure_reference);
		$ref_dirlist->{'sAMAccountName'}{$data_structure_reference->{'USER'}}=$data_structure_reference;
            }
        );

        USERS:
        foreach my $user (@users) {
            my $pid = $pm->start() and next USERS;

            my %child_return=();

            my $ref_tree=&smbclient_dirlist({sharename=>$ref_user->{$user}{'sophomorixSchoolname'},
                                             smb_admin_pass=>$smb_admin_pass,
                                             user=>$user,
                                             home_dir=>$ref_user->{$user}{'homeDirectory'},
                                             home_subdir=>$subdir,
                                             json=>$json,
                                             sophomorix_config=>\%sophomorix_config,
                                             sophomorix_result=>\%sophomorix_result,
                                             });

            # add entry to recognise listing
            $ref_tree->{'USER'}=$user;
            # send it back to the parent process
            $pm->finish(0, $ref_tree);  # note that it's a scalar REFERENCE, not the scalar itself
        }
        $pm->wait_all_children;
    }
    my $jsoninfo="DIRLISTING";
    my $jsoncomment="Listing of subdirs in homes";
    &json_dump({json => $json,
                jsoninfo => $jsoninfo,
                jsoncomment => $jsoncomment,
                #object_name => $options{'school'},
                log_level => $Conf::log_level,
                hash_ref => $ref_dirlist,
                sophomorix_config => \%sophomorix_config,
              });
    
    # &list_home_subdir({ldap=>$ldap,
    #                    root_dse=>$root_dse,
    #                    root_dns=>$root_dns,
    #                    smb_admin_pass=>$smb_admin_pass,
    #                    userstring=>$user,
    #                    subdir=>$subdir,
    #                    json=>$json,
    #                    sophomorix_config=>\%sophomorix_config,
    #                    sophomorix_result=>\%sophomorix_result,
    #                   });
    &AD_unbind_admin($ldap);
    &log_script_end(\@arguments,\%sophomorix_result,\%sophomorix_config,$json);
    exit;
}





# --collect-copy --from-user <user1> --to-user <user2> --file <file1>,<dir1>, ...
if ( ($collect_copy==1 or $collect_move==1) and $from_user ne "" and $to_user ne "" and $file_list ne ""){
    &print_title("Collecting to unix dir ...");
    print "   * From user: $from_user\n";
    print "   * To user:   $to_user\n";
    print "   * Files:     $file_list\n";
    my $target_dir;

    if ($json>=1){
        # prepare json object
        my %json_progress=();
        $json_progress{'JSONINFO'}="PROGRESS";
        $json_progress{'COMMENT_EN'}=$sophomorix_config{'INI'}{'LANG.PROGRESS'}{'COLLECTCOPY_PREFIX_EN'}.
                                     " $from_user --> $to_user ($file_list)".
                                     $sophomorix_config{'INI'}{'LANG.PROGRESS'}{'COLLECTCOPY_POSTFIX_EN'};
        $json_progress{'COMMENT_DE'}=$sophomorix_config{'INI'}{'LANG.PROGRESS'}{'COLLECTCOPY_PREFIX_DE'}.
                                     " $from_user --> $to_user ($file_list)".
                                     $sophomorix_config{'INI'}{'LANG.PROGRESS'}{'COLLECTCOPY_POSTFIX_DE'};
        $json_progress{'STEP'}="1";
        $json_progress{'FINAL_STEP'}="1";
        # print JSON Object
        &Sophomorix::SophomorixBase::json_progress_print({ref_progress=>\%json_progress,
                                                          json=>$json,
                                                          sophomorix_config=>\%sophomorix_config,
                                                        });
    }




    if ($collect_copy==1){
        $target_dir=&smbclient_mget_recurse({ldap=>$ldap,
                                             root_dse=>$root_dse,
                                             root_dns=>$root_dns,
                                             smb_admin_pass=>$smb_admin_pass,
                                             type=>"copy",
                                             from_user=>$from_user,
                                             file_list=>$file_list,
                                             copy_account_data=>$copy_account_data,
                                             json=>$json,
                                             sophomorix_config=>\%sophomorix_config,
                                             sophomorix_result=>\%sophomorix_result,
                                           });
    } elsif ($collect_move==1){
        $target_dir=&smbclient_mget_recurse({ldap=>$ldap,
                                             root_dse=>$root_dse,
                                             root_dns=>$root_dns,
                                             smb_admin_pass=>$smb_admin_pass,
                                             type=>"move",
                                             from_user=>$from_user,
                                             file_list=>$file_list,
                                             copy_account_data=>$copy_account_data,
                                             json=>$json,
                                             sophomorix_config=>\%sophomorix_config,
                                             sophomorix_result=>\%sophomorix_result,
                                           });
    }

    my $from_unix_path=$target_dir;

    my $subdir_mput;
    if (not defined $subdir){
        my $transfer=$sophomorix_config{'INI'}{'LANG.FILESYSTEM'}{'TRANSFER_DIR_HOME_'.
                     $sophomorix_config{'GLOBAL'}{'LANG'}};
        $subdir_mput=$transfer."/".$from_user;
    } else {
        $subdir_mput=$subdir."/".$from_user;
    }
    &print_title("Copying to user...");
    print "   * From:    $from_unix_path\n";
    print "   * To user: $to_user\n";

    &smbclient_mput_recurse({ldap=>$ldap,
                             root_dse=>$root_dse,
                             root_dns=>$root_dns,
                             smb_admin_pass=>$smb_admin_pass,
                             localdir=>$from_unix_path,
                             target_subdir=>$subdir_mput,
                             userstring=>$to_user,
                             json=>$json,
                             sophomorix_config=>\%sophomorix_config,
                             sophomorix_result=>\%sophomorix_result,
                           });
}



# --collect-copy-exam <user1>-exam 
if ($collect_copy_exam){
    my ($firstname_utf8_AD,$lastname_utf8_AD,$adminclass_AD,$existing_AD,$exammode_AD,$role_AD,
        $home_directory_AD,$user_account_control_AD,$toleration_date_AD,
        $deactivation_date_AD,$school_AD,$status_AD,$firstpassword_AD,$unid_AD)=
            &AD_get_user({ldap=>$ldap,
                          root_dse=>$root_dse,
                          root_dns=>$root_dns,
                          user=>$collect_copy_exam,
                        });
    if ($existing_AD ne "TRUE"){
        print "\nERROR: $collect_copy_exam does not exist\n\n";
        exit 88;
    }

    if ( $role_AD ne $sophomorix_config{'INI'}{'EXAMMODE'}{'USER_ROLE'} ){
        print "\nERROR: $collect_copy_exam is not am examuser (sohomorixRole: $role_AD)\n\n";
        exit 88;
    }

    if ( $exammode_AD eq "---" ){
        print "\nERROR: Cannot determine supervisror (sophomorixExamMode: $exammode_AD)\n\n";
        exit 88;
    }

    print "   * Examuser:         $collect_copy_exam\n";

    my $target_user=$exammode_AD;
    print "   * Collect to:       $target_user\n";

    my $transfer=$sophomorix_config{'INI'}{'LANG.FILESYSTEM'}{'TRANSFER_DIR_HOME_'.
                     $sophomorix_config{'GLOBAL'}{'LANG'}};

    my $subdir_mput;
    if (not defined $subdir){
        # use current date
        $subdir_mput=$transfer."/".$sophomorix_config{'DATE'}{'LOCAL'}{'TIMESTAMP_FILE'}."-nosession/".$collect_copy_exam;
        print "   * Subdir (no session): $subdir_mput\n";
    } else {
        # use subdir
        $subdir_mput=$subdir."/".$collect_copy_exam; # the session
        print "   * Subdir (session): $subdir_mput\n";
    }
    if ($json>=1){
        # prepare json object
        my %json_progress=();
        $json_progress{'JSONINFO'}="PROGRESS";
        $json_progress{'COMMENT_EN'}=$sophomorix_config{'INI'}{'LANG.PROGRESS'}{'COLLECTCOPY_PREFIX_EN'}.
                                     " $collect_copy_exam".
                                     $sophomorix_config{'INI'}{'LANG.PROGRESS'}{'COLLECTCOPY_POSTFIX_EN'};
        $json_progress{'COMMENT_DE'}=$sophomorix_config{'INI'}{'LANG.PROGRESS'}{'COLLECTCOPY_PREFIX_DE'}.
                                     " $collect_copy_exam".
                                     $sophomorix_config{'INI'}{'LANG.PROGRESS'}{'COLLECTCOPY_POSTFIX_DE'};
        $json_progress{'STEP'}="1";
        $json_progress{'FINAL_STEP'}="1";
        # print JSON Object
        &Sophomorix::SophomorixBase::json_progress_print({ref_progress=>\%json_progress,
                                                          json=>$json,
                                                          sophomorix_config=>\%sophomorix_config,
                                                        });
    }

    my $target_dir=&smbclient_mget_recurse({ldap=>$ldap,
                                            root_dse=>$root_dse,
                                            root_dns=>$root_dns,
                                            smb_admin_pass=>$smb_admin_pass,
                                            type=>"copy",
                                            from_user=>$collect_copy_exam,
                                            copy_account_data=>$copy_account_data,
                                            file_list=>$transfer,
                                            json=>$json,
                                            sophomorix_config=>\%sophomorix_config,
                                            sophomorix_result=>\%sophomorix_result,
                                          });
    my $from_unix_path=$target_dir;
    &smbclient_mput_recurse({ldap=>$ldap,
                             root_dse=>$root_dse,
                             root_dns=>$root_dns,
                             smb_admin_pass=>$smb_admin_pass,
                             localdir=>$from_unix_path,
                             target_subdir=>$subdir_mput,
                             userstring=>$target_user,
                             json=>$json,
                             sophomorix_config=>\%sophomorix_config,
                             sophomorix_result=>\%sophomorix_result,
                           });
}



&AD_unbind_admin($ldap);
&log_script_end(\@arguments,\%sophomorix_result,\%sophomorix_config,$json);


################################################################################
# Sub
################################################################################
sub smbclient_scopy_recurse {
    my ($arg_ref) = @_;
    my $ldap = $arg_ref->{ldap};
    my $root_dse = $arg_ref->{root_dse};
    my $root_dns = $arg_ref->{root_dns};
    my $scopy = $arg_ref->{scopy};
    my $move = $arg_ref->{move};
    my $smb_admin_pass = $arg_ref->{smb_admin_pass};
    my $from_user_option = $arg_ref->{from_user};
    my $from_path = $arg_ref->{from_path};
    my $to_user_option = $arg_ref->{to_user};
    my $to_path = $arg_ref->{to_path};
    my $to_path_addon = $arg_ref->{to_path_addon};
    my $json = $arg_ref->{json};
    my $ref_sophomorix_config = $arg_ref->{sophomorix_config};
    my $ref_sophomorix_result = $arg_ref->{sophomorix_result};
    my $ref_arguments = $arg_ref->{arguments};

    my $scopy_move;
    if ($scopy==1 and $move==0){
	$scopy_move="scopy";
    } elsif ($scopy==0 and $move==1){
	$scopy_move="rename";        
    } else {
        &log_script_exit("Copy and move not allowed together",1,1,0,
        $ref_arguments,$ref_sophomorix_result,$ref_sophomorix_config,$json);
    }

    # the hash that stores everything
    my %copy=();

    $copy{'OPTIONS'}{'FROM'}=$from_user_option;
    $copy{'OPTIONS'}{'TO'}=$to_user_option;
    $copy{'OPTIONS'}{'FROM_PATH'}=$from_path;
    $copy{'OPTIONS'}{'TO_PATH'}=$to_path;

    @{ $copy{'OPTIONS'}{'FROM_LIST'} }=split(/,/,$from_user_option);
    @{ $copy{'OPTIONS'}{'TO_LIST'} }=split(/,/,$to_user_option);

    $copy{'OPTIONS'}{'FROM_COUNT'}=$#{ $copy{'OPTIONS'}{'FROM_LIST'} }+1;
    $copy{'OPTIONS'}{'TO_COUNT'}=$#{ $copy{'OPTIONS'}{'TO_LIST'} }+1;

    if ($copy{'OPTIONS'}{'FROM_COUNT'} > $copy{'OPTIONS'}{'TO_COUNT'}){
	$copy{'OPTIONS'}{'MAX_COUNT'}=$copy{'OPTIONS'}{'FROM_COUNT'};
    } else {
	$copy{'OPTIONS'}{'MAX_COUNT'}=$copy{'OPTIONS'}{'TO_COUNT'};
    }

    
    
    # 1 -> many, many -> one is supported but not many to many
    if ($copy{'OPTIONS'}{'FROM_COUNT'}>1 and $copy{'OPTIONS'}{'TO_COUNT'}>1){
        print "ERROR: Copying from $copy{'OPTIONS'}{'FROM_COUNT'} users to $copy{'OPTIONS'}{'TO_COUNT'} users not supported\n\n";
        exit;
    }

    ############################################################
    #  1) analyze users and dirs
    ############################################################
    foreach my $from ( @{ $copy{'OPTIONS'}{'FROM_LIST'} } ){
        foreach my $to ( @{ $copy{'OPTIONS'}{'TO_LIST'} } ){
            ############################################################
            # from user
            ############################################################
            my ($firstname_utf8_AD_from_user,
                $lastname_utf8_AD_from_user,
                $adminclass_AD_from_user,
                $existing_AD_from_user,
                $exammode_AD_from_user,
                $role_AD_from_user,
                $home_directory_AD_from_user,
                $user_account_control_AD_from_user,
                $toleration_date_AD_from_user,
                $deactivation_date_AD_from_user,
                $school_AD_from_user,
                $status_AD_from_user,
                $firstpassword_AD_from_user,
                $unid_AD_from_user,
                $firstname_ASCII_AD_from_user,
                $lastname_ASCII_AD_from_user,
                $firstname_initial_AD_from_user,
                $lastname_initial_AD_from_user,
                $user_token_AD_from_user,
                $file_AD_from_user)=
                &AD_get_user({ldap=>$ldap,
                              root_dse=>$root_dse,
                              root_dns=>$root_dns,
                              user=>$from,
                            });

            if ($existing_AD_from_user eq "FALSE"){
                &log_script_exit("ERROR: Source user $from not found",1,1,0,
                    $ref_arguments,$ref_sophomorix_result,$ref_sophomorix_config,$json);
            }

            my $smb_dir_home_from_user=$home_directory_AD_from_user;
            $smb_dir_home_from_user=~s/\\/\//g;
            my ($string_from_user,$rel_path_home_from_user)=split("/".$school_AD_from_user."/",$smb_dir_home_from_user);

            # home relative to school
            $rel_path_home_from_user=~s/^\///g;

            # path incl. --from-path
            my $rel_path_from_user;
            if ($from_path ne ""){
                # append subdir
                $rel_path_from_user=$rel_path_home_from_user."/".$from_path;
            } else {
                $rel_path_from_user=$rel_path_home_from_user;
            }

            my $addon_calc="";
            # --to-path-addon (saved at every from_user)
            if ($to_path_addon eq "login"){
                $addon_calc="/".
                             $from;
            } elsif ($to_path_addon eq "fullinfo"){
                my $last=$lastname_ASCII_AD_from_user;
                $last=~s/\s+/_/g;
                my $first=$firstname_ASCII_AD_from_user;
                $first=~s/\s+/_/g;
                $addon_calc="/".
                            $adminclass_AD_from_user."_".
                            $last."_".
                            $first."_".
                            $from;
            } elsif ($to_path_addon eq "fullinfo-utf8"){
                my $last=$lastname_utf8_AD_from_user;
                $last=~s/\s+/_/g;
                my $first=$firstname_utf8_AD_from_user;
                $first=~s/\s+/_/g;
                $addon_calc="/".
                            $adminclass_AD_from_user."_".
                            $last."_".
                            $first."_".
                            $from;
            }

            # save some stuff
            $copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_SCHOOL'}=$school_AD_from_user;
            $copy{'FROM'}{$from}{'TO'}{$to}{'HOME'}=$rel_path_home_from_user;
            $copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'}=$rel_path_from_user;
            $copy{'FROM'}{$from}{'TO'}{$to}{'TARGET_PATH_ADDON'}=$addon_calc;

            &scan_smb_dir($root_dns,
                          "FROM",
                          \%copy,
                          $from,
                          $to,
                          $smb_admin_pass,
                          $ref_sophomorix_config,
                          $ref_sophomorix_result);

            ############################################################
            # to user
            ############################################################
            my ($firstname_utf8_AD_to_user,
                $lastname_utf8_AD_to_user,
                $adminclass_AD_to_user,
                $existing_AD_to_user,
                $exammode_AD_to_user,
                $role_AD_to_user,
                $home_directory_AD_to_user,
                $user_account_control_AD_to_user,
                $toleration_date_AD_to_user,
                $deactivation_date_AD_to_user,
                $school_AD_to_user,
                $status_AD_to_user,
                $firstpassword_AD_to_user,
                $unid_AD_to_user)=
                &AD_get_user({ldap=>$ldap,
                              root_dse=>$root_dse,
                              root_dns=>$root_dns,
                              user=>$to,
                            });
            if ($existing_AD_to_user eq "FALSE"){
                &log_script_exit("ERROR: Target user $to not found",1,1,0,
                    $ref_arguments,$ref_sophomorix_result,$ref_sophomorix_config,$json);
            }

            my $smb_dir_home_to_user=$home_directory_AD_to_user;
            $smb_dir_home_to_user=~s/\\/\//g;
            my ($string_to_user,$rel_path_home_to_user)=split("/".$school_AD_to_user."/",$smb_dir_home_to_user);

            # home relative to school
            $rel_path_home_to_user=~s/^\///g;

            # path incl. --to-path
            my $rel_path_to_user;
            if ($to_path ne ""){
                # append subdir
                $rel_path_to_user=$rel_path_home_to_user."/".$to_path;
            } else {
                $rel_path_to_user=$rel_path_home_to_user;
            }

            # calculate TARGET
            my $rel_dir  = dirname($rel_path_to_user);
            my $rel_last  = basename($rel_path_to_user);
            my $target_mkdir;
            my $target_path;
            if ($rel_path_to_user=~m/\/$/){
                # ends with / --> required dir
                $target_mkdir=$rel_dir."/".$rel_last.$copy{'FROM'}{$from}{'TO'}{$to}{'TARGET_PATH_ADDON'};
                $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_MKDIR'}=$target_mkdir;

                $target_path=$rel_dir."/".$rel_last.$copy{'FROM'}{$from}{'TO'}{$to}{'TARGET_PATH_ADDON'}; 
                # if source is a file (and target a dir), append its name to target path (make 'put' work)
                if ($copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_NODE'} eq "FILE"){
                    my $filename  = basename($copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'});
                    $target_path=$target_path."/".$filename;
                }

                $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH'}=$target_path;
            } else {
                # no /: required file
                $target_mkdir=$rel_dir.$copy{'FROM'}{$from}{'TO'}{$to}{'TARGET_PATH_ADDON'};
                $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_MKDIR'}=$target_mkdir;

                $target_path=$rel_dir.$copy{'FROM'}{$from}{'TO'}{$to}{'TARGET_PATH_ADDON'}."/".$rel_last;
                $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH'}=$target_path;
            }

            # save some stuff
            $copy{'TO'}{$to}{'FROM'}{$from}{'HOME'}=$rel_path_home_to_user;
            $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_SCHOOL'}=$school_AD_to_user;
            $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH_ADDON'}=$copy{'FROM'}{$from}{'TO'}{$to}{'TARGET_PATH_ADDON'};

            &scan_smb_dir($root_dns,
                          "TO",
                          \%copy,
                          $from,
                          $to,
                          $smb_admin_pass,                                 
                          $ref_sophomorix_config,
                          $ref_sophomorix_result);
        } # end TO loop
    } # end FROM loop

    print Dumper(\%copy); 


    my $copy_count=0;
    ############################################################
    #  2) do the copy/move loops
    ############################################################
    foreach my $from ( @{ $copy{'OPTIONS'}{'FROM_LIST'} } ){
        foreach my $to ( @{ $copy{'OPTIONS'}{'TO_LIST'} } ){
            print "$scopy_move: $from  -----> $to (start)\n";

            ############################################################
            # A) source nonexisting
            if ($copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_NODE'} eq "NONEXISTING"){
		my $warning_message="WARNING: Source file/dir nonexisting: $copy{'FROM'}{$from}{'TO'}{$to}{SOURCE_SCHOOL}".
		                    " -> $copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'}";
		&result_sophomorix_add_log($ref_sophomorix_result,$warning_message);
	        $copy_count++;
		if ($json>=1){
                    # prepare json object
                    my %json_progress=();
                    $json_progress{'JSONINFO'}="PROGRESS";
                    $json_progress{'COMMENT_EN'}=$warning_message;
                    $json_progress{'COMMENT_DE'}=$warning_message;
                    $json_progress{'STEP'}=$copy_count;
                    $json_progress{'FINAL_STEP'}=$copy{'OPTIONS'}{'MAX_COUNT'};
                    # print JSON Object
                    &Sophomorix::SophomorixBase::json_progress_print({ref_progress=>\%json_progress,
                                                                      json=>$json,
                                                                      sophomorix_config=>$ref_sophomorix_config,
								     });
		}
		next;
                #&log_script_exit("ERROR Source file/dir nonexisting: $copy{'FROM'}{$from}{'TO'}{$to}{SOURCE_SCHOOL} -> $copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'}",1,1,0,
                #    $ref_arguments,$ref_sophomorix_result,$ref_sophomorix_config,$json);
            } # end A)


            ############################################################
            # B) file -> file/nonexisting (last path name is considered the filename)
            if ($copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_NODE'} eq "FILE" and
                   ($copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_NODE'} eq "NONEXISTING" or $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_NODE'} eq "FILE")
               ){
                my $rm="";
                if ($copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_NODE'} eq "FILE"){
                    $rm="rm \"$copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH'}\";";
                }
                
                &smb_mkdir_parent($root_dns,
                                  $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_SCHOOL'},
                                  $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_MKDIR'},
                                  $smb_admin_pass,
                                  $copy{'TO'}{$to}{'FROM'}{$from}{'HOME'}, # start below from here
                                  $ref_sophomorix_config,
                                  $ref_sophomorix_result);

                if ($copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_SCHOOL'} eq $copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_SCHOOL'}){
                    my $smbclient_command=$sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
                        " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
                         "%'******'".
                        " //$root_dns/$copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_SCHOOL'} "." ".
                        $sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT_PROTOCOL_OPT'}.
                        " -c '$rm $scopy_move \"$copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'}\" \"$copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH'}\"'";
                    my ($return_value,@out_lines)=&Sophomorix::SophomorixBase::smb_command($smbclient_command,$smb_admin_pass);
                } else {
                    # from school to another
                    &smb_get_put_copy($root_dns,
                                      $copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'},
                                      $from,
                                      $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH'},
                                      $to,
                                      $scopy_move,
                                      \%copy,
                                      $ref_sophomorix_config,
                                      $ref_sophomorix_result);
                }
            } # end B)


            ############################################################
            # C) file -> dir (copy into dir if no other dir is in the way)
            if ($copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_NODE'} eq "FILE" and $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_NODE'} eq "DIR"){
                my $target;
                if ($copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_NODE'} eq "FILE"){
                    $target=$copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH'};
                } elsif ($copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_NODE'} eq "DIR"){
                    my $filename  = basename($copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'});
                    $target=$copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH'}."/".$filename;
                }

                my $rm;
                if (not exists $copy{'TO'}{$to}{'FROM'}{$from}{'LOOKUP'}{$target}){
                    $rm="";
                } elsif ($copy{'TO'}{$to}{'FROM'}{$from}{'LOOKUP'}{$target} eq "FILE"){
                    $rm="rm \"$target\";";
                } elsif ($copy{'TO'}{$to}{'FROM'}{$from}{'LOOKUP'}{$target} eq "DIR"){
                    my $errlog="ERROR Overwriting directory $copy{'TO'}{$to}{'FROM'}{$from}{TARGET_SCHOOL} -> ".
			"$target with non-directory not possible";
                    &log_script_exit($errlog,1,1,0,$ref_arguments,$ref_sophomorix_result,$ref_sophomorix_config,$json);
                }

                if ($copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_SCHOOL'} eq $copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_SCHOOL'}){
                    my $smbclient_command=$sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
                        " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
                        "%'******'".
                        " //$root_dns/$copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_SCHOOL'} "." ".
                        $sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT_PROTOCOL_OPT'}.
                        " -c '$rm $scopy_move \"$copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'}\" \"$target\"'";
                    print "$smbclient_command\n";
                    my ($return_value,@out_lines)=&Sophomorix::SophomorixBase::smb_command($smbclient_command,$smb_admin_pass);
                } else {
                    # from school to another
                    &smb_get_put_copy($root_dns,
                                      $copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'},
                                      $from,
                                      $target,
                                      $to,
                                      $scopy_move,
                                      \%copy,
                                      $ref_sophomorix_config,
                                      $ref_sophomorix_result);
                }
            } # end C)


            ############################################################
            # D) dir -> file (error)
            if ($copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_NODE'} eq "DIR" and 
                $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_NODE'} eq "FILE"
               ){
		my $errlog= "ERROR Overwriting file $copy{'TO'}{$to}{'FROM'}{$from}{TARGET_SCHOOL} -> ".
                            "$copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH'} with ".
                            "directory $copy{'FROM'}{$from}{'TO'}{$to}{SOURCE_SCHOOL} -> ".
                            "$copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'} not possible";
               &log_script_exit($errlog,1,1,0,$ref_arguments,$ref_sophomorix_result,$ref_sophomorix_config,$json);
            } # end D)


            ############################################################
            # E) dir -> dir (copy recursively)
            if ($copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_NODE'} eq "DIR" and
                  ($copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_NODE'} eq "DIR" or 
                   $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_NODE'} eq "NONEXISTING"
                  )
               ){
                my (@source_parts)=split("/",$copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'});
                my $last_source_dir = pop @source_parts;

                ############################################################
                # create parent dirs on target
                print "##### Creating parent dirs in target\n";

                &smb_mkdir_parent($root_dns,
                                  $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_SCHOOL'},
                                  $copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_MKDIR'},
                                  $smb_admin_pass,
                                  $copy{'TO'}{$to}{'FROM'}{$from}{'HOME'}, # start below from here
                                  $ref_sophomorix_config,
                                  $ref_sophomorix_result);

                ############################################################
                # create DIRS
                print "##### Creating dirs in target\n";
                my @mkdir_list=();
                foreach my $source_dir (@{ $copy{'FROM'}{$from}{'TO'}{$to}{'LISTS'}{'DIRS'} }){
                    my $target_dir=$source_dir;
                    # --no-target-directory
                    if ($no_target_directory==1){
                        $target_dir=~s/^$copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'}/$copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH'}/;
                    } else {
                        $target_dir=~s/^$copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'}/$copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH'}\/$last_source_dir/;
                    }

                    if (exists $copy{'TO'}{$to}{'FROM'}{$from}{'LOOKUP'}{$target_dir}){
                        if ($copy{'TO'}{$to}{'FROM'}{$from}{'LOOKUP'}{$target_dir} eq "DIR"){
                            next;
                        } elsif ($copy{'TO'}{$to}{'FROM'}{$from}{'LOOKUP'}{$target_dir} eq "FILE"){
                            # There is a file, where a dir should be created
                            &log_script_exit("ERROR Overwriting file $target_dir with directory not possible",1,1,0,
                            $ref_arguments,$ref_sophomorix_result,$ref_sophomorix_config,$json);
                        }
                    } else {
                        push @mkdir_list,$target_dir;
                    }
                }

                # do it
                foreach my $mkdir_dir (@mkdir_list){
                    my $smbclient_command=$sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
                        " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
                        "%'******'".
                        " //$root_dns/$copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_SCHOOL'} "." ".
                        $sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT_PROTOCOL_OPT'}.
                        " -c 'mkdir \"$mkdir_dir\"'";
                    print "$smbclient_command\n";
                    my ($return_value,@out_lines)=&Sophomorix::SophomorixBase::smb_command($smbclient_command,$smb_admin_pass);
                }

                ############################################################
                # scopy/rename FILES
                print "##### Copying files\n";
                foreach my $source_file (@{ $copy{'FROM'}{$from}{'TO'}{$to}{'LISTS'}{'FILES'} }){
                    my $target_file=$source_file;
                    # --no-target-directory
                    if ($no_target_directory==1){
                        $target_file=~s/^$copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'}/$copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH'}/;
                    } else {
                        $target_file=~s/^$copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'}/$copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH'}\/$last_source_dir/;
                    }

                    # decide if file must be removed on target before scopy (=overwrite)
                    my $rm="";
                    if (exists $copy{'TO'}{$to}{'FROM'}{$from}{'LOOKUP'}{$target_file}){
                        if ($copy{'TO'}{$to}{'FROM'}{$from}{'LOOKUP'}{$target_file} eq "FILE"){
                            $rm="rm \"$target_file\";";
                        } elsif ($copy{'TO'}{$to}{'FROM'}{$from}{'LOOKUP'}{$target_file} eq "DIR"){
                            $rm="deltree $target_file;";
                        }
                    }

                    if ($copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_SCHOOL'} eq $copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_SCHOOL'}){
                        # scopy/move within school
                        my $smbclient_command=$sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
                            " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
                            "%'******'".
                            " //$root_dns/$copy{'TO'}{$to}{'FROM'}{$from}{'TARGET_SCHOOL'} "." ".
                            $sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT_PROTOCOL_OPT'}.
                            " -c '$rm $scopy_move \"$source_file\" \"$target_file\"'";
                        print "$smbclient_command\n";
                        my ($return_value,@out_lines)=&Sophomorix::SophomorixBase::smb_command($smbclient_command,$smb_admin_pass);
                    } else {
                        # from school to another
                        &smb_get_put_copy($root_dns,
                                          $source_file,
                                          $from,
                                          $target_file,
                                          $to,
                                          $scopy_move,
                                          \%copy,
                                          $ref_sophomorix_config,
                                          $ref_sophomorix_result);
                    }
                }

                if ($scopy_move eq "rename"){
                    # delete source dirs bottom up
                    my @reversed_dirs = reverse(@{ $copy{'FROM'}{$from}{'TO'}{$to}{'LISTS'}{'DIRS'} });
                    foreach my $source_dir (@reversed_dirs){
                        # Test if dir must be kept: --keep-source-directory
                        if ($source_dir eq $copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'} and $keep_source_directory==1){
	        	    print "Keeping $copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'}\n";
                            next;
                        }
                        my $smbclient_command=$sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
                            " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
                            "%'******'".
                            " //$root_dns/$copy{'FROM'}{$from}{'TO'}{$to}{'SOURCE_SCHOOL'} "." ".
                            $sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT_PROTOCOL_OPT'}.
                            " -c 'rmdir \"$source_dir\"'";
                        print "$smbclient_command\n";
                        my ($return_value,@out_lines)=&Sophomorix::SophomorixBase::smb_command($smbclient_command,$smb_admin_pass);
                    }
                }
            }

            print "$scopy_move: $from  -----> $to (end)\n";
	    $copy_count++;
            if ($json>=1){
                # prepare json object
                my %json_progress=();
                $json_progress{'JSONINFO'}="PROGRESS";
                $json_progress{'COMMENT_EN'}=$ref_sophomorix_config->{'INI'}{'LANG.PROGRESS'}{'SCOPY_FILES_PREFIX_EN'}.
                                             " $from --> $to".
                                             $ref_sophomorix_config->{'INI'}{'LANG.PROGRESS'}{'SCOPY_FILES_POSTFIX_EN'};
                $json_progress{'COMMENT_DE'}=$ref_sophomorix_config->{'INI'}{'LANG.PROGRESS'}{'SCOPY_FILES_PREFIX_DE'}.
                                             " $from --> $to".
                                             $ref_sophomorix_config->{'INI'}{'LANG.PROGRESS'}{'SCOPY_FILES_POSTFIX_DE'};
                $json_progress{'STEP'}=$copy_count;
                $json_progress{'FINAL_STEP'}=$copy{'OPTIONS'}{'MAX_COUNT'};
                # print JSON Object
                &Sophomorix::SophomorixBase::json_progress_print({ref_progress=>\%json_progress,
                                                                  json=>$json,
                                                                  sophomorix_config=>$ref_sophomorix_config,
                                                                });
            }
        } # end to loop
    } # end FROM loop
    &log_script_end(\@arguments,\%sophomorix_result,\%sophomorix_config,$json);
}



sub scan_smb_dir {
    my ($root_dns,
        $location,
        $ref_copy,
        $from,
        $to,
        $smb_admin_pass,
        $ref_sophomorix_config,
        $ref_sophomorix_result)=@_;

    my $rel_path; # what to scan
    my $school; 
    if ($location eq "TO"){
        $school=$ref_copy->{'TO'}{$to}{'FROM'}{$from}{'TARGET_SCHOOL'};
	$rel_path=$ref_copy->{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH'};
        print "##### Scanning $location new:  School: $school Subdir: $ref_copy->{'TO'}{$to}{'FROM'}{$from}{'TARGET_PATH'} ...\n";
    } else {
	$school=$ref_copy->{'FROM'}{$from}{'TO'}{$to}{'SOURCE_SCHOOL'};
	$rel_path=$ref_copy->{'FROM'}{$from}{'TO'}{$to}{'SOURCE_PATH'};
    }

    my @scanlist=($rel_path);

    my $num=0;
    foreach my $rel_item (@scanlist){
        $num++;
        my $type=&get_type_inode($root_dns,$school,$rel_item,$smb_admin_pass,$ref_sophomorix_config,$ref_sophomorix_result);
        if ($num==1){
            if ($location eq "FROM"){
                $ref_copy->{'FROM'}{$from}{'TO'}{$to}{'SOURCE_NODE'}=$type;
            } else {
                $ref_copy->{'TO'}{$to}{'FROM'}{$from}{'TARGET_NODE'}=$type;
            }
        }
        if ($type eq "DIR"){
            if ($location eq "FROM"){
                $ref_copy->{'FROM'}{$from}{'TO'}{$to}{'LOOKUP'}{$rel_item}="DIR";
                push @{ $ref_copy->{'FROM'}{$from}{'TO'}{$to}{'LISTS'}{'DIRS'} },$rel_item;
            } else {
                $ref_copy->{'TO'}{$to}{'FROM'}{$from}{'LOOKUP'}{$rel_item}="DIR";
                push @{ $ref_copy->{'TO'}{$to}{'FROM'}{$from}{'LISTS'}{'DIRS'} },$rel_item;
            }

            # scan the contents
            my $smbclient_command=$sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
                " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
                "%'******'".
                " //$root_dns/$school "." ".
                $sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT_PROTOCOL_OPT'}.
                " -c 'cd \"$rel_item\"; ls'";
            my ($return_value,@out_lines)=&Sophomorix::SophomorixBase::smb_command($smbclient_command,$smb_admin_pass);

            foreach my $status (@out_lines){
                my $smb_type="";
                my $smb_name="";

                # simple and works, but fails with  " D ", ... in filename
                #my (@list_tmp)=split(/( D | N | A )/,$status); # split with 1 chars of space before/after

                # best effort is to split at: whitespace D|N|A whitespace 0|0-9 whitespace
                my (@list_tmp)=split(/(\s+D\s+0\s+|\s+N\s+[0-9]+\s+|\s+A\s+[0-9]+\s+)/,$status); # split with 1 chars of space before/after
                #print Dumper(\@list_tmp);

                foreach my $item (@list_tmp){
                   # if ($item eq " D "){
                   if ($item=~m/\s+D\s+0\s+/){
                       # directory
                       $smb_type="DIR";
                       last;
                   # } elsif ($item eq " N " or $item eq " A "){
                   } elsif ($item=~m/\s+N\s+[0-9]+\s+/ or $item=~m/\s+A\s+[0-9]+\s+/){
                       # node/files
                       $smb_type="FILE";
                       last;
                   } else {
                       $smb_name=$smb_name.$item;
                   }      
                }
                $smb_name=&Sophomorix::SophomorixBase::remove_embracing_whitespace($smb_name);

                if ($smb_name eq "" or 
                    $smb_name eq "." or 
                    $smb_name eq ".." or
                    ($smb_name=~m/blocks of size/ and $smb_name=~m/available/)){
                    next;
                } else {
                    my $dir_rel_path=$rel_item."/".$smb_name;
                    if ($smb_type eq "DIR"){
                        push @scanlist, $dir_rel_path;
                    } elsif ($smb_type eq "FILE"){
                        if ($location eq "FROM"){
                            $ref_copy->{'FROM'}{$from}{'TO'}{$to}{'LOOKUP'}{$dir_rel_path}="FILE";
                            push @{ $ref_copy->{'FROM'}{$from}{'TO'}{$to}{'LISTS'}{'FILES'} },$dir_rel_path;
                        } else {
                            $ref_copy->{'TO'}{$to}{'FROM'}{$from}{'LOOKUP'}{$dir_rel_path}="FILE";
                            push @{ $ref_copy->{'TO'}{$to}{'FROM'}{$from}{'LISTS'}{'FILES'} },$dir_rel_path;
                        }
                    }
                }
            }
        } elsif ($type eq "FILE"){
            if ($location eq "FROM"){
                push @{ $ref_copy->{'FROM'}{$from}{'TO'}{$to}{'LISTS'}{'FILES'} },$rel_item;
            } else {
                push @{ $ref_copy->{'TO'}{$to}{'FROM'}{$from}{'LISTS'}{'FILES'} },$rel_item;                
            }
        }
    }
    if ($location eq "FROM"){
        $ref_copy->{'FROM'}{$from}{'TO'}{$to}{'COUNT'}{'FILES'}=$#{ $ref_copy->{'FROM'}{$from}{'TO'}{$to}{'LISTS'}{'FILES'}  }+1;
        $ref_copy->{'FROM'}{$from}{'TO'}{$to}{'COUNT'}{'DIRS'}= $#{ $ref_copy->{'FROM'}{$from}{'TO'}{$to}{'LISTS'}{'DIRS'}  }+1;
    } else {
        $ref_copy->{'TO'}{$to}{'FROM'}{$from}{'COUNT'}{'FILES'}=$#{ $ref_copy->{'TO'}{$to}{'FROM'}{$from}{'LISTS'}{'FILES'}  }+1;
        $ref_copy->{'TO'}{$to}{'FROM'}{$from}{'COUNT'}{'DIRS'}= $#{ $ref_copy->{'TO'}{$to}{'FROM'}{$from}{'LISTS'}{'DIRS'}  }+1;
    }
}




sub get_type_inode {
    # FILE, DIR or NONEXISTING
    my ($root_dns,$school,$rel_path,$smb_admin_pass,$ref_sophomorix_config,$ref_sophomorix_result)=@_;
    my $smbclient_command=$ref_sophomorix_config->{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
            " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
            "%'******'".
            " //$root_dns/$school "." ".
            $ref_sophomorix_config->{'INI'}{'EXECUTABLES'}{'SMBCLIENT_PROTOCOL_OPT'}.
            " -c 'allinfo \"$rel_path\"; exit;'";
    my ($return_value,@out_lines)=&Sophomorix::SophomorixBase::smb_command($smbclient_command,$smb_admin_pass);
    my $type;
    foreach my $stat (@out_lines){
        if ($stat=~m/stream:/ and $stat=~m/[::\$DATA]/){ # only files contain stream data
            $type="FILE";
            last;
        } elsif ($stat=~m/attributes/ and $stat=~m/D/){ # RD and D are Folder attributes
            $type="DIR";
            last;
        } elsif ($stat=~m/attributes/ and $stat=~m/RD/){
            $type="DIR";
            last;
        } else {
            $type="NONEXISTING";
            # nothing
        }
    }

    return $type;
}



sub smb_mkdir_parent {
   my ($root_dns,
        $school,
        $target_mkdir,
        $smb_admin_pass,
        $start_below,
        $ref_sophomorix_config,
        $ref_sophomorix_result)=@_;
    my (@dirs)=split("/",$target_mkdir);
    my @mkdir_paths=();
    my $mkdir="";
    print "Done: Creating parent dirs from $start_below until $target_mkdir\n";
    foreach my $dir (@dirs){
        $mkdir=$mkdir."/".$dir;
        $mkdir=~s/^\///g;
        push @mkdir_paths, $mkdir;
    }
    foreach my $mkdir (@mkdir_paths){
        if ($start_below=~m/^$mkdir/){
            # skip above start dir
            next;
        }
        my $smbclient_command=$ref_sophomorix_config->{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
            " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
            "%'******'".
            " //$root_dns/$school "." ".
            $ref_sophomorix_config->{'INI'}{'EXECUTABLES'}{'SMBCLIENT_PROTOCOL_OPT'}.
            " -c 'mkdir \"$mkdir\"'";
        my ($return_value,@out_lines)=&Sophomorix::SophomorixBase::smb_command($smbclient_command,$smb_admin_pass);
    }
    print "Done: Creating parent dirs\n";
}



sub smb_get_put_copy {
    # copy file from one school to another
    my ($root_dns,
        $source_file,
        $from_user,
        $target_file,
        $to_user,
        $scopy_move,
        $ref_copy,
        $ref_sophomorix_config,
        $ref_sophomorix_result)=@_;

        my $tmp = tempdir( DIR => $ref_sophomorix_config->{'PATHS'}{'TMP_SMB'}, CLEANUP =>  1 );

        # 1) download source
        my $source_dirname  = dirname($source_file);
        my $source_filename  = basename($source_file);

        my $smbclient_command_get=$ref_sophomorix_config->{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
            " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
            "%'******'".
            " //$root_dns/$ref_copy->{'FROM'}{$from_user}{'TO'}{$to_user}{'SOURCE_SCHOOL'} "." ".
            $ref_sophomorix_config->{'INI'}{'EXECUTABLES'}{'SMBCLIENT_PROTOCOL_OPT'}.
            " -c 'lcd \"$tmp\"; cd \"$source_dirname\"; prompt; get \"$source_filename\"; exit;'";
        print "$smbclient_command_get\n";
        my ($return_value_get,@out_lines_get)=&Sophomorix::SophomorixBase::smb_command($smbclient_command_get,$smb_admin_pass);

        # 2) upload target
        my $target_dirname  = dirname($target_file);
        my $target_filename  = basename($target_file);
        my $smbclient_command_put=$ref_sophomorix_config->{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
            " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
            "%'******'".
            " //$root_dns/$ref_copy->{'TO'}{$to_user}{'FROM'}{$from_user}{'TARGET_SCHOOL'} "." ".
            $ref_sophomorix_config->{'INI'}{'EXECUTABLES'}{'SMBCLIENT_PROTOCOL_OPT'}.
            " -c 'lcd \"$tmp\"; cd \"$target_dirname\"; prompt; put \"$source_filename\" \"$target_filename\"; exit;'";
        print "$smbclient_command_put\n";
        my ($return_value_put,@out_lines_put)=&Sophomorix::SophomorixBase::smb_command($smbclient_command_put,$smb_admin_pass);
    if ($scopy_move eq "rename"){
        # delete the source if target exists
        # ???
        # delete
        my $smbclient_command_get=$ref_sophomorix_config->{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
            " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
            "%'******'".
            " //$root_dns/$ref_copy->{'FROM'}{$from_user}{'TO'}{$to_user}{'SOURCE_SCHOOL'} "." ".
            $ref_sophomorix_config->{'INI'}{'EXECUTABLES'}{'SMBCLIENT_PROTOCOL_OPT'}.
            " -c 'cd \"$source_dirname\"; rm \"$source_filename\"; exit;'";
        print "$smbclient_command_get\n";
        my ($return_value_get,@out_lines_get)=&Sophomorix::SophomorixBase::smb_command($smbclient_command_get,$smb_admin_pass);        
    }
}



sub smbclient_mget_recurse {
    # save the data from smb share to a local unix dir with tmp filename
    # return abs-path
    my ($arg_ref) = @_;
    my $ldap = $arg_ref->{ldap};
    my $root_dse = $arg_ref->{root_dse};
    my $root_dns = $arg_ref->{root_dns};
    my $smb_admin_pass = $arg_ref->{smb_admin_pass};
    my $type = $arg_ref->{type};
    my $from_user = $arg_ref->{from_user};
    my $file_list = $arg_ref->{file_list};
    my $json = $arg_ref->{json};
    my $copy_account_data = $arg_ref->{copy_account_data};
    my $ref_sophomorix_config = $arg_ref->{sophomorix_config};
    my $ref_sophomorix_result = $arg_ref->{sophomorix_result};

    my $transfer=$ref_sophomorix_config->{'INI'}{'LANG.FILESYSTEM'}{'TRANSFER_DIR_HOME_'.
                 $ref_sophomorix_config->{'GLOBAL'}{'LANG'}};
    my $to_dir=$ref_sophomorix_config->{'INI'}{'EXAMMODE'}{'TMP_COLLECT_DIR'};
    system("mkdir -p $to_dir");

    my $tmp = tempdir( DIR => $to_dir, CLEANUP =>  1 );
    my $target_dir = $tmp."/".$from_user;
    my ($firstname_utf8_AD,$lastname_utf8_AD,$adminclass_AD,$existing_AD,$exammode_AD,$role_AD,
        $home_directory_AD,$user_account_control_AD,$toleration_date_AD,
        $deactivation_date_AD,$school_AD,$status_AD,$firstpassword_AD,$unid_AD)=
            &AD_get_user({ldap=>$ldap,
                          root_dse=>$root_dse,
                          root_dns=>$root_dns,
                          user=>$from_user,
                        });
    if ($existing_AD ne "TRUE"){
        print "\nERROR: $collect_copy_exam does not exist\n\n";
        return $target_dir;
    }
    my $smb_dir_home=$home_directory_AD;
    $smb_dir_home=~s/\\/\//g;
    my @file_list = split(/,/,$file_list);
    foreach my $file_path (@file_list){
        my $dirname  = dirname($file_path);
        my $filename  = basename($file_path);        

        # lcd path
        my $lcd_path=$tmp."/".$from_user."/".$dirname;
        $lcd_path=~s/\/\.$//; # remove /. in the end
        system("mkdir -p $lcd_path");

        # cd path
        my $smb_dir_sub=$smb_dir_home."/".$dirname;
        my ($string1,$rel_path_home)=split(/$school_AD/,$smb_dir_home); # to home
        my ($string2,$rel_path_sub)=split(/$school_AD/,$smb_dir_sub); # to subdir in home
        my $cd_path=$rel_path_sub;
        $cd_path=~s/\/\.$//; # remove /. in the end
        # file or dir
        my $smbclient_command=$sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
            " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
            "%'******'".
            " //$root_dns/$school_AD "." ".
            $sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT_PROTOCOL_OPT'}.
            " -c 'cd \"$cd_path\"; allinfo \"$filename\"; exit;'";
        my ($return_value,@out_lines)=&Sophomorix::SophomorixBase::smb_command($smbclient_command,$smb_admin_pass);

        foreach my $stat (@out_lines){
            if ($stat=~m/stream:/ and $stat=~m/[::\$DATA]/){ # only files contain stream data
                # file
                print "   * $filename is a file ($file_path)\n";
                my $smbclient_command=$sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
                    " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
                    "%'******'".
                    " //$root_dns/$school_AD "." -c 'cd \"$cd_path\"; lcd \"$lcd_path\";".
                    " prompt; recurse; get $filename; exit;'";
                &Sophomorix::SophomorixBase::smb_command($smbclient_command,$smb_admin_pass);
                if ($type eq "move"){
                    # remove file that was collected
                    my $smbclient_command=$sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
                        " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
                        "%'******'".
                        " //$root_dns/$school_AD "." -c 'cd \"$cd_path\";".
                        " prompt; rm \"$filename\"; exit;'";
                    &Sophomorix::SophomorixBase::smb_command($smbclient_command,$smb_admin_pass);
                }
                last;
            } elsif ($stat=~m/attributes/ and $stat=~m/D/){ # RD and D are Folder attributes
                print "   * $filename is a directory ($file_path)\n";
                if ($copy_account_data==1){
                    # dir
                    $cd_path=$cd_path;
                    # prepare local unix path
                    $lcd_path=$lcd_path;
                } else {
                    # dir
                    $cd_path=$cd_path."/".$filename;
                    # prepare local unix path
                    $lcd_path=$lcd_path."/".$filename;
                }
                system("mkdir -p $lcd_path");

                my $smbclient_command=$sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
                    " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
                    "%'******'".
                    " //$root_dns/$school_AD "." -c 'cd \"$cd_path\"; lcd \"$lcd_path\";".
                    " prompt; recurse; mget *; exit;'";
                &Sophomorix::SophomorixBase::smb_command($smbclient_command,$smb_admin_pass);
                if ($type eq "move"){
                    # remove the dir that was collected
                    if ($filename eq $transfer and $dirname eq "."){
                        # the transfer dir itself, emtied by function
                        &clean_transfer_dir({ldap=>$ldap,
                                             root_dse=>$root_dse,
                                             root_dns=>$root_dns,
                                             smb_admin_pass=>$smb_admin_pass,
                                             userstring=>$from_user,
                                             json=>$json,
                                             sophomorix_config=>\%sophomorix_config,
                                             sophomorix_result=>\%sophomorix_result,
                                           });
                    } else {
                        # other dirs, romove them completely
		        # example: smb://linuxmuster.local/<school>/subdir1/subdir2
                        my $smb_share="smb://".$root_dns."/".$school_AD.$cd_path;
 
                        # rewrite smb_dir with msdfs root
                        $smb_share=&Sophomorix::SophomorixBase::rewrite_smb_path($smb_share,$ref_sophomorix_config);

                        my $smb = new Filesys::SmbClient(username  => $DevelConf::sophomorix_file_admin,
                                                         password  => $smb_admin_pass,
                                                         debug     => 0);
                        my $return=$smb->rmdir_recurse($smb_share);
                        if($return==1){
                            print "OK: Deleted with succes $smb_share\n"; # smb://linuxmuster.local/<school>/subdir1/subdir2
                        } else {
                            print "ERROR: rmdir_recurse $smb_share $!\n";
                        }
                    }
                }
                last;
            } 
        }
    }
    print "   * Data copied to $target_dir\n";
    return $target_dir;
}



sub smbclient_mput_recurse {
    my ($arg_ref) = @_;
    my $ldap = $arg_ref->{ldap};
    my $root_dse = $arg_ref->{root_dse};
    my $root_dns = $arg_ref->{root_dns};
    my $smb_admin_pass = $arg_ref->{smb_admin_pass};
    my $localdir = $arg_ref->{localdir};
    my $target_subdir = $arg_ref->{target_subdir};
    my $userstring = $arg_ref->{userstring};
    my $json = $arg_ref->{json};
    my $ref_sophomorix_config = $arg_ref->{sophomorix_config};
    my $ref_sophomorix_result = $arg_ref->{sophomorix_result};

    # $localdir: sourcedir (unix-Pfad)
    # $userstring: list of users to put to
    # $target_subdir: subdir under userhome/transfer
    my $user_count=0;
    my @users=split(/,/,$userstring);
    my $max_user_count=$#users;
    foreach my $user (@users){
        $user_count++;
        print "   * Copying to user $user\n";
        if ($json>=1){
            # prepare json object
            my %json_progress=();
            $json_progress{'JSONINFO'}="PROGRESS";
            $json_progress{'COMMENT_EN'}=$ref_sophomorix_config->{'INI'}{'LANG.PROGRESS'}{'MPUTFILES_PREFIX_EN'}.
                                         " $user".
                                         $ref_sophomorix_config->{'INI'}{'LANG.PROGRESS'}{'MPUTFILES_POSTFIX_EN'};
            $json_progress{'COMMENT_DE'}=$ref_sophomorix_config->{'INI'}{'LANG.PROGRESS'}{'MPUTFILES_PREFIX_DE'}.
                                         " $user".
                                         $ref_sophomorix_config->{'INI'}{'LANG.PROGRESS'}{'MPUTFILES_POSTFIX_DE'};
            $json_progress{'STEP'}=$user_count;
            $json_progress{'FINAL_STEP'}=$max_user_count;
            # print JSON Object
            &Sophomorix::SophomorixBase::json_progress_print({ref_progress=>\%json_progress,
                                                              json=>$json,
                                                              sophomorix_config=>$ref_sophomorix_config,
                                                            });
        }

        my ($firstname_utf8_AD,$lastname_utf8_AD,$adminclass_AD,$existing_AD,$exammode_AD,$role_AD,
                        $home_directory_AD,$user_account_control_AD,$toleration_date_AD,
                        $deactivation_date_AD,$school_AD,$status_AD,$firstpassword_AD,$unid_AD)=
                        &AD_get_user({ldap=>$ldap,
                                      root_dse=>$root_dse,
                                      root_dns=>$root_dns,
                                      user=>$user,
                                    });
        if ($existing_AD eq "TRUE"){
            my $smb_dir_home=$home_directory_AD;
            $smb_dir_home=~s/\\/\//g;
            my $smb_dir_sub=$smb_dir_home."/".$target_subdir;
#            my ($string1,$rel_path_home)=split("/".$school_AD."/",$smb_dir_home);
#            my ($string2,$rel_path_sub)=split("/".$school_AD."/",$smb_dir_sub);
            my ($string1,$rel_path_home)=split(/$school_AD/,$smb_dir_home);
            my ($string2,$rel_path_sub)=split(/$school_AD/,$smb_dir_sub);

            my @subdirs=split(/\//,$target_subdir);
            my $remember="";
            my $md_commands="cd $rel_path_home; ";
            foreach my $subdir (@subdirs){
                my $md_path=$remember.$subdir;
                $md_commands=$md_commands."md \"".$md_path."\"; ";
                $remember=$md_path."/";
                if ($sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT_RELY_ON_MKDIR_IGNORE_ERROR'} eq "FALSE"){
                    # Dirty fix:  #### for ech subdir a smbclient command (which can fail)
                    my $cd_path=$rel_path_home;
                    my $md_command=$sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
                        " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
                        "%'******'".
                        " //$root_dns/$school_AD "." -c 'cd \"$cd_path\"; md \"$md_path\"'";
                    &Sophomorix::SophomorixBase::smb_command($md_command,$smb_admin_pass);
                }
            }

            if ($sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT_RELY_ON_MKDIR_IGNORE_ERROR'} eq "FALSE"){
                # without md_commands (dirty fix above needed)
                my $smbclient_command=$sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
                    " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
                    "%'******'".
                    " //$root_dns/$school_AD "." -c 'cd \"$target_subdir\"; lcd \"$localdir\";".
                    " prompt; recurse; mput *; exit;'";
                &Sophomorix::SophomorixBase::smb_command($smbclient_command,$smb_admin_pass);
            } else {
                # including md_commands  
                my $smbclient_command=$sophomorix_config{'INI'}{'EXECUTABLES'}{'SMBCLIENT'}.
                    " --debuglevel=$debug_level -U ".$DevelConf::sophomorix_file_admin.
                    "%'******'".
                    " //$root_dns/$school_AD "." -c '$md_commands cd \"$target_subdir\"; lcd \"$localdir\";".
                    " prompt; recurse; mput *; exit;'";
                &Sophomorix::SophomorixBase::smb_command($smbclient_command,$smb_admin_pass);
            }
        } else {
            print "\nERROR: cannot upload to nonexisting user $user\n\n";
        }
    }
}



sub clean_transfer_dir {
    my ($arg_ref) = @_;
    my $ldap = $arg_ref->{ldap};
    my $root_dse = $arg_ref->{root_dse};
    my $root_dns = $arg_ref->{root_dns};
    my $smb_admin_pass = $arg_ref->{smb_admin_pass};
    my $userstring = $arg_ref->{userstring};
    my $json = $arg_ref->{json};
    my $ref_sophomorix_config = $arg_ref->{sophomorix_config};
    my $ref_sophomorix_result = $arg_ref->{sophomorix_result};

    my $transfer=$ref_sophomorix_config->{'INI'}{'LANG.FILESYSTEM'}{'TRANSFER_DIR_HOME_'.
                 $ref_sophomorix_config->{'GLOBAL'}{'LANG'}};
    &clean_home_without_transfer({ldap=>$ldap,
                                  root_dse=>$root_dse,
                                  root_dns=>$root_dns,
                                  smb_admin_pass=>$smb_admin_pass,
                                  userstring=>$userstring,
                                  subdir=>$transfer,
                                  json=>$json,
                                  sophomorix_config=>\%sophomorix_config,
                                  sophomorix_result=>\%sophomorix_result,
                                });
}



sub clean_home_without_transfer {
    my ($arg_ref) = @_;
    my $ldap = $arg_ref->{ldap};
    my $root_dse = $arg_ref->{root_dse};
    my $root_dns = $arg_ref->{root_dns};
    my $smb_admin_pass = $arg_ref->{smb_admin_pass};
    my $userstring = $arg_ref->{userstring};
    my $subdir = $arg_ref->{subdir};
    my $json = $arg_ref->{json};
    my $ref_sophomorix_config = $arg_ref->{sophomorix_config};
    my $ref_sophomorix_result = $arg_ref->{sophomorix_result};

    my @users=split(/,/,$userstring);
    my $transfer=$ref_sophomorix_config->{'INI'}{'LANG.FILESYSTEM'}{'TRANSFER_DIR_HOME_'.
                 $ref_sophomorix_config->{'GLOBAL'}{'LANG'}};
    foreach my $user (@users){
        my ($firstname_utf8_AD,$lastname_utf8_AD,$adminclass_AD,$existing_AD,$exammode_AD,$role_AD,
                        $home_directory_AD,$user_account_control_AD,$toleration_date_AD,
                        $deactivation_date_AD,$school_AD,$status_AD,$firstpassword_AD,$unid_AD)=
                        &AD_get_user({ldap=>$ldap,
                                      root_dse=>$root_dse,
                                      root_dns=>$root_dns,
                                      user=>$user,
                                    });
        if ($existing_AD eq "TRUE"){
            my $smb_dir=$home_directory_AD;
            $smb_dir=~s/\\/\//g;
            if (defined $subdir){
                $smb_dir="smb:".$smb_dir."/".$subdir;
            } else {
                # clean homedir
                $smb_dir="smb:".$smb_dir;
            }

            # rewrite smb_dir with msdfs root
            $smb_dir=&Sophomorix::SophomorixBase::rewrite_smb_path($smb_dir,$ref_sophomorix_config);

            my $smb = new Filesys::SmbClient(username  => $DevelConf::sophomorix_file_admin,
                                         password  => $smb_admin_pass,
                                         debug     => 0);
            my $fd = $smb->opendir($smb_dir);
            while (my $file = $smb->readdir_struct($fd)) {
                if ($file->[1] eq "."){next};
                if ($file->[1] eq ".."){next};

                # skipping some dirs
                if (not defined $subdir){
                    # skip transfer dir when cleaning home
                    if ($file->[0] == 7 and $file->[1] eq $transfer){next};
                }
                my $path=$smb_dir."/".$file->[1];

                my $return;
                if ($file->[0] == 7) {
                    # its a dir
                    $return=$smb->rmdir_recurse($path);
                } elsif ($file->[0] == 8) {
                    # its a file
                    $return=$smb->unlink($path);
                }

                if ($return==1){
                    print "   * OK: Deleted with succes $path\n";
                } else {
                    print "\nERROR: rmdir_recurse $path $!\n\n";
                }
            }
        } else {
            print "\nERROR: cannot clean home (without transfer) of nonexisting user $user\n\n";
        }

    }
}


# sub list_home_subdir {
#     my ($arg_ref) = @_;
#     my $ldap = $arg_ref->{ldap};
#     my $root_dse = $arg_ref->{root_dse};
#     my $root_dns = $arg_ref->{root_dns};
#     my $smb_admin_pass = $arg_ref->{smb_admin_pass};
#     my $userstring = $arg_ref->{userstring};
#     my $subdir = $arg_ref->{subdir};
#     my $json = $arg_ref->{json};
#     my $ref_sophomorix_config = $arg_ref->{sophomorix_config};
#     my $ref_sophomorix_result = $arg_ref->{sophomorix_result};

#     my @users=split(/,/,$userstring);
#     my $transfer=$ref_sophomorix_config->{'INI'}{'LANG.FILESYSTEM'}{'TRANSFER_DIR_HOME_'.
#                  $ref_sophomorix_config->{'GLOBAL'}{'LANG'}};
 
#     my %dirlist=();
#     foreach my $user (@users){
#         push @{ $dirlist{'LISTS'}{'sAMAccountName'} },$user;
#         my ($firstname_utf8_AD,$lastname_utf8_AD,$adminclass_AD,$existing_AD,$exammode_AD,$role_AD,
#             $home_directory_AD,$user_account_control_AD,$toleration_date_AD,
#             $deactivation_date_AD,$school_AD,$status_AD,$firstpassword_AD,$unid_AD)=
#             &AD_get_user({ldap=>$ldap,
#                           root_dse=>$root_dse,
#                           root_dns=>$root_dns,
#                           user=>$user,
#                         });
#         if ($existing_AD eq "TRUE"){
#             my $smb_dir=$home_directory_AD;
#             $smb_dir=~s/\\/\//g;
#             if (defined $subdir){
#                 $smb_dir="smb:".$smb_dir."/".$subdir;
#             } else {
#                 # clean homedir
#                 $smb_dir="smb:".$smb_dir;
#             }

#             $dirlist{'sAMAccountName'}{$user}{'SMB_PATH'}=$smb_dir;
#             my $ref_dirlist=&smb_dirlist({smb_admin_pass => $smb_admin_pass,
#                                           smb_dir => $smb_dir,
#                                           dirlist => \%dirlist,
#                                           user => $user,
#                                           transfer => $transfer,
#                                           sophomorix_config => \%sophomorix_config,
#                                         });
#         } else {
#             print "\nERROR: cannot list home of nonexisting user $user\n\n";
#         }
#     }
#     @{ $dirlist{'LISTS'}{'sAMAccountName'} } = sort @{ $dirlist{'LISTS'}{'sAMAccountName'} };
#     my $jsoninfo="DIRLISTING";
#     my $jsoncomment="Listing of subdirs in homes";
#     &json_dump({json => $json,
#                 jsoninfo => $jsoninfo,
#                 jsoncomment => $jsoncomment,
#                 #object_name => $options{'school'},
#                 log_level => $Conf::log_level,
#                 hash_ref => \%dirlist,
#                 sophomorix_config => \%sophomorix_config,
#               });
# }



sub smb_dirlist {
    my ($arg_ref) = @_;
    my $smb_admin_pass = $arg_ref->{smb_admin_pass};
    my $smb_dir = $arg_ref->{smb_dir};
    my $transfer = $arg_ref->{transfer};
    my $user = $arg_ref->{user};
    my $ref_dirlist = $arg_ref->{dirlist};
    my $ref_sophomorix_config = $arg_ref->{sophomorix_config};

    $ref_dirlist->{'sAMAccountName'}{$user}{'COUNT'}{'directories'}=0;
    $ref_dirlist->{'sAMAccountName'}{$user}{'COUNT'}{'files'}=0;

    # rewrite smb_dir with msdfs root
    $smb_dir=&Sophomorix::SophomorixBase::rewrite_smb_path($smb_dir,$ref_sophomorix_config);

    my $smb = new Filesys::SmbClient(username  => $DevelConf::sophomorix_file_admin,
                                     password  => $smb_admin_pass,
                                     debug     => 0);
    my $fd = $smb->opendir($smb_dir);
    while (my $file = $smb->readdir_struct($fd)) {
        if ($file->[1] eq "."){next};
        if ($file->[1] eq ".."){next};
        my $name=$file->[1];
        my $typenum=$file->[0];
        $ref_dirlist->{'sAMAccountName'}{$user}{'TREE'}{$name}{'TYPENUM'}=$typenum;

        # more info
        my $filestat=$smb_dir."/".$name;
        my @stat = $smb->stat($filestat);

	#print "@stat\n";
        my $owner_id=$stat[4];
        my $gowner_id=$stat[5];
        my $size_bytes=$stat[7];
        my $time_access=$stat[10];
        my $time_mod=$stat[11];
        my $time_change=$stat[12];

        $ref_dirlist->{'sAMAccountName'}{$user}{'TREE'}{$name}{'OWNER_ID'}=$owner_id;
        $ref_dirlist->{'sAMAccountName'}{$user}{'TREE'}{$name}{'GOWNER_ID'}=$gowner_id;
        $ref_dirlist->{'sAMAccountName'}{$user}{'TREE'}{$name}{'TIME_ACCESS'}=$time_access;
        $ref_dirlist->{'sAMAccountName'}{$user}{'TREE'}{$name}{'TIME_MOD'}=$time_mod;
        $ref_dirlist->{'sAMAccountName'}{$user}{'TREE'}{$name}{'TIME_CHANGE'}=$time_change;

        if ($file->[0] == 7) {
            # its a dir
            $ref_dirlist->{'sAMAccountName'}{$user}{'TREE'}{$name}{'TYPE'}="directory";
            $ref_dirlist->{'sAMAccountName'}{$user}{'COUNT'}{'directories'}++;
        } elsif ($file->[0] == 8) {
            # its a file
            $ref_dirlist->{'sAMAccountName'}{$user}{'TREE'}{$name}{'TYPE'}="file";
            $ref_dirlist->{'sAMAccountName'}{$user}{'TREE'}{$name}{'SIZE_BYTES'}=$size_bytes;
            $ref_dirlist->{'sAMAccountName'}{$user}{'COUNT'}{'files'}++;
        }
    }
}
