HEX
Server: Apache/2.4.41 (FreeBSD) OpenSSL/1.0.2s mod_fcgid/2.3.9
System: FreeBSD salazo 12.0-RELEASE-p1303-ZFS hostBSD 12.0-RELEASE-p1303-ZFS DMR amd64
User: admin (1000)
PHP: 7.4.3
Disabled: NONE
Upload Files
File: /usr/local/www/apache24/cgi-bin/easytecc4/index.pl
#!/usr/iports/bin/perl

BEGIN {
	if(-e '/etc/sudoers'){
		
		my $osversion = `/usr/bin/uname -K`;
		chomp $osversion;
		
		my $perl;
		
		if($osversion >= 1300000){
			
			$perl = '5.34';
		
		} elsif($osversion >= 1200000){
			
			$perl = '5.26';
		
		} elsif($osversion >= 1003000){
			
			$perl = '5.24';

		} else {
			
			$perl = '5.20';
			
		}
		
		@INC = (
				"/usr/iports/lib/perl5/site_perl",
				"/usr/iports/lib/perl5/amd64-freebsd-thread-multi",
				"/usr/iports/lib/perl5/$perl",
				"/usr/iports/lib/perl5/$perl/mach",
				"/usr/iports/lib/perl5/site_perl/mach/$perl",
				"/usr/local/lib/perl5/site_perl",
				"/usr/local/lib/perl5/amd64-freebsd-thread-multi",
				"/usr/local/lib/perl5/$perl",
				"/usr/local/lib/perl5/$perl/mach",
				"/usr/local/lib/perl5/site_perl/mach/$perl",
				"/usr/local/www/apache24/cgi-bin/easytecc4"
		);
				
			
	} else {
		push @INC, '/home/httpd/cgi-bin/easytecc4';
	}
}

my $fb = "";			### Mario: /etc/sudoers existiert nur auf unseren FreeBSD-Servern ###
if (-e '/etc/sudoers') {
    $fb = '1';
	$ENV{'SHELL'} = '/bin/sh';
}

my ($easytecc_prefix, $droot_prefix, $droot_regex, $awstats_updateall, $awstats_conf_prefix, $lang_basedir);

if ($fb) {
	#'use lib' does not care about codelevel conditions...
	#use lib '/usr/local/www/apache24/cgi-bin/easytecc4';
	$easytecc_prefix = '/usr/local/www/apache24/cgi-bin/easytecc4';
	$droot_prefix = '/usr/local/www/apache24/noexec';
	$droot_regex = '\/usr\/local\/www\/apache24\/noexec\/';
	$cgi_prefix = '/usr/local/www/apache24/cgi-bin';
	$awstats_updateall = '/usr/local/www/awstats/tools/awstats_updateall.pl -configdir=/usr/local/etc/awstats';
	$mysqlbackup_dir = '/usr/local/etc/easytecc/mysqlbackup';
	$mysql = '/usr/iports/bin/mysql';
	$awstats_conf_prefix = '/usr/local/etc/awstats';
	$lang_basedir = '/usr/local/www/apache24/cgi-bin/easytecc4/lang';
	$autoresponder = '/usr/sbin/autoresponder';
}
else{
	#'use lib' does not care about codelevel conditions...
	#use lib '/home/httpd/cgi-bin/easytecc4';
	$easytecc_prefix = '/home/httpd/cgi-bin/easytecc4';
	$droot_prefix = '/home/httpd/docs';
	$droot_regex = '\/home\/httpd\/docs\/';
	$cgi_prefix = '/home/httpd/cgi-bin';
	$awstats_updateall = '/usr/local/awstats/tools/awstats_updateall.pl';
	$mysqlbackup_dir = '/var/lib/mysqlbackup';
	$mysql = '/usr/local/mysql/bin/mysql';
	$awstats_conf_prefix = '/etc/awstats';
	$lang_basedir = '/home/httpd/cgi-bin/easytecc4/lang';
	$autoresponder = '/usr/local/bin/autoresponder';
}

our $easytecc_version='07.09.2022';

use Data::Dumper;
use CGI qw(:all);
use CGI::Carp "fatalsToBrowser";
use easytecc_class;
use easytecc3 qw(ascii_domain is_domain is_email);
use validator qw(validate_input);
use HTML::Template;
use CGI::Cookie;
use CGI::Session;
use DBI;
use HTML::Entities qw(encode_entities decode_entities encode_entities_numeric);
use Encode;
use JSON;
use Encode::Guess;
use Data::FormValidator;
use HTTP::Request;
use LWP::UserAgent;
use Net::IDN::Encode ':all';
use URI::Escape;
use Socket qw(inet_aton);
use Digest::MD5 qw(md5_hex);

#perl zu alt
#use MIME::Base64 qw(encode_base64 decode_base64 encode_base64url decode_base64url);
use MIME::Base64 qw(encode_base64 decode_base64);

$| = 1;

#Jimmy: Log around the world
use Log::Dispatch;
use Log::Dispatch::File;
use File::Spec;
use Time::Format qw(%time %strftime);

use constant LOG_DIR    => '/home/web/log';
use constant LOG_FILE   => 'easytecc4.log';

our $loglevel = 'debug'; #'debug','info','notice','warning','error','critical','alert','emergency' # most reasonable is 'warning' or 'error' for production

sub dienice ($);
sub logline($$);

#
# Begin setup logging agent
#

our $log = new Log::Dispatch(
		callbacks => sub {
	    	my %h=@_;
    	    my ($package, $filename, $line) = caller;
        	my $level = sprintf '%-8.8s', $h{level};
	        return $strftime{'%b %e %T'}." \[$$]: ".$level." => ".$h{message}."\n";
	    }
);

our $debug = 0;
$debug = 1 if(-e '/etc/easytecc'); #run logline("debug",...) only when $debug=1
my $debug_content = 0; #spam the log with html content

if ($debug) {
	$log->add( Log::Dispatch::File->new( name      => 'logfile',
    	                                 min_level => $loglevel,
        	                             mode      => 'append',
            	                         filename  => File::Spec->catfile(LOG_DIR, LOG_FILE),
            	                    	)
	);
}

#
# End setup logging agent
#

logline("notice","#############################################################");
logline("notice","              $$      NEW REQUEST      $$");
logline("notice","#############################################################");

my $cgi = new CGI;
our %input = $cgi->Vars;

logline("debug","input was:" . Data::Dumper->Dump([\%input]));

foreach(keys %input){
	$input{$_} =  decode("utf-8", $input{$_});
	$input{$_} =~ s/^\s+//;
	$input{$_} =~ s/\s+$//;
}

if(exists($input{dir})){
	$input{dir} = decode_base64url($input{dir});
}

if(exists($input{file})){
	$input{file} = decode_base64url($input{file});
}

if(exists($input{full_file})){
	$input{full_file} = decode_base64url($input{full_file});
}	

logline("debug","input is:" . Data::Dumper->Dump([\%input]));

my $action = 'login';
my $results = '';
my $success_text = '';
my $success_text2 = '';
my $success_text3 = '';
my $success_text4 = '';
my $success_text5 = '';
my $validation_result = '';
my %lang_dict;
my $lang = '';
our $session = '';
my $lang_cookie =  cookie( -name => 'LANG' );
my $new_lang_cookie = '';
my $session_id = cookie( -name => 'LOGIN' );

# bricht autonistaller
#if($session_id){
#	$session_id = easytecc3::decrypt($session_id);
#}

my $lang_new = $input{'lang_new'};

my %available_lang;

# tjahmm, doppeln wir das mal. ich wusste gar nicht, dass man scheisse so hoch stapeln kann.
my @lang_array;

# noch ne lang!

my $lang_selected = $lang_new || $lang_cookie || 'deu';

opendir (DIR, $lang_basedir) or die $!;
while (my $language_file = readdir(DIR)) {

    next if ($language_file !~ m/^([a-z][a-z][a-z])\.csv$/);

    my ($lang_code) = $language_file =~ m/^([a-z][a-z][a-z])\.csv$/;
	
	my $lang = {};
	
	$lang->{'lang_code'} = $lang_code;
			
	if($lang_code eq $lang_selected){
		
		$lang->{'lang_selected'} = "SELECTED";
				
	}
			
	push(@lang_array, $lang);
	
	$available_lang{$lang_code} = $lang_code;

}
closedir(DIR);

@lang_array = sort { $a->{'lang_code'} cmp $b->{'lang_code'} } @lang_array;

	#logline("debug"," -M A R I O- --> available_lang is:" . Data::Dumper->Dump([\%available_lang]));


my %json_output = ();

our %error_fields;

my $image_basedir = '/easytecc3/images';

my %actions = ( 'login' => 'login',
				'exec_login' => 'start',
				'logout' => 'logout',
				'change_lang' => 'start',
				'change_user' => 'start',
				'start' => 'start',
				'error' => 'error',
				'show_cloneworx' => 'show_cloneworx',
				'show_vhosts' => 'show_vhosts',
				'show_email' => 'show_email',
				'show_ftpuser' => 'show_ftpuser',
				'show_adminuser' => 'show_adminuser',
				'show_quota' => 'show_quota',
				'show_special_spamfilter' => 'show_special_spamfilter',
				'show_virusfilter' => 'show_virusfilter',
				'show_scan_antivirus' => 'show_scan_antivirus',
				'show_dbbackup' => 'show_dbbackup',
				'show_mysqlbackup_details' => 'show_mysqlbackup_details',
				'show_cronjobs' => 'show_cronjobs',
				'show_frontpage' => 'show_frontpage',
				'show_filemanager' => 'show_filemanager',
				'show_htpasswd' => 'show_htpasswd',
				'show_logfiles' => 'show_logfiles',
				'domainsearch' => 'domainsearch',
				'change_errordocs' => 'change_errordocs',
				'show_webmailer' => 'show_webmailer',
				'new_vhost' => 'new_vhost',
	            'change_vhost' => 'change_vhost',
	            'delete_vhost' => 'delete_vhost',
	            'change_popuser' => 'change_popuser',
	            'change_forward' => 'change_forward',
				'change_forward_single_edit' => 'change_forward_single_edit',
	            'new_autoreply' => 'new_autoreply',
	            'change_autoreply' => 'change_autoreply',
	            'delete_autoreply' => 'delete_autoreply',
	            'new_ftpuser' => 'new_ftpuser',
	            'change_ftpuser' => 'change_ftpuser',
				'delete_ftpuser' => 'delete_ftpuser',
				'new_adminuser' => 'new_adminuser',
				'change_adminuser' => 'change_adminuser',
				'delete_adminuser' => 'delete_adminuser',
	            'change_spamfilter' => 'change_spamfilter',
	            'new_special_spamfilter' => 'new_special_spamfilter',
	            'change_special_spamfilter' => 'change_special_spamfilter',
	            'delete_special_spamfilter' => 'delete_special_spamfilter',
	            'change_virusfilter' => 'change_virusfilter',
	            'auto_cronjob' => 'auto_cronjob',
	            'new_cronjob' => 'new_cronjob',
	            'change_cronjob' => 'change_cronjob',
	            'delete_cronjob' => 'delete_cronjob',
	            'new_fileman' => 'new_fileman',
	            'change_fileman' => 'change_fileman',
	            'new_htaccess' => 'new_htaccess',
	            'change_htaccess' => 'change_htaccess',
	            'delete_htaccess' => 'delete_htaccess',
	            'new_frontpage' => 'new_frontpage',
	            'delete_frontpage' => 'delete_frontpage',
	            'delete_logfiles' => 'delete_logfiles',
	            'instant_mysqlbackup' => 'instant_mysqlbackup',
	            'change_mysqlbackup' => 'change_mysqlbackup',
	            'confirm_restore_mysqlbackup' => 'confirm_restore_mysqlbackup',
	            'download_mysqlbackup' => 'download_mysqlbackup',
	            'delete_mysql_auto_backup' => 'delete_mysql_auto_backup',
	            'exec_restore_mysqlbackup' => 'exec_restore_mysqlbackup',
	            'exec_delete_mysql_auto_backup' => 'exec_delete_mysql_auto_backup',
	            'new_mysqluser' => 'new_mysqluser',
	            'change_mysqluser' => 'change_mysqluser',
	            'exec_new_vhost' => 'exec_new_vhost',
	            'exec_delete_vhost' => 'exec_delete_vhost',
	            'exec_change_vhost' => 'exec_change_vhost',
	            'exec_delete_popuser' => 'exec_delete_popuser',
	            'exec_change_popuser' => 'exec_change_popuser',
	            'exec_delete_forward' => 'exec_delete_forward',
	            'exec_change_forward' => 'exec_change_forward',
				'exec_change_forward_single_edit' => 'exec_change_forward_single_edit',
	            'exec_new_autoreply' => 'exec_new_autoreply',
	            'exec_change_autoreply' => 'exec_change_autoreply',
	            'exec_delete_autoreply' => 'exec_delete_autoreply',
	            'exec_new_ftpuser' => 'exec_new_ftpuser',
	            'exec_delete_ftpuser' => 'exec_delete_ftpuser',
	            'exec_change_ftpuser' => 'exec_change_ftpuser',
				'exec_new_adminuser' => 'exec_new_adminuser',
				'exec_delete_adminuser' => 'exec_delete_adminuser',
				'exec_change_adminuser' => 'exec_change_adminuser',
	            'exec_change_spamfilter' => 'exec_change_spamfilter',
	            'exec_new_special_spamfilter' => 'exec_new_special_spamfilter',
	            'exec_change_special_spamfilter' => 'exec_change_special_spamfilter',
	            'exec_delete_special_spamfilter' => 'exec_delete_special_spamfilter',
	            'exec_change_virusfilter' => 'exec_change_virusfilter',
	            'exec_scan_antivirus' => 'exec_scan_antivirus',
	            'exec_new_cronjob' => 'exec_new_cronjob',
	            'exec_auto_cronjob' => 'exec_auto_cronjob',
	            'exec_delete_cronjob' => 'exec_delete_cronjob',
	            'exec_change_cronjob' => 'exec_change_cronjob',
	            'exec_change_errordocs' => 'exec_change_errordocs',
	            'exec_new_htaccess' => 'exec_new_htaccess',
	            'exec_delete_htaccess' => 'exec_delete_htaccess',
	            'exec_change_htaccess' => 'exec_change_htaccess',
	            'exec_new_frontpage' => 'exec_new_frontpage',
	            'exec_delete_frontpage' => 'exec_delete_frontpage',
	            'exec_delete_logfiles' => 'exec_delete_logfiles',
	            'exec_delete_mysqlbackup' => 'exec_delete_mysqlbackup',
	            'exec_change_mysqlbackup' => 'exec_change_mysqlbackup',
	            'exec_new_mysqluser' => 'exec_new_mysqluser',
	            'exec_delete_mysqluser' => 'exec_delete_mysqluser',
	            'exec_change_mysqluser' => 'exec_change_mysqluser',
	            'exec_domainsearch' => 'exec_domainsearch',
	            'write_db_pass' => 'write_db_pass',
	            'add_mysql_password' => 'add_mysql_password',
	            'exec_add_mysql_password' => 'exec_add_mysql_password',
	            'modify_dir' => 'modify_dir',
	            'exec_modify_dir' => 'exec_modify_dir',
	            'modify_file' => 'modify_file',
	            'exec_modify_file' => 'exec_modify_file',
	            'download_file' => 'download_file',
	            'new_sendmail_cw' => 'new_sendmail_cw',
	            'exec_new_sendmail_cw' => 'exec_new_sendmail_cw',
	            'delete_sendmail_cw' => 'delete_sendmail_cw',
	            'exec_delete_sendmail_cw' => 'exec_delete_sendmail_cw',
	            'awstats_migration' => 'awstats_migration',
	            'exec_awstats_migration' => 'exec_awstats_migration',
	            'roundcube_migration' => 'roundcube_migration',
	            'exec_roundcube_migration' => 'exec_roundcube_migration',
				'confirm_delete_forward' => 'confirm_delete_forward',
				'confirm_delete_mysqlbackup' => 'confirm_delete_mysqlbackup',
				'exec_delete_alert' => 'exec_delete_alert',
				'show_single_edit_email' => 'show_single_edit_email',
				'new_forward_single_edit' => 'new_forward_single_edit',
				'exec_new_forward_single_edit' => 'exec_new_forward_single_edit',
				'new_install' => 'new_install',
				'confirm_new_install' => 'confirm_new_install',
				'exec_new_install' => 'exec_new_install',
				'add_ssl_vhost' => 'add_ssl_vhost',
			    'exec_add_ssl_vhost' => 'exec_add_ssl_vhost',
				'change_ssl_vhost' => 'change_ssl_vhost',
			    'exec_change_ssl_vhost' => 'exec_change_ssl_vhost',
				'show_save_note' => 'show_save_note',
				'exec_show_save_note' => 'exec_show_save_note',
				'new_quotamessage' => 'new_quotamessage',
	            'exec_new_quotamessage' => 'exec_new_quotamessage',
				'new_mailserver_cert' => 'new_mailserver_cert',
	            'exec_new_mailserver_cert' => 'exec_new_mailserver_cert',
				'info_mailuser' => 'info_mailuser',
				'confirm_expunge_mailbox' => 'confirm_expunge_mailbox',
				'exec_expunge_mailbox' => 'exec_expunge_mailbox',
				'new_dir' => 'new_dir',
				'exec_new_dir' => 'exec_new_dir',
				'change_firewall' => 'change_firewall',
				'list_add_ip' => 'list_add_ip',
				'exec_list_add_ip' => 'exec_list_add_ip',
				'search_logs' => 'search_logs',
				'web2ban_edit_rule' => 'web2ban_edit_rule',
				'exec_web2ban_edit_rule' => 'exec_web2ban_edit_rule',
				'web2ban_add_rule' => 'web2ban_add_rule',
				'exec_web2ban_add_rule' => 'exec_web2ban_add_rule',
				'logrotate' => 'logrotate',
				'exec_logrotate' => 'exec_logrotate',
				'whois' => 'whois',
				'show_create_dkim' => 'show_create_dkim',
				'scan2ban_add_port' => 'scan2ban_add_port',
				'exec_scan2ban_add_port' => 'exec_scan2ban_add_port',
				'import_mailuser' => 'import_mailuser',
				'exec_import_mailuser' => 'exec_import_mailuser',
				'stop_import_mailuser' => 'stop_import_mailuser',
				'showlog_import_mailuser' => 'showlog_import_mailuser',
				'mailuser_interface' => 'mailuser_interface',
				'change_autoresponder_sieve' => 'change_autoresponder_sieve',
				'exec_change_autoresponder_sieve' => 'exec_change_autoresponder_sieve',
				'change_forward_sieve' => 'change_forward_sieve',
				'exec_change_forward_sieve' => 'exec_change_forward_sieve'
				);

#bei diesen Aktionen wird Fehlermeldung über ajax an Browser gesendet anstatt neue Seite zu laden
my %ajax_actions = ( 'new_forward_single_edit' => 'new_forward_single_edit',
					 'exec_new_forward_single_edit' => 'exec_new_forward_single_edit',
					 'exec_edit_forward' => 'exec_edit_forward',
					 'new_vhost' => 'new_vhost',
					 'exec_new_vhost' => 'exec_new_vhost',
					 'change_vhost' => 'change_vhost',
					 'exec_change_vhost' => 'exec_change_vhost',
					 'delete_vhost' => 'delete_vhost',
					 'exec_delete_vhost' => 'exec_delete_vhost',
					 'change_popuser' => 'change_popuser',
					 'exec_change_popuser' => 'exec_change_popuser',
					 'change_forward' => 'change_forward',
					 'change_forward_single_edit' => 'change_forward_single_edit',
					 'exec_change_forward' => 'exec_change_forward',
					 'exec_change_forward_single_edit' => 'exec_change_forward_single_edit',
					 'exec_delete_popuser' => 'exec_delete_popuser',
					 'exec_delete_forward' => 'exec_delete_forward',
					 'new_autoreply' => 'new_autoreply',
					 'exec_new_autoreply' => 'exec_new_autoreply',
					 'change_autoreply' => 'change_autoreply',
					 'exec_change_autoreply' => 'exec_change_autoreply',
					 'delete_autoreply' => 'delete_autoreply',
					 'exec_delete_autoreply' => 'exec_delete_autoreply',
					 'new_ftpuser' => 'new_ftpuser',
					 'exec_new_ftpuser' => 'exec_new_ftpuser',
					 'change_ftpuser' => 'change_ftpuser',
					 'exec_change_ftpuser' => 'exec_change_ftpuser',
					 'delete_ftpuser' => 'delete_ftpuser',
					 'exec_delete_ftpuser' => 'exec_delete_ftpuser',
					 'new_adminuser' => 'new_adminuser',
					 'exec_new_adminuser' => 'exec_new_adminuser',
					 'change_adminuser' => 'change_adminuser',
					 'exec_change_adminuser' => 'exec_change_adminuser',
					 'delete_adminuser' => 'delete_adminuser',
					 'exec_delete_adminuser' => 'exec_delete_adminuser',
					 'change_special_spamfilter' => 'change_special_spamfilter',
					 'exec_change_special_spamfilter' => 'exec_change_special_spamfilter',
					 'delete_special_spamfilter' => 'delete_special_spamfilter',
					 'exec_delete_special_spamfilter' => 'exec_delete_special_spamfilter',
					 'delete_logfiles' => 'delete_logfiles',
					 'exec_delete_logfiles' => 'exec_delete_logfiles',
					 'auto_cronjob' => 'auto_cronjob',
					 'exec_auto_cronjob' => 'exec_auto_cronjob',
					 'change_mysqlbackup' => 'change_mysqlbackup',
					 'exec_change_mysqlbackup' => 'exec_change_mysqlbackup',
					 'show_mysqlbackup_details' => 'show_mysqlbackup_details',
					 'instant_mysqlbackup' => 'instant_mysqlbackup',
					 'confirm_delete_mysqlbackup' => 'confirm_delete_mysqlbackup',
					 'confirm_restore_mysqlbackup' => 'confirm_restore_mysqlbackup',
					 'exec_restore_mysqlbackup' => 'exec_restore_mysqlbackup',
					 'exec_delete_mysqlbackup' => 'exec_delete_mysqlbackup',
					 'delete_mysql_auto_backup' => 'delete_mysql_auto_backup',
					 'exec_delete_mysql_auto_backup' => 'exec_delete_mysql_auto_backup',
					 'new_cronjob' => 'new_cronjob',
					 'change_cronjob' => 'change_cronjob',
					 'delete_cronjob' => 'delete_cronjob',
					 'exec_new_cronjob' => 'exec_new_cronjob',
					 'exec_delete_cronjob' => 'exec_delete_cronjob',
					 'exec_change_cronjob' => 'exec_change_cronjob',
					 'delete_sendmail_cw' => 'delete_sendmail_cw',
					 'exec_delete_sendmail_cw' => 'exec_delete_sendmail_cw',
					 'exec_delete_alert' => 'exec_delete_alert',
					 'modify_file' => 'modify_file',
					 'exec_modify_file' => 'exec_modify_file',
					 'modify_dir' => 'modify_dir',
					 'exec_modify_dir' => 'exec_modify_dir',
					 'new_htaccess' => 'new_htaccess',
					 'exec_new_htaccess' => 'exec_new_htaccess',
					 'change_htaccess' => 'change_htaccess',
					 'delete_htaccess' => 'delete_htaccess',
					 'exec_change_htaccess' => 'exec_change_htaccess',
					 'exec_delete_htaccess' => 'exec_delete_htaccess',
					 'confirm_new_install' => 'confirm_new_install',
	 				 'add_ssl_vhost' => 'add_ssl_vhost',
					 'exec_add_ssl_vhost' => 'exec_add_ssl_vhost',
	 				 'change_ssl_vhost' => 'change_ssl_vhost',
					 'exec_change_ssl_vhost' => 'exec_change_ssl_vhost',					 
					 'show_save_note' => 'show_save_note',
					 'exec_show_save_note' => 'exec_show_save_note',
					 'info_mailuser' => 'info_mailuser',
					 'confirm_expunge_mailbox' => 'confirm_expunge_mailbox',
					 'exec_expunge_mailbox' => 'exec_expunge_mailbox',
					 'new_dir' => 'new_dir',
					 'exec_new_dir' => 'exec_new_dir',
					 'list_add_ip' => 'list_add_ip',
					 'exec_list_add_ip' => 'exec_list_add_ip',
					 'search_logs' => 'search_logs',
					 'web2ban_edit_rule' => 'web2ban_edit_rule',
					 'exec_web2ban_edit_rule' => 'exec_web2ban_edit_rule',
					 'web2ban_add_rule' => 'web2ban_add_rule',
					 'exec_web2ban_add_rule' => 'exec_web2ban_add_rule',
					 'logrotate' => 'logrotate',
					 'exec_logrotate' => 'exec_logrotate',
					 'whois' => 'whois',
					 'show_create_dkim' => 'show_create_dkim',
					 'scan2ban_add_port' => 'scan2ban_add_port',
				     'exec_scan2ban_add_port' => 'exec_scan2ban_add_port',
					 'import_mailuser' => 'import_mailuser',
					 'exec_import_mailuser' => 'exec_import_mailuser',
					 'stop_import_mailuser' => 'stop_import_mailuser',
					 'showlog_import_mailuser' => 'showlog_import_mailuser',
					 'change_autoresponder_sieve' => 'change_autoresponder_sieve',
					 'exec_change_autoresponder_sieve' => 'exec_change_autoresponder_sieve',
					 'change_forward_sieve' => 'change_forward_sieve',
					 'exec_change_forward_sieve' => 'exec_change_forward_sieve'
					 );

my %no_header_actions = ('download_mysqlbackup' => '1',
						 'download_file' => '1');

## als erstes gucken, ob er einen Sprachcookie hat, wenn nicht, dann eines setzen
unless($lang_cookie){
	logline("info","Neues Sprachcookie.");
	$new_lang_cookie = cookie(-name => 'LANG', -expires => '+12M', -value => 'deu');
	$lang = 'deu';
}
# hat schon ein Cookie, gucken ob auch verwendbare Sprache drin ist und ob Sprache geändert werden soll
# Cookies werden von Browser akzeptiert, ansonsten hätte er ja kein vorhandenes ;-)
else{
	# Sprache soll geändert werden
	# defined und exists, um "Use of uninitialized value" in Log zu verhindern
	if(defined $lang_new && exists $available_lang{$lang_new}){
		logline("info","Neue Sprache = $lang_new.");
		$new_lang_cookie = cookie(-name => 'LANG', -expires => '+12M', -value => $available_lang{$lang_new});
		$lang = $lang_new;
	}
	# ist Sprache in Cookie wirklich anwendbar? Wenn ja dann vorhandenes Cookie weiterverwenden
	elsif(exists $available_lang{$lang_cookie}){
		logline("info","Vorhandenes Sprachcookie OK = $lang_cookie.");
		$lang = $lang_cookie;
	}
	# wenn nicht, dann Default-Sprache de setzen
	else{
		logline("warning","Sprachcookie UNGÜLTIG = $lang_cookie.");
		$new_lang_cookie = cookie(-name => 'LANG', -expires => '+12M', -value => 'deu');
		$lang = 'deu';
	}
}

logline("info","\$input{'action'} = " . $input{'action'});

if($session_id && $input{'action'} ne 'exec_login'){
	#Falls mit gültiger Session auf Startseite( z.B. Logo) geklickt wird, dann gibt es kein $input{'action'}
	#in diesem Fall die Hauptseite anzeigen
	$input{'action'} = 'start' if $input{'action'} eq '';

	# cookie ziehen
	# wenn session_check einen Rückgabewert hat, dann ist etwas faul im Staate Dänemark.
	# Daher Cookie löschen und Loginseite anzeigen. Cookie wird gelöscht, indem es mit
	# expiredate in der Vergangenheit neu gesetzt wird. Cookie wird dann vom Browser
	# automatisch gelöscht.
	CGI::Session->name("LOGIN");
	#$session = CGI::Session->new("driver:file", $session_id, {Directory=>'/tmp'});
	$session = CGI::Session->load("driver:file", $session_id, {Directory=>'/tmp'});
	#$session = CGI::Session->load();
	my $remote_ip = $session->remote_addr();
	my $id = $session->id();

	logline("debug","Remote ip=$remote_ip id=$id.");

	if($session->param('auth_domains')){
		logline("warning","Zugriff auf easytecc mit session aus usertool");
		$input{'action'} = 'login';
		$session->delete();
	}

	if ($session->is_expired){
		logline("notice","Session abgelaufen");
		$input{'action'} = 'login';
		$session->delete();
	}

	if ($session->is_empty){
		logline("error","Session konnte nicht geladen werden");
		$input{'action'} = 'login';
	}
}
elsif($input{'action'} eq 'exec_login'){
	my $remote_ip = $cgi->remote_addr();
	logline("notice","Loginversuch von $remote_ip");
	#nix
}
else{
	my $remote_ip = $cgi->remote_addr();
	logline("warning","Kein Session-Cookie gefunden für $remote_ip");
	$input{'action'} = 'login';
}

# bei Logout Session von Server löschen. Cookie von Browser löschen schenken wir uns
if(exists $input{'action'} && $input{'action'} eq 'logout'){
	logline("debug","Logout");
	$session->delete();
	$session->flush();
	$session = undef;
	
	#print header(	-type=>'text/html',
    #	            -charset=>'utf-8',
    #    	        -cookie=>cookie(-name => 'LOGIN', -expires => '-1d', -value => '')
	#);
	
}

### Mario: i am looking for a future-way for enabling/disabling wanted/unwanted features
###        with two config files
###        default config file: easytecc.default.conf (which will be overwritten on update)
###        custom  config file: easytecc.custom.conf (which does not exist in our source code,
###                             therefore will not overwrite custom configuration from our
###                             customers)
###        Decisive for this decision are recurring problems such as
###                             "fjuers: Display passwords (DSGVO) unwanted",
###                             "dgoels: Autoresponder without umlauts unwanted",
###                             "dgoels: unfiltered forwarding unwanted".

### pico -w /usr/local/etc/easytecc/easytecc.custom.conf
#   ShowMailuserPasswords=NO
#	ShowASCIIAutoresponder=NO

if ($fb) {
	my $easytecc_default_conf = '/usr/local/www/apache24/cgi-bin/easytecc4/config/easytecc.default.conf';
} else {
	my $easytecc_default_conf = 			'/home/httpd/cgi-bin/easytecc4/config/easytecc.default.conf';
}
my $easytecc_custom_conf  = '/usr/local/etc/easytecc/easytecc.custom.conf';
our %easytecc_custom_conf_entries;
if (-e $easytecc_custom_conf) {
	#my $username = getpwuid( $< );
	#my $fileowner = getpwuid((stat($easytecc_custom_conf))[4]);
	#if ($username ne $fileowner) {
	#	logline("error","file $easytecc_custom_conf belongs to $fileowner, but owner should be $username.");
	#}
	open(my $CUSTOMCONF, "<", "$easytecc_custom_conf") or die "Can't open < $easytecc_custom_conf: $!";
	if (length($easytecc_custom_conf))	{
		logline("info", "length(file $easytecc_custom_conf) true");
		while (my $line = <$CUSTOMCONF>) {   
			chomp($line);
			my ($custom_conf_key, $custom_conf_value) = split /=/, $line;
			$easytecc_custom_conf_entries{$custom_conf_key} = $custom_conf_value;
			logline("info", "\$easytec_custom_conf: $custom_conf_key= ###$custom_conf_value###");
		}
	}
	close($CUSTOMCONF) && logline("info","closed ") || logline("error","close failed: $!");
} else {
	logline("error", "file $easytecc_custom_conf does not exist.");
}


# new vhost logic. well, logic is the wrong word, actually. 
if(exists $input{'action'} && $input{'action'} eq 'exec_new_vhost'){
	
	if(!$input{'ftp'}){
		
		$input{'ftpuser'} = '';
		$input{'ftppass'} = '';
		$input{'ftppass'} = '';
		$input{'ftpquota'} = '';
        $input{'suexec'} = '';
        $input{'ssh'} = '';
		
	}
	
	if(!$input{'mysql_db'}){
		
		$input{'db'} = '';
		$input{'dbuser'} = '';
		$input{'dbpass'} = '';
		
	}
	
}

# disallow add new adminusers via description
# should be empty if adminuser edits adminuser >> force reading from existing passwd entry
# if some fake action is taken, reset it to FTP
if($session 
    && $session->param('user') ne 'admin' 
	&& exists $input{'action'} 
	&& $input{'action'} =~ m/(exec_new_ftpuser|exec_change_ftpuser)/
	&& length($input{'gecos'})
	&& $input{'gecos'} =~ m/^CUST/
){
	$input{'gecos'} = 'FTP';
}

# workaround for hardcoded default_home...
if(exists $input{'action'} && $input{'action'} =~ m/(exec_new_ftpuser|exec_new_adminuser)/){
	
	if(!length($input{'home'}) && length($input{'default_home'}) > 0){
	
		$input{'home'} = $input{'default_home'};
		$input{'home'} =~ s/\/benutzer$/\/$input{'ftpuser'}/;
		
	}
	
}

if(exists $input{'action'} && $input{'action'} eq 'change_user' && length($input{'user_new'}) && $session->param('is_admin_session') eq '1'){
	
		$session->param('user',$input{'user_new'});
		$session->flush();
		
		if($input{'user_new'} eq 'admin'){
			$input{'action'} = 'show_adminuser';
		} else {
			$input{'action'} = 'start';
		}
		
	}

# workaround for cert stuff
if(exists $input{'action'} && $input{'action'} =~ m/exec_(add|change)_ssl_vhost/){
	
	if(length($input{'letsencrypt'}) && $input{'letsencrypt'}){
		
	}
	else {
			
		my $prefix;						
		if($fb){
				$prefix = '/etc/apache24/';
		}
		
		else {
				$prefix = '/etc/httpd/conf/';
		}
		
		if(length($input{'csr'}) && $input{'csr'}){
			
			my $csr_dir = $prefix . 'ssl.csr/';
			if(! -d $csr_dir){
					
				if($fb){
					system("/usr/iports/bin/sudo /usr/sbin/webmkdir -p $csr_dir");
				}
				else {
					system("/usr/sbin/admmkdir -p $csr_dir");
				}
				
			}
			$input{'csr_file'} = $csr_dir . $input{'domain'} . '.cert.csr';
			
			my $key_dir = $prefix . 'ssl.key/';
			if(! -d $key_dir){
					
				if($fb){
					system("/usr/iports/bin/sudo /usr/sbin/webmkdir -p $key_dir");
				}
				else {
					system("/usr/sbin/admmkdir -p $key_dir");
				}
				
			}
			$input{'key_file'} = $key_dir . $input{'domain'} . '.cert.key';
			
			
			if(length($input{'csr_country'})){
				
				$input{'csr_country'} = uc $input{'csr_country'};
				
			}
									
		}
		
		else {
		
			my $cert_dir = $prefix . 'ssl.crt/';
			my $key_dir = $prefix . 'ssl.key/';
			my $chain_dir = $prefix . 'ssl.crt/';
			
							
			if(
			   length($input{'cert'}) && $input{'cert'} =~ m/[\r\n]/ ||
			   length($input{'cert_file'})
			){
				
				if(! -d $cert_dir){
					
					if($fb){
						system("/usr/iports/bin/sudo /usr/sbin/webmkdir -p $cert_dir");
					}
					else {
						system("/usr/sbin/admmkdir -p $cert_dir");
					}
					
				}
							
				my $cert_file = $cert_dir . $input{'domain'} . '.cert.crt';
				if(open(my $fh, '>', $cert_file)){
					
					binmode($fh);
					
					if(length($input{'cert_file'})){
						
						my $infh = $cgi->upload('cert_file');
						
						
						#logline("debug","infh is:" . Data::Dumper->Dump([$infh]));
						
												
						while(read($infh, my $data, 1024)) {
							print $fh $data;
						}
						close $infh;
											
					}
					
					else {
									
						print $fh $input{'cert'};
						
					}
					
					close $fh;
					
				}
						
				$input{'cert'} = $cert_file;
				
			}
			
			if(
			   length($input{'key'}) && $input{'key'} =~ m/[\r\n]/ ||
			   length($input{'key_file'})
			){
				
				if(! -d $key_dir){
					
					if($fb){
						system("/usr/iports/bin/sudo /usr/sbin/webmkdir -p $key_dir");
					}
					else {
						system("/usr/sbin/admmkdir -p $key_dir");
					}
					
				}
				
				my $key_file = $key_dir . $input{'domain'} . '.cert.key';
				if(open(my $fh, '>', $key_file)){
					
					binmode($fh);
					
					if(length($input{'key_file'})){
						
						my $infh = $cgi->upload('key_file');
												
						while(read($infh, my $data, 1024)) {
							print $fh $data;
						}
						
						close $infh;
											
					}
					
					else {
									
						print $fh $input{'key'};
						
					}
					
					close $fh;
					
				}
						
				$input{'key'} = $key_file;
				
			}
			
			if(
			   length($input{'chain'}) && $input{'chain'} =~ m/[\r\n]/ ||
			   length($input{'chain_file'})
			){
				
				if(! -d $chain_dir){
					
					if($fb){
						system("/usr/iports/bin/sudo /usr/sbin/webmkdir -p $chain_dir");
					}
					else {
						system("/usr/sbin/admmkdir -p $chain_dir");
					}
					
				}
				
				my $chain_file = $chain_dir . $input{'domain'} . '.chain.crt';
				if(open(my $fh, '>', $chain_file)){
					
					binmode($fh);
					
					if(length($input{'chain_file'})){
						
						my $infh = $cgi->upload('chain_file');
												
						while(read($infh, my $data, 1024)) {
							print $fh $data;
						}
						
						close $infh;
											
					}
					
					else {
									
						print $fh $input{'chain'};
						
					}
					
					close $fh;
					
				}
						
				$input{'chain'} = $chain_file;
				
			}
		
		}	
		
	}
	
}

#fix idn
# erschreckend, einfach nur erschreckend
if(exists $input{'special_spam_user_domain'}){
	
	if($input{'special_spam_user_domain'} =~ m/@/){
		$input{'special_spam_user_domain'} = email_to_ascii($input{'special_spam_user_domain'});
	} else {
		$input{'special_spam_user_domain'} = ascii_domain($input{'special_spam_user_domain'});
	}	
		
}

if(exists $input{'domain'}){
	$input{'domain'} = ascii_domain($input{'domain'});
}

#foreach(keys(%ENV)) {
#  logline("debug","env: " . $_ . $ENV{$_} . "\n");
#}


# mailuser hack map actions forward before validation
# reverse mapping below or in called functions
if($session && $session->param('is_mailuser')){

	if($input{'action'} eq 'mailuser_interface'){
		
		if($input{'active_tab'} eq '_password'){
			
			# 2fa part
			if(defined($input{'2fa'})){
			
				$input{'action'} = "mailuser_interface";
			
			} else {
						
				$input{'action'} = 'exec_change_popuser';
				$input{'old_user1'} = $input{'user1'} = $session->param('user');
				$input{'old_pass1'} = ''; 
				
				# quota
				my $mailquota = {};
				
				if (easytecc3::extern_mx() || $fb) {
					$mailpasswd = easytecc3::get_mailpasswd();
					my %passwd = %{$mailpasswd->file_parsed_hash()};
					($mailquota, undef, undef, undef) = easytecc3::getquota_mail(\%passwd);
				}
				else{
					($mailquota, undef, undef, undef) = easytecc3::getquota_ftp();
				}
				
				$input{'old_quota1'} = $input{'quota1'} = $mailquota->{$session->param('user')}{'quota'} / 1024;
				$input{'domain'} = $session->param('user');
				$input{'domain'} =~ s/^[^\@]+\@//;
				$input{'domain'} = 'www.' . $input{'domain'};
				
				logline("debug","is_mailuser=1, setting action=exec_change_popuser from tab _password");
				
			}
			
		}
		elsif($input{'active_tab'} eq '_mailbox'){
		
			$input{'action'} = 'confirm_expunge_mailbox';
			$input{'mailuser'} = $session->param('user');
			logline("debug","is_mailuser=1, setting action=confirm_expunge_mailbox from tab _mailbox");
		
		}
		elsif($input{'active_tab'} eq '_spamfilter'){
					
			$input{'special_spam_user_domain'} = $session->param('user');
		
			if(-f "/home/" . $session->param('user') . "/.spamproc"){
		
				$input{'action'} = 'exec_change_special_spamfilter';
				
			} else {
				
				$input{'action'} = 'exec_new_special_spamfilter';
								
			}
		}
		elsif($input{'active_tab'} eq '_forward'){
			
			$input{'action'} = "mailuser_interface";
			
		}
		elsif($input{'active_tab'} eq '_autoresponder'){
			
			$input{'action'} = "mailuser_interface";
			
		}
				
	}
	elsif($input{'action'} eq 'exec_expunge_mailbox'){
		
		logline("debug","is_mailuser=1, leaving action=exec_expunge_mailbox");
		
	}
	else {
		
		$input{'action'} = 'mailuser_interface';
		logline("debug","is_mailuser=1, setting action=mailuser_interface");
		
	}
		
}

if(exists($input{'action'}) && exists($actions{$input{'action'}})){
	logline("debug","Going to validate input data if any.");
			
	logline("debug","input is:" . Dumper(%input));
	
	$action = $actions{$input{'action'}};
	$results = validate_input(\%input, \$session);
	$validation_result = easytecc3::result_debug($results) if ref($results);
	logline("error","validation_result = $validation_result") if $validation_result;	#TODO JIMMY: das ist ein fucking hash - schön machen für log
		
}

# erfolgloser Loginversuch
if($input{'action'} eq 'exec_login' && $validation_result){
	logline("debug","exec_login + validation_result");
	$action = 'login';
	print header(	-type=>'text/html',
					-charset=>'utf-8',
					'-X-easytecc-login'=>'failed') unless $new_lang_cookie;
	print header(	-type=>'text/html',
    	            -charset=>'utf-8',
        	        -cookie=>$new_lang_cookie,
					'-X-easytecc-login'=>'failed') if $new_lang_cookie;
}
# wenn login erfolgreich dann Cookie setzen
elsif($input{'action'} eq 'exec_login' && ! $validation_result){
	# validator.pm guckt nur, ob user mit korrektem Passwort angemeldet.
	# usertool und easytecc3 teilen sich validator, daher hier gucken, ob username wirklich admin
	# da sich sonst endkunde mit normalem ftpuser in easytecc einloggen könnte

	# user logic
	
	#if($input{'user'} ne 'admin'){
	#	logline("warning","Zugriff auf easytecc nicht mit user admin.");
	#	$action = 'login';
	#	print header(	-type=>'text/html',
	#					-charset=>'utf-8') unless $new_lang_cookie;
	#	print header(	-type=>'text/html',
	#					-charset=>'utf-8',
	#					-cookie=>$new_lang_cookie) if $new_lang_cookie;
	#}
    #else{
		$session = CGI::Session->new("driver:file", undef, {Directory=>'/tmp'});
		
		# bricht autonistaller
		#my $login_cookie = new CGI::Cookie(-name=>'LOGIN', -value=>easytecc3::encrypt("",$session->id), -expires => "12h");
		
		$session->name('LOGIN');
		$session->expire("12h");
		

		print $session->header(	-type=>'text/html',
								-charset=>'utf-8',
								'-X-easytecc-login'=>'ok') unless $new_lang_cookie;
		print $session->header(	-type=>'text/html',
								-charset=>'utf-8',
								-cookie=>$new_lang_cookie,
								'-X-easytecc-login'=>'ok') if $new_lang_cookie;
		
		# bricht autoinstaller
		#if($new_lang_cookie){
		#	print $cgi->header(	-type=>'text/html',	-charset=>'utf-8', cookie=>[$login_cookie,$new_lang_cookie]);
		#} else {
		#	print $cgi->header(	-type=>'text/html',	-charset=>'utf-8', cookie=>$login_cookie);
		#}
		
		$session->param('user', $input{'login_user'});
		
		if($input{'login_user'} eq 'admin'){
			$session->param('is_admin_session', '1');
		}
		
		if(-e '/usr/local/etc/easytecc/mailuser/' . $input{'login_user'}){
			
			$session->param('is_mailuser', '1');
			$action = 'mailuser_interface';
			logline("debug","setting is_mailuser=1 action=mailuser_interface");
					
		} else {
			
			$action = 'start';
			
		}
		
		if(exists($input{'display_server_name'})){
			$display_server_name = $input{'display_server_name'};
			$session->param(-name=>'display_server_name',-value=>$display_server_name);
			logline("debug","display_server_name from param:" . $display_server_name);
		}
		
		$session->flush();
		
				
		logline("notice","Login erfolgreich.");
    #}
}
# Funktionen wie download_mysqlbackup liefern Download direkt mit anderem http-Header aus
elsif(defined $no_header_actions{$action}){
	#nix
	logline("debug","\$no_header_actions{\$action} = " . $no_header_actions{$action});
}
else{
	logline("debug","Common header printed.");
	print header(	-type=>'text/html',
					-charset=>'utf-8') unless $new_lang_cookie;

	print header(	-type=>'text/html',
					-charset=>'utf-8',
					-cookie=>$new_lang_cookie) if $new_lang_cookie;
}


# workaround for easytecc iframe in domains
my $display_server_name = undef;
if($session){
	$display_server_name = $session->param('display_server_name');
	logline("debug","display_server_name from session:" . $display_server_name);
}
if(!$display_server_name){
	$display_server_name = $ENV{'HTTP_X_FORWARDED_HOST'};
}
if(!$display_server_name){
	$display_server_name = $ENV{'SERVER_NAME'};
}

$display_server_name =~ s/^www\.//;

# special layout
# search user,domain,role

my $template_user = '';
my $template_domain = $display_server_name;
my $template_role = 'CUSTOMER';

if($session){
	
	$template_user = $session->param('user');
	if($session->param('is_mailuser')){
	
		$template_role = 'MAILUSER';
	
	}
	elsif($template_user eq 'admin'){
	
		$template_role = 'ADMIN';
		
	}
		
}

my $template_base = "$easytecc_prefix/html-templates";

if(length($template_user) && -d "$template_base/$template_user"){
	
	HTML::Template->config(path => "$template_base/$template_user");
	logline("debug","added $template_base/$template_user to template search path");
	
}

if(-d "$template_base/$template_domain"){
	
	HTML::Template->config(path => "$template_base/$template_domain");
	logline("debug","added $template_base/$template_domain to template search path");
	
}

if(-d "$template_base/$template_role"){
	
	HTML::Template->config(path => "$template_base/$template_role");
	logline("debug","added $template_base/$template_role to template search path");

	
}

HTML::Template->config(path => "$template_base");
HTML::Template->config(die_on_bad_params => 0);	
	
my $nav_sidebar = HTML::Template->new(filename => 'nav_sidebar.html');
$nav_sidebar->param('FB' => $fb);

our $header = HTML::Template->new(filename => 'header.html');
$header->param('FB' => $fb);
$header->param('lang' => $lang);
$header->param('selected_lang_' . $lang => 'selected');
$header->param('lang_select' => \@lang_array);



my $whoami = '';

# decide about left menue
if($session && $session->param('user')){

	if($session->param('user') eq 'admin'){
		
		$header->param('is_admin' => '1');
		$nav_sidebar->param('is_admin' => '1');
		
		$header->param('show_vhosts' => '1');
		$nav_sidebar->param('show_vhosts' => '1');
		$session->param('show_vhosts','1');
		
		$header->param('show_email' => '1');
		$nav_sidebar->param('show_email' => '1');
		$session->param('show_email','1');
		
		$header->param('show_ftp' => '1');
		$nav_sidebar->param('show_ftp' => '1');
		$session->param('show_ftp','1');
		
		$header->param('show_quota' => '1');
		$nav_sidebar->param('show_quota' => '1');
		$session->param('show_quota','1');
		
		$header->param('show_spam' => '1');
		$nav_sidebar->param('show_spam' => '1');
		$session->param('show_spam','1');
		
		$header->param('show_fileman' => '1');
		$nav_sidebar->param('show_fileman' => '1');
		$session->param('show_fileman','1');
		
		$header->param('show_logs' => '1');
		$nav_sidebar->param('show_logs' => '1');
		$session->param('show_logs','1');
		
		$header->param('show_db' => '1');
		$nav_sidebar->param('show_db' => '1');
		$session->param('show_db','1');
		
		$header->param('show_cron' => '1');
		$nav_sidebar->param('show_cron' => '1');
		$session->param('show_cron','1');
		
		$header->param('show_inst' => '1');
		$nav_sidebar->param('show_inst' => '1');
		$session->param('show_inst','1');
		
		if(-d '/usr/local/etc/easytecc/shell2ban'){
		
			$header->param('show_firewall' => '1');
			$nav_sidebar->param('show_firewall' => '1');
			$session->param('show_firewall','1');
			
		}
	
	} elsif($session->param('is_mailuser')){
	
		my $mailuser = $session->param('user');
		
		my @addresses;
		my @aliases;
		
		my $virtmaps_lhs;
		my $virtmaps_rhs;
				
		if($fb){
		
			$virtmaps_rhs = `sed '/procmail -a $mailuser/!d ; s/:.*//' /etc/mail/aliases 2>/dev/null`;
			chomp($virtmaps_rhs);
			
		} else {
			
			$virtmaps_rhs = `sed 's/:.*[\t,]$mailuser/#MATCH#/ ; s/#MATCH#,.*/#MATCH#/ ; /#MATCH#\$/!d ; s/#MATCH#//' /etc/mail/aliases 2>/dev/null`;
			chomp($virtmaps_rhs);
			
			if(!length($virtmaps_rhs)){
				
				$virtmaps_rhs = $mailuser
				
			}
			
		}
		
		foreach $virtmaps_rhs(split(/\n/,$virtmaps_rhs)){
		
			$virtmaps_lhs = `grep '[^[:print:]]$virtmaps_rhs\$' /etc/mail/virtmaps 2>/dev/null | cut -f 1 2>/dev/null`;
			chomp($virtmaps_lhs);
		
			if(length($virtmaps_lhs)){
				
				push(@addresses,split('\n',$virtmaps_lhs));
				
			}
			
		}
		
		#unique
		@addresses = keys %{{ map { $_ => 1 } @addresses }};
		
		if(!@addresses){
			
			$header->param('addresses' => 'L__Keine gültige E-Mail-Adresse__L');
						
		} else {
			
			$header->param('addresses' => join(', ',@addresses));
									   
		}
		
		
		if(scalar(@addresses) == 1){
				
			$session->param('mailaddress' => shift @addresses);
			$session->flush();
			
		} 			
				
		#if($mailuser !~ /\@/){
		#	
		#	my $passwd = file->new({file_name => '/etc/passwd'});
		#	$passwd->read_file;
		#	my %passwd = %{$passwd->file_parsed_hash()};
		#
		#	my $domain = $passwd{$session->param('user')}{'gecos'};
		#	$domain=~ s/\s.*$//;
		#	
		#	$mailuser .= '@' . $domain;
		#	
		#}
				
		$header->param('user' => $mailuser);
		
		$header->param('act_mailuser_interface' => '1');
		logline("debug","is_mailuser=1, setting header act_mailuser_interface=1, user=" . $session->param('user'));
				
	} else {
	
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};

		# Mario: gecos field = "General information about the user."
		my $gecos = $passwd{$session->param('user')}{'gecos'};
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.vhost-1.email-1.ftp-2.quota.spam.fileman-1.logs-1';
		
		}
	
		if($gecos =~ m/\.vhost/){
		
			$header->param('show_vhosts' => '1');
			$nav_sidebar->param('show_vhosts' => '1');
			$session->param('show_vhosts','1');
		
		}
		
		if($gecos =~ m/\.email/){
		
			$header->param('show_email' => '1');
			$nav_sidebar->param('show_email' => '1');
			$session->param('show_email','1');
		
		}
		
		if($gecos =~ m/\.ftp/){
		
			$header->param('show_ftp' => '1');
			$nav_sidebar->param('show_ftp' => '1');
			$session->param('show_ftp','1');
		
		}
	
		if($gecos =~ m/\.quota/){
		
			$header->param('show_quota' => '1');
			$nav_sidebar->param('show_quota' => '1');
			$session->param('show_quota','1');
		
		}
		
		if($gecos =~ m/\.spam/){
		
			$header->param('show_spam' => '1');
			$nav_sidebar->param('show_spam' => '1');
			$session->param('show_spam','1');
		
		}
		
		if($gecos =~ m/\.fileman/){
		
			$header->param('show_fileman' => '1');
			$nav_sidebar->param('show_fileman' => '1');
			
			my $dir_encoded = encode_base64url($passwd{$session->param('user')}{'home'});
			$nav_sidebar->param('dir_encoded' => $dir_encoded);
			
			$session->param('show_fileman','1');
		
		}
		
		if($gecos =~ m/\.logs/){
		
			$header->param('show_logs' => '1');
			$nav_sidebar->param('show_logs' => '1');
			$session->param('show_logs','1');
		
		}
		
		if($gecos =~ m/\.db/){
		
			$header->param('show_db' => '1');
			$nav_sidebar->param('show_db' => '1');
			$session->param('show_db','1');
		
		}
		
		if($gecos =~ m/\.cron/){
		
			$header->param('show_cron' => '1');
			$nav_sidebar->param('show_cron' => '1');
			$session->param('show_cron','1');
		
		}
		
		if($gecos =~ m/\.inst/){
		
			$header->param('show_inst' => '1');
			$nav_sidebar->param('show_inst' => '1');
			$session->param('show_inst','1');
		
		}
		
		$whoami = $session->param('user') . '@';
		
	}
	
	if($session && $session->param('is_admin_session') eq '1'){
	
		$header->param('is_admin_session' => '1');
	
	}	
	
	$header->param('is_logged_in' => '1');
		
}

# mailuser hack map actions reverse after validation
if($session && $session->param('is_mailuser')){

	if($validation_result){

		if($input{'action'} eq 'exec_change_popuser'){
		
			$action = $input{'action'} = 'mailuser_interface';
			$input{'active_tab'} = '_password';
			logline("debug","is_mailuser=1, error from validation, setting action=mailuser_interface from exec_change_popuser, tab=_password");
										
		}
		elsif($input{'action'} eq 'exec_new_special_spamfilter'){
		
			$action = $input{'action'} = 'mailuser_interface';
			$input{'active_tab'} = '_spamfilter';
			logline("debug","is_mailuser=1, error from validation, setting action=mailuser_interface from exec_new_special_spamfilter, tab=_spamfilter");
										
		}
		
	}
	
}	

if($validation_result){
							
	if($input{'action'} eq 'exec_new_sendmail_cw' || $input{'action'} eq 'exec_new_quotamessage' ||  $input{'action'} eq 'exec_new_mailserver_cert'){
		$action = 'show_email';
	}
	elsif($input{'action'} eq 'exec_new_mysqluser'){
		$action = 'show_dbbackup';
	}
	
	$action =~ s/^exec_//;
	
}

my $baseaction = $action;
$baseaction =~ s/^exec_//;

if($baseaction =~ m/special_spamfilter/ && !$session->param('is_mailuser')){
	
	$baseaction = 'change_spamfilter';
	
} elsif($baseaction =~ m/single_edit_email/){

	$baseaction = 'show_email';

}

$header->param('act_' . $baseaction => 'class="active hidden-sm"');
$header->param('server_name' => $whoami . $display_server_name);

my $footer = HTML::Template->new(filename => 'footer.html');
$footer->param('is_admin' => $fb);
$footer->param('easytecc_version' => $easytecc_version);

$nav_sidebar->param('act_' . $baseaction => 'class="active"');


# no sidebar with installer and mailusers
if (($action =~ /new_install/ && !$input{'error'}) || ($session && $session->param('is_mailuser'))) {
#	$footer->param('nav_sidebar' => $nav_sidebar->output);
} else {

	$header->param('container' => '
				<div class="col-sm-9 col-sm-push-3 col-lg-10 col-lg-push-2 main-content"> 
	');

	$footer->param('nav_sidebar' => $nav_sidebar->output);
	$footer->param('container_end' => '</div>');

}

#navigation(\$header);


# workaround for mailuser_interface
#if($session && $session->param('is_mailuser')){
		
#	if($action ne 'confirm_expunge_mailbox'){
	
#		$action = $input{'action'} = 'mailuser_interface';
	
#	}
		
#}

#if(!exists($input{'action'}) || $input{'action'} !~ /(mailuser_interface|info_mailuser|exec_change_popuser|confirm_expunge_mailbox|exec_expunge_mailbox|exec_change_special_spamfilter)/){

logline("info","action = $action");


# jump to action code
$html = &$action;

## mailuser hack, reverse mapping after exec
#if($session && $session->param('is_mailuser')){
#	
#	if($input{'action'} eq 'exec_change_popuser'){
#		
#		$action = $input{'action'} = 'mailuser_interface';
#		$input{'active_tab'} = '_password';
#		logline("debug","is_mailuser=1 after exec setting action=mailuser_interface from exec_change_popuser, tab=_password");
#									
#	}
#		
#}


$$html->param('header' => $header->output);
$$html->param('footer' => $footer->output);

# wenn Formular fehlerhaft ausgefüllt erneut anzeigen und Werte wieder einfgen + CSS-Fehlerklasse als Markierung
# wenn also bei exec_new_ftpuser Fehler aufgetreten, dann wird $action auf new_ftpuser gesetzt und Fomrular wird mit Fehlermeldungen
# und bereits eingegebenen Formulardaten erneut angezeigt

if($validation_result) {
	logline("error","Calling html_error().");
	html_error();
}

logline("debug","Calling html_out().");
html_out();


logline("alert","<<< Exiting index.pl - should never happen to reach this....");
exit(0);

#
#              _         
#    ___ _   _| |_   ___ 
#   / __| | | | '_ \/ __|
#   \__ \ |_| | |_) \__ \
#  |___/\__,_|_.__/|___/
#
#
#


sub html_out {
	
	# my $html_ref = shift;
	# $html = $html_ref if ref($html_ref);
	# ausgewhälte Sprache anzeigen. Im html-Output sind sämtliche umzuwandelnde Strings markiert, so daß
	# mit Hilfe von CSV Suchen und Ersetzen erfolgen kann. Z.B. ich bin doof steht in en.csv
	# "ich bin doof","I am silly"
	# in html-Output ist deutsch, d.h. wenn Ausgabe auch auf deutsch erfolgen soll, dann braucht keine csv geladen zu werden, sondern nur
	# die  entfernt werden.
	$$html->param('FB' => $fb);
	$$html->param('easytecc_version' => $easytecc_version);
		
	$$html->param('show_progress' => 1) if $input{'show_progress'};
	 	
	$success_text = $input{'success_text'} ? decode_base64url($input{'success_text'}) : $success_text;
	$success_text2 = $input{'success_text2'} ? decode_base64url($input{'success_text2'}) : $success_text2;
	$success_text3 = $input{'success_text3'} ? decode_base64url($input{'success_text3'}) : $success_text3;
	$success_text4 = $input{'success_text4'} ? decode_base64url($input{'success_text4'}) : $success_text4;
	$success_text5 = $input{'success_text5'} ? decode_base64url($input{'success_text5'}) : $success_text5;
	
	my $success_template = '';
	my $html_with_lang_prefix = '';
	if ($success_text) {
		$success_template = HTML::Template->new(filename => 'success_div.html');
		$success_template->param('success_text' => $success_text);
		$success_template->param('success_text2' => $success_text2);
		$success_template->param('success_text3' => $success_text3);
		$success_template->param('success_text4' => $success_text4);
		$success_template->param('success_text5' => $success_text5);
		
		if (length($input{'active_tab'}) && $input{'active_tab'} != '1') {
			$$html->param('success_tab'.$input{'active_tab'} => $success_template->output);
		}
		else{
			$$html->param('success' => $success_template->output);	
		}
		
	}
	
	logline("debug","action = $input{'action'}");
	
	
	if(exists $ajax_actions{$input{'action'}} && $json_output{'success_message'}){
			$html_with_lang_prefix = $success_template->output;	
	}
	else{
		$html_with_lang_prefix = $$html->output;	
	}

	logline("debug","success_text = $success_text");
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	logline("debug","lang:$lang html=$html_with_lang_prefix") if $debug_content;

	# \n = LF
	# \r = CR
	# \f = FF
	#$var =~ s/\n|\r//g;
	#UNIX has '\n' end of line;
	#Windows family has '\r\n' instead;
	#Mac OS has '\r';

	# convert all to  \n

	#windows, nur \r entfernen
	if($html_with_lang_prefix =~ /\r\n/){
		$html_with_lang_prefix =~ s/\r//g;
	}
	#appel, \r gegen \n ersetzen
	elsif($html_with_lang_prefix =~ /\r/){
		$html_with_lang_prefix =~ s/\r/\n/g;
	}

	#$html_with_lang_prefix = encode("utf-8", $html_with_lang_prefix);

	#if(-e "$lang_basedir/$lang.csv"){
    if( -e ("$lang_basedir/$lang.csv")){
		logline("debug","Ausgabe: $lang.csv");

		my $lang_file = `cat $lang_basedir/$lang.csv`;
		#$lang_file = encode("utf-8", $lang_file);

		#windows
		if($lang_file =~ /\r\n/){
			$lang_file =~ s/\r//g;
		}
		#appel
		elsif($lang_file =~ /\r/){
			$lang_file =~ s/\r/\n/g;
		}

		my @lang_array = split /\n\n/, $lang_file;
		foreach(@lang_array){
			my($lh,$rh) = split /",[\n]{0,1}"/, $_;
			$lh =~ s/^"//;
			$rh =~ s/"$//;
			$lang_dict{$lh} = $rh;
			#logline("warning","lh=$lh\trh=$rh");
		}

		$html_with_lang_prefix =~ s/L__(.*?)__L/{&regex_lang($1)}/gcse;

	}
	else{
		logline("warning","No $lang*.csv file");
	}

	#on critical errors sub error() ist called and sets $json_output{'critical_error'} = 1
	#without executing action and showing html again. Show just the error message, otherwise user would click again
	#which could end in a mess from multiple form submission
	if(exists $ajax_actions{$input{'action'}} || $json_output{'critical_error'} == '1'){
		$json_output{'ajax_html'} = $html_with_lang_prefix;
	
		if ($validation_result) {
			$json_output{'error'} = '1';
		}
	
		logline("debug","result is json");	
	
		print to_json(\%json_output);		
	}
	else{
		
		#binmode(STDOUT, ":utf8");
		logline("debug","result is html");	
		print $html_with_lang_prefix;
		
	}
	
	logline("debug","Flush session.");
	$session->flush() if $session;

	logline("debug","<<< Exiting index.pl in ".(caller(0))[3]."().");
	exit(0);
}

sub regex_lang{
	my $lang_value = shift;
	return($lang_dict{$lang_value}) if exists $lang_dict{$lang_value};
	
	#for easier detection of missing translation
	#return('LANG NOT FOUND') if not exists $lang_dict{$lang_value};
	
	#to show defalut .de translation if lang not found
	return("L__ $lang_value __L") if not exists $lang_dict{$lang_value};
	
	#just remove L__...__L wrapper and always use .de if lang not found
	#return("$lang_value") if not exists $lang_dict{$lang_value};
	
	if (exists $lang_dict{$lang_value}) {
		logline("debug","Translation for '$lang_value' is available.");
		return ( $lang_dict{$lang_value} );
	} else {
		logline("error","NO translation for '$lang_value' is available.");
		return ("L__ $lang_value __L");
	}
}

sub html_error {
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	
	# Fehlermeldung kann von Validator oder aus Ausführung exec_... kommen, wenn bei Ausführung von Änderung
	# oder Überprüfungen, die mit dem Validator zu kompliziert wären ein Problem festgestellt wird. %error_fields
	# wird von validator generiert oder wir erstellen es selbst in exec_...
	my $from_sub = shift;
	my $html_error = '';

	if(ref($from_sub)){
		logline("error","Error from sub.");
		%error_fields = %$from_sub;
		$action =~ s/^exec_//;
		
		#Fehlerauflistung - html_error MUSS hier gefüllt werden, nach '&$action' sonst verloren
		foreach(keys %error_fields){
				logline("error","html_error field=$_ error_fields = ".$error_fields{$_});
				$html_error .= qq~<li>$error_fields{$_}</li>~;
		}
		
		#um Endlosschleife zu verhindern, wenn Fehler nicht bei exec_ sondern schon für Anzeige von Formular auftritt
		if (defined $error_fields{'template'}) {
			$html = $error_fields{'template'};
		}
		else{
			$html = &$action;	
		}		
	}
	else{
		%error_fields = %$validation_result;
		logline("error","Error from validation.");

		#Fehlerauflistung
		foreach(keys %error_fields){
			logline("error","html_error field=$_ error_fields = ".$error_fields{$_});		
			$html_error .= qq~<li>$error_fields{$_}</li>~;
			$$html->param('error_class_' . $_ => 'has-error');
			$$html->param('error_text_' . $_ => qq~<span class="help-block">~ . encode_entities($error_fields{$_}, '<>&"') . qq~</span>~);
		}
	}
		
	#wenn Fehler, dann muss FB hier gesetzt werden, da in html_out() nicht mehr möglich
	$$html->param('FB' => $fb);


	
	#Formularfelder wieder ausfüllen
	foreach(keys %input){
	
#kaputt		logline("info","### keys ###\n".%input{$_});
			
		# select-Boxen können nicht ausgefüllt werden
		next if /^.*_select/;
		# $input{'special'} enthält Sonderzeichen, diese nicht erneut rein
		next if /^special$/;


		#$$html->param($_ => $input{$_});
		
		$$html->param($_ => encode('utf-8', $input{$_}));
		$$html->param('checked_' . $_ => ' checked');
	}

	$html_error = qq~<ul class="form-error">$html_error</ul>~ if length($html_error);

	my $error_template = HTML::Template->new(filename => 'error.html');
		
	if ($error_fields{'non_specific'} && ! $html_error) {
		$error_template->param('error_text' => qq~&nbsp;~ . $error_fields{'non_specific'});
	}
	elsif ($error_fields{'non_specific'} && $html_error) {
		
		if(keys %error_fields > 1){
					
			$error_template->param('error_text' => qq~L__Ein Fehler ist aufgetreten, bitte beachten Sie die Warnmeldungen.__L<br><br><p>~ . $error_fields{'non_specific'} . qq~</p>$html_error~);
		
		} else {
		
			$error_template->param('error_text' => qq~L__Ein Fehler ist aufgetreten, bitte beachten Sie die Warnmeldungen.__L<br><br><p></p>$html_error~);
					
		}
	
	}
	elsif ($input{'action'} eq 'exec_modify_file' || $input{'action'} eq 'exec_modify_dir') {
		$error_template->param('error_text' => $error_fields{'type'});
	}
	else{
		$error_template->param('error_text' => qq~L__Ein Fehler ist aufgetreten, bitte beachten Sie die Warnmeldungen.__L $html_error~);	
	}
	
	#1 is default
	if (length($input{'active_tab'}) && $input{'active_tab'} != '1') {
		$$html->param('error_tab'.$input{'active_tab'} => $error_template->output);
	}
	else{
		#change_htaccess has three forms
		if ($input{'action'} eq 'exec_change_htaccess' && $input{'type'} eq 'newuser') {
			$$html->param('error_newuser' => $error_template->output);
		}
		elsif ($input{'action'} eq 'exec_change_htaccess' && $input{'type'} eq 'changepass') {
			$$html->param('error_changepass' => $error_template->output);
		}
		else{
			
			$$html->param('error' => $error_template->output);
					

		}
	}
	
	
	# wenn Fehler aus sub kommt
	if(ref($from_sub)){
		
		
		logline("error","Error from sub 2.");
	
		
		#my $header = HTML::Template->new(filename => 'header.html');
		#my $footer = HTML::Template->new(filename => 'footer.html');

		#$header->param('FB' => $fb);
		#$footer->param('FB' => $fb);
		$$html->param('header' => $header->output);
		$$html->param('footer' => $footer->output);

		
		#$header->param('act_' . $baseaction => 'class="active hidden-sm"');
		
		
		
		# wenn z.B. in exec_change_popuser ein fehler, dann wird html mit Templatevariablen error_class im html-quelltext
		# zurckgeliefert. Darum diesen Output erneut als html-Template einlesen, um Variable nachtrglich setzen zu können
		# Ansonsten würde im hmtl was an Browser geschickt wird z.B. <TMPL_VAR NAME=quota1> stehen
		my $html_tmp = $$html->output;
		
		#logline("debug","$html_tmp");
		
		my $html_tmp2 = HTML::Template->new(scalarref => \$html_tmp);
		
		foreach(keys %error_fields){
			$html_error .= qq~<li>$_: $error_fields{$_}</li>~;
			#$html_tmp2->param('error_class_' . $_ => qq~class="form-error-label"~);
			$html_tmp2->param('error_class_' . $_ => "has-error");
		}
		#print $html->output;
		$html = \$html_tmp2;
		
		
		
		
		## wenn z.B. in exec_change_popuser ein fehler, dann wird html mit Templatevariablen error_class im html-quelltext
		## zurckgeliefert. Darum diesen Output erneut als html-Template einlesen, um Variable nachtrglich setzen zu können
		## Ansonsten würde im hmtl was an Browser geschickt wird z.B. <TMPL_VAR NAME=quota1> stehen
		##my $html_tmp = $$html->output;
		##my $html_tmp2 = HTML::Template->new(scalarref => \$html_tmp);
		#
		#foreach(keys %error_fields){
		#	$html_error .= qq~<li>$_: $error_fields{$_}</li>~;
		#	#$html_tmp2->param('error_class_' . $_ => qq~class="form-error-label"~);
		#	$$html->param('error_class_' . $_ => "has-error");
		#}
		##print $html->output;
		##$html = \$html_tmp2;
		
		
		
		

		logline("debug","<<< Leaving ".(caller(0))[3]."().");
		html_out();
	}

	# $html ist die globale Variable die HTML::Templateobjekt entählt. An html_out muss Referenz auf dieses Objekt übergeben werden und
	# vorher müssen Templatevariablen ersetzt werden.
	# also erstmal html-Ausgabe die Templatevariablen enthlt in Variable $html_tmp rein
	
	
	
	
	my $html_tmp = $$html->output;
	# in zweite Variable kommt Referenz auf html-Ausgabevariable, so da auf Templatevariablen zugegriffen werden kann
	my $html_tmp2 = HTML::Template->new(scalarref => \$html_tmp);
	foreach(keys %error_fields){
		# z.B. tritt bei exec_change_pop3user ein Fehler auf. Es wird wieder change_pop3user aufgerufen
		# und value von ftpquota wird ber Funktion value() + error_class
		#
		# return(qq~"$input{$input}" <TMPL_VAR NAME=error_class_$input> ~);
		#
		# zurckgegeben. Nun befindet sich im htmlquelltext TMPL_VAR was sonst angezeigt werden würde. Darum wird die Ausgabe
		# nochmal als htmltemplate eingelesen (als scalarref), so da auf TMPL_VAR zugegriffen werden kann
		$html_tmp2->param('error_class_' . $_ => qq~class="form-error-label"~);
	}
	#$html_tmp2 ist nun html-Ausgabe die Fehlermeldungen und Fehlerklassen enthlt. Weiter an html_out wo abhängig von der Spache
	#die Ausgabe erfolgt
	$html = \$html_tmp2;
	
	
	
	##my $html_tmp = $$html->output;
	## in zweite Variable kommt Referenz auf html-Ausgabevariable, so da auf Templatevariablen zugegriffen werden kann
	##my $html_tmp2 = HTML::Template->new(scalarref => \$html_tmp);
	#foreach(keys %error_fields){
	#	# z.B. tritt bei exec_change_pop3user ein Fehler auf. Es wird wieder change_pop3user aufgerufen
	#	# und value von ftpquota wird ber Funktion value() + error_class
	#	#
	#	# return(qq~"$input{$input}" <TMPL_VAR NAME=error_class_$input> ~);
	#	#
	#	# zurckgegeben. Nun befindet sich im htmlquelltext TMPL_VAR was sonst angezeigt werden würde. Darum wird die Ausgabe
	#	# nochmal als htmltemplate eingelesen (als scalarref), so da auf TMPL_VAR zugegriffen werden kann
	#	$$html->param('error_class_' . $_ => qq~has-error~);
	#}
	##$html_tmp2 ist nun html-Ausgabe die Fehlermeldungen und Fehlerklassen enthlt. Weiter an html_out wo abhängig von der Spache
	##die Ausgabe erfolgt
	##$html = \$html_tmp2;
	
	
	
	
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	html_out();
}

sub navigation{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	
	my $template_ref = shift;
	my $template = $$template_ref;

	opendir(DIR, "$awstats_conf_prefix");
		my @allfiles = grep !/^\.\.?$/, readdir DIR;
	closedir DIR;
	my $awstats = scalar(@allfiles);

	#wenn Statistik noch auf Webalizer läuft, dann Migration auf awstats anbieten, also wenn awstats-conf-dir leer und kein cronjob vorhanden
	if($awstats == '0' && ! `grep awstats_updateall /home/web/cronfile` && `grep webalizer /home/web/cronfile`){
		$mainnav->param('awstats_migration' => qq~<br /><a href="/cgi-bin/easytecc3/index.pl?action=awstats_migration"><b>L__Webalizer-AWStats-Migration__L</b></a>~);
	}

	#twig-roundcube-migration: Button nur anzeigen, wenn /home/httpd/docs/twig existiert und nicht Rechte 700 hat
	if(! -e '/usr/local/etc/easytecc/twig-migration-done'){
		logline("debug","Still twig, offering roundcube.");	
		$mainnav->param('twig_migration' => qq~<br /><a href="/cgi-bin/easytecc3/index.pl?action=roundcube_migration"><b>L__Twig-Roundcube-Migration__L</b></a>~);
		$mainnav->param('webmail' => '/twig');
	}
	else{
		$mainnav->param('webmail' => '/webmail');
	}

	$template->param(mainnav => $mainnav->output);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
}

sub ajax_error_handler{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	# $error_hash_ref ist referenz auf Hash, der die Formularfelder mit Fehlermeldungen enthält
	# mailvalidator liefert Ergebnis und das wird in easytecc3::result_debug aufbereitet
	my $error_hash_ref = shift;
	my %error_hash = %$error_hash_ref;
	my $error_text = '';
	my %callback = ('error' => \%error_hash);	
	
	#foreach(keys %error_hash){
	#	$error_text .= "$_:" . $error_hash{$_} . '<br>';
	#}
	
	$error_text = to_json(\%callback);

	logline("error","ajax_error_handler error_text: $error_text.");

	my $template = HTML::Template->new(	scalarref => \$error_text, 
										option => 'value' 
	);
	$html = \$template;

	print header(	-type=>'text/html',
					-charset=>'utf-8');

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(html_out()); # Jimmy: Kann das gehen? html_out() schmeisst ein exit(0) im gleichen prozess... html_out() sollte reichen
}

sub login{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'login.html');
	$template->param('server_name' => $display_server_name);
	my $cmd = '/bin/ls -l ' . $droot_prefix . '/easytecc4/img/login-bg-*|/usr/bin/wc -l';
	my $login_bg_image_count = `$cmd`;
	chomp $login_bg_image_count;
	$login_bg_image_count =~ s/[^0-9]//g;
	$template->param('login_img_random' => int(rand($login_bg_image_count)) +1);
	
	$template->param('selected_lang_' . $lang => 'selected');
	$template->param('lang_select' => \@lang_array);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub logout{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'login.html');
	$template->param('server_name' => $display_server_name);
    
	#my $cmd = 'ls -l ' . $droot_prefix . '/easytecc/img/login-bg-*|wc -l';
	#my $login_bg_image_count = `$cmd`;
	#chomp $login_bg_image_count;
	#$login_bg_image_count =~ s/[^0-9]//g;
	#$template->param('login_img_random' => int(rand($login_bg_image_count)) +1);
	
	#$template->param('selected_lang_' . $lang => 'selected');
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl';
	
	return login();
	#return(\$template);
	
	#return '';
	
}

sub start{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	
	# mailuser
	#if($session->param('user') =~ /\@/){
		
	#	return mailuser_start();
				
	#}
	
	my $template = HTML::Template->new(filename => 'index.html');
		
	my $template_dashboard_box_cloneworkx = HTML::Template->new(filename => 'dashboard_box_cloneworkx.html');
	my $template_dashboard_box_domains = HTML::Template->new(filename => 'dashboard_box_domains.html');
	my $template_dashboard_box_emailadresses = HTML::Template->new(filename => 'dashboard_box_emailadresses.html');
	my $template_dashboard_box_filemanager = HTML::Template->new(filename => 'dashboard_box_filemanager.html');
	my $template_dashboard_box_ftpuser = HTML::Template->new(filename => 'dashboard_box_ftpuser.html');
	my $template_dashboard_box_clients = HTML::Template->new(filename => 'dashboard_box_clients.html');
	my $template_dashboard_box_logfiles = HTML::Template->new(filename => 'dashboard_box_logfiles.html');
#	my $template_dashboard_box_order_webmail = HTML::Template->new(filename => 'dashboard_box_order_webmail.html');
	my $template_dashboard_installer = HTML::Template->new(filename => 'dashboard_box_installer.html');
	my $template_dashboard_2fa = HTML::Template->new(filename => 'dashboard_box_2fa.html');
	my $template_dashboard_box_otheractions = HTML::Template->new(filename => 'dashboard_box_otheractions.html');
	my $template_dashboard_box_support = HTML::Template->new(filename => 'dashboard_box_support.html');

	$show_vhosts = '';
	$show_email = '';
	$show_ftp = '';
	$show_quota = '';
	$show_spam = '';
	$show_fileman = '';
	$show_logs = '';
	$show_db = '';
	$show_cron = '';
	$show_inst = '';
	$show_firewall = '';
	
	if($session->param('user') eq 'admin'){
	
		$show_vhosts = '1';
		$show_email = '1';
		$show_ftp = '1';
		$show_quota = '1';
		$show_spam = '1';
		$show_fileman = '1';
		$show_logs = '1';
		$show_db = '1';
		$show_cron = '1';
		$show_inst = '1';
		$show_firewall = '1';
		
	} else {
	
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};

		my $gecos = $passwd{$session->param('user')}{'gecos'};
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.vhost-1.email-1.ftp-2.quota.spam.fileman-1.logs-1.db-2.cron-2.inst';
		
		}
	
		if($gecos =~ m/\.vhost/){
		
			$show_vhosts = '1';
		
		}
		
		if($gecos =~ m/\.email/){
		
			$show_email = '1';
		
		}
		
		if($gecos =~ m/\.ftp/){
		
			$show_ftp = '1';
		
		}
	
		if($gecos =~ m/\.quota/){
		
			$show_quota = '1';
		
		}
		
		if($gecos =~ m/\.spam/){
		
			$show_spam = '1';
		
		}
		
		if($gecos =~ m/\.fileman/){
		
			$show_fileman = '1';
		
		}
		
		if($gecos =~ m/\.logs/){
		
			$show_logs = '1';
		
		}
		
		if($gecos =~ m/\.db/){
		
			$show_db = '1';
		
		}
		
		if($gecos =~ m/\.cron/){
		
			$show_cron = '1';
		
		}
		
		if($gecos =~ m/\.inst/){
		
			$show_inst = '1';
		
		}
		
	}

	
	#$template->param('dashboard_box_cloneworkx' => $template_dashboard_box_cloneworkx->output);
	
	if($show_vhosts eq '1'){
	
		$template->param('dashboard_box_domains' => $template_dashboard_box_domains->output);
		
	}
	
	if($show_email eq '1'){
	
		$template->param('dashboard_box_emailadresses' => $template_dashboard_box_emailadresses->output);
		
	}
	
	if($show_fileman eq '1'){
	
		$template->param('dashboard_box_filemanager' => $template_dashboard_box_filemanager->output);
		
	}
	
	if($show_ftp eq '1'){
		
		$template->param('dashboard_box_ftpuser' => $template_dashboard_box_ftpuser->output);
		
	}
	
	if($show_logs eq '1'){
	
		$template->param('dashboard_box_logfiles' => $template_dashboard_box_logfiles->output);
		
	}
#	$template->param('dashboard_box_order_webmail' => $template_dashboard_box_order_webmail->output);
	
	if($show_inst eq '1'){
		
		$template->param('dashboard_box_installer' => $template_dashboard_installer->output);
		
	}
	
	#if($fb && $show_ftp eq '1' && ! -f '/usr/local/etc/easytecc/2fa/' . $session->param('user') ){
		
	#	$template_dashboard_2fa->param('user' => $session->param('user'));
	#	$template->param('dashboard_box_2fa' => $template_dashboard_2fa->output);
		
	#}
	
#	if($show_firewall eq '1'){
		
#		$template->param('dashboard_box_firewall' => $template_dashboard_firewall->output);
		
#	}
	
	if($show_quota eq '1' && $show_spam eq '1' && $show_db eq '1' && $show_cron eq '1'){
		
		$template->param('dashboard_box_otheractions' => $template_dashboard_box_otheractions->output);
		
	}
	
	$session->param('show_vhosts',$show_vhosts);
	$session->param('show_email',$show_email);
	$session->param('show_ftp',$show_ftp);
	$session->param('show_quota',$show_quota);
	$session->param('show_spam',$show_spam);
	$session->param('show_fileman',$show_fileman);
	$session->param('show_logs',$show_logs);
	$session->param('show_db',$show_db);
	$session->param('show_cron',$show_cron);
	$session->param('show_inst',$show_inst);
	
	if($session->param('user') eq 'admin'){
	
		$template->param('dashboard_box_support' => $template_dashboard_box_support->output);
		$template->param('dashboard_box_clients' => $template_dashboard_box_clients->output);
		
	}
	
	# Warninformationen:
	# Serverquota < 100MB frei
	# Quota von User weniger als 10%
	# Logfiles für Webserver nehmen mehr als 50% von Webspeicher ein
	# admin-Postfach mehr als 500MB voll
	# kein cronjob zum automatischen Löschen von Logs
	my $has_warning = '';
	my $extern_mx = easytecc3::extern_mx();
	my @serverquota = ();
	my $admin_mail_used = '';

	my %mailpasswd = ();
	my %mailquota = ();
	my ($mailquotaref, $sum_maillimit, $sum_mailuse, $mailserverlimit);

	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};

	# Zum gucken, ob es FTP-User gibt, die passwd vom Webserver auslesen, und gucken ob es zum
	# document root der Domain einen FTP-User mit passendem home-Verzeichnis gibt
	logline("debug","Creating File Object \%webserver_passwd.");
	my $webserver_passwd = file->new({file_name => '/etc/passwd'});
	$webserver_passwd->read_file;
	my %webserver_passwd = %{$webserver_passwd->file_parsed_hash()};
	my %home_lookup =  %{$webserver_passwd->lookup2_hash()};
	my ($quotaref, $sum_ftplimit, $sum_ftpuse, $ftpserverlimit) = easytecc3::getquota_ftp();
	my %quota = %$quotaref;

	if ($extern_mx || $fb){
		$mailpasswd = easytecc3::get_mailpasswd();
		%mailpasswd = %{$mailpasswd->file_parsed_hash()};
		($mailquotaref, $sum_maillimit, $sum_mailuse, $mailserverlimit) = easytecc3::getquota_mail(\%mailpasswd);
		%mailquota = %$mailquotaref;
	}
	else{
		%mailpasswd = %webserver_passwd;
		%mailquota = %quota;
		$sum_maillimit = $sum_ftplimit;
		$sum_mailuse = $sum_ftpuse;
		$mailserverlimit = $ftpserverlimit;
	}

    my $userregex;
	my %domain_home;
	my %allowed_domains;
    my $admins;
    
	foreach(keys %domains){
	
		# filter domains
		if($session->param('user') ne 'admin'){
		
			$admins = $domains{$_}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $session->param('user') . '#';
			
			logline("debug"," M A R I O - admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				next;
			}
		}

		logline("info","domain_home=" . $domains{$_}{'droot'});
		$domain_home{$domains{$_}{'droot'}} = $domains{$_}{'domains'};
		$allowed_domains{$_} = 1;
	}

	####################################################
	############# SSL-Warning if certificate expires within 30 days

  
    logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);

    # Mario: Die folgenden beiden Variablen werden in der easytecc_class.pm ausgewertet.
	my %config = %{$httpd_conf->config_hash()};
    
    my $ssl_warning_text="";
	    	
	foreach my $domain (sort keys %allowed_domains){
    	 
        # an dieser Stelle wird die Variable $domain noch mit www.domain.tld übergeben..
        if($config{'ssl_enabled'} && $domains{$domain}{'ssl'}){
            
			logline("debug","cert:" . $domains{$domain}{'ssl_cert'} . "\n");
			
			
			
			my $has_letsencrypt = $domains{$domain}{'special_ssl'} =~ m/letsencrypt/;
			
			
			my $ssl_expire_date = "";
			my $ssl_expires_within_x_days;
			my ($ssl_expire_date, $ssl_expires_within_x_days) =	https_cert_expire($domains{$domain}{'ssl_cert'});
			            
			if(length($ssl_expire_date)){
			
				$domain =~ s/^www.//;
				if ($ssl_expires_within_x_days < 0){
					$ssl_warning_text.='L__Das SSL-Zertifikat für__L <a href="index.pl?action=show_vhosts">'.$domain.'</a> L__ist abgelaufen__L.<br />';
				} elsif ($has_letsencrypt && $ssl_expires_within_x_days < 25 || $ssl_expires_within_x_days < 25){
				    $ssl_warning_text.='L__Das SSL-Zertifikat für__L <a href="index.pl?action=show_vhosts">'.$domain.'</a> L__ist noch gültig bis zum__L '.$ssl_expire_date.'.<br />';
				}
				
			}
        }
	}
	
    unless ($ssl_warning_text eq ""){
        my $template_dashboard_box_alert_quota_100MB_free = HTML::Template->new(filename => 'dashboard_box_alert.html');
	
        $template_dashboard_box_alert_quota_100MB_free->param('box_alert_text' => qq~$ssl_warning_text~);
	
        $template->param('dashboard_alert_quota_100MB_free' => $template_dashboard_box_alert_quota_100MB_free->output);
	
        $has_warning = '1';
    }
 
	####################################################
	############# Quotawarnung Webserver weniger als 100 MB frei
	my $webserver_100MB = sprintf("%.0f", $ftpserverlimit - $sum_ftpuse);
	if($webserver_100MB < 100 && $session->param('user') eq 'admin'){
		$webserver_100MB = '0' if $webserver_100MB < 0;
		my $template_dashboard_box_alert_quota_100MB_free = HTML::Template->new(filename => 'dashboard_box_alert.html');
		$template_dashboard_box_alert_quota_100MB_free->param('box_alert_text' => qq~L__Speichergrenze von Webserver fast erreicht__L:L__Freier Speicher:__L $webserver_100MB. L__Bitte löschen Sie nicht mehr benötigte Daten. Möglich ist auch ein Speicherupgrade des Servers gemäß unserer Preisliste, das einfach per Fax bestellt werden kann. Die aktuelle Preisliste finden Sie hier__L: <a href="http://www.hostnet.de/uebersicht-server.html" target="_blank">L__Preisliste__L</a><br />~);
		$template->param('dashboard_alert_quota_100MB_free' => $template_dashboard_box_alert_quota_100MB_free->output);
		$has_warning = '1';
	}

	####################################################
	############# Quotawarnung FTP-user
	my @ftp_user = ();
	my @user = ();

	foreach my $ftpuser (sort keys %webserver_passwd){
		next if $ftpuser eq 'ftp';
		my $ftpquota = '';
		my $ftpquota_sized = '';
		my $ftpused = '';
		my $quotabalken = '';
		my $domain = '';

		$ftpquota = $quota{$ftpuser}{'quota'};
		$ftpquota_sized = easytecc3::getsize($ftpquota);
		$ftpused = $quota{$ftpuser}{'use'};

		#nur die User anzeigen, die weniger als 10% Quota zur Verfgung haben
		my $percentval = ($ftpused/$ftpquota)*100 if $ftpquota > 0;
		$percentval = 0 if $ftpquota == 0;
		next if $percentval < 90;

		next unless $ftpused;
		next if $webserver_passwd{$ftpuser}{'gecos'} =~ /- POP/;
		$quotabalken = easytecc3::quotabar($ftpquota, $ftpused, 'used');

		if(exists $domain_home{$webserver_passwd{$ftpuser}{'home'}}){
			#$domain = @{$domain_home{$passwd{$ftpuser}{'home'}}};
			$domain = join '<br />', @{$domain_home{$webserver_passwd{$ftpuser}{'home'}}};
		}
		else {
			# filter domains
			if($session->param('user') ne 'admin'){
			
				my $home = $webserver_passwd{$ftpuser}{'home'};
				my $self_home = $webserver_passwd{$session->param('user')}{'home'};
				my $allowed = 0;
				
				if($home ne $self_home && $home !~ m#^$self_home/#){
				
					foreach my $dir (keys %domain_home){
					
						if($home eq $dir || $home =~ m#^$dir/#){
					
							$allowed = '1';
							
						}
					
					}
					
					if($allowed != 1){
					
						next;
					
					} 
				}
			}
		}

		#if($ftpuser eq 'admin' || $ftpuser eq 'web'){
		#	push(@ftp_user, $ftpuser . '|' .
		#	$domain . '|' .
		#	$webserver_passwd{$ftpuser}{'gecos'} . '|' .
		#	$webserver_passwd{$ftpuser}{'home'} . '|' .
		#	$ftpquota_sized . '|' .
		#	$quotabalken . '|' .
		#	qq~<a href='/cgi-bin/easytecc3/index.pl?action=change_ftpuser&amp;ftpuser=$ftpuser'>L__Editieren__L</a>~);
		#}
		#else{
		#	push(@ftp_user, $ftpuser . '|' .
		#	$domain . '|' .
		#	$webserver_passwd{$ftpuser}{'gecos'} . '|' .
		#	$webserver_passwd{$ftpuser}{'home'} . '|' .
		#	$ftpquota_sized . '|' .
		#	$quotabalken . '|' .
		#	qq~<a href='/cgi-bin/easytecc3/index.pl?action=change_ftpuser&amp;ftpuser=$ftpuser'>L__Editieren__L</a><br /><a href='/cgi-bin/easytecc3/index.pl?action=delete_ftpuser&amp;ftpuser=$ftpuser'>L__Löschen__L</a>~);
		#}
		
#		if($ftpuser eq 'admin' || $ftpuser eq 'web'){
#			push(@ftp_user, $ftpuser . '&nbsp;&nbsp;' .
#			qq~<a href="#" class="tooltip1 modal-form-horizontal" data-toggle="modal" data-original-title="Bearbeiten" onclick="modal_popup(this, 'change_ftpuser&amp;ftpuser=$ftpuser'); return false;"><i class="fa fa-pencil fa-lg"></i></a>~);
#		}
#		else{
			push(@ftp_user, $ftpuser . '&nbsp;&nbsp;' .
			qq~<a href="#" class="tooltip1 modal-form-horizontal" data-toggle="modal" data-original-title="Bearbeiten" onclick="modal_popup(this, 'change_ftpuser&amp;ftpuser=$ftpuser'); return false;"><i class="fa fa-pencil fa-lg"></i></a>~);
#		}
	}

	#$template->param('warning_ftpuser_quota' => '<br /><h1>L__Achtung! Folgende FTP-User nutzen mindestens 90% ihrer Quota:__L</h1>') if scalar @ftp_user > 0;
	#easytecc3::table(\$template,'<td>L__FTP-User__L</td><td>L__Domain__L</td><td>L__Beschreibung__L</td><td>L__Homeverzeichnis__L</td><td>L__FTP-Quota__L</td><td>L__Quotanutzung__L</td><td>L__Aktionen__L</td>', \@ftp_user, 'table_ftpuser') if scalar @ftp_user > 0;
	if (scalar @ftp_user > 0 && $show_ftp eq '1'){
		my $template_dashboard_box_alert_ftpuser_less_10percent_free = HTML::Template->new(filename => 'dashboard_box_alert.html');
		$template_dashboard_box_alert_ftpuser_less_10percent_free->param('box_alert_text' => 'L__Folgende FTP-Benutzer nutzen mindestens 90% ihrer Quota:__L<br>' . join(qq~<br>~, @ftp_user));
		$template_dashboard_box_alert_ftpuser_less_10percent_free->param('box_alert_href' => '/cgi-bin/easytecc4/index.pl?action=show_quota');
		$template_dashboard_box_alert_ftpuser_less_10percent_free->param('box_alert_href_text' => 'L__Quota bearbeiten__L');
		$template->param('dashboard_alert_ftpuser_less_10percent_free' => $template_dashboard_box_alert_ftpuser_less_10percent_free->output);
		$has_warning = '1';
	}
	
	
	
	my $servername = `sed 's/^.* // ; s/\$/.han-solo.net/' /etc/FQDN 2>/dev/null`;
	chomp $servername;
	
	
	####################################################
	############# Quotawarnung Email-user
	foreach my $user(sort keys %mailpasswd){
		#&& $user ne 'admin' damit admin bei externem Mailserver angezeigt wird. Er hat kein POP in Beschreibung
		
		if($mailpasswd{$user}{'gecos'} !~ / - POP$/ && $user ne 'admin' && ($user ne 'admin@' . $servername || $session->param('user') ne 'admin')){
			next;
		}	
		
		
		# wenn admin Quotagrenze erreicht und kein externer Mailserver, dann taucht admin schon bei FTP-User auf die Quotagrenze erreicht haben.
		next if ($user eq 'admin' && ! $extern_mx);

		my $domain =  $mailpasswd{$user}{'gecos'};
		$domain =~ s/ - POP$//;
		my $mailquota_sized =  $mailquota{$user}{'quota'} / 1024;

		#genutzte Quota vom User admin auf externem Mailserver
		#wird spter evtl. gebraucht. Wenn kein externer Mailserver, dann /var/spool/mail/admin von Webserver nehmen
		$admin_mail_used = $mailquota{$user}{'use'}  / 1024 if ($user eq 'admin' && $extern_mx);

		#nur die User anzeigen, die weniger als 10% Quota zur Verfgung haben
		my $percentval = ($mailquota{$user}{'use'}/$mailquota{$user}{'quota'})*100 if $mailquota{$user}{'quota'} > 0;
		$percentval = 0 if $mailquota{$user}{'quota'} == 0;
		next if $percentval < 90;

		# filter domains
		if($session->param('user') ne 'admin'){
		
			my $admins = $domains{'www.' . $domain}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $session->param('user') . '#';
			
			logline("debug","admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				next;
			}
		}
		
		my $quotabalken = easytecc3::quotabar($mailquota{$user}{'quota'}, $mailquota{$user}{'use'}, 'used');

		my $wwwdomain = 'www.' . $domain;
		if($user eq 'admin@' . $servername){
			$wwwdomain = $servername;
		}
		
		push(@user, $user . '&nbsp;&nbsp;' .
		qq~<a href="#" data-dismiss="modal" class="tooltip1 modal-form-inline" data-toggle="modal" data-original-title="E-Mail-Benutzer bearbeiten" onclick="modal_popup(this, 'change_popuser&amp;domain=$wwwdomain'); return false;"><i class="fa fa-pencil fa-lg"></i></a>~);

	}

	#$template->param('warning_mailuser_quota' => '<br /><h1>L__Achtung! Folgende E-Mail-User nutzen mindestens 90% ihrer Quota:__L</h1>') if scalar @user > 0;
	#easytecc3::table(\$template,'<td>L__Username__L</td><td>L__Domain__L</td><td>L__E-Mail-Quota__L</td><td>L__Quotanutzung__L</td><td  colspan="3">L__Aktionen__L</td>', \@user, 'table_mailuser') if scalar @user > 0;

	if (scalar @user > 0 && $show_email eq '1'){
		my $template_dashboard_box_alert_mailuser_less_10percent_free = HTML::Template->new(filename => 'dashboard_box_alert.html');
		$template_dashboard_box_alert_mailuser_less_10percent_free->param('box_alert_text' => 'L__Folgende E-Mail-Benutzer nutzen mindestens 90% ihrer Quota:__L<br>' . join(qq~<br>~, @user));
		$template_dashboard_box_alert_mailuser_less_10percent_free->param('box_alert_href' => '/cgi-bin/easytecc4/index.pl?action=show_quota');
		$template_dashboard_box_alert_mailuser_less_10percent_free->param('box_alert_href_text' => 'L__Quota bearbeiten__L');
		$template->param('dashboard_alert_mailuser_less_10percent_free' => $template_dashboard_box_alert_mailuser_less_10percent_free->output);
		$has_warning = '1';
	}
	
	####################################################
	############# Logfiles für Webserver nehmen mehr als 50% von Webspeicher ein
	my @logs = ();

	if ($fb) {
		@logs = `/usr/iports/bin/sudo /usr/sbin/dellogs`;
	}
	else{
		@logs = `/usr/sbin/dellogs`;
	}


	my $all_logs_size = '';

	my $quota = `cat /etc/vsd/quota`;
	chomp $quota;

	foreach(@logs){
		my ($domain, $logfile, $size) = split /\|/, $_;
		$logfile =~ s/^\s+(.*)\s+$/$1/g;
		$size =~ s/^\s+(.*)\s+$/$1/g;

		if($logfile =~ /^(Access Logs|Error Logs|Messages|Maillogs)/){
			logline("info","log = $logfile size = $size");
			$size =~ /^(.*)\s(.*)$/;
			# Grösse kann in kB oder MB angegeben werden, alles auf MB umrechnen und summieren
			my $size_unscaled = $1;
			my $scale = $2;
			$size_unscaled = $size_unscaled/1024 if $scale eq 'kB';
			$all_logs_size += $size_unscaled;
		}
	}
	logline("info","all_logs_size = $all_logs_size M");

	my $percentval = ($all_logs_size/$quota)*100;
	##kaufm. Rundung
	$percentval = sprintf("%.0f", $percentval);
	my $balken_usage = $percentval;
	my $balken_free = 100 - $balken_usage;

	if($percentval >= 50 && $session->param('user') eq 'admin'){
		logline("warning","percentval = $percentval");
		#$quotabalken = qq|<img src="/easytecc3/images/red.gif" width="$balken_usage" height="15" align="bottom" alt="$balken_usage % genutzt" border="0" /><img src="/easytecc3/images/grey.gif" width="$balken_free" height="15" align="bottom" alt="$balken_free % frei" border="0" />|;
		#$template->param('in_use' => sprintf "%.2f", $all_logs_size);
		#$template->param('percent' => ' (' . $percentval . '%)');
		#$template->param('bar' => $quotabalken);
		#$template->param('warning_logfiles_half_webserver_quota' => qq~<br /><h1>L__Achtung!__L $percentval % L__der Serverquota werden nur für Logfiles verwendet__L!</h1> $quotabalken ~ .  sprintf("%.2f", $all_logs_size) . qq~ MB Logfiles vorhanden. <b><a href="/cgi-bin/easytecc3/index.pl?action=delete_logfiles&amp;logfile=all">L__Alle Logs löschen__L</a></b>~)
		my $template_dashboard_box_alert_logs_more_50percent_use = HTML::Template->new(filename => 'dashboard_box_alert.html');
		$template_dashboard_box_alert_logs_more_50percent_use->param('box_alert_text' => qq~$percentval % L__der Serverquota werden nur für Logfiles verwendet__L!~);
		$template_dashboard_box_alert_logs_more_50percent_use->param('box_alert_href' => '/cgi-bin/easytecc4/index.pl?action=show_logfiles');
		$template_dashboard_box_alert_logs_more_50percent_use->param('box_alert_href_text' => 'L__Logfiles ansehen__L');
		$template->param('dashboard_alert_logs_more_50percent_use' => $template_dashboard_box_alert_logs_more_50percent_use->output);
		$has_warning = '1';
	}

	####################################################
	############# kein cronjob zum automatischen löschen von Logs
	# warum nur unter linux? auf den bsds funktioniert das dellogs nicht weniger oder mehr...
	if($session->param('user') eq 'admin' && !$fb){
		unless(`grep 'dellogs -a' /home/web/cronfile`){
			my $template_dashboard_box_alert_logs_no_delete_cronjob = HTML::Template->new(filename => 'dashboard_box_warning.html');
			#$template_dashboard_box_alert_logs_no_delete_cronjob->param('box_alert_text' => qq~L__Die Logs werden aktuell nicht automatisch gelöscht!__L~);
			#$template_dashboard_box_alert_logs_no_delete_cronjob->param('box_alert_href' => '/cgi-bin/easytecc4/index.pl?action=auto_cronjob&amp;cronjob=delete_all_logs');
			$template_dashboard_box_alert_logs_no_delete_cronjob->param('box_alert_text' => qq~L__Die Logs werden aktuell nicht automatisch gelöscht!__L<br>
			<a href="#" class="modal-form-horizontal" data-toggle="modal" onclick="modal_popup(this, 'delete_logfiles&amp;logfile=add_cron'); return false;">L__Logs zukünftig automatisch löschen__L</a>
			~);
			$template->param('dashboard_alert_logs_no_delete_cronjob' => $template_dashboard_box_alert_logs_no_delete_cronjob->output);
			$has_warning = '1';
			#$template->param('warning_logfiles_no_cron' => qq~<br /><h1>L__Achtung! Die Logs werden aktuell nicht automatisch gelöscht!__L</h1><a href="/cgi-bin/easytecc3/index.pl?action=auto_cronjob&amp;cronjob=delete_all_logs">L__Logs zukünftig automatisch löschen__L</a>~);
		}
	}
	
	if($session->param('user') eq 'admin' && $fb && ! -f '/usr/local/etc/newsyslog.conf.d/apache_mysql_mail.conf' ){
		
		my $template_dashboard_box_alert_logs_no_delete_cronjob = HTML::Template->new(filename => 'dashboard_box_warning.html');
		#$template_dashboard_box_alert_logs_no_delete_cronjob->param('box_alert_text' => qq~L__Die Logs werden aktuell nicht automatisch gelöscht!__L~);
		#$template_dashboard_box_alert_logs_no_delete_cronjob->param('box_alert_href' => '/cgi-bin/easytecc4/index.pl?action=auto_cronjob&amp;cronjob=delete_all_logs');
		$template_dashboard_box_alert_logs_no_delete_cronjob->param('box_alert_text' => qq~L__Es ist keine Logrotation eingerichtet, Logdateien werden aktuell nicht automatisch gelöscht!__L<br>
		<a href="#" class="modal-form-horizontal" data-toggle="modal" onclick="modal_popup(this, 'logrotate'); return false;">L__Logrotation einrichten__L</a>
		~);
		$template->param('dashboard_alert_logs_no_delete_cronjob' => $template_dashboard_box_alert_logs_no_delete_cronjob->output);
		$has_warning = '1';
		#$template->param('warning_logfiles_no_cron' => qq~<br /><h1>L__Achtung! Die Logs werden aktuell nicht automatisch gelöscht!__L</h1><a href="/cgi-bin/easytecc3/index.pl?action=auto_cronjob&amp;cronjob=delete_all_logs">L__Logs zukünftig automatisch löschen__L</a>~);
		
	}
	
	if($fb && $show_ftp eq '1' && ! -f '/usr/local/etc/easytecc/2fa/' . $session->param('user') ){
		
		my $user = $session->param('user');
		
		my $template_dashboard_box_alert_2fa = HTML::Template->new(filename => 'dashboard_box_warning.html');
		#$template_dashboard_box_alert_logs_no_delete_cronjob->param('box_alert_text' => qq~L__Die Logs werden aktuell nicht automatisch gelöscht!__L~);
		#$template_dashboard_box_alert_logs_no_delete_cronjob->param('box_alert_href' => '/cgi-bin/easytecc4/index.pl?action=auto_cronjob&amp;cronjob=delete_all_logs');
		$template_dashboard_box_alert_2fa->param('box_alert_text' => qq~L__Dieser Account ist noch nicht durch Zwei-Faktor-Authentifizierung abgesichert!__L<br>
		<a href="#" class="modal-form-horizontal" data-toggle="modal" onclick="modal_popup(this, 'change_ftpuser&amp;ftpuser=$user'); return false;">L__Zwei-Faktor-Authentifizierung einrichten__L</a>
		~);
		$template->param('dashboard_alert_2fa' => $template_dashboard_box_alert_2fa->output);
		$has_warning = '1';
		#$template->param('warning_logfiles_no_cron' => qq~<br /><h1>L__Achtung! Die Logs werden aktuell nicht automatisch gelöscht!__L</h1><a href="/cgi-bin/easytecc3/index.pl?action=auto_cronjob&amp;cronjob=delete_all_logs">L__Logs zukünftig automatisch löschen__L</a>~);
	
	}

	if($session->param('user') eq 'admin' && $fb && -f '/usr/local/etc/easytecc/shell2ban/.disabled' ){
		
		my $template_dashboard_box_alert_firewall = HTML::Template->new(filename => 'dashboard_box_warning.html');
		#$template_dashboard_box_alert_logs_no_delete_cronjob->param('box_alert_text' => qq~L__Die Logs werden aktuell nicht automatisch gelöscht!__L~);
		#$template_dashboard_box_alert_logs_no_delete_cronjob->param('box_alert_href' => '/cgi-bin/easytecc4/index.pl?action=auto_cronjob&amp;cronjob=delete_all_logs');
		$template_dashboard_box_alert_firewall->param('box_alert_text' => qq~L__Die Firewall ist deaktiviert!__L<br>
		<a href="/cgi-bin/easytecc4/index.pl?action=change_firewall">L__Firewall aktivieren__L</a>
		~);
		$template->param('dashboard_alert_firewall' => $template_dashboard_box_alert_firewall->output);
		$has_warning = '1';
		#$template->param('warning_logfiles_no_cron' => qq~<br /><h1>L__Achtung! Die Logs werden aktuell nicht automatisch gelöscht!__L</h1><a href="/cgi-bin/easytecc3/index.pl?action=auto_cronjob&amp;cronjob=delete_all_logs">L__Logs zukünftig automatisch löschen__L</a>~);
		
	}
	
	my $admin_mail_used;
	
	####################################################
	############# admin-Postfach mehr als 500MB voll
	if($extern_mx){
		#nix wurde vorher schon ausgelesen
	}
	else{
	
	
		if ($fb) {
		#hmtja, dateien zählen wenn wir imap-quota haben und dann ohne timeout... kriegt ein TODO tag!
		#TODO: s.o.
		#my $servername = `grep -m1 han-solo.net /etc/hosts | awk '{print \$2}'`;
		my $servername =  `sed 's/^.* // ; s/\$/.han-solo.net/' /etc/FQDN 2>/dev/null`;
		chomp($servername);
		
		my $dir = '/home/admin@' . $servername;
		
			# und das gleich zweimal...
			#$admin_mail_used = `/usr/iports/bin/sudo /usr/bin/du -Ams $dir`;
			$admin_mail_used = `/usr/iports/bin/sudo /usr/sbin/doveadm -f flow quota get -u "admin\@$servername" | sed '/Type=MESSAGE/d ; s/^.*Type=STORAGE Value=// ; s/ Limit=.*//'`;
			chomp $admin_mail_used;
			$admin_mail_used /= 1024;	
				
		}
		else{
		$admin_mail_used = `du -ms /root/mail`;	
		}
	
		logline("debug","admin_mail_used1=$admin_mail_used");
		$admin_mail_used =~ /^([0-9]{1,20})\s+/;
		$admin_mail_used = $1; # in Megabyte
		logline("debug","admin_mail_used2=$admin_mail_used");
		
	}

	if($admin_mail_used >= 500 && $session->param('user') eq 'admin' && ! (`grep 'rm .*/root/mail' /home/web/cronfile` || `grep 'rm .*/home/admin@$servername' /home/web/cronfile`)){
		$admin_mail_used = sprintf("%.0f", $admin_mail_used);
		logline("warning","admin_mail_used3 = $admin_mail_used");
		my $template_dashboard_box_alert_admin_mail_more_500MB_use = HTML::Template->new(filename => 'dashboard_box_alert.html');
		$template_dashboard_box_alert_admin_mail_more_500MB_use->param('box_alert_text' => qq~L__Im Postfach des Users admin befinden sich__L $admin_mail_used MB L__E-Mails__L.<br>
		<a href="#" class="modal-form-horizontal" data-toggle="modal" onclick="modal_popup(this, 'auto_cronjob&amp;cronjob=delete_admin_email'); return false;">L__Inhalt von admin-Postfach zukünftig automatisch löschen__L</a>
		~);
		
		#$template_dashboard_box_alert_admin_mail_more_500MB_use->param('box_alert_href' => '/cgi-bin/easytecc4/index.pl?action=auto_cronjob&amp;cronjob=delete_admin_email');
		#$template_dashboard_box_alert_admin_mail_more_500MB_use->param('box_alert_href_text' => 'L__Inhalt von admin-Postfach zukünftig automatisch löschen__L');
		$template->param('dashboard_alert_admin_mail_more_500MB_use' => $template_dashboard_box_alert_admin_mail_more_500MB_use->output);
		$has_warning = '1';
		#$template->param('warning_admin_mail' => qq~<br /><h1>L__Achtung! Im Postfach des Users admin befinden sich__L $admin_mail_used MB L__E-Mails__L.</h1><a href="/cgi-bin/easytecc3/index.pl?action=auto_cronjob&amp;cronjob=delete_admin_email">L__Inhalt von admin-Postfach zukünftig automatisch löschen__L</a>~);
	}

	if ($has_warning) {
		$template->param('has_warning' => '1');
	}
	
	add_dobackup_cron();
	
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub error{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $error = shift;
	
	logline("debug","######################################### got error $error");
	
	
	my $template = '';
	
	if(exists $ajax_actions{$input{'action'}}){
		$template = HTML::Template->new(filename => 'error_div.html');
		$json_output{'critical_error'} = '1';
	}
	else{
		$template = HTML::Template->new(filename => 'error.html');
	}

	logline("error","Throwing error =  ".$error);
	$template->param('error_text' => $error);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub modal_error{
#this is for functions where a modal should popup but there was an error,
#e.g. filemanager -> modify_file -> edit and file is binary so it can't be edited
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $error = shift;
	
	my $template = HTML::Template->new(filename => 'modal_error.html');
	
	logline("error","Throwing error =  ".$error);
	$template->param('error_text' => $error);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub modal_message{
#this is for functions where a modal should popup but there was an error,
#e.g. filemanager -> modify_file -> edit and file is binary so it can't be edited
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my ($title,$message) = @_;
	
	my $template = HTML::Template->new(filename => 'modal_message.html');
	
	$template->param('message_title' => $title);
	$template->param('message_text' => $message);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub awstats_migration{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'awstats_migration.html');
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub roundcube_migration{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'roundcube_migration.html');

	my $apache = `grep httpd_enable /etc/rc.conf`;
	chomp $apache;
	my $php_error_text = '';
	my $php_version = `egrep '^extension_dir' /etc/php.ini`;

	if($php_version !~ /php5\.(2|3|4|5|6|7|8|9)/){
		$php_error_text = 'L__Die PHP-Version ist zu alt. Für Roundcube ist mindestens PHP5.2 notwendig, bitte führen Sie ein PHP-Update gemäß <a href="http://www.hostnet.de/faq" target="_blank">PHP-Updateanleitung</a> durch oder wenden sich an den Support um das Update durchführen zu lassen.__L';
	}

	if($apache =~ /"1"/s){
		return(error('L__Die Apacheversion ist zu alt. Bitte führen Sie ein Apacheupdate gemäß <a href="http://www.hostnet.de/faq" target="_blank">Apache-Updateanleitung</a> durch oder wenden sich an den Support um ein Apacheupdate durchführen zu lassen und Roundcube nutzen zu können.__L<br />' . $php_error_text));
	}
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_awstats_migration{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};
	
	foreach my $domain (sort keys %domains){
		if($domains{$domain}{'access_log'} ne ''){
			my $got = `$easytecc_prefix/gen_awstats.pl $domain`;
			return(error("L__Fehler beim Anlegen der Statistik für Domain__L $domain:$got")) if $got;
		}
	}
	logline("debug","Creating File Object \$cronfile.");
	my $cronfile = file->new({file_name => '/home/web/cronfile'});
	$cronfile->read_file;
	my $min =  int(rand('50'));
	push @{$cronfile->file_content}, qq~$min 23 * * * /usr/local/awstats/tools/awstats_updateall.pl now 1>/dev/null 2>/dev/null\n~;

	# alte webalizer cronjobs entfernen
	my @new_cronfile = ();
	foreach($cronfile->file_content){
		#cronjob löschen
		if (/webalizer -c/){
			logline("debug","cronjob löschen:$_");
			next;
		}
		# alles andere in zu schreibendes cronfile
		push @new_cronfile, $_;
	}

	$cronfile->file_content(\@new_cronfile);
	my $got = $cronfile->write_file;
	if ($got) {
		logline("error","cronfile->write_file = ".$got);
		return(error($got));
	}

	$template->param('result' => 'Die AWStats-Auswertungen wurden erfolgreich angelegt und werden tglich zwischen 00:00-01:00 automatisch aktualisiert');
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_roundcube_migration{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;

    my @new_httpd_conf = ();
    #Alias /twig auf Redirect /twig /webmail ändern und zusätzlichen Alias Alias /webmail /home/httpd/docs/roundcube
    foreach($httpd_conf->file_content){
    	if(/^Alias\s+\/twig/){
	        push @new_httpd_conf, qq~Alias /webmail $droot_prefix/roundcube~;
    	}
    	elsif(/^Alias\s+\/easytecc\s+/){
    	    push @new_httpd_conf, qq~<Directory $droot_prefix/twig>
RewriteEngine On
RewriteRule ^(.*) http://%{SERVER_NAME}/webmail [R,L]
</Directory>

Alias /twig $droot_prefix/twig
~;
			push @new_httpd_conf, $_;
    	}
    	elsif(m/^ServerName.*\.han-solo\.net/){
	        push @new_httpd_conf, $_;
    	    push @new_httpd_conf, qq~Alias /webmail $droot_prefix/roundcube~;
    	}
    	else{
	        push @new_httpd_conf, $_;
    	}
    }

    $httpd_conf->file_content(\@new_httpd_conf);
    my $got = $httpd_conf->write_file;
	if ($got) {
		logline("debug","<<< Leaving ".(caller(0))[3]."().");
		return(error($got)) 	
	}

    system("touch /usr/local/etc/easytecc/twig-migration-done");

    $template->param('result' => qq~L__Die Roundcube-Umstellung wurde erfolgreich durchgeführt.__L<br /> <a href="/webmail" target="_blank"><b>L__Zum Webmailer__L</b></a>~);
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_cloneworx{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_cloneworx.html');


	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_vhosts{
	
	logline("debug","sub show_vhosts STARTS NOW");
	
	if($session->param('show_vhosts') ne '1'){
		return start();
	}
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_vhosts.html');
	
	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};
	my %config = %{$httpd_conf->config_hash()};

	logline("debug","Creating File Object \$passwd.");
	my $passwd = file->new({file_name => '/etc/passwd'});
	$passwd->read_file;
	my %passwd = %{$passwd->file_parsed_hash()};
	my %home_lookup =  %{$passwd->lookup2_hash()};

	my ($quotaref, $sum_ftplimit, $sum_ftpuse, $ftpserverlimit) = easytecc3::getquota_ftp();
	my %quota = %$quotaref;

	my $table_data = {};
	
	my $gecos = '';

	
	# hide new vhost non admin
	if($session->param('user') eq 'admin'){
			
		$template->param('show_new_vhost' => '1');
		
	} else {
	
		$gecos = $passwd{$session->param('user')}{'gecos'};	
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.vhost-1';
			
		}
	
		if($gecos =~ m/\.vhost-[1-9]/){
		
			$template->param('show_new_vhost' => '1');
			
		}
	
	}
		
	my @domains = ();
	foreach my $domain (sort keys %domains){
        logline("debug"," Domain: $domain");
		# filter domains
		if($session->param('user') ne 'admin'){
		
			my $admins = $domains{$domain}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$readuserregex = '#' . $session->param('user') . '#';
			$writeuserregex = '#' . uc $session->param('user') . '#';
			
			if($admins =~ m/$writeuserregex/){
			
				$table_data->{$domain}{'show_edit'} = '1';
				$table_data->{$domain}{'show_delete'} = '1';	
				
			} elsif($admins =~ m/$readuserregex/){
			
				$table_data->{$domain}{'show_edit'} = '1';
								
			} else {
			
				next;
				
			}
			
		} else {
		
			$table_data->{$domain}{'show_edit'} = '1';
			$table_data->{$domain}{'show_delete'} = '1';
				
		}
	
		my $ftpuser = '';
		my $ftpquota = '';
		my $ftpquota_sized = '';
		my $ftpused = '';
		my $quotabalken = '';
		my $ssl = '';
		my $ip = '';
		my $domain_ohne_www = $domain;
		$domain_ohne_www =~ s/^www\.//;

		if(exists $home_lookup{$domains{$domain}{'droot'}}){
			$ftpuser = $home_lookup{$domains{$domain}{'droot'}};
			$ftpquota = $quota{$ftpuser}{'quota'};
			$ftpquota_sized = easytecc3::getsize($ftpquota);
			$ftpused = $quota{$ftpuser}{'use'};
			$quotabalken = easytecc3::quotabar($ftpquota, $ftpused);
		}

		#logline("debug","$domain ssl_enabled=" . $config{'ssl_enabled'} . 'ssl=' . $domains{$domain}{'ssl'});

		my $alias_domain;
		my %alias_domains;
						
		foreach $alias_domain (@{$domains{$domain}{'domains'}}){
			
			$alias_domain =~ s/^www\.//;
			
			if($alias_domain ne $domain_ohne_www){
			
				$alias_domains{$alias_domain} = 1;
				
			}
								
		}
		
		$table_data->{$domain}{'alias_domains'} = join(', ',keys %alias_domains);
		
		
		# wenn SSL-Domain, dann Icon in vHost-Liste
		if($config{'ssl_enabled'} && $domains{$domain}{'ssl'}){
			$ssl = 1;
						
			my ($cert_expire_date,$cert_expire_days)= https_cert_expire($domains{$domain}{'ssl_cert'});
			
			if(length($cert_expire_date)){
							
				my $cert_expire = "$cert_expire_date ($cert_expire_days Tage)";
				$table_data->{$domain}{'cert_expire'} = $cert_expire;
				
				if($cert_expire_days < 25){
					$table_data->{$domain}{'cert_warning'} = '1';
				}
				
				if($cert_expire_days < 0){
					$table_data->{$domain}{'cert_failure'} = '1';
				} 
							
				
			}
			
		}

		# wenn separate IP, dann ebenfalls Icon
		if($config{'main_ip'} ne $domains{$domain}{'ip'}){
			$ip = $domains{$domain}{'ip'};
		}

		logline("debug","show_vhosts_domain=" . $domain);
		
		$table_data->{$domain}{'idn_domain_no_www'} = encode('utf-8', domain_to_unicode($domain_ohne_www));
		
		if($domain_ohne_www ne $table_data->{$domain}{'idn_domain_no_www'}){
			$table_data->{$domain}{'domain_no_www'} = $domain_ohne_www;
		}
				
		$table_data->{$domain}{'domain'} = $domain;
		$table_data->{$domain}{'idn_domain'} = encode('utf-8', domain_to_unicode($domain));
		$table_data->{$domain}{'ssl'} = $ssl;
		$table_data->{$domain}{'ip'} = $ip;
		#$table_data->{$domain}{'droot'} = $domains{$domain}{'droot'};
		$table_data->{$domain}{'droot'} = easytecc3::substr_e4($domains{$domain}{'droot'});
		$table_data->{$domain}{'droot_tooltip'} = $domains{$domain}{'droot'};
				
		if(-d $domains{$domain}{'droot'}){
			$table_data->{$domain}{'dir_encoded'} = encode_base64url($domains{$domain}{'droot'});
		}
				
		
		$table_data->{$domain}{'pop'} = $domains{$domain}{'pop'};
		$table_data->{$domain}{'for'} = $domains{$domain}{'for'};
		$table_data->{$domain}{'aut'} = $domains{$domain}{'aut'};
#		$table_data->{$domain}{'quota'} = $domains{$domain}{'quota'};
		# show units
		$table_data->{$domain}{'quota'} = easytecc3::getsize($domains{$domain}{'quota'} * 1024);
		$table_data->{$domain}{'statslink'} = $domains{$domain}{'statslink'};
		$table_data->{$domain}{'custom_tag'} = $domains{$domain}{'custom_tag'};
		
		# default
		if($domains{$domain}{'custom_tag'}){
			
			$table_data->{$domain}{'note_title'} = $domains{$domain}{'custom_tag'};
			$table_data->{$domain}{'note_text'} = '';
			
		}	
		
		my @keys = ('DOMAIN',$domain);
		my $note = note_from_hashfile(\@keys);
												
		if($note->{title}){
						
			$table_data->{$domain}{'note_title'} = $note->{title};
			$table_data->{$domain}{'note_text'} = $note->{text};
								
		}
				
		$table_data->{$domain}{'admin_users'} = $domains{$domain}{'admin_users'};
		
	}
	
	my $table_data_sorted = {};
	foreach $domain (keys %{$table_data}){
        $table_data_sorted->{$table_data->{$domain}{'idn_domain'}} = $table_data->{$domain};
    }
	
	easytecc3::table_e4($template, $table_data_sorted, 'table_tr_show_vhosts_template.html');
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_email{
	
	if($session->param('show_email') ne '1'){
		return start();
	}
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_email.html');
	my $email = '';
	my $quotabalken = '';
	my @domains = ();
	my %passwd = ();

	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};

	$mailpasswd = easytecc3::get_mailpasswd();
	%passwd = %{$mailpasswd->file_parsed_hash()};
	#key=domain, value anzahl user
	my %domain_count_lookup = %{$mailpasswd->lookup_hash_domain_count()};

	logline("debug","Creating File Object \$virtmaps.");
	my $virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
	$virtmaps->read_file;
	my %email = %{$virtmaps->file_parsed_hash()};
	my %virtmaps_domain_count_lookup = %{$virtmaps->lookup_hash_domain_count()};
	my %domain_autoreply_count_lookup = %{$virtmaps->lookup_hash_autoreply_count()};
	
	logline("debug","email is:" . Data::Dumper->Dump([\%email]));
	logline("debug","virtmaps_domain_count_lookup is:" . Data::Dumper->Dump([\%virtmaps_domain_count_lookup]));
	logline("debug","domain_autoreply_count_lookup is:" . Data::Dumper->Dump([\%domain_autoreply_count_lookup]));
	
	
	foreach( sort keys %domain_autoreply_count_lookup){
		logline("debug","Foreach domain_autoreply_count_lookup=$_ count=" . $domain_autoreply_count_lookup{$_});	
	}
	
	logline("debug","Creating File Object \$aliases.");
	my $aliases = file->new({file_name => '/etc/mail/aliases'});
	$aliases->read_file;
	my %aliases = %{$aliases->file_parsed_hash()};
	
	logline("debug","Creating File Object \$passwd.");
	my $passwd_ftp = file->new({file_name => '/etc/passwd'});
	$passwd_ftp->read_file;
	my %passwd_ftp = %{$passwd_ftp->file_parsed_hash()};
	my %home_lookup =  %{$passwd_ftp->lookup2_hash()};

	my ($quotaref, $sum_ftplimit, $sum_ftpuse, $ftpserverlimit) = easytecc3::getquota_ftp();
	my %quota = %$quotaref;
	
	# hide mailserver domains for non admin, show edit
	my $show_email = '';
	my $show_edit_email = '';
	my $show_vhosts = '';

	my $servername = `sed 's/^.* // ; s/\$/.han-solo.net/' /etc/FQDN 2>/dev/null`;
	chomp $servername;
	
	if($session->param('user') eq 'admin'){
	
		$template->param('show_mailserver_domains' => '1');
		$template->param('show_quotamessage' => '1');
		
# mailserver cert - derzeit zu gefährlich wegen reverse dns etc.		
		
		#$template->param('show_mailserver_cert' => '1');
		#
		##my $mailserver_certs=`ls -1 /etc/letsencrypt/archive/ | while read DOMAIN; do grep -qE "^[^#]*Server(Name|Alias).* (www\\.)?\$DOMAIN" /etc/apache24/httpd.conf && echo "\$DOMAIN"; done | sort`;
		#
		##my $mailserver_certs=`find /etc/letsencrypt/renewal/ -name "*.conf" -exec sed '1,/^\\[\\[webroot_map\\]\\]\$/d ; /^www\\./d ; s/ =.*//' {} \\; | while read DOMAIN; do grep -qE "^[^#]*ServerName (www\\.)?\$DOMAIN" /etc/apache24/httpd.conf && echo "\$DOMAIN"; done | sort -u`;
		#
		#my $mailserver_certs=`grep -Eh '^[^#]*SSLCertificateKeyFile' /etc/apache24/httpd.conf /etc/apache24/extra/httpd-ssl.conf | sed 's/\\/[^\\/]*\$// ; s/^.*\\///' | sort -u`;		
		#chomp($mailserver_certs);
		#
		#logline("debug","###############mailserver certs: #$mailserver_certs#");
		#
		#my @mailserver_certs = split(/[\r\n]/,$mailserver_certs);
		#
		#my $current_mailserver_cert = `readlink /usr/ssl/wild.han.pem | sed 's/\\/[^\/]*\$// ; s/^.*\\///'`;
		#chomp $current_mailserver_cert;
		#
		#logline("debug","###############mailserver cert: $current_mailserver_cert");
		#	
		#my $template_mailserver_cert_select = HTML::Template->new(filename => 'mailserver_cert_select.html');
		#easytecc3::template_loop(\%input,\$template_mailserver_cert_select, \@mailserver_certs, 'mailserver_cert_select', $current_mailserver_cert);
		#$template->param('mailserver_cert_select' => $template_mailserver_cert_select->output);
		#
		
		$show_email = '1';
		$show_edit_email = '1';
		$show_vhosts = '1';
		
		$domains{$servername}{'pop'} = 1;
		$domains{$servername}{'for'} = 0;
		$domains{$servername}{'aut'} = 0;
				
	} else {
	
		my $gecos = $passwd_ftp{$session->param('user')}{'gecos'};	
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.vhost-1.email-1';
		
		}
	
		if($gecos =~ m/\.vhost/){
	
			$show_vhosts = '1';
	
		}
	
		if($gecos =~ m/\.email/){
	
			$show_email = '1';
	
			if($gecos =~ m/\.email-[1-9]/){
			
				$show_edit_email = '1';
				
			}
	
		}
		
	}
	
	if(!$fb){
		delete($domains{$servername});
	}
			
	my $table_data = {};
	foreach my $domain (sort keys %domains){
		
		# filter domains
		if($session->param('user') ne 'admin'){
		
			my $admins = $domains{$domain}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
						
			$readuserregex = '#' . $session->param('user') . '#';
			$writeuserregex = '#' . uc $session->param('user') . '#';
			
			if($admins =~ m/$writeuserregex/){
		
				if($show_vhosts eq '1'){ 
				
					$table_data->{$domain}{'show_edit_vhost'} = '1';
					
				}
											
			} elsif($admins =~ m/$readuserregex/){

				if($show_vhosts eq '1'){ 
			
					$table_data->{$domain}{'show_vhost'} = '1';
					
				}
			
			} else {
		
				next;
			
			}
						
		} elsif($domain ne $servername) {
		
			$table_data->{$domain}{'show_edit_vhost'} = '1';
			
		}
			
		$table_data->{$domain}{'show_edit_email'} = $show_edit_email;
		$table_data->{$domain}{'show_email'} = $show_email;
	
		my $popcount = '0';
		my $forcount = '0';
		my $autcount = '0';
		my $mailquota = '';
	
		if($domain eq $servername){
			$mailquota = $quota{'admin'}{'quota'} / 1024;
			$domains{$domain}{'aut'} = 0;
			$domains{$domain}{'for'} = 0;
			$domains{$domain}{'pop'} = 1;
			$popcount = '1';
		}
				
		else{
		
			$mailquota = $domains{$domain}{'quota'};
		
			my $ftpdir = $domains{$domain}{'droot'};
			while(length($ftpdir) && $ftpdir !~ /\/(data|noexec)$/){
				
				if(exists $home_lookup{$ftpdir}){
					
					my $ftpuser = $home_lookup{$ftpdir};
					$mailquota = (($domains{$domain}{'quota'} * 1024 ) - $quota{$ftpuser}{'quota'}) / 1024;
					last;
					
				}
				
				$ftpdir =~ s/\/[^\/]*$//;
				
			}	
					
		}
		$mailquota = easytecc3::getsize($mailquota * 1024);

		logline("debug","Foreach Domain: $domain.");

		my $domain_ohne_www = $domain;
		$domain_ohne_www =~ s/^www\.//;
		my $serveralias = '<br />';

		#foreach(@{$domains{$domain}{'domains'}}){
		#	next if /^www\./;
		#	next if /^$domain_ohne_www$/;
		#	$serveralias .= encode('utf-8', domain_to_unicode($_)) . '<br />';
		#}
		
		foreach(@{$domains{$domain}{'domains'}}){
			if (defined $domain_autoreply_count_lookup{$_}) {
			$autcount = $autcount + $domain_autoreply_count_lookup{$_};
			}
		}

		my $splitted_domains = join '|', @{$domains{$domain}{'domains'}};
		#$splitted_domains = quotemeta($splitted_domains);
		#$splitted_domains =~ s/\\/\\\\/g;
		$splitted_domains =~ s/\*/\\*/g;
		logline("debug","splitted_domains = $splitted_domains");
		
		foreach my $virtmaps_domain( keys %virtmaps_domain_count_lookup) {
			if($virtmaps_domain =~  /^($splitted_domains)$/){				
			$forcount = $forcount + $virtmaps_domain_count_lookup{$virtmaps_domain};
			}
		}
		
		
		
		#todo: unbedingt optimieren und Iterationen weg mit lookup hash aus parsingfunktion von virtmaps
		#foreach my $virtmaps_lhs(keys %email){
		#	my $virtmaps_rhs = $email{$virtmaps_lhs};
		#	my $line = $virtmaps_lhs . ' ' . $virtmaps_rhs;
		#	#logline("debug","line = $line");
		#	
		#	#if($line =~  /@(?:$splitted_domains)(?: |\t)+[a-zA-Z_\.\-0-9]+[^_aut](.+)$/){
		#	if($virtmaps_lhs =~  /@(?:$splitted_domains)$/){
		#		#logline("debug","match $1");
		#		
		#		#if ($1 eq '_aut'){
		#		if ($aliases{$virtmaps_rhs} =~ /\/autoresponder/){
		#			logline("debug","match aut");
		#			$autcount++;
		#		}
		#		$forcount++;		
		#	}
		#}

		#if (defined $domain_count_lookup{$domain_ohne_www}) {
		#	$popcount = $popcount + $domain_count_lookup{$domain_ohne_www};
		#}
		
		foreach(@{$domains{$domain}{'domains'}}){
			
			$_ =~ s/^www\.//;
			
			if (defined $domain_count_lookup{$_}) {
				$popcount = $popcount + $domain_count_lookup{$_};
			}
			
		}
		
		#foreach my $line (keys %passwd){
		#	if($passwd{$line}{'gecos'} =~ /^(?:$splitted_domains) - POP/){
		#		logline("debug","passwd pop: " . $passwd{$line}{'gecos'});
		#		$popcount++;
		#	}
		#}
	
		$table_data->{$domain}{'domain'} = $domain;
		$table_data->{$domain}{'idn_domain'} = encode('utf-8', domain_to_unicode($domain));
		$table_data->{$domain}{'idn_domain_no_www'} = encode('utf-8', domain_to_unicode($domain_ohne_www));
		$table_data->{$domain}{'pop'} = $domains{$domain}{'pop'};
		$table_data->{$domain}{'popcount'} = $popcount;
		$table_data->{$domain}{'for'} = $domains{$domain}{'for'};
		$table_data->{$domain}{'forcount'} = $forcount;
		$table_data->{$domain}{'aut'} = $domains{$domain}{'aut'};
		$table_data->{$domain}{'autcount'} = $autcount;
		$table_data->{$domain}{'mailquota_MB'} = $mailquota;
		
		if ($domains{$domain}{'pop'} >= 1 ||
			$domains{$domain}{'for'} >= 1 ||
			$domains{$domain}{'aut'} >= 1) {
			
			$table_data->{$domain}{'edit_email_icons'} = 1;	
		}
		
		# href to list of email adresses for single edit
		if ($domains{$domain}{'for'} >= 1) {
			
			if(-e '/usr/local/etc/easytecc/showsingleeditemail'){
			
				$table_data->{$domain}{'href_single_edit_email'} = 1;
				
			}
			
		}
		
	}
	
	my $table_data_sorted = {};
	foreach $domain (keys %{$table_data}){
        $table_data_sorted->{$table_data->{$domain}{'idn_domain'}} = $table_data->{$domain};
    }

	easytecc3::table_e4($template, $table_data_sorted, 'table_tr_show_email_template.html');
	
	if (length($input{'active_tab'})) {
		$template->param('show_email_active_tab'.$input{'active_tab'} => 1);
	}
	else{
		$template->param('show_email_active_tab1' => 1);	
	}
	
	#dkim
	if(-f '/etc/opendkim.conf'){
		
		$template->param('dkim_available' => 1);
		
	}	
	
	#separate function for mailserver domains
	new_sendmail_cw($template);
	
	#quotamessagestuff
	
	my $quotasender;
	if(-e '/etc/mail/quotafrom'){
		$quotasender = `/bin/cat /etc/mail/quotafrom 2>/dev/null`;
		chomp($quotasender);
	} elsif(-e '/etc/mail/quotamessage'){
		$quotasender = `/usr/bin/grep -i -m1 '^From: ' /etc/mail/quotamessage`;
		chomp($quotasender);
		$quotasender =~ s/^From:\s+//gi;
	} else {
		$quotasender = 'MAIL_FROM';
	}
	if(!length($quotasender) || $quotasender eq 'MAIL_FROM'){
		$quotasender = 'Mailserver Warning <mailserver@${MAIL_DOMAIN}>';
	}
		
	$quotasender =~ s/\"?\$\{//g;
	$quotasender =~ s/\}\"?//g;
	
	my $quotasubject;
	if(-e '/etc/mail/quotamessage'){
		$quotasubject = `/usr/bin/grep -i -m1 '^Subject: ' /etc/mail/quotamessage`;
		chomp($quotasubject);
		$quotasubject =~ s/^Subject:\s+//gi;
	} else {
		$quotasubject = 'MAIL_SUBJECT';
	}
	if(!length($quotasubject) || $quotasubject eq 'MAIL_SUBJECT'){
		$quotasubject = 'Ihre Mailbox ist zu "${MAIL_QUOTA_PERCENT}"% voll!';
	}
	
	$quotasubject =~ s/\"?\$\{//g;
	$quotasubject =~ s/\}\"?//g;
			
	my $quotamessage;
	if(-e '/etc/mail/quotamessage'){
		$quotamessage = `/bin/cat /etc/mail/quotamessage 2>/dev/null`;
		$quotamessage =~ s/^(From|Subject):\s.*$//gmi;
		$quotamessage =~ s/^\s*//gs;
		$quotamessage =~ s/\s*$//gs;
	} elsif(-e '/usr/sbin/quota-warning.sh'){
		$quotamessage = `/bin/cat /usr/sbin/quota-warning.sh 2>/dev/null`;
		$quotamessage =~ s/^.*Content-Transfer-Encoding: 8bit//gs;
		$quotamessage =~ s/EOF.*$//gs;
		$quotamessage =~ s/^\s*//gs;
		$quotamessage =~ s/\s*$//gs;
	} else {
		$quotamessage = '';
	}
	$quotamessage =~ s/\"?\$\{//g;
	$quotamessage =~ s/\}\"?//g;

	$template->param('quotasender' => $quotasender);
	$template->param('quotasubject' => $quotasubject);
	$template->param('quotamessage' => $quotamessage);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_ftpuser{
	
	if($session->param('show_ftp') ne '1'){
		return start();
	}
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_ftpuser.html');

	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};

	my %domain_home;
	my %admin_users;
	foreach(keys %domains){
			
		# filter domains
		if($session->param('user') ne 'admin'){
		
			my $admins = $domains{$_}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $session->param('user') . '#';
			
			logline("debug","admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				next;
			}
		} 
		
		# gather admin users
		else {
		
			my @admins = split(/[\s,]+/, $domains{$_}{'admin_users'});
			foreach my $admin (@admins){
			
				$admin_users{$admin} = $admin;
			
			}
		
		}
		
		logline("debug","domain_home=" . $domains{$_}{'droot'});
		logline("debug","domain_domains=" . $domains{$_}{'domains'});
		$domain_home{$domains{$_}{'droot'}} = $domains{$_}{'domains'};
	}

	logline("debug","Creating File Object \$passwd.");
	my $passwd = file->new({file_name => '/etc/passwd'});
	$passwd->read_file;
	my %passwd = %{$passwd->file_parsed_hash()};

	my $show_new_ftp = '';
	my $show_edit_ftp = '';
	
	if($session->param('user') eq 'admin'){
	
		$show_new_ftp = '1';
		$show_edit_ftp = '1';
		
	} else {	
	
		my $gecos = $passwd{$session->param('user')}{'gecos'};	
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.ftp-2';
			
		}
		
		if($gecos =~ m/\.ftp-1/){
			
			$show_edit_ftp = '1';
				
		} elsif($gecos =~ m/\.ftp-2/){
			
			$show_new_ftp = '1';
			$show_edit_ftp = '1';
				
		}
	
	}	
		
	$template->param('show_new_ftp' => $show_new_ftp);
	$template->param('show_edit_ftp' => $show_edit_ftp);
		
	my ($quotaref, $sum_ftplimit, $sum_ftpuse, $ftpserverlimit) = easytecc3::getquota_ftp();
	my %quota = %$quotaref;

	#Zähler für Tabelle wenn es zu FTP-User keine Domain gibt, z.B. alle Systemuser
	my $count = 1;
	my @ftp_user = ();
	my $table_data = {};
	foreach my $ftpuser (sort keys %passwd){
		# User web und ftp nicht bei ftpusern anzeigen. Stiftet nur Verwirrung
		next if $ftpuser eq 'web';
		next if $ftpuser eq 'ftp';
		next if $ftpuser eq 'cyrus';
		next if $ftpuser eq 'dovecot';
		next if $ftpuser eq 'dovenull';
		next if $ftpuser eq 'mysql';
		next if $ftpuser eq 'pgsql';
		next if $ftpuser eq 'virtmail';
		next if $ftpuser eq 'svn';
		next if $ftpuser eq 'haproxy';
		
		my $ftpquota = '';
		my $ftpquota_sized = '';
		my $ftpused = '';
		my $quotabalken = '';
		my $domain = '';
		my $has_domain = '';

		$ftpquota = $quota{$ftpuser}{'quota'};
		$ftpquota_sized = easytecc3::getsize($ftpquota);
		$ftpused = $quota{$ftpuser}{'use'};
		logline("debug","ftpuser=$ftpuser\tftpused=$ftpused");
		next unless $ftpused;
		next if $passwd{$ftpuser}{'gecos'} =~ /- POP/;
		
		if($session->param('user') eq 'admin' && $passwd{$ftpuser}{'gecos'} =~ /^CUST/){
			next;
		}
		
		$quotabalken = easytecc3::quotabar($ftpquota, $ftpused, 'table');

		if(exists $domain_home{$passwd{$ftpuser}{'home'}}){
			#$domain = @{$domain_home{$passwd{$ftpuser}{'home'}}};
			foreach(@{$domain_home{$passwd{$ftpuser}{'home'}}}){
				$domain .= encode('utf-8', domain_to_unicode($_)) . '<br />';
			}
			$has_domain = 1;
		} else {
		
			# filter domains
			if($session->param('user') ne 'admin'){
			
				my $home = $passwd{$ftpuser}{'home'};
				my $self_home = $passwd{$session->param('user')}{'home'};
				my $allowed = 0;
				
				if($home ne $self_home && $home !~ m#^$self_home/#){
				
					foreach my $dir (keys %domain_home){
					
						if($home eq $dir || $home =~ m#^$dir/#){
					
							$allowed = '1';
							
						}
					
					}
					
					if($allowed != 1){
					
						next;
					
					} 
				
				}
			
			}
		
		}

		if($session->param('user') eq 'admin'){
			$table_data->{$ftpuser}{'is_admin_user'} = '1';
		}
				
		#wenn keiner domain zugeordnet, dann nicht no_domain... ausgeben sondern mit Hilfe von Flag leeres Feld		
		$domain = "no_domain$count" unless $domain;
		$count++;
		
		$table_data->{$ftpuser}{'has_domain'} = $domain if $has_domain;				
		$table_data->{$ftpuser}{'domain'} = $domain;
		$table_data->{$ftpuser}{'ftpuser'} = $ftpuser;
		$table_data->{$ftpuser}{'gecos'} = $passwd{$ftpuser}{'gecos'};
		$table_data->{$ftpuser}{'home_tooltip'} = $passwd{$ftpuser}{'home'};
		$table_data->{$ftpuser}{'home'} = easytecc3::substr_e4($passwd{$ftpuser}{'home'});
		$table_data->{$ftpuser}{'ftpquota_MB'} = $ftpquota_sized;
		$table_data->{$ftpuser}{'ftpquota_used_MB'} = easytecc3::getsize($quota{$ftpuser}{'use'});
		$table_data->{$ftpuser}{'ftpquota_used_percent'} = $quota{$ftpuser}{'use'} > 0 ? sprintf("%.0f",($quota{$ftpuser}{'use'} / $quota{$ftpuser}{'quota'}) * 100) : '0';
		$table_data->{$ftpuser}{'alert_ftpuser_quota'} = easytecc3::quota_alert($quota{$ftpuser}{'quota'}, $quota{$ftpuser}{'use'}, '.8');
		$table_data->{$ftpuser}{'show_edit_ftp'} = $show_edit_ftp;
		
		my @keys = ('FTPUSER',$ftpuser);
		my $note = note_from_hashfile(\@keys);
												
		if($note->{title}){
						
			$table_data->{$ftpuser}{'note_title'} = $note->{title};
			$table_data->{$ftpuser}{'note_text'} = $note->{text};
								
		}
		
		if ($ftpuser !~ /^(admin|cyrus|dovecot|dovenull|mysql|pgsql|virtmail|svn|haproxy)$/ && $ftpuser ne $session->param('user') && $show_edit_ftp eq '1') {			
			$table_data->{$ftpuser}{'icon_delete_ftpuser'} = 1;	
		}		
	}

	easytecc3::table_e4($template, $table_data, 'table_tr_show_ftpuser_template.html');
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_adminuser{
	
	if($session->param('user') ne 'admin'){
		return start();
	}
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_adminuser.html');

	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};

	my %admin_domains;
	my %full_admin_domains;
	foreach my $domain(keys %domains){
		my @admins = split(/[\s,]+/, $domains{$domain}{'admin_users'});
						
		foreach my $admin (@admins){
					
			my $domainlist = $admin_domains{lc($admin)};
			if($domainlist ne ''){
			
				$domainlist .= ', ';
				
			}
			
			$domain = encode('utf-8', domain_to_unicode($domain));
			$domain =~ s/^www\.//;
			
			$domainlist .= $domain;
			# want this for tooltip
			$full_admin_domains{lc($admin)} = $domainlist;
			
			if(length($domainlist) > 23){
				$domainlist = substr($domainlist,0,20) . '...';
			}
			$admin_domains{lc($admin)} = $domainlist;
			
		}
	}

	logline("debug","Creating File Object \$passwd.");
	my $passwd = file->new({file_name => '/etc/passwd'});
	$passwd->read_file;
	my %passwd = %{$passwd->file_parsed_hash()};
	my %home_lookup =  %{$passwd->lookup2_hash()};

	my ($quotaref, $sum_ftplimit, $sum_ftpuse, $ftpserverlimit) = easytecc3::getquota_ftp();
	my %quota = %$quotaref;

	#Zähler für Tabelle wenn es zu FTP-User keine Domain gibt, z.B. alle Systemuser
	my $count = 1;
	my @ftp_user = ();
	my $table_data = {};
	foreach my $ftpuser (sort keys %passwd){
		
		next if $passwd{$ftpuser}{'gecos'} !~ /^CUST/;
		
		my $ftpquota = '';
		my $ftpquota_sized = '';
		my $ftpused = '';
		my $quotabalken = '';
		my $domain = '';
		my $has_domain = '';

		$ftpquota = $quota{$ftpuser}{'quota'};
		$ftpquota_sized = easytecc3::getsize($ftpquota);
		$ftpused = $quota{$ftpuser}{'use'};
		logline("debug","ftpuser=$ftpuser\tftpused=$ftpused");
		next unless $ftpused;
		next if $passwd{$ftpuser}{'gecos'} =~ /- POP/;
		$quotabalken = easytecc3::quotabar($ftpquota, $ftpused, 'table');

		#if($admin_users{$ftpuser} ne $ftpuser){
		#	next;
		#}
	
		$table_data->{$ftpuser}{'is_admin_user'} = '1';
				
		if(exists $admin_domains{$ftpuser}){
			$domain .= $admin_domains{$ftpuser} . '<br />';
			$has_domain = 1;
		} 
				
		#wenn keiner domain zugeordnet, dann nicht no_domain... ausgeben sondern mit Hilfe von Flag leeres Feld		
		$domain = "no_domain$count" unless $domain;
		$count++;
		
		$table_data->{$ftpuser}{'has_domain'} = $domain if $has_domain;				
		$table_data->{$ftpuser}{'domain_tooltip'} = $full_admin_domains{$ftpuser};
		$table_data->{$ftpuser}{'domain'} = $domain;
		$table_data->{$ftpuser}{'idn_domain'} = $domain;
		$table_data->{$ftpuser}{'ftpuser'} = $ftpuser;
		$table_data->{$ftpuser}{'gecos'} = $passwd{$ftpuser}{'gecos'};
		$table_data->{$ftpuser}{'home_tooltip'} = $passwd{$ftpuser}{'home'};
		$table_data->{$ftpuser}{'home'} = easytecc3::substr_e4($passwd{$ftpuser}{'home'});
		$table_data->{$ftpuser}{'ftpquota_MB'} = $ftpquota_sized;
		$table_data->{$ftpuser}{'ftpquota_used_MB'} = easytecc3::getsize($quota{$ftpuser}{'use'});
		$table_data->{$ftpuser}{'ftpquota_used_percent'} = $quota{$ftpuser}{'use'} > 0 ? sprintf("%.0f",($quota{$ftpuser}{'use'} / $quota{$ftpuser}{'quota'}) * 100) : '0';
		$table_data->{$ftpuser}{'alert_ftpuser_quota'} = easytecc3::quota_alert($quota{$ftpuser}{'quota'}, $quota{$ftpuser}{'use'}, '.8');
		
		my @keys = ('ADMINUSER',$ftpuser);
		my $note = note_from_hashfile(\@keys);
												
		if($note->{title}){
						
			$table_data->{$ftpuser}{'note_title'} = $note->{title};
			$table_data->{$ftpuser}{'note_text'} = $note->{text};
								
		}
				
		if ($ftpuser !~ /^(admin|cyrus|dovecot|dovenull|mysql|pgsql|virtmail|svn|haproxy)$/) {			
			$table_data->{$ftpuser}{'icon_delete_ftpuser'} = 1;	
		}		
	}

	if(length($input{'adminuser'}) > 0 && $passwd{$input{'adminuser'}}{'gecos'} =~ /^CUST/){
	
		$template->param('adminuser' => $input{'adminuser'});
		
		my $ftp_table_data = {};
		
		logline("debug","Creating File Object \$httpd_conf.");
		my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
		$httpd_conf->read_file;
		my %domains = %{$httpd_conf->file_parsed_hash()};
		my %config = %{$httpd_conf->config_hash()};
		
		if (easytecc3::extern_mx() || $fb){
			$mailpasswd = easytecc3::get_mailpasswd();
			%mailpasswd = %{$mailpasswd->file_parsed_hash()};

			#%mailpasswd = %{easytecc3::get_mailpasswd()};
			($mailquotaref, $sum_maillimit, $sum_mailuse, $mailserverlimit) = easytecc3::getquota_mail(\%mailpasswd);

			logline("debug","show_quota mailquotaref=$mailquotaref");

			%mailquota = %$mailquotaref;

		}
		else{
			%mailpasswd = %passwd;
			%mailquota = %quota;
			$sum_maillimit = $sum_ftplimit;
			$sum_mailuse = $sum_ftpuse;
			$mailserverlimit = $ftpserverlimit;
		}
		
		my($active_user_chars_ref, $active_domain_chars_ref, $active_users_ref, $active_domains_ref) = easytecc3::get_userchars();
		my %active_users = %$active_users_ref;
		my %active_domains = %$active_domains_ref;
		
		my %domain_home;
		my %allowed_domains;
		my $domain_table_data = {};
		
		foreach my $domain (sort keys %domains){
		
			# filter domains
			my $admins = $domains{$domain}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $input{'adminuser'} . '#';
			
			logline("debug","admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				next;
			}
		
			foreach my $alias_domain (@{$domains{$domain}{'domains'}}){
					
				$alias_domain =~ s/^www\.//;
				$alias_domain =~ s/^\*\.//;
				
				$allowed_domains{$alias_domain} = 1;
				
				logline("debug","allowed_domain:$alias_domain");
				
			}
			
			my $sanitized_domain = $domain;
			$sanitized_domain =~ s/^www\.//;
			$sanitized_domain =~ s/^\*\.//;
				
			$allowed_domains{$sanitized_domain} = 1;
		
			logline("debug","domain_home=" . $domains{$domain}{'droot'});
			logline("debug","domain_domains=" . $domains{$domain}{'domains'});
			$domain_home{$domains{$domain}{'droot'}} = $domains{$domain}{'domains'};
			
			$domain_table_data->{$domain}{'show_edit'} = '1';
			$domain_table_data->{$domain}{'show_delete'} = '1';
			
			my $ftpuser = '';
			my $ftpquota = '';
			my $ftpquota_sized = '';
			my $ftpused = '';
			my $quotabalken = '';
			my $ssl = '';
			my $ip = '';
			my $domain_ohne_www = $domain;
			$domain_ohne_www =~ s/^www\.//;

			if(exists $home_lookup{$domains{$domain}{'droot'}}){
				$ftpuser = $home_lookup{$domains{$domain}{'droot'}};
				$ftpquota = $quota{$ftpuser}{'quota'};
				$ftpquota_sized = easytecc3::getsize($ftpquota);
				$ftpused = $quota{$ftpuser}{'use'};
				$quotabalken = easytecc3::quotabar($ftpquota, $ftpused);
			}

			logline("debug","$domain ssl_enabled=" . $config{'ssl_enabled'} . 'ssl=' . $domains{$domain}{'ssl'});

			# wenn SSL-Domain, dann Icon in vHost-Liste
			if($config{'ssl_enabled'} && $domains{$domain}{'ssl'}){
				$ssl = 1;
			}

			# wenn separate IP, dann ebenfalls Icon
			if($config{'main_ip'} ne $domains{$domain}{'ip'}){
				$ip = $domains{$domain}{'ip'};
			}

			logline("debug","show_vhosts_domain=" . $domain);
			
			$domain_table_data->{$domain}{'idn_domain_no_www'} = encode('utf-8', domain_to_unicode($domain_ohne_www));
			$domain_table_data->{$domain}{'domain'} = $domain;
			$domain_table_data->{$domain}{'idn_domain'} = encode('utf-8', domain_to_unicode($domain));
			$domain_table_data->{$domain}{'ssl'} = $ssl;
			$domain_table_data->{$domain}{'ip'} = $ip;
			#$table_data->{$domain}{'droot'} = $domains{$domain}{'droot'};
			$domain_table_data->{$domain}{'droot'} = easytecc3::substr_e4($domains{$domain}{'droot'});
			$domain_table_data->{$domain}{'droot_tooltip'} = $domains{$domain}{'droot'};
			
			if(-d $domains{$domain}{'droot'}){
				$domain_table_data->{$domain}{'dir_encoded'} = encode_base64url($domains{$domain}{'droot'});
			}
						
			$domain_table_data->{$domain}{'pop'} = $domains{$domain}{'pop'};
			$domain_table_data->{$domain}{'for'} = $domains{$domain}{'for'};
			$domain_table_data->{$domain}{'aut'} = $domains{$domain}{'aut'};
	#		$table_data->{$domain}{'quota'} = $domains{$domain}{'quota'};
			# show units
			$domain_table_data->{$domain}{'quota'} = easytecc3::getsize($domains{$domain}{'quota'} * 1024);
			$domain_table_data->{$domain}{'statslink'} = $domains{$domain}{'statslink'};
			$domain_table_data->{$domain}{'custom_tag'} = $domains{$domain}{'custom_tag'};
			$domain_table_data->{$domain}{'admin_users'} = $domains{$domain}{'admin_users'};
			
			$domain_table_data->{$domain}{'hide_note'} = 1;
					
		}

		easytecc3::table_e4($template, $domain_table_data, 'table_tr_show_vhosts_template.html');
		
		foreach my $ftpuser (sort keys %passwd){
				
			# do NOT show system users here
			next if $ftpuser eq 'ftp';	
			next if $ftpuser eq 'cyrus';
			next if $ftpuser eq 'dovecot';
			next if $ftpuser eq 'dovenull';
			next if $ftpuser eq 'virtmail';
			next if $ftpuser eq 'svn';
			next if $ftpuser eq 'haproxy';
			
			my $ftpquota = '';
			my $ftpquota_sized = '';
			my $ftpused = '';
			my $quotabalken = '';
			my $domain = '';
			
			logline("debug","foreach ftpuser = $ftpuser");

			$ftpquota = $quota{$ftpuser}{'quota'};
			$ftpquota_sized = easytecc3::getsize($ftpquota);
			$ftpused = $quota{$ftpuser}{'use'};

			next unless $ftpused;
			next if $passwd{$ftpuser}{'gecos'} =~ /- POP/;
			#$quotabalken = easytecc3::quotabar($ftpquota, $ftpused, 'used');

			my @domainlist = ();
			if(exists $domain_home{$passwd{$ftpuser}{'home'}}){
				foreach(@{$domain_home{$passwd{$ftpuser}{'home'}}}){
					push @domainlist, encode('utf-8', domain_to_unicode($_));
				}
				$domain = join '<br />', @domainlist;
			} else {
			
				my $home = $passwd{$ftpuser}{'home'};
				my $self_home = $passwd{$input{'adminuser'}}{'home'};
				my $allowed = 0;
				
				if($home ne $self_home && $home !~ m#^$self_home/#){
				
					foreach my $dir (keys %domain_home){
					
						if($home eq $dir || $home =~ m#^$dir/#){
					
							$allowed = '1';
							
						}
					
					}
					
					if($allowed != 1){
					
						next;
					
					} 
				
				}

			}
			
			$ftp_table_data->{$ftpuser}{'alert_ftpuser_quota'} = easytecc3::quota_alert($ftpquota, $ftpused, '.8');
			$ftp_table_data->{$ftpuser}{'ftpuser'} = $ftpuser;
			$ftp_table_data->{$ftpuser}{'domain'} = $domain;
			$ftp_table_data->{$ftpuser}{'gecos'} = $passwd{$ftpuser}{'gecos'};
			$ftp_table_data->{$ftpuser}{'home_tooltip'} = $passwd{$ftpuser}{'home'};
			$ftp_table_data->{$ftpuser}{'home'} = easytecc3::substr_e4($passwd{$ftpuser}{'home'});
			$ftp_table_data->{$ftpuser}{'ftpquota_sized'} = $ftpquota_sized;
			$ftp_table_data->{$ftpuser}{'ftpquota_used_sized'} = easytecc3::getsize($ftpused);
			$ftp_table_data->{$ftpuser}{'ftpquota_used_percent'} = sprintf("%.0f", ($ftpused/$ftpquota)*100) if $ftpquota > 0;

			$ftp_table_data->{$ftpuser}{'show_ftp'} = '1';
			$ftp_table_data->{$ftpuser}{'show_edit_ftp'} = '1';
			
		}

		#easytecc3::table(\$template,'<td>L__User__L</td><td>L__Domain__L</td><td>L__Beschreibung__L</td><td>L__Homeverzeichnis__L</td><td>L__FTP-Quota__L</td><td>L__Quotanutzung__L</td><td>L__Aktionen__L</td>', \@ftp_user, 'table_ftpuser');
		easytecc3::table_e4($template, $ftp_table_data, 'table_tr_show_quota_ftpuser_template.html');
		
		
		my $mail_table_data = {};
		foreach my $mailuser (sort keys %mailpasswd){
			
			next if ($mailpasswd{$mailuser}{'gecos'} !~ / - POP$/ && $mailuser ne 'admin');
			
			#wenn kein externer mailserver muss admin nicht bei popusern auftauchen
			next if( ! easytecc3::extern_mx() && $mailuser eq 'admin');
			
			logline("debug","foreach POP mailpasswd = $mailuser");
			
			my $domain =  $mailpasswd{$mailuser}{'gecos'};
			$domain =~ s/ - POP$//;
			
			logline("debug","mailuser $mailuser domain: #$domain#");
			
			my $admins = $domains{'www.' . $domain}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $input{'adminuser'} . '#';
			
			logline("debug","admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				delete $active_users{$mailuser};
				next;
			}
		
			my $mailquota_sized =  $mailquota{$mailuser}{'quota'} / 1024;
			#my $quotabalken = easytecc3::quotabar($mailquota{$user}{'quota'}, $mailquota{$user}{'use'}, 'used');
			my $change_mailuser = '';

			if ($fb) {
				$change_mailuser = qq~<a href='/cgi-bin/easytecc3/index.pl?action=change_forward&amp;domain=www.$domain'>L__Editieren__L</a>~
			}
			else{
				$change_mailuser = qq~<a href='/cgi-bin/easytecc3/index.pl?action=change_popuser&amp;domain=www.$domain'>L__Editieren__L</a>~
			}

			my $idn_mailuser = encode('utf-8', email_to_unicode($mailuser));
			
			logline("debug","#$mailuser#$idn_mailuser#");
			
			my $idn_domain = encode('utf-8', domain_to_unicode($domain));
			
			$mail_table_data->{$idn_mailuser}{'alert_mailuser_quota'} = easytecc3::quota_alert($mailquota{$mailuser}{'quota'}, $mailquota{$mailuser}{'use'}, '.8');
			$mail_table_data->{$idn_mailuser}{'mailuser'} = $mailuser;
			$mail_table_data->{$idn_mailuser}{'idn_mailuser'} = $idn_mailuser;
			$mail_table_data->{$idn_mailuser}{'domain'} = $idn_domain;
			$mail_table_data->{$idn_mailuser}{'idn_domain'} = $idn_domain;
			$mail_table_data->{$idn_mailuser}{'domain_www'} = 'www.' . $domain;
			$mail_table_data->{$idn_mailuser}{'gecos'} = $mailpasswd{$mailuser}{'gecos'};
			$mail_table_data->{$idn_mailuser}{'mailquota_sized'} = easytecc3::getsize($mailquota{$mailuser}{'quota'});
			$mail_table_data->{$idn_mailuser}{'mailquota_used_sized'} = easytecc3::getsize($mailquota{$mailuser}{'use'});
			$mail_table_data->{$idn_mailuser}{'mailquota_used_percent'} = sprintf("%.0f", ($mailquota{$mailuser}{'use'}/$mailquota{$mailuser}{'quota'})*100) if $mailquota{$mailuser}{'quota'} > 0;

			$mail_table_data->{$idn_mailuser}{'show_email'} = '1';
			$mail_table_data->{$idn_mailuser}{'show_edit_email'} = '1';
						
			my @keys = ('EMAILUSER',$mailuser);
			my $note = note_from_hashfile(\@keys);
															
			if($note->{title}){
									
				$mail_table_data->{$idn_mailuser}{'note_title'} = $note->{title};
				$mail_table_data->{$idn_mailuser}{'note_text'} = $note->{text};
											
			}
						
			#push(@user, $user.'|'.domain_to_unicode($domain).'|'.qq~$mailquota_sized MB~.'|'.qq~$quotabalken~.'|'.$change_mailuser);
		}
		
		#easytecc3::table(\$template,'<td>L__User__L</td><td>L__Domain__L</td><td>L__E-Mail-Quota__L</td><td>L__Quotanutzung__L</td><td colspan="3">L__Aktionen__L</td>', \@user, 'table_mailuser');
		easytecc3::table_e4($template, $mail_table_data, 'table_tr_show_quota_mailuser_template.html');
	
		my @special_spamfilter = ();
		
		foreach $domain (sort keys %active_domains){
			
			$domain = ascii_domain($domain);
			$domain =~ s/^www\.//;
			$domain =~ s/^\*\.//;
						
			if(!exists $allowed_domains{$domain}){
			
				delete $active_domains{$domain};
			
			}
		}
	
		my $spam_table_data = {};
	
		foreach(sort keys %active_users){
			if(/^$input{'ulist'}/ || $input{'ulist'} eq 'all'){
				push(@special_spamfilter,  $_ . '|' . qq~<a href='/cgi-bin/easytecc3/index.pl?action=change_special_spamfilter&amp;user=$_'>L__Editieren__L</a><br /><a href='/cgi-bin/easytecc3/index.pl?action=delete_special_spamfilter&amp;spam_user_domain=$_'>L__Löschen__L</a>~);
				my $idn_mailuser = encode('utf-8', email_to_unicode($_)); 
				$spam_table_data->{$idn_mailuser}{'special_spam_user_domain'} = $_;
				$spam_table_data->{$idn_mailuser}{'special_spam_idn_user_domain'} = $idn_mailuser;
				$spam_table_data->{$idn_mailuser}{'hide_note'} = 1;
				
			}
		}
		foreach(sort keys %active_domains){
			if(/^$input{'dlist'}/ || $input{'dlist'} eq 'all'){
				push(@special_spamfilter,  $_ . '|' . qq~<a href="/cgi-bin/easytecc3/index.pl?action=change_special_spamfilter&amp;domain=~ . ascii_domain($_) . qq~">L__Editieren__L</a><br /><a href="/cgi-bin/easytecc3/index.pl?action=delete_special_spamfilter&amp;spam_user_domain=~ . ascii_domain($_) . qq~">L__Löschen__L</a>~);
				my $idn_domain = encode('utf-8', domain_to_unicode($_));
				$spam_table_data->{$idn_domain}{'special_spam_user_domain'} = encode('utf-8',ascii_domain($_));
				$spam_table_data->{$idn_domain}{'special_spam_idn_user_domain'} = $idn_domain;
				$spam_table_data->{$idn_domain}{'hide_note'} = 1;
			}
		}
		
		#easytecc3::table(\$template,'<td>L__User/Domain__L</td><td colspan="6">L__Aktionen__L</td>', \@special_spamfilter, 'special_spamfilter');

		easytecc3::table_e4($template, $spam_table_data, 'table_tr_show_special_spamfilter_template.html');
	
		logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	
	
		my %logs;
		my @logs = ();

		if ($fb) {
			@logs = `/usr/iports/bin/sudo /usr/sbin/dellogs`;
		}
		else{
			@logs = `/usr/sbin/dellogs`;
		}

		#actually no maillog download for external mailservers
		my $extern_mx = easytecc3::extern_mx();
		my @logfiles = ();
		my $all_logs_size = '';
		my $quotabalken = '';
		my $quota = `cat /etc/vsd/quota`;
		chomp $quota;
		my $domain_tmp = '';
		my @syslog = ();
		my %sorted_logs;
		my $table_data_domainlog = {};
				
		foreach(@logs){
		
			last if /^Geben Sie/;
			next if /^-/;
			next if /^$/;
			next if /^dellogs/;
			next if /(Domainname|Alle|Systemlogs)/;
			my ($domain, $logfile, $size) = split /\|/, $_;
			$domain =~ s/\s//gc;
			# in Zeile für errorlog taucht keine Domain auf, bei so einer Zeile einfach die zuletzt gespeicherte Domain nehmen
			# hostnet.de | speedlog                  |      1.00 MB
			#             | error_log_hostnet.de     |      8.00 kB
			$domain_tmp = $domain if $domain;
			$logfile =~ s/^\s+//;
			$logfile =~ s/\s+$//;
			$size =~ s/^\s+(.*)\s+$/$1/gc;
		
			my $admins = $domains{'www.' . $domain_tmp}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $input{'adminuser'} . '#';
			
			logline("debug","admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				next;
			}
			
			#use logfile name from httpd.conf instead dellogs
			if ($logfile =~ /^access_log/ && length($domains{"www.$domain"}{'access_log'})) {
				$logfile = $domains{"www.$domain"}{'access_log'};
				$logfile =~ s/^.*\///;
				$sorted_logs{$domain}{'access'} = $logfile;
				$sorted_logs{$domain}{'access_size'} = $size;
			}
			elsif ($logfile =~ /^error_log/ && length($domains{"www.$domain_tmp"}{'error_log'})) {
				$logfile = $domains{"www.$domain_tmp"}{'error_log'};
				$logfile =~ s/^.*\///;
				$sorted_logs{$domain_tmp}{'error'} = $logfile;
				$sorted_logs{$domain_tmp}{'error_size'} = $size;
			}
			#else{
			#$sorted_logs{$domain_tmp}{'error'} = $logfile;
			#		$sorted_logs{$domain_tmp}{'error_size'} = $size;	
			#}
			
			if($logfile =~ /^(Access Logs|Error Logs|Messages|Maillogs)/){
				$size =~ /^(.*)\s(.*)$/;
				# Grösse kann in kB oder MB angegeben werden, alles auf MB umrechnen und summieren
				my $size_unscaled = $1;
				my $scale = $2;
				$size_unscaled = $size_unscaled/1024 if $scale eq 'kB';
				$all_logs_size += $size_unscaled;
			}
			
		}

		foreach(sort keys %sorted_logs){
			my $domain = $_;
			if($sorted_logs{$_}{'access'}){
				my $logfile = $sorted_logs{$_}{'access'};
				
				$table_data_domainlog->{$domain}{'deleteable'} = '1';
				$table_data_domainlog->{$domain}{'idn_domain'} = encode('utf-8', domain_to_unicode($domain));
				$table_data_domainlog->{$domain}{'domain'} = $domain;
				$table_data_domainlog->{$domain}{'logfile_name'} = $sorted_logs{$_}{'access'};
				$table_data_domainlog->{$domain}{'logfile_size_sized'} = $sorted_logs{$_}{'access_size'};
				my $logfile_encoded = encode_base64url($logfile);
				$table_data_domainlog->{$domain}{'logfile_href_download'} = qq~/cgi-bin/easytecc4/index.pl?action=download_file&amp;file=$logfile_encoded&amp;type=logfile~;
				
				#push(@logfiles, domain_to_unicode($_).'|'.$sorted_logs{$_}{'access'}.'|'.$sorted_logs{$_}{'access_size'}.'|'.
				#	qq~<a href="/cgi-bin/easytecc3/index.pl?action=download_file&amp;file=$logfile&amp;type=logfile">L__Download__L</a>~ .'|'.
				#	qq~<a href="/cgi-bin/easytecc3/index.pl?action=delete_logfiles&amp;domain=$domain">L__Löschen__L</a>~
				#);
			}
			if($sorted_logs{$_}{'error'}){
				my $logfile = $sorted_logs{$_}{'error'};
				#'z' is ugly workaround for sorted access and error log output. Nobody has seen it ;)
				$table_data_domainlog->{$domain . 'z'}{'logfile_name'} = $sorted_logs{$_}{'error'};
				$table_data_domainlog->{$domain . 'z'}{'logfile_size_sized'} = $sorted_logs{$_}{'error_size'};
				my $logfile_encoded = encode_base64url($logfile);
				$table_data_domainlog->{$domain . 'z'}{'logfile_href_download'} = qq~/cgi-bin/easytecc4/index.pl?action=download_file&amp;file=$logfile_encoded&amp;type=logfile~;
				
				#push(@logfiles, ''.'|'.$sorted_logs{$_}{'error'}.'|'.$sorted_logs{$_}{'error_size'}.'|'.
				#	qq~<a href="/cgi-bin/easytecc3/index.pl?action=download_file&amp;file=$logfile&amp;type=logfile">L__Download__L</a>~ .'|'.
				#	''
				#);
			}
		}

		#push(@logfiles, @syslog);

		my $percentval = ($all_logs_size/$quota)*100;
		##kaufm. Rundung
		$percentval = sprintf("%.0f", $percentval);
		my $balken_usage = $percentval;
		my $balken_free = 100 - $balken_usage;

		if(($quota * .8) <= $all_logs_size){
			$template->param('logfile_size_alert' => 1);
		#	$quotabalken = qq|<img src="/easytecc3/images/red.gif" width="$balken_usage" height="15" align="bottom" alt="$balken_usage % genutzt" border="0" /><img src="/easytecc3/images/grey.gif" width="$balken_free" height="15" align="bottom" alt="$balken_free % frei" border="0" />|;
		}
		#else{
		#	$quotabalken = qq|<img src="/easytecc3/images/green.gif" width="$balken_usage" height="15" align="bottom" alt="$balken_usage % genutzt" border="0" /><img src="/easytecc3/images/grey.gif" width="$balken_free" height="15" align="bottom" alt="$balken_free % frei" border="0" />|;
		#}

		$template->param('in_use_MB' => sprintf "%.2f", $all_logs_size);
		$template->param('percent' => ' (' . $percentval . '%)');
		#$template->param('bar' => $quotabalken);
		
		#easytecc3::table(\$template,'<td>L__Domainname__L</td><td>L__Logfile__L</td><td>L__Größe__L</td><td colspan="4">L__Aktionen__L</td>', \@logfiles, 'table1');

		easytecc3::table_e4($template, $table_data_domainlog, 'table_tr_show_logfiles_domain_template.html');

		
		my @db = ();
		my $html_error = '';

		my ($dbh, $mysql_connect_error) = easytecc3::mysql_connect();
		
		# Grsse der Datenbanken ermitteln, von der Funktion wird auch datadir übermittelt. kann man vielleicht noch mal brauchen
		my (%database_size, $datadir) = easytecc3::get_size_mysql();

		# seems to be a dummy.	
		my $grant_ok = '1';
		my $query = 'SHOW databases';
		
		my @user = ();
	
		# gather allowed dirs
		my %allowed_dirs;
		
		foreach my $domain (keys %domains){

			my $admins = $domains{$domain}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $input{'adminuser'} . '#';
			
			logline("debug","admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				next;
			}
		
			$allowed_dirs{$domains{$domain}{'droot'}} = '1';
			
			my $doc_root_alias = $domains{$domain}{'droot'};
			$doc_root_alias =~ s#/apache24/noexec/#/apache24/data/#;
			$allowed_dirs{$doc_root_alias} = '1';
			
		}
				
		$allowed_dirs{$passwd{$input{'adminuser'}}{'home'}} = '1';

		foreach my $user(sort keys %passwd){
			# chown nicht an POP-User ermöglichen
			next if $passwd{$user}{'gecos'} =~ / - POP/;

			my $home = $passwd{$user}{'home'};
			
			foreach my $dir (keys %allowed_dirs){
	
				if($home eq $dir || $home =~ m#^$dir/#){
		
					push(@user,$user);
			
				}
				
			}
			
		}
		
		my $userlist = '\'' . join('\',\'', @user) . '\'';
		
		$query = "SHOW DATABASES WHERE `Database` IN (SELECT DISTINCT Db AS `Database` FROM mysql.db WHERE User IN ($userlist))";
			
		my $sth   = $dbh->prepare( $query );
		$sth->execute;

		my $db_table_data = {};
		while ( my @row = $sth->fetchrow_array ){ # alle rows auslesen

			foreach my $item (@row){
				next if $item eq 'information_schema';
				# Datenbanken mit . sind Sicherungen von getback auf die kein Zugriff ber mysql-Schnittstelle mglich ist
				# und daher auch kein Backup gemacht werden kann.
				#next if $item =~ /\./;
				# wenn show databases DB mysql oder db01 anzeigt, gehen wir davon aus, da Rechte des Users der Sicherungen durchfhrt ok sind
				# ansonsten Formular für mysqluser anzeigen
				$grant_ok = '1' if $item eq 'mysql';
				$grant_ok = '1' if $item eq 'db01';

				# berprüfen ob Backup angelegt
				my $backup = "Ja";
				my $backup_config = "/usr/local/etc/easytecc/mysqlbackup/$item.dbb";
				my $backup_dir = "$mysqlbackup_dir/$item";
				my @dir_entries = ();
				my $in_use_for_backup = '';
				my $backup_has_error = '0';
				my $backup_has_lock = '0';
				my $backup_count = '0';

				if (-d $backup_dir){
					opendir(D,$backup_dir) || dienice("opendir $backup_dir: $!");
					@dir_entries = grep !/^\.\.?$/, readdir(D); #read in dir entries to array
					closedir D;
					
					#$backup_has_lock = 1 if (grep /\.lock$/, @dir_entries);
					
					foreach my $error_file(@dir_entries){
					logline("warning","error_file1=$error_file item=$item");
					$backup_has_lock = 1 if ($error_file =~ /\.lock$/);
					next if $error_file !~ /^(.*)\.error$/;
					my $name_of_backup = $1;
					logline("warning","error_file2=$error_file");
						$backup_has_error = 1;
						my $error_text = `cat $backup_dir/$error_file`;
						my $error_template = HTML::Template->new(filename => 'error_div.html');
						$error_template->param('alert_has_close_action' => 'alert_has_close_action');
						$error_template->param('alert_close_action' => "exec_delete_alert&amp;database=$item&amp;error=$error_file");
						$error_template->param('error_text' => qq~$item Backup $name_of_backup: $error_text~);
						$html_error .= $error_template->output;
					}
					
					$backup_count = scalar(@dir_entries) - $backup_has_lock - $backup_has_error;
					
					if($backup_count > 0){
						$in_use_for_backup = `du -s $backup_dir` unless $fb;
						$in_use_for_backup = `/usr/iports/bin/sudo /usr/bin/du -As $backup_dir` if $fb;
						$in_use_for_backup = easytecc3::getsize($in_use_for_backup);
					}
				}

				# kein automatisches Backup und keine Dumps
				if ( ! -e $backup_config && $backup_count == '0'){
					$db_table_data->{$item}{'db_name'} = $item;
					$db_table_data->{$item}{'db_size_sized'} = easytecc3::getsize($database_size{$item});
					
					$db_table_data->{$item}{'edit_db'} = 1;
					
					#$backup = "L__Nein__L";
					#push(@db, $item . '|' .
					#easytecc3::getsize($database_size{$item}) . '|' .
					#$backup . '|' .
					#$in_use_for_backup . '|' .
					#qq~<a href="/cgi-bin/easytecc3/index.pl?action=show_mysqlbackup_details&amp;database=$item">L__Backup anlegen__L</a><br />~);
				}
				# kein automatisches Backup aber Dumps vorhanden
				elsif ( ! -e $backup_config && $backup_count > 0){
					$db_table_data->{$item}{'has_dbbackup'} = 1;
					$db_table_data->{$item}{'db_name'} = $item;
					$db_table_data->{$item}{'db_size_sized'} = easytecc3::getsize($database_size{$item});
					$db_table_data->{$item}{'dbbackup_size_sized'} = $in_use_for_backup;
					$db_table_data->{$item}{'dbbackup_count'} = $backup_count;
					
					$db_table_data->{$item}{'edit_db'} = 1;
					
					#$backup = "L__Nein__L";
					#push(@db, $item . '|' .
					#easytecc3::getsize($database_size{$item}) . '|' .
					#$backup . '|' .
					#$in_use_for_backup . '|' .
					#qq~<a href="/cgi-bin/easytecc3/index.pl?action=show_mysqlbackup_details&amp;database=$item">L__Details__L</a><br />~);
				}
				# automatischs Backup ist vorhanden
				else{
					$db_table_data->{$item}{'db_has_auto_backup'} = 1;
					$db_table_data->{$item}{'has_dbbackup'} = 1;
					$db_table_data->{$item}{'db_name'} = $item;
					$db_table_data->{$item}{'db_size_sized'} = easytecc3::getsize($database_size{$item});
					$db_table_data->{$item}{'dbbackup_size_sized'} = $in_use_for_backup;
					$db_table_data->{$item}{'dbbackup_count'} = $backup_count;
					
					$db_table_data->{$item}{'edit_db'} = 1;
					
					#$backup = "L__Ja__L";
					#push(@db, $item . '|' .
					#easytecc3::getsize($database_size{$item}) . '|' .
					#$backup . '|' .
					#$in_use_for_backup . '|' .
					#qq~<a href="/cgi-bin/easytecc3/index.pl?action=show_mysqlbackup_details&amp;database=$item">L__Details__L</a>~);
				}
				
				$db_table_data->{$item}{'hide_note'} = 1;
				
			}
		}
	
		easytecc3::table_e4($template, $db_table_data, 'table_tr_show_dbbackup_template.html');
		
		logline("debug","Creating File Object \$cronfile.");
		my $cronfile = file->new({file_name => '/home/web/cronfile'});
		$cronfile->read_file;
		my %cronjobs = %{$cronfile->file_parsed_hash()};

		my $cron_table_data = {};
		foreach my $cronjob (sort keys %cronjobs){
			
			next if $cronjobs{$cronjob}{'job'} =~ /easytecc4\/dobackup\.pl/;
			next if $cronjobs{$cronjob}{'job'} =~ /tools\/awstats_updateall\.pl/;
							
			# check dirs
			my $allowed = 0;
			
			foreach my $dir (keys %allowed_dirs){
						
				if($cronjobs{$cronjob}{'job'} =~ m#$dir/#){
		
					# check if other dirs are affected
					my $job = $cronjobs{$cronjob}{'job'};
					$job =~ s#$dir/##;
					
					if($job !~ m#/home/# && $job !~ m#(/usr/local/www/|/home/httpd/docs/)#){
					
						$allowed = 1;
						last;
					
					}

				}
						
				# check domains
				if($allowed == 0){
				
					foreach my $domain (keys %allowed_domains){
					
						if($cronjobs{$cronjob}{'job'} =~ m#(ftp|http)s?://(www\.)?$domain/#){
						
							$allowed = 1;
							last;
						
						}
					
					}
				
				}
				
			}
			
			if($allowed != 1){
				
				next;
				
			}
				
			my $cronjob_string_no_dev_null = $cronjobs{$cronjob}{'job'};
			$cronjob_string_no_dev_null =~ s/(1|2)>.*$//;
			
			$cron_table_data->{$cronjob}{'cronjob'} = $cronjobs{$cronjob}{'count'};
			$cron_table_data->{$cronjob}{'cron_command_tooltip'} = $cronjobs{$cronjob}{'job'};
			#$table_data->{$cronjob}{'cron_command'} = easytecc3::substr_e4($cronjobs{$cronjob}{'job'});
			$cron_table_data->{$cronjob}{'cron_command'} = easytecc3::substr_e4($cronjob_string_no_dev_null);
			$cron_table_data->{$cronjob}{'cron_minute'} = $cronjobs{$cronjob}{'min'};
			$cron_table_data->{$cronjob}{'cron_hour'} = $cronjobs{$cronjob}{'std'};
			$cron_table_data->{$cronjob}{'cron_day'} = $cronjobs{$cronjob}{'mday'};
			$cron_table_data->{$cronjob}{'cron_month'} = $cronjobs{$cronjob}{'mon'};
			$cron_table_data->{$cronjob}{'cron_weekday'} = $cronjobs{$cronjob}{'wday'};
			
			$cron_table_data->{$cronjob}{'edit_cron'} = 1;
			$cron_table_data->{$cronjob}{'new_cron'} = 0;
			
			#push(@cronjobs, $cronjobs{$cronjob}{'job'} . '|' .
			#$cronjobs{$cronjob}{'min'} . '|' .
			#$cronjobs{$cronjob}{'std'} . '|' .
			#$cronjobs{$cronjob}{'mday'} . '|' .
			#$cronjobs{$cronjob}{'mon'} . '|' .
			#$cronjobs{$cronjob}{'wday'} . '|' .
			#qq~<a href="/cgi-bin/easytecc3/index.pl?action=change_cronjob&amp;cronjob=$cronjobs{$cronjob}{'count'}">L__Editieren__L</a>&nbsp;&nbsp;&nbsp;~ .
			#qq~<a href="/cgi-bin/easytecc3/index.pl?action=delete_cronjob&amp;cronjob=$cronjobs{$cronjob}{'count'}">L__Löschen__L</a>~);
		}

		easytecc3::table_e4($template, $cron_table_data, 'table_tr_show_cronjobs_template.html');
		
	}
		
	easytecc3::table_e4($template, $table_data, 'table_tr_show_adminuser_template.html');
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}



sub show_quota{
	
	if($session->param('show_quota') ne '1'){
		return start();
	}
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_quota.html');
	my $type = $input{'type'};
	my @serverquota = ();
	my %mailpasswd = ();
	my %mailquota = ();
	my ($mailquotaref, $sum_maillimit, $sum_mailuse, $mailserverlimit);

	my $zpool_size_MB;
	my $zfs_disk_freespace_MB;
	my $zfs_disk_usage_MB;
	my $alert_diskspace = '';
	my $df_used_in_KB		= 0;
	my $df_available_in_KB	= 0;;
	my $disk_freespace_MB	= 0;;
	my $disk_usage_MB		= 0;
	
	if($session->param('user') eq 'admin'){

		if ( $fb eq '1' ) {
		
			logline("debug","DISK SPACE ALLOCATION check: is XEN server");
			
			my $is_xen_server = `/bin/sh -c '/sbin/sysctl kern.vm_guest 2>/dev/null'`;
			chomp($is_xen_server);
			
			logline("debug","DISK SPACE ALLOCATION check: ###$is_xen_server###");
			
			if ( $is_xen_server =~ m/xen/ ) {
	
				logline("debug","DISK SPACE ALLOCATION for ZFS starts now ... on XEN");
			
				#my $zfs_available		= `/sbin/zfs list -Hp -oavail vsd`;
				my $zfs_available		= `/bin/sh -c '/sbin/zfs list -Hp -oavail vsd 2> /dev/null'`;
			
				logline("debug","\$zfs_available = $zfs_available eq '' ");

				$zfs_disk_freespace_MB  = $zfs_available / 1048576;

				$disk_freespace_MB	= $zfs_disk_freespace_MB;
	
				#my $zpool_size			= `/sbin/zpool list -Hp -osize vsd`;
				my $zpool_size			= `/bin/sh -c '/sbin/zpool list -Hp -osize vsd 2> /dev/null'`;

				$zpool_size_MB          = $zpool_size / 1048576;
				$zfs_disk_usage_MB      = $zpool_size_MB - $zfs_disk_freespace_MB;
				
				$disk_usage_MB		= $zfs_disk_usage_MB;

				### Mario: bei 80% Ausnutzung soll die Zeile ROT sein! ###
				#my $disk_emptyspace     = ( $zfs_available * 100 ) / $zpool_size;
				#my $disk_comsumption    = 100 - $disk_emptyspace;
				#if ( $disk_comsumption gt 80 ) {
				#		
				#		#$template->param('alert_diskspace' => easytecc3::quota_alert($ftpserverlimit, $sum_ftpuse, '.8'));
				#}
	
				$template->param('alert_diskspace' => easytecc3::quota_alert($zpool_size, $zpool_size - $zfs_available, '.8'));
	
				logline("debug","\$disk_emptyspace = $disk_emptyspace");
				logline("debug","DISK SPACE ALLOCATION for ZFS ended.");
			
			} else {
			
				logline("debug","DISK SPACE ALLOCATION for ZFS starts now ... on DMR");
				
				$disk_usage_MB			= `/bin/sh -c "/bin/df -cm | /usr/bin/grep total | /usr/bin/sed 's/total *//' | /usr/bin/cut -d' ' -f2"`;
				$disk_freespace_MB		= `/bin/sh -c "/bin/df -cm | /usr/bin/grep total | /usr/bin/sed 's/total *//' | /usr/bin/cut -d' ' -f3"`;

			}
		
		}

	}


	
	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};

	# zum gucken, ob es FTP-User gibt, die passwd vom Webserver auslesen, und gukcen ob es zum
	# document root der Domain einen FTP-User mit passendem home-Verzeichnis gibt
	logline("debug","Creating File Object \$webserver_passwd.");
	my $webserver_passwd = file->new({file_name => '/etc/passwd'});
	$webserver_passwd->read_file;
	my %webserver_passwd = %{$webserver_passwd->file_parsed_hash()};
	my %home_lookup =  %{$webserver_passwd->lookup2_hash()};
	my ($quotaref, $sum_ftplimit, $sum_ftpuse, $ftpserverlimit) = easytecc3::getquota_ftp();
	my %quota = %$quotaref;

	my $show_email = '';
	my $show_edit_email = '';
	my $show_ftp = '';
	my $show_edit_ftp = '';
	
	# hide webserver quota for non admin	
	if($session->param('user') eq 'admin'){
	
		$template->param('show_server_quota' => '1');
		$show_email = '1';
		$show_edit_email = '1';
		$show_ftp = '1';
		$show_edit_ftp = '1';
	
	} else {
		
		my $gecos = $webserver_passwd{$session->param('user')}{'gecos'};	
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.email-1.ftp-2';
		
		}
	
		if($gecos =~ m/\.email/){
	
			$show_email = '1';
	
			if($gecos =~ m/\.email-[1-9]/){
			
				$show_edit_email = '1';
				
			}
	
		}
		
		if($gecos =~ m/\.ftp/){
	
			$show_ftp = '1';
	
			if($gecos =~ m/\.ftp-[1-9]/){
			
				$show_edit_ftp = '1';
				
			}
	
		}
	
	}
	
	$template->param('show_email' => $show_email);
	$template->param('show_ftp' => $show_ftp);
	
	if (easytecc3::extern_mx() || $fb){
		$mailpasswd = easytecc3::get_mailpasswd();
		%mailpasswd = %{$mailpasswd->file_parsed_hash()};

		#%mailpasswd = %{easytecc3::get_mailpasswd()};
		($mailquotaref, $sum_maillimit, $sum_mailuse, $mailserverlimit) = easytecc3::getquota_mail(\%mailpasswd);

		logline("debug","show_quota mailquotaref=$mailquotaref");

		%mailquota = %$mailquotaref;

		#my %mailquota_tmp = %mailquota;
		#foreach(sort keys %mailquota_tmp){
		#	logline("debug","show_quota mailquota key=$_ value=" . $mailquota_tmp{$_} . "\n$sum_maillimit, $sum_mailuse, $mailserverlimit");	
		#	my $hash_ref = $mailquota_tmp{$_};
		#	%mailquota = %$hash_ref;
		#	last;
		#	#warum auch immer...
		#	#%mailquota = %hash if $fb;
		#	foreach(sort keys %mailquota){
		#	logline("debug","1show_quota zweiter hash key=$_ value=" . $mailquota{$_});		
		#	}
		#}
		#foreach(sort keys %mailquota){
		#	logline("debug","2show_quota zweiter hash key=$_ value=" . $mailquota{$_});		
		#}

	}
	else{
		%mailpasswd = %webserver_passwd;
		%mailquota = %quota;
		$sum_maillimit = $sum_ftplimit;
		$sum_mailuse = $sum_ftpuse;
		$mailserverlimit = $ftpserverlimit;
	}

	my %domain_home;
	foreach(keys %domains){
	
		# filter domains
		if($session->param('user') ne 'admin'){
		
			my $admins = $domains{$_}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $session->param('user') . '#';
			
			logline("debug","admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				next;
			}
		}
	
	
		logline("debug","domain_home=" . $domains{$_}{'droot'});
		logline("debug","domain_domains=" . $domains{$_}{'domains'});
		$domain_home{$domains{$_}{'droot'}} = $domains{$_}{'domains'};
	}
	
	#nicht easytecc3::getsize nehmen, da man durch Rundung zuwenig belegten Platz angezeigt bekommt
	#push @serverquota, sprintf("%.2f", $sum_ftplimit/1000) . ' GB' . '|' . sprintf("%.2f", $ftpserverlimit/1000) . ' GB' . '|' . sprintf("%.2f", $sum_ftpuse/1000) . ' GB';
	#easytecc3::table(\$template,'<td>L__Summe der Limits Webserver__L</td><td>L__Maximaler Serverplatz Webserver__L</td><td colspan="5">L__Quotanutzung__L</td>', \@serverquota, 'table_webserver');

	#if ($ftpserverlimit > 0){
	#	if(($sum_ftpuse/$ftpserverlimit)*100 >= 90){
	#	$template->param('alert_webserver_quota' => 1);
	#	}
	#}
	
	$template->param('alert_webserver_quota' => easytecc3::quota_alert($ftpserverlimit, $sum_ftpuse, '.8'));
	$template->param('disk_freespace_GB' => sprintf("%.2f", $disk_freespace_MB/1024) . ' GB');
	$template->param('disk_usage_GB'     => sprintf("%.2f",     $disk_usage_MB/1024) . ' GB');
	$template->param('webserver_quota_used_percent' => sprintf("%.0f", ($sum_ftpuse/$ftpserverlimit)*100)) if $ftpserverlimit > 0;
	$template->param('webserver_quota_used_GB' => sprintf("%.2f", $sum_ftpuse/1000) . ' GB');
	$template->param('webserver_quota_GB' => sprintf("%.2f", $ftpserverlimit/1000) . ' GB');
	$template->param('webserver_quota_sum_GB' => sprintf("%.2f", $sum_ftplimit/1000) . ' GB');
	
	#wenn externer Mailserver, dann darber bersicht zeigen
	if(easytecc3::extern_mx()){
		#@serverquota = ();
		#push @serverquota, sprintf("%.2f", $sum_maillimit/1000) . ' GB' . '|' . sprintf("%.2f", $mailserverlimit/1000) . ' GB' . '|' . sprintf("%.2f", $sum_mailuse/1000) . ' GB';
		#easytecc3::table(\$template,'<td>L__Summe der Limits Mailserver__L</td><td>L__Maximaler Serverplatz Mailserver__L</td><td colspan="5">L__Quotanutzung__L</td>', \@serverquota, 'table_mailserver');
	
	#if ($mailserverlimit > 0){
	#	if(($sum_mailuse/$mailserverlimit)*100 >= 90){
	#	$template->param('alert_mailserver_quota' => 1);
	#	}
	#}
	
	$template->param('has_extern_mailserver' => 1);
	$template->param('alert_mailserver_quota' => easytecc3::quota_alert($mailserverlimit, $sum_mailuse, '.8'));
	$template->param('mailserver_quota_used_percent' => sprintf("%.0f", ($sum_mailuse/$mailserverlimit)*100)) if $mailserverlimit > 0;
	$template->param('mailserver_quota_used_GB' => sprintf("%.2f", $sum_mailuse/1000) . ' GB');
	$template->param('mailserver_quota_GB' => sprintf("%.2f", $mailserverlimit/1000) . ' GB');
	$template->param('mailserver_quota_sum_GB' => sprintf("%.2f", $sum_maillimit/1000) . ' GB');
	}

	#my @ftp_user = ();
	my $table_data = {};
	
	foreach my $ftpuser (sort keys %webserver_passwd){
				
		# do NOT show system users here
		next if $ftpuser eq 'ftp';	
		next if $ftpuser eq 'cyrus';
		next if $ftpuser eq 'dovecot';
		next if $ftpuser eq 'dovenull';
		next if $ftpuser eq 'virtmail';
		next if $ftpuser eq 'svn';
		next if $ftpuser eq 'haproxy';
		
		my $ftpquota = '';
		my $ftpquota_sized = '';
		my $ftpused = '';
		my $quotabalken = '';
		my $domain = '';
		
		logline("debug","foreach ftpuser = $ftpuser");

		$ftpquota = $quota{$ftpuser}{'quota'};
		$ftpquota_sized = easytecc3::getsize($ftpquota);
		$ftpused = $quota{$ftpuser}{'use'};

		next unless $ftpused;
		next if $webserver_passwd{$ftpuser}{'gecos'} =~ /- POP/;
		#$quotabalken = easytecc3::quotabar($ftpquota, $ftpused, 'used');

		my @domainlist = ();
		if(exists $domain_home{$webserver_passwd{$ftpuser}{'home'}}){
			foreach(@{$domain_home{$webserver_passwd{$ftpuser}{'home'}}}){
				push @domainlist, encode('utf-8', domain_to_unicode($_));
			}
			$domain = join '<br />', @domainlist;
		} else {
		
			# filter domains
			if($session->param('user') ne 'admin'){
			
				my $home = $webserver_passwd{$ftpuser}{'home'};
				my $self_home = $webserver_passwd{$session->param('user')}{'home'};
				my $allowed = 0;
				
				if($home ne $self_home && $home !~ m#^$self_home/#){
				
					foreach my $dir (keys %domain_home){
					
						if($home eq $dir || $home =~ m#^$dir/#){
					
							$allowed = '1';
							
						}
					
					}
					
					if($allowed != 1){
					
						next;
					
					} 
				
				}
			
			}
		}
		
		$table_data->{$ftpuser}{'alert_ftpuser_quota'} = easytecc3::quota_alert($ftpquota, $ftpused, '.8');
		$table_data->{$ftpuser}{'ftpuser'} = $ftpuser;
		$table_data->{$ftpuser}{'domain'} = $domain;
		$table_data->{$ftpuser}{'gecos'} = $webserver_passwd{$ftpuser}{'gecos'};
		$table_data->{$ftpuser}{'home_tooltip'} = $webserver_passwd{$ftpuser}{'home'};
		$table_data->{$ftpuser}{'home'} = easytecc3::substr_e4($webserver_passwd{$ftpuser}{'home'});
		$table_data->{$ftpuser}{'ftpquota_sized'} = $ftpquota_sized;
		$table_data->{$ftpuser}{'ftpquota_used_sized'} = easytecc3::getsize($ftpused);
		$table_data->{$ftpuser}{'ftpquota_used_percent'} = sprintf("%.0f", ($ftpused/$ftpquota)*100) if $ftpquota > 0;

		$table_data->{$ftpuser}{'show_ftp'} = $show_ftp;
		$table_data->{$ftpuser}{'show_edit_ftp'} = $show_edit_ftp;
		
		if($ftpuser eq 'admin' || $ftpuser eq 'web'){
			#push(@ftp_user, $ftpuser.'|'.$domain.'|'.$webserver_passwd{$ftpuser}{'gecos'}.'|'.$webserver_passwd{$ftpuser}{'home'}.'|'.$ftpquota_sized.'|'.$quotabalken.'|'.
			#qq~<a href='/cgi-bin/easytecc3/index.pl?action=change_ftpuser&amp;ftpuser=$ftpuser'>L__Editieren__L</a>~);
		
		}
		else{
			#push(@ftp_user, $ftpuser.'|'.$domain.'|'.$webserver_passwd{$ftpuser}{'gecos'}.'|'.$webserver_passwd{$ftpuser}{'home'}.'|'.$ftpquota_sized.'|'.$quotabalken.'|'.
			#qq~<a href='/cgi-bin/easytecc3/index.pl?action=change_ftpuser&amp;ftpuser=$ftpuser'>L__Editieren__L</a><br /><a href='/cgi-bin/easytecc3/index.pl?action=delete_ftpuser&amp;ftpuser=$ftpuser'>L__Löschen__L</a>~);
		}
	}

	#easytecc3::table(\$template,'<td>L__User__L</td><td>L__Domain__L</td><td>L__Beschreibung__L</td><td>L__Homeverzeichnis__L</td><td>L__FTP-Quota__L</td><td>L__Quotanutzung__L</td><td>L__Aktionen__L</td>', \@ftp_user, 'table_ftpuser');
	easytecc3::table_e4($template, $table_data, 'table_tr_show_quota_ftpuser_template.html');
	
	my $servername = `sed 's/^.* // ; s/\$/.han-solo.net/' /etc/FQDN 2>/dev/null`;
	chomp $servername;
		
	$table_data = {};
	foreach my $mailuser (sort keys %mailpasswd){
		
		if($mailpasswd{$mailuser}{'gecos'} !~ / - POP$/ && $mailuser ne 'admin' && ($mailuser ne 'admin@' . $servername || $session->param('user') ne 'admin')){
			next;
		}	
		 
		#wenn kein externer mailserver muss admin nicht bei popusern auftauchen
		next if( ! easytecc3::extern_mx() && $mailuser eq 'admin');
		
		logline("debug","foreach POP mailpasswd = $mailuser");
		
		my $domain =  $mailpasswd{$mailuser}{'gecos'};
		$domain =~ s/ - POP$//;
		
		if($mailuser eq 'admin@' . $servername){
			$domain = $servername;
		}
		
				
		logline("debug","mailuser $mailuser domain: #$domain#");
		
		
		
		# filter domains
		if($session->param('user') ne 'admin'){
		
			my $admins = $domains{'www.' . $domain}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $session->param('user') . '#';
			
			logline("debug","admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				next;
			}
		}
		
		
		
		my $mailquota_sized =  $mailquota{$mailuser}{'quota'} / 1024;
		#my $quotabalken = easytecc3::quotabar($mailquota{$user}{'quota'}, $mailquota{$user}{'use'}, 'used');
		my $change_mailuser = '';

		if ($fb) {
			$change_mailuser = qq~<a href='/cgi-bin/easytecc3/index.pl?action=change_forward&amp;domain=www.$domain'>L__Editieren__L</a>~
		}
		else{
			$change_mailuser = qq~<a href='/cgi-bin/easytecc3/index.pl?action=change_popuser&amp;domain=www.$domain'>L__Editieren__L</a>~
		}

		my $idn_mailuser = encode('utf-8', email_to_unicode($mailuser));
		my $idn_domain = encode('utf-8', domain_to_unicode($domain));
		
		my $wwwdomain = 'www.' . $domain;
		if($domain eq $servername){
			$wwwdomain = $servername;
		}
		
		$table_data->{$idn_mailuser}{'alert_mailuser_quota'} = easytecc3::quota_alert($mailquota{$mailuser}{'quota'}, $mailquota{$mailuser}{'use'}, '.8');
		$table_data->{$idn_mailuser}{'idn_mailuser'} = $idn_mailuser;
		$table_data->{$idn_mailuser}{'mailuser'} = $mailuser;
		$table_data->{$idn_mailuser}{'domain'} = $idn_domain;
		$table_data->{$idn_mailuser}{'idn_domain'} = $idn_domain;
		$table_data->{$idn_mailuser}{'domain_www'} = $wwwdomain;
		$table_data->{$idn_mailuser}{'gecos'} = $mailpasswd{$mailuser}{'gecos'};
		$table_data->{$idn_mailuser}{'mailquota_sized'} = easytecc3::getsize($mailquota{$mailuser}{'quota'});
		$table_data->{$idn_mailuser}{'mailquota_used_sized'} = easytecc3::getsize($mailquota{$mailuser}{'use'});
		$table_data->{$idn_mailuser}{'mailquota_used_percent'} = sprintf("%.0f", ($mailquota{$mailuser}{'use'}/$mailquota{$mailuser}{'quota'})*100) if $mailquota{$mailuser}{'quota'} > 0;

		$table_data->{$idn_mailuser}{'show_email'} = $show_email;
		$table_data->{$idn_mailuser}{'show_edit_email'} = $show_edit_email;
		
		#push(@user, $user.'|'.domain_to_unicode($domain).'|'.qq~$mailquota_sized MB~.'|'.qq~$quotabalken~.'|'.$change_mailuser);
	}

	#easytecc3::table(\$template,'<td>L__User__L</td><td>L__Domain__L</td><td>L__E-Mail-Quota__L</td><td>L__Quotanutzung__L</td><td colspan="3">L__Aktionen__L</td>', \@user, 'table_mailuser');
	easytecc3::table_e4($template, $table_data, 'table_tr_show_quota_mailuser_template.html');
		
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_special_spamfilter{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);

	#included by change_spamfilter tab3
	my $template = shift;
	my($active_user_chars_ref, $active_domain_chars_ref, $active_users_ref, $active_domains_ref) = easytecc3::get_userchars();
	my %active_users = %$active_users_ref;
	my %active_domains = %$active_domains_ref;
	my @special_spamfilter = ();
	
	# filter domains and users
	if($session->param('user') ne 'admin' && (keys %active_users || keys %active_domains)){
		
		my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
		$httpd_conf->read_file;
		my %domains = %{$httpd_conf->file_parsed_hash()};
		
		# filter users
		if (keys %active_users) {
			
			my %mailpasswd;
			
			if (easytecc3::extern_mx() || $fb){
				
				my $mailpasswd = easytecc3::get_mailpasswd();
				%mailpasswd = %{$mailpasswd->file_parsed_hash()};
		        #logline("debug"," -M A R I O- --> file_parsed_hash() " . $domain_ohne_www );

			} else {
				
				my $mailpasswd = file->new({file_name => '/etc/passwd'});
				$mailpasswd->read_file;
				%mailpasswd = %{$mailpasswd->file_parsed_hash()};
				#logline("debug"," -M A R I O- --> else: file_parsed_hash() " . $domain_ohne_www );
			}
			
			foreach my $mailuser (sort keys %mailpasswd){
				
				next if ($mailpasswd{$mailuser}{'gecos'} !~ / - POP$/);
		
				my $domain =  $mailpasswd{$mailuser}{'gecos'};
				$domain =~ s/ - POP$//;
	
				my $admins = $domains{'www.' . $domain}{'admin_users'};
				$admins =~ s/[\s,]+/#/g;
				$admins = '#' . $admins . '#';
				$userregex = '#' . $session->param('user') . '#';
			
				logline("debug","admins:$admins\nuserregex:$userregex");
			
				if($admins !~ m/$userregex/i){
				
					delete $active_users{$mailuser};
					
				}
			}
			
		}
		
		# filter domains
		if (keys %active_domains) {
			
			my %allowed_domains;
				
			foreach $domain (sort keys %domains){

				my $admins = $domains{$domain}{'admin_users'};
				$admins =~ s/[\s,]+/#/g;
				$admins = '#' . $admins . '#';
				$userregex = '#' . $session->param('user') . '#';
			
				logline("debug","admins:$admins\nuserregex:$userregex");
				
				if($admins =~ m/$userregex/i){

					foreach my $alias_domain (@{$domains{$domain}{'domains'}}){
					
						$alias_domain =~ s/^www\.//;
						$alias_domain =~ s/^\*\.//;
						
						$allowed_domains{$alias_domain} = 1;
						
						logline("debug","allowed_domain:$alias_domain");
						
					}
					
					$domain =~ s/^www\.//;
					$domain =~ s/^\*\.//;
						
					$allowed_domains{$domain} = 1;
					
					logline("debug","allowed_domain:$domain");
				
				}
			}
			
			foreach $domain (sort keys %active_domains){
			
				$domain = ascii_domain($domain);
				$domain =~ s/^www\.//;
				$domain =~ s/^\*\.//;
							
				if(!exists $allowed_domains{$domain}){
				
					delete $active_domains{$domain};
				
				}
			}
		}
	}
	
	if (keys %active_users || keys %active_domains) {
		$template->param('has_special_spamfilter' => '1');
	}
	
	foreach(keys %active_domains){
		logline("debug","active_domains = " . $_);
	}

	foreach(keys %active_users){
		logline("debug","active_users = " . $_);
	}

	my $table_data = {};
	
		foreach(sort keys %active_users){
			if(/^$input{'ulist'}/ || $input{'ulist'} eq 'all'){
				push(@special_spamfilter,  $_ . '|' . qq~<a href='/cgi-bin/easytecc3/index.pl?action=change_special_spamfilter&amp;user=$_'>L__Editieren__L</a><br /><a href='/cgi-bin/easytecc3/index.pl?action=delete_special_spamfilter&amp;spam_user_domain=$_'>L__Löschen__L</a>~);
				my $idn_mailuser = encode('utf-8', email_to_unicode($_)); 
				$table_data->{$idn_mailuser}{'special_spam_user_domain'} = $_;
				$table_data->{$idn_mailuser}{'special_spam_idn_user_domain'} = $idn_mailuser;
			}
		}
		foreach(sort keys %active_domains){
			if(/^$input{'dlist'}/ || $input{'dlist'} eq 'all'){
				push(@special_spamfilter,  $_ . '|' . qq~<a href="/cgi-bin/easytecc3/index.pl?action=change_special_spamfilter&amp;domain=~ . ascii_domain($_) . qq~">L__Editieren__L</a><br /><a href="/cgi-bin/easytecc3/index.pl?action=delete_special_spamfilter&amp;spam_user_domain=~ . ascii_domain($_) . qq~">L__Löschen__L</a>~);
				my $idn_domain = encode('utf-8', domain_to_unicode($_));
				$table_data->{$idn_domain}{'special_spam_user_domain'} = encode('utf-8',ascii_domain($_));
				$table_data->{$idn_domain}{'special_spam_idn_user_domain'} = $idn_domain;
			}
		}
		
		foreach (keys %{ $table_data }){
			
			my @keys = ('SPAMFILTER',$table_data->{$_}{'special_spam_user_domain'});
			my $note = note_from_hashfile(\@keys);
															
			if($note->{title}){
									
				$table_data->{$_}{'note_title'} = $note->{title};
				$table_data->{$_}{'note_text'} = $note->{text};
											
			}
		}

	#easytecc3::table(\$template,'<td>L__User/Domain__L</td><td colspan="6">L__Aktionen__L</td>', \@special_spamfilter, 'special_spamfilter');

	easytecc3::table_e4($template, $table_data, 'table_tr_show_special_spamfilter_template.html');
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return($template);
}

sub show_virusfilter{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_virusfilter.html');
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_scan_antivirus{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_scan_antivirus.html');
	$template->param('result' => $result);
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_dbbackup{
	
	if($session->param('show_db') ne '1'){
		return start();
	}
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_dbbackup.html');
	my @db = ();
	my $html_error = '';

	my ($dbh, $mysql_connect_error) = easytecc3::mysql_connect();
	if ($mysql_connect_error == '1'){
		return(add_mysql_password());
	}

	if (! -e "$mysqlbackup_dir") {
		mkdir("$mysqlbackup_dir", 0775);
		`chmod 775 $mysqlbackup_dir`;
	}
    
    if ($fb) {
        my $correct_sqldumproot = `/usr/iports/bin/sudo /usr/sbin/chown.pl admin:vuser "/usr/local/etc/easytecc/mysqlbackup" d 2>&1`;
        return(error("L__Fehler beim Setzen des Besitzers für__L /usr/local/etc/easytecc/mysqlbackup: $correct_sqldumproot")) if $correct_sqldumproot;
    }
    else {
        my $correct_sqldumproot = `/home/httpd/cgi-bin/easytecc4/chmod.pl 775 "/usr/local/etc/easytecc/mysqlbackup" 2>&1`;
        return(error("L__Fehler beim Setzen des Besitzers für__L /usr/local/etc/easytecc/mysqlbackup: $correct_sqldumproot")) if $correct_sqldumproot;
    }
        
	# Grsse der Datenbanken ermitteln, von der Funktion wird auch datadir übermittelt. kann man vielleicht noch mal brauchen
	my (%database_size, $datadir) = easytecc3::get_size_mysql();

	foreach(sort keys %database_size){
		logline("debug","key=$_ value=" . $database_size{$_});
	}

	# vorhandene Datenbanken auslesen
	# wenn Datenbank "mysql" nicht auftaucht, hat mysqluser vermutlich zuwenig Rechte,
	# in diesem Fall Formular für mysql-User anzeigen
	my $grant_ok = '';
	my $query = 'SHOW databases';
	
	my $new_db = '';
	my $edit_db = '';
	
	if($session->param('user') eq 'admin'){
	
		$new_db = '1';
		$edit_db = '1';
		$template->param('is_admin' => 1);
	
	} else {
	
		my @user = ();
	
		# gather allowed dirs
		my %allowed_dirs;
		
		my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
		$httpd_conf->read_file;
		my %domains = %{$httpd_conf->file_parsed_hash()};
		
		foreach my $domain (keys %domains){

			my $admins = $domains{$domain}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $session->param('user') . '#';
			
			logline("debug","admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				next;
			}
		
			$allowed_dirs{$domains{$domain}{'droot'}} = '1';
		}
		
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};

		my $gecos = $passwd{$session->param('user')}{'gecos'};
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.db-2';
		
		}
			
		if($gecos =~ m/\.db-[1-9]/){
		
			$edit_db = '1';
		
		}
		
		if($gecos =~ m/\.db-2/){
		
			$new_db = '1';
		
		}
				
		$allowed_dirs{$passwd{$session->param('user')}{'home'}} = '1';

		foreach my $user(sort keys %passwd){
			# chown nicht an POP-User ermöglichen
			next if $passwd{$user}{'gecos'} =~ / - POP/;

			my $home = $passwd{$user}{'home'};
			
			foreach my $dir (keys %allowed_dirs){
	
				if($home eq $dir || $home =~ m#^$dir/#){
		
					push(@user,$user);
			
				}
				
			}
			
		}
		
		my $userlist = '\'' . join('\',\'', @user) . '\'';
		
		$query = "SHOW DATABASES WHERE `Database` IN (SELECT DISTINCT Db AS `Database` FROM mysql.db WHERE User IN ($userlist))";
	
		# a very strange mechanism...
		$grant_ok = '1'
	
	}
	
	$template->param('new_db' => $new_db);
		
	my $sth   = $dbh->prepare( $query );
	$sth->execute;

	my $table_data = {};
	while ( my @row = $sth->fetchrow_array ){ # alle rows auslesen

		foreach my $item (@row){
			next if $item eq 'information_schema';
			# Datenbanken mit . sind Sicherungen von getback auf die kein Zugriff ber mysql-Schnittstelle mglich ist
			# und daher auch kein Backup gemacht werden kann.
			#next if $item =~ /\./;
			# wenn show databases DB mysql oder db01 anzeigt, gehen wir davon aus, dass Rechte des Users der Sicherungen durchfhrt ok sind
			# ansonsten Formular für mysqluser anzeigen
			$grant_ok = '1' if $item eq 'mysql';
			$grant_ok = '1' if $item eq 'db01';

			# Überprüfen, ob Backup angelegt
			my $backup = "Ja";
			my $backup_config = "/usr/local/etc/easytecc/mysqlbackup/$item.dbb";
			my $backup_dir = "$mysqlbackup_dir/$item";
			my @dir_entries = ();
			my $in_use_for_backup = '';
			my $backup_has_error = '0';
			my $backup_has_lock = '0';
			my $backup_count = '0';

			if (-d $backup_dir){
				opendir(D,$backup_dir) || dienice("opendir $backup_dir: $!");
				@dir_entries = grep !/^\.\.?$/, readdir(D); #read in dir entries to array
				closedir D;
				
				#$backup_has_lock = 1 if (grep /\.lock$/, @dir_entries);
				
				foreach my $error_file(@dir_entries){
					logline("info","file1=$error_file item=$item");
					$backup_has_lock = 1 if ($error_file =~ /\.lock$/);
					next if $error_file !~ /^(.*)\.error$/;
					my $name_of_backup = $1;
					logline("info","file2=$error_file");
					$backup_has_error = 1;
					my $error_text = `cat $backup_dir/$error_file`;
					my $error_template = HTML::Template->new(filename => 'error_div.html');
					$error_template->param('alert_has_close_action' => 'alert_has_close_action');
					$error_template->param('alert_close_action' => "exec_delete_alert&amp;database=$item&amp;error=$error_file");
					$error_template->param('error_text' => qq~$item Backup $name_of_backup: $error_text~);
					$html_error .= $error_template->output;
				}
				
				$backup_count = scalar(@dir_entries) - $backup_has_lock - $backup_has_error;
				
				if($backup_count > 0){
					$in_use_for_backup = `du -s $backup_dir` unless $fb;
					$in_use_for_backup = `/usr/iports/bin/sudo /usr/bin/du -As $backup_dir` if $fb;
					$in_use_for_backup = easytecc3::getsize($in_use_for_backup);
				}
			}

			# kein automatisches Backup und keine Dumps
			if ( ! -e $backup_config && $backup_count == '0'){
				$table_data->{$item}{'db_name'} = $item;
				$table_data->{$item}{'db_size_sized'} = easytecc3::getsize($database_size{$item});
				
				$table_data->{$item}{'edit_db'} = $edit_db;
				
				#$backup = "L__Nein__L";
				#push(@db, $item . '|' .
				#easytecc3::getsize($database_size{$item}) . '|' .
				#$backup . '|' .
				#$in_use_for_backup . '|' .
				#qq~<a href="/cgi-bin/easytecc3/index.pl?action=show_mysqlbackup_details&amp;database=$item">L__Backup anlegen__L</a><br />~);
			}
			# kein automatisches Backup aber Dumps vorhanden
			elsif ( ! -e $backup_config && $backup_count > 0){
				$table_data->{$item}{'has_dbbackup'} = 1;
				$table_data->{$item}{'db_name'} = $item;
				$table_data->{$item}{'db_size_sized'} = easytecc3::getsize($database_size{$item});
				$table_data->{$item}{'dbbackup_size_sized'} = $in_use_for_backup;
				$table_data->{$item}{'dbbackup_count'} = $backup_count;
				
				$table_data->{$item}{'edit_db'} = $edit_db;
				
				#$backup = "L__Nein__L";
				#push(@db, $item . '|' .
				#easytecc3::getsize($database_size{$item}) . '|' .
				#$backup . '|' .
				#$in_use_for_backup . '|' .
				#qq~<a href="/cgi-bin/easytecc3/index.pl?action=show_mysqlbackup_details&amp;database=$item">L__Details__L</a><br />~);
			}
			# automatischs Backup ist vorhanden
			else{
				$table_data->{$item}{'db_has_auto_backup'} = 1;
				$table_data->{$item}{'has_dbbackup'} = 1;
				$table_data->{$item}{'db_name'} = $item;
				$table_data->{$item}{'db_size_sized'} = easytecc3::getsize($database_size{$item});
				$table_data->{$item}{'dbbackup_size_sized'} = $in_use_for_backup;
				$table_data->{$item}{'dbbackup_count'} = $backup_count;
				
				$table_data->{$item}{'edit_db'} = $edit_db;
				
				#$backup = "L__Ja__L";
				#push(@db, $item . '|' .
				#easytecc3::getsize($database_size{$item}) . '|' .
				#$backup . '|' .
				#$in_use_for_backup . '|' .
				#qq~<a href="/cgi-bin/easytecc3/index.pl?action=show_mysqlbackup_details&amp;database=$item">L__Details__L</a>~);
			}
			
			my @keys = ('DBBACKUP',$item);
			my $note = note_from_hashfile(\@keys);
															
			if($note->{title}){
									
				$table_data->{$item}{'note_title'} = $note->{title};
				$table_data->{$item}{'note_text'} = $note->{text};
											
			}
			
		}
	}

	# alles für die Katz, mysqluser hat zuwenig Rechte
	unless($grant_ok){
		$dbh->disconnect;
		logline("warning","Leaving show_dbbackup() grant_ok: $grant_ok");
		return(add_mysql_password());
	}

	easytecc3::table_e4($template, $table_data, 'table_tr_show_dbbackup_template.html');
	
	#easytecc3::table(\$template,'<td>L__Datenbank__L</td><td>L__Größe__L</td><td>L__Automatisches Backup__L</td><td>L__Backup-Speichernutzung__L</td><td colspan="3">L__Aktionen__L</td>', \@db, 'table1');

	#my $mysqlbackup_space_in_use = `du -s $mysqlbackup_dir` unless $fb;
	#my $mysqlbackup_space_in_use = `/usr/iports/bin/sudo /usr/bin/du -s $mysqlbackup_dir` if $fb;
	#$mysqlbackup_space_in_use = easytecc3::getsize($mysqlbackup_space_in_use);
	#$template->param('mysqlbackup_space_in_use' => 'L__Backup-Gesamtspeichernutzung__L: ' . $mysqlbackup_space_in_use);

	$dbh->disconnect;
	
	$template->param('error' => $html_error) if $html_error;
	
	if($new_db eq '1'){;
		if (length($input{'active_tab'})) {
			$template->param('show_dbbackup_active_tab'.$input{'active_tab'} => 1);
		}
		else{
			$template->param('show_dbbackup_active_tab1' => 1);	
		}
	} else {
	
		$template->param('show_dbbackup_active_tab1' => 1);	
		
	}
		
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_mysqlbackup_details{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_mysqlbackup_details.html');
	my $database = $input{'database'};
	my %backup = ();
	my %backup_lock = ();
	my %backup_error = ();
	my @backup;

	my $edit_db = '';
		
	if($session->param('user') eq 'admin'){

		$edit_db = '1';
										
	} else {
	
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};
	
		my $gecos = $passwd{$session->param('user')}{'gecos'};
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.db-1';
		
		}
			
		if($gecos =~ m/\.db-[1-9]/){
		
			$edit_db = '1';
		
		}
	
	}
	
	$template->param('edit_db' => $edit_db);
	
	
	if(-d "$mysqlbackup_dir/$database"){
		my $command = "du -s $mysqlbackup_dir/$database/*" unless $fb;
		$command = "/usr/iports/bin/sudo /usr/bin/du -As $mysqlbackup_dir/$database/*" if $fb;

		logline("debug","Executing $command : ");

		open (COMMAND, "$command|") || dienice("open $command|: $!");
		while(my $line = <COMMAND>){
			if ($fb) {
				my @out = split /\n/, $line;
				logline("debug","out = $out");

				foreach(@out){
					my @path = split /\//, $_;
					my $print = $path[0] . "    " . $path[-1];
					$line = $print;
				}
			}

			logline("debug","mysqlbackup = $line");
			# Output in kB
			# 676     mysql
			# 88996   ndb_3_fs
			my($size, $backup) = split /\s+/, $line;
			logline("debug","size = $size, backup = $backup");
			
			if ($line =~ /\s+(.*)\.error$/){
				logline("debug","mysqlbackuperror = $1");
				next;
			}
			if ($line =~ /\s+(.*)\.lock$/){
				logline("debug","mysqlbackuplock = $1");
				$backup{$1}{'reload_button'} = '1';
				next;
			}
			
			# ich sag nix mehr, ich sag einfach nix mehr...
			$backup =~ s/^.*\///g;
			
			$backup{$backup}{'size'} = easytecc3::getsize($size);
			my $modtime = (stat("$mysqlbackup_dir/$database/$backup"))[9];
			logline("debug","modtime = $modtime");
			
			my @formatedtime = localtime($modtime);
			$backup{$backup}{'date'} = easytecc3::zeit(\@formatedtime);
		}
		close COMMAND;

		my $table_data = {};
		foreach (sort keys %backup){
			my $backup = $_;
			logline("notice","backup=$backup");
			
			#für den Fall, da grösseres Backup gerade komprimiert wird, dann gibt es .lock und .gz-Datei. Es soll aber nur "Backup in Arbeit" angezeigt werden
			#Darum skippen, wenn es .gz und eine .lock gibt
			if($backup =~ /^(.*)\.gz$/){
				#next if exists $backup_lock{$1};
				next if (-e "$mysqlbackup_dir/$database/$1.lock");
			}
			
			$table_data->{$backup}{'database'} = $input{'database'};
			$table_data->{$backup}{'nameofbackup'} = $backup;
			$table_data->{$backup}{'dateofbackup'} = $backup{$backup}{'date'};
			$table_data->{$backup}{'sizeofbackup'} = $backup{$backup}{'size'};
			$table_data->{$backup}{'reload_button'} = $backup{$backup}{'reload_button'};
			$table_data->{$backup}{'backup_error'} = $backup{$backup}{'backup_error'};
			$table_data->{$backup}{'edit_db'} = $edit_db;
						
			#if(exists $backup_lock{$_}){
			#	push(@backup, $_.'|'.$backup{$_}{'date'}.'|'.$backup{$_}{'size'}.'|'.
			#	qq~<img src="/easytecc3/images/data_time.gif" />L__Backup in Arbeit__L&nbsp;&nbsp;&nbsp;
			#	<a href="/cgi-bin/easytecc3/index.pl?action=show_mysqlbackup_details&amp;database=$database">L__Aktualisieren__L</a>~);
			#	$table_data->{$backup}{'reload_button'} = 1;
			#}
			#elsif(exists $backup_error{$_}){
			#	push(@backup, $_.'|'.$backup{$_}{'date'}.'|'.$backup{$_}{'size'}.'|'.
			#	qq~<img src="/easytecc3/images/data_error.gif" />Backupfehler!&nbsp;&nbsp;&nbsp;
			#	<a href="/cgi-bin/easytecc3/index.pl?action=exec_delete_mysqlbackup&amp;database=$database&amp;backup=$_&amp;has_error=1">L__Löschen__L</a>~);
			#	$table_data->{$backup}{'backup_error'} = 1;
			#}
			#else{
				

				#push(@backup, $_.'|'.$backup{$_}{'date'}.'|'.$backup{$_}{'size'}.'|'.
				#qq~<a href="/cgi-bin/easytecc3/index.pl?action=confirm_restore_mysqlbackup&amp;database=$database&amp;backup=$_">L__Einspielen__L</a>&nbsp;&nbsp;&nbsp;~ .
				#qq~<a href="/cgi-bin/easytecc3/index.pl?action=download_mysqlbackup&amp;database=$database&amp;backup=$_">Download</a>&nbsp;&nbsp;&nbsp;~ .
				#qq~<a href="/cgi-bin/easytecc3/index.pl?action=exec_delete_mysqlbackup&amp;database=$database&amp;backup=$_">L__Löschen__L</a>~);
			#}
		}

		easytecc3::table_e4($template, $table_data, 'table_tr_show_mysqlbackup_details_template.html');
		#easytecc3::table(\$template,'<td>Name</td><td>L__Datum__L</td><td>L__Größe__L</td><td colspan="4">L__Aktionen__L</td>', \@backup, 'backups');
	}
	else{
		logline("notice","Kein Backup vorhanden");
		$template->param('backups' => 'L__Kein Backup vorhanden__L');
	}

	$template->param('database' => $database);

	if(-e "/usr/local/etc/easytecc/mysqlbackup/$database.dbb"){
		logline("debug","mysqlbackup vorhanden:$database");
		$template->param('delete_auto_backup' => '1');
	}
	else{
		$template->param('edit_new_auto_mysqlbackup' => 'L__Anlegen__L');
	}

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_cronjobs{
		
	if($session->param('show_cron') ne '1'){
		return start();
	}
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_cronjobs.html');
	my @cronjobs = ();

	logline("debug","Creating File Object \$cronfile.");
	my $cronfile = file->new({file_name => '/home/web/cronfile'});
	$cronfile->read_file;
	my %cronjobs = %{$cronfile->file_parsed_hash()};

	logline("debug","Creating File Object \$passwd.");
	my $passwd = file->new({file_name => '/etc/passwd'});
	$passwd->read_file;
	my %passwd = %{$passwd->file_parsed_hash()};

	
	# gather allowed dirs and domains
	my %allowed_dirs;
	my %allowed_domains;
	
	my $edit_cron = '';
	my $new_cron = '';
	
	if($session->param('user') eq 'admin'){
	
		$edit_cron = '1';
		$new_cron = '1';
			
	} else {
	
		my $gecos = $passwd{$session->param('user')}{'gecos'};
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.cron-2';
		
		}
			
		if($gecos =~ m/\.cron-[1-9]/){
		
			$edit_cron = '1';
		
		}
		
		if($gecos =~ m/\.cron-2/){
		
			$new_cron = '1';
		
		}
		
		my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
		$httpd_conf->read_file;
		my %domains = %{$httpd_conf->file_parsed_hash()};
		
		foreach my $domain (keys %domains){

			my $admins = $domains{$domain}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $session->param('user') . '#';
			
			logline("debug","admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				next;
			}
		
			foreach my $alias_domain (@{$domains{$domain}{'domains'}}){
					
				$alias_domain =~ s/^www\.//;
				$alias_domain =~ s/^\*\.//;
				
				$allowed_domains{$alias_domain} = 1;
			
			}
					
			$allowed_dirs{$domains{$domain}{'droot'}} = '1';
			
			if($fb && $domains{$domain}{'droot'} !~ m#/apache24/data/#){
			
				my $doc_root_alias = $domains{$domain}{'droot'};
				$doc_root_alias =~ s#/apache24/noexec/#/apache24/data/#;
				$allowed_dirs{$doc_root_alias} = '1';
			
			}
			
			$domain =~ s/^www\.//;
			$domain =~ s/^\*\.//;
				
			$allowed_domains{$domain} = 1;
			
		}
		
		$allowed_dirs{$passwd{$session->param('user')}{'home'}} = '1';

	} 
	
	$template->param('edit_cron' => $edit_cron);
	$template->param('new_cron' => $new_cron);
		
	my $table_data = {};
	foreach my $cronjob (sort keys %cronjobs){
		next if $cronjobs{$cronjob}{'job'} =~ /easytecc4\/dobackup\.pl/;
		next if $cronjobs{$cronjob}{'job'} =~ /tools\/awstats_updateall\.pl/;
		
		$cronjobs{$cronjob}{'job'} = encode('utf-8',$cronjobs{$cronjob}{'job'});
				
		if($session->param('user') ne 'admin'){
		
			my $allowed = 0;
			
			# check dirs
			foreach my $dir (keys %allowed_dirs){
		
				if($cronjobs{$cronjob}{'job'} =~ m#$dir/#){
		
					# check if other dirs are affected
					my $job = $cronjobs{$cronjob}{'job'};
					$job =~ s#$dir/##;
					
					if($job !~ m#/home/# && $job !~ m#(/usr/local/www/|/home/httpd/docs)#){
					
						$allowed = 1;
						last;
					
					}

				}
				
			}
			
			# check domains
			if($allowed == 0){
			
				foreach my $domain (keys %allowed_domains){
				
					if($cronjobs{$cronjob}{'job'} =~ m#(ftp|http)s?://(www\.)?$domain/#){
					
						$allowed = 1;
						last;
					
					}
				
				}
			
			}
			
			if($allowed != 1){
			
				next;
			
			}
		
		}
			
		my $cronjob_string_no_dev_null = $cronjobs{$cronjob}{'job'};
		$cronjob_string_no_dev_null =~ s/(1|2)*\s*>\s*\/dev\/null//;
		$cronjob_string_no_dev_null =~ s/(1|2)\s*>\s*&(1|2)//;
		
		$table_data->{$cronjob}{'cronjob'} = $cronjobs{$cronjob}{'count'};
		$table_data->{$cronjob}{'cron_command_tooltip'} = $cronjobs{$cronjob}{'job'};
		#$table_data->{$cronjob}{'cron_command'} = easytecc3::substr_e4($cronjobs{$cronjob}{'job'});
		$table_data->{$cronjob}{'cron_command'} = easytecc3::substr_e4($cronjob_string_no_dev_null);
		$table_data->{$cronjob}{'cron_minute'} = $cronjobs{$cronjob}{'min'};
		$table_data->{$cronjob}{'cron_hour'} = $cronjobs{$cronjob}{'std'};
		$table_data->{$cronjob}{'cron_day'} = $cronjobs{$cronjob}{'mday'};
		$table_data->{$cronjob}{'cron_month'} = $cronjobs{$cronjob}{'mon'};
		$table_data->{$cronjob}{'cron_weekday'} = $cronjobs{$cronjob}{'wday'};
		
		$table_data->{$cronjob}{'edit_cron'} = $edit_cron;
		$table_data->{$cronjob}{'new_cron'} = $new_cron;
		
		my $old_cron_key = $cronjobs{$cronjob}{'job'};
		$old_cron_key =~ s/[^a-z0-9]+/-/gi;
		my @old_keys = ('CRONJOB',$old_cron_key);
		
		# new key format
		my $cron_key = encode_base64url($cronjobs{$cronjob}{'job'} . $cronjobs{$cronjob}{'min'} . $cronjobs{$cronjob}{'std'} . $cronjobs{$cronjob}{'mday'} . $cronjobs{$cronjob}{'mon'} . $cronjobs{$cronjob}{'wday'});
		my @keys = ('CRONJOB',$cron_key);
		$table_data->{$cronjob}{'cron_key'} = $cron_key;
						
		my $note = note_from_hashfile(\@old_keys);
		if($note->{title}){
			
			note_to_hashfile(\@keys,decode('utf-8',$note->{title}),decode('utf-8',$note->{text}));
			note_to_hashfile(\@old_keys,'','');
			
		}
		
		$note = note_from_hashfile(\@keys);
		if($note->{title}){
					
			$table_data->{$cronjob}{'note_title'} = $note->{title};
			$table_data->{$cronjob}{'note_text'} = $note->{text};
										
		}
				
				
		#push(@cronjobs, $cronjobs{$cronjob}{'job'} . '|' .
		#$cronjobs{$cronjob}{'min'} . '|' .
		#$cronjobs{$cronjob}{'std'} . '|' .
		#$cronjobs{$cronjob}{'mday'} . '|' .
		#$cronjobs{$cronjob}{'mon'} . '|' .
		#$cronjobs{$cronjob}{'wday'} . '|' .
		#qq~<a href="/cgi-bin/easytecc3/index.pl?action=change_cronjob&amp;cronjob=$cronjobs{$cronjob}{'count'}">L__Editieren__L</a>&nbsp;&nbsp;&nbsp;~ .
		#qq~<a href="/cgi-bin/easytecc3/index.pl?action=delete_cronjob&amp;cronjob=$cronjobs{$cronjob}{'count'}">L__Löschen__L</a>~);
	}

	easytecc3::table_e4($template, $table_data, 'table_tr_show_cronjobs_template.html');
	
	#easytecc3::table(\$template,'<td>L__Kommando__L</td><td>L__Minuten__L</td><td>L__Stunden__L</td><td>L__Tage__L</td><td>L__Monate__L</td><td>L__Wochentag__L</td><td>L__Aktionen__L</td>', \@cronjobs, 'table1');

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_frontpage{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
    my $template = HTML::Template->new(filename => 'show_frontpage.html');
    my @allfiles = ();
    my @frontpage_domains = ();

    unless(`grep 'httpd_enable="F"' /etc/rc.conf`){
	    $template = HTML::Template->new(filename => 'frontpage_not_enabled.html');
    }
    else{
		opendir(DIR, '/usr/local/frontpage') || dienice("opendir /usr/local/frontpage: $!");
			@allfiles = grep !/^\.\.?$/, readdir DIR;
		closedir DIR;

		foreach my $file(@allfiles){
			next unless $file =~ /:80\.cnf$/;
			my $domain = $file;
			$domain =~ s/:80\.cnf$//;
			# ohne www. anzeigen
			my $domain_ohne_www = $domain;
			$domain_ohne_www =~ s/^www\.//;
			push(@frontpage_domains, $domain_ohne_www . '|' . qq~<a href="/cgi-bin/easytecc3/index.pl?action=delete_frontpage&amp;domain=$domain">L__Löschen__L</a>~);
		}

		easytecc3::table(\$template,'<td>L__Domain__L</td><td colspan="6">L__Aktionen__L</td>', \@frontpage_domains, 'table1');
    }

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_filemanager{
	
	if($session->param('show_fileman') ne '1'){
		return start();
	}
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_filemanager.html');
	my ($directories_ref, $files_ref, $allowed_primary) = get_files();
	
	if($session->param('user') eq 'admin'){
		$allowed_primary = 1;
	}
	
	$input{'dir'} =~ s#^$droot_prefix/?##;
	
	my @directories = @$directories_ref;
	my @files = @$files_ref;
	my @filemanager = ();
	my $chdir = '';
	my $dir = '';
	my $pwd =  $droot_prefix . '/' . $input{'dir'};
	
	
	#if($input{'dir'} !~ m#/snapshots/#){
	#	
	#	$pwd =  $droot_prefix . '/' . $input{'dir'};
	#	
	#} else {
	#	
	#	$pwd =  $input{'dir'};
	#
	#}
	
	
	my $show_password_protection='0';
	
	if(scalar @files || scalar @directories >1 || $session->param('user') eq 'admin'){
		
		$show_password_protection='1';
		
	}
	
	$template->param('show_password_protection' => $show_password_protection && $allowed_primary);
	$template->param('show_new_dir' => $allowed_primary);
	
	my $result = $validation_result;
	if($result){
		# in diesem Fall wird show_filemanager nicht mit $input{'action'} = exec...
		# aufgerufen, so daß hier abgebrochen wird
		logline("debug","<<< Leaving ".(caller(0))[3]."().");
		return(error($result));
	}
	else{
		# stat() gibt uns nur die UID, in easytecc muss natürlich der Name erscheinen
		# $passwd{$user}{'uid'}, key ist Username und uid die UID,
		# daraus basteln wir uns einen lookup-hash
		logline("debug","Creating File Object \$passwd.");
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};
		my %username_lookup = %{$passwd->lookup_hash()};
		my $table_data_dir = {};
		my $table_data_file = {};
		
		my $edit_fileman = '';
		
		if($session->param('user') eq 'admin'){
	
			$edit_fileman = '1';
									
		} else {
		
			my $gecos = $passwd{$session->param('user')}{'gecos'};
			
			if($gecos !~ m/^CUST/){

				$gecos = 'CUST.fileman-1';
			
			}
				
			if($gecos =~ m/\.fileman-[1-9]/){
			
				$edit_fileman = '1';
			
			}
		
		}
		
		$template->param('edit_fileman' => $edit_fileman);
		
		
#		my $snapshot_dir = $pwd;
#		$snapshot_dir =~ s#/usr/local/www/apache24/noexec/#/usr/local/www/apache24/data/#;
#		my $snapshot_list = `ls -d1 /snapshots/*/$snapshot_dir 2>&1 | sed 's/^.*bckp_// ; s/\\/.*//' 2>&1`;
#		my @snapshots;
#		my $snapshot;
#		
#		logline("debug","#####################$snapshot_dir\n$snapshot_list\n");
#		
#		foreach $snapshot (split(/[\r\n]+/,$snapshot_list)){
#			
#			my ($day,$month,$year) = $snapshot =~ m/^([0-9]{2})([0-9]{2})([0-9]{4})$/;
#					
#			# add to list
#            push(@snapshots, { snapshot_name => "$day.$month.$year", snapshot_href => '/cgi-bin/easytecc4/index.pl?action=show_filemanager&amp;dir=' . encode_base64url('/snapshots/bckp_' . $snapshot .  $snapshot_dir)});
#			
#		}
#		
#		$template->param('snapshots' => \@snapshots);
		
		foreach (@directories){
			my $full_path = $droot_prefix;
			$dir = $input{'dir'} . '/' . $_ if $input{'dir'};
			$dir = $_ unless $input{'dir'};
			$chdir =  $full_path . '/' . $input{'dir'} . '/' . $_ if $input{'dir'};
			$chdir =  $full_path . '/' . $_ unless $input{'dir'};

			my ($filesize, $filedate, $owner, $fileperm, $nlink) = (stat($chdir))[7,9,4,2,3];
			$fileperm = sprintf "%lo", ($fileperm & 07777);
			
			#$filesize = `du -Ask $chdir`;
			#$filesize = $nlink;
			
			logline("debug","_:$_ dir:$dir input_dir: $input{'dir'}\n");
			
			if($_ eq '..'){
				#logline("debug","..=$_");
				$dir = '' unless $input{'dir'} =~ /\//;
				$dir = $input{'dir'} if $dir;
				# aus /home/httpd/docs/bla/fasel mach
				# /home/httpd/docs/bla
				$dir =~ s/\/[^\/]{0,100}$// if $dir;
				$filesize = `ls -1 $full_path/$input{'dir'} | wc -l`;

				#$table_data_dir->{'..'}{'topdir_href'} = qq~/cgi-bin/easytecc3/index.pl?action=show_filemanager&amp;dir=$dir~;
				#$table_data_dir->{'..'}{'topdir_mtime'} = easytecc3::getdate($filedate);
				#$table_data_dir->{'..'}{'topdir_chmod'} = $fileperm;
				#$table_data_dir->{'..'}{'topdir_user'} = $username_lookup{$owner};
				#$table_data_dir->{'..'}{'topdir_size_sized'} = easytecc3::filesize($filesize);
				
				my $dir_encoded = encode_base64url($dir);
				
				$template->param('topdir_href' => qq~/cgi-bin/easytecc4/index.pl?action=show_filemanager&amp;dir=$dir_encoded~);
				$template->param('topdir_mtime' => easytecc3::getdate($filedate));
				$template->param('topdir_chmod' => $fileperm);
				$template->param('topdir_user' => $username_lookup{$owner});
				#$template->param('topdir_size_sized' => easytecc3::filesize($filesize));
				$template->param('topdir_size_sized' => $filesize);
				
				#push(@filemanager,
				#	'<img src="/easytecc3/images/folder.gif" align="middle" />' . qq~<a href="/cgi-bin/easytecc3/index.pl?action=show_filemanager&amp;dir=$dir">~ . $_ . '</a>|' .
				#	easytecc3::filesize($filesize) . '|' .
				#	easytecc3::getdate($filedate) . '|' .
				#	qq~$fileperm/$username_lookup{$owner}~  . '|' . ''
				#);
			}
			else{
				
				my $dir_encoded = encode_base64url($dir);
				
				$filesize = `ls -1 $chdir | wc -l`;
				
				$table_data_dir->{$_}{'dir'} = $dir;
				$table_data_dir->{$_}{'dir_href'} = qq~/cgi-bin/easytecc4/index.pl?action=show_filemanager&amp;dir=$dir_encoded~;
				$table_data_dir->{$_}{'dir_name'} = $_;
				$table_data_dir->{$_}{'dir_mtime'} = easytecc3::getdate($filedate);
				$table_data_dir->{$_}{'dir_chmod'} = $fileperm;
				$table_data_dir->{$_}{'dir_user'} = $username_lookup{$owner};
				#$table_data_dir->{$_}{'dir_size_sized'} = easytecc3::filesize($filesize);
				$table_data_dir->{$_}{'dir_size_sized'} = $filesize;
				my $dirlink = uri_escape($dir);
				$table_data_dir->{$_}{'dir_href_url'} = qq~http://$ENV{'SERVER_NAME'}/$dirlink~;
				$table_data_dir->{$_}{'dir_href_chmod'} = qq~modify_dir&amp;type=chmod&amp;dir=$dir_encoded~;
				$table_data_dir->{$_}{'dir_href_cms_fix'} = qq~modify_dir&amp;type=cms_fix&amp;dir=$dir_encoded~;
				$table_data_dir->{$_}{'dir_href_cp'} = qq~modify_dir&amp;type=cp&amp;dir=$dir_encoded~;
				$table_data_dir->{$_}{'dir_href_mv'} = qq~modify_dir&amp;type=mv&amp;dir=$dir_encoded~;
				$table_data_dir->{$_}{'dir_href_rm'} = qq~modify_dir&amp;type=rm&amp;dir=$dir_encoded~;
				$table_data_dir->{$_}{'edit_fileman'} = $edit_fileman;
				
				my $dir_key = $chdir;
				$dir_key =~ s/[^a-z0-9]+/-/gi;
				$table_data_dir->{$_}{'dir_key'} = $dir_key;
				
				my @keys = ('DIRECTORY',$dir_key);
				my $note = note_from_hashfile(\@keys);
																
				if($note->{title}){
										
					$table_data_dir->{$_}{'note_title'} = $note->{title};
					$table_data_dir->{$_}{'note_text'} = $note->{text};
												
				}
				
				#push(@filemanager,
				#	'<img src="/easytecc3/images/folder.gif" align="middle" />' . qq~<a href="/cgi-bin/easytecc3/index.pl?action=show_filemanager&amp;dir=$dir">~ . $_ . '</a>|' .
				#	easytecc3::filesize($filesize) . '|' .
				#	easytecc3::getdate($filedate) . '|' .
				#	qq~<a href="/cgi-bin/easytecc3/index.pl?action=modify_dir&amp;type=chmod&amp;dir=$dir">~ . qq~$fileperm/$username_lookup{$owner}~  . '</a>|' .
				#	qq~<a href="http://$ENV{'SERVER_NAME'}/$dir" target="_blank">L__Ansehen__L</a>&nbsp;&nbsp;
				#	<a href="/cgi-bin/easytecc3/index.pl?action=modify_dir&amp;type=cp&amp;dir=$dir">L__Kopieren__L</a>&nbsp;&nbsp;
				#	<a href="/cgi-bin/easytecc3/index.pl?action=modify_dir&amp;type=mv&amp;dir=$dir">L__Umbenennen__L</a>&nbsp;&nbsp;
				#	<a href="/cgi-bin/easytecc3/index.pl?action=modify_dir&amp;type=rm&amp;dir=$dir">L__Löschen__L</a>~
				#);
			}
		}
		
		foreach (@files){
			my $chdir = '';
			my $filelink = '';
			#logline("debug","file = $file");
			my $full_path = $droot_prefix;
			my $dir = $input{'dir'};
			$chdir =  $full_path . '/' . $dir . '/' . $_ if $input{'dir'};
			$chdir =  $full_path . '/' . $_ unless $input{'dir'};
			$filelink = $dir . '/' . $_ if $input{'dir'};
			$filelink = $_ unless $input{'dir'};
			$filelink = uri_escape($filelink);
			# hard hack the /
			$filelink =~ s/%2F/\//g;
						
			logline("debug","filelink: $filelink");

			my($filesize, $filedate, $owner, $fileperm) = (stat($chdir))[7,9,4,2];
			my $fileperm_o = sprintf "%lo",  $fileperm;
			$fileperm = sprintf "%lo", ($fileperm & 07777);

			my ($dummy,$ext) = split(/\./,$_);
			my $icon = "file.gif";
			if ($ext eq 'htm' || $ext eq 'html' || $ext eq 'shtml') { $icon = "html.gif"; }
			if ($ext eq 'txt') { $icon = "txt.gif"; }
			if ($ext eq 'pl' || $ext eq 'cgi') { $icon = "cgi.gif"; }
			if ($ext eq 'zip') { $icon = "zip.gif"; }
			if ($ext eq 'exe') { $icon = "exe.gif"; }
			if ($ext eq 'gif') { $icon = "gif.gif"; }
			if ($ext eq 'jpg') { $icon = "jpg.gif"; }
			
			my $dir_encoded = encode_base64url($dir);
			my $file = $_;
			my $file_encoded = encode_base64url($file);
			
			$table_data_file->{$_}{'file_href'} = qq~/cgi-bin/easytecc4/index.pl?action=show_filemanager&amp;dir=$dir_encoded~;
			$table_data_file->{$_}{'file_name'} = $file;
			$table_data_file->{$_}{'file_mtime'} = easytecc3::getdate($filedate);
			$table_data_file->{$_}{'file_chmod'} = $fileperm;
			$table_data_file->{$_}{'file_user'} = $username_lookup{$owner};
			$table_data_file->{$_}{'file_size_sized'} = easytecc3::filesize($filesize);
			$table_data_file->{$_}{'file_href_url'} = qq~http://$ENV{'SERVER_NAME'}/$filelink~;
			$table_data_file->{$_}{'file_href_download'} = qq~/cgi-bin/easytecc4/index.pl?action=download_file&amp;dir=$dir_encoded&amp;file=$file_encoded~;
			$table_data_file->{$_}{'file_href_edit'} = qq~modify_file&amp;type=edit&amp;dir=$dir_encoded&amp;file=$file_encoded~;
			$table_data_file->{$_}{'file_href_chmod'} = qq~modify_file&amp;type=chmod&amp;dir=$dir_encoded&amp;file=$file_encoded~;
			$table_data_file->{$_}{'file_href_cp'} = qq~modify_file&amp;type=cp&amp;dir=$dir_encoded&amp;file=$file_encoded~;
			$table_data_file->{$_}{'file_href_mv'} = qq~modify_file&amp;type=mv&amp;dir=$dir_encoded&amp;file=$file_encoded~;
			$table_data_file->{$_}{'file_href_rm'} = qq~modify_file&amp;type=rm&amp;dir=$dir_encoded&amp;file=$file_encoded~;
			$table_data_file->{$_}{'edit_fileman'} = $edit_fileman;

			my $file_key = $chdir;
			$file_key =~ s/[^a-z0-9]+/-/gi;
			$table_data_file->{$_}{'file_key'} = $file_key;
			
			my @keys = ('FILE',$file_key);
			my $note = note_from_hashfile(\@keys);
															
			if($note->{title}){
									
				$table_data_file->{$_}{'note_title'} = $note->{title};
				$table_data_file->{$_}{'note_text'} = $note->{text};
											
			}
			
			#push(@filemanager, qq~<img src="/easytecc3/images/$icon" align="middle" /><a href="/cgi-bin/easytecc3/index.pl?action=modify_file&amp;type=edit&amp;dir=$dir&amp;file=$_">$_~ . '</a>|' .
			#	easytecc3::filesize($filesize) . '|' .
			#	easytecc3::getdate($filedate) . '|' .
			#	qq~<a href="/cgi-bin/easytecc3/index.pl?action=modify_file&amp;type=chmod&amp;dir=$dir&amp;file=$_">~ . qq~$fileperm/$username_lookup{$owner}~  . '</a>|' .
			#	qq~<a href="http://$ENV{'SERVER_NAME'}/$filelink" target="_blank">L__Ansehen__L</a>&nbsp;&nbsp;
			#	<a href="/cgi-bin/easytecc3/index.pl?action=modify_file&amp;type=cp&amp;dir=$dir&amp;file=$_">L__Kopieren__L</a>&nbsp;&nbsp;
			#	<a href="/cgi-bin/easytecc3/index.pl?action=modify_file&amp;type=mv&amp;dir=$dir&amp;file=$_">L__Umbenennen__L</a>&nbsp;&nbsp;
			#	<a href="/cgi-bin/easytecc3/index.pl?action=modify_file&amp;type=rm&amp;dir=$dir&amp;file=$_">L__Löschen__L</a>&nbsp;&nbsp;
			#	<a href="/cgi-bin/easytecc3/index.pl?action=download_file&amp;dir=$dir&amp;file=$_">Download</a>~
			#);
		}

		#easytecc3::table(\$template,'<td>L__Dateiname__L</td><td>L__Größe__L</td><td>L__Letzte Änderung__L</td><td>L__CHMOD/user__L</td><td colspan="3">L__Aktionen__L</td>', \@filemanager, 'table1');

		$template->param('pwd' => $pwd);
		$template->param('pwd_encoded' => encode_base64url($pwd));
		$template->param('dir_password_protection' => encode_base64url($input{'dir'}));
		easytecc3::table_e4($template, $table_data_dir, 'table_tr_show_filemanager_dir_template.html');
		easytecc3::table_e4($template, $table_data_file, 'table_tr_show_filemanager_file_template.html');
		
		# Aktionsmöglichkeiten für .htaccess:
		# -anlegen oder
		# -editieren, löschen
		# wenn es .htaccess gibt
		if(-e qq~$pwd/.htaccess~){
			#und darin Authentifizierung enthalten
			if(`grep AuthUserFile $pwd/.htaccess`){
				#dann Option für editieren und löschen von .htaccess
				$template->param('has_password_protection' => 1);
			#	$template->param('htaccess_action' => qq~
			#	<a href="/cgi-bin/easytecc3/index.pl?action=change_htaccess&amp;dir=$input{'dir'}">L__Passwortschutz editieren__L</a><br />
			#	<a href="/cgi-bin/easytecc3/index.pl?action=delete_htaccess&amp;dir=$input{'dir'}&amp;type=delete_all">L__Passwortschutz löschen__L</a>~);
			}
			#else{
			#	#oder Option zum Anlegen von Passwortschutz
			#	$template->param('htaccess_action' => qq~
			#	<a href="/cgi-bin/easytecc3/index.pl?action=new_htaccess&amp;dir=$input{'dir'}">L__Passwortschutz anlegen__L</a>~);
			#}
		}
		#else{
		#	#oder Option zum Anlegen von Passwortschutz
		#	$template->param('htaccess_action' => qq~
		#	<a href="/cgi-bin/easytecc3/index.pl?action=new_htaccess&amp;dir=$input{'dir'}">L__Passwortschutz anlegen__L</a>~);
		#}
	}

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_htpasswd{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_htpasswd.html');
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_logfiles{
	
	if($session->param('show_logs') ne '1'){
		return start();
	}
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_logfiles.html');
	my %logs;

	my @logs = ();

	if ($fb) {
		@logs = `/usr/iports/bin/sudo /usr/sbin/dellogs`;
	}
	else{
		@logs = `/usr/sbin/dellogs`;
	}

    #actually no maillog download for external mailservers
    my $extern_mx = easytecc3::extern_mx();
	my @logfiles = ();
	my $all_logs_size = '';
	my $quotabalken = '';
	my $quota = `cat /etc/vsd/quota`;
	chomp $quota;
	my $domain_tmp = '';
	my @syslog = ();
	my %sorted_logs;
	my $table_data_syslog = {};
	my $table_data_domainlog = {};
	
	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};
	
	
	my $edit_logs = '';
		
	if($session->param('user') eq 'admin'){

		$edit_logs = '1';
		$template->param('is_admin' => '1');
								
	} else {
	
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};
	
		my $gecos = $passwd{$session->param('user')}{'gecos'};
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.logs-1';
		
		}
			
		if($gecos =~ m/\.logs-[1-9]/){
		
			$edit_logs = '1';
		
		}
	
	}
			
	foreach(@logs){
	
		last if /^Geben Sie/;
		next if /^-/;
		next if /^$/;
		next if /^dellogs/;
		next if /(Domainname|Alle|Systemlogs)/;
		my ($domain, $logfile, $size) = split /\|/, $_;
		$domain =~ s/\s//gc;
		# in Zeile für errorlog taucht keine Domain auf, bei so einer Zeile einfach die zuletzt gespeicherte Domain nehmen
		# hostnet.de | speedlog                  |      1.00 MB
		#             | error_log_hostnet.de     |      8.00 kB
		$domain_tmp = $domain if $domain;
		$logfile =~ s/^\s+//;
		$logfile =~ s/\s+$//;
		$size =~ s/^\s+(.*)\s+$/$1/gc;
		
		# filter domains
		if($session->param('user') ne 'admin'){
		
			my $admins = $domains{'www.' . $domain_tmp}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $session->param('user') . '#';
			
			logline("debug","admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				next;
			}
		}
		
		#use logfile name from httpd.conf instead dellogs
		if ($logfile =~ /^access_log/ && length($domains{"www.$domain"}{'access_log'})) {
			$logfile = $domains{"www.$domain"}{'access_log'};
			$logfile =~ s/^.*\///;
			$sorted_logs{$domain}{'access'} = $logfile;
			$sorted_logs{$domain}{'access_size'} = $size;
		}
		elsif ($logfile =~ /^error_log/ && length($domains{"www.$domain_tmp"}{'error_log'})) {
			$logfile = $domains{"www.$domain_tmp"}{'error_log'};
			$logfile =~ s/^.*\///;
			$sorted_logs{$domain_tmp}{'error'} = $logfile;
			$sorted_logs{$domain_tmp}{'error_size'} = $size;
		}
		#else{
		#$sorted_logs{$domain_tmp}{'error'} = $logfile;
		#		$sorted_logs{$domain_tmp}{'error_size'} = $size;	
		#}
		

		if($logfile =~ /^(Access Logs|Error Logs|Messages|Maillogs)/){
			$size =~ /^(.*)\s(.*)$/;
			# Grösse kann in kB oder MB angegeben werden, alles auf MB umrechnen und summieren
			my $size_unscaled = $1;
			my $scale = $2;
			$size_unscaled = $size_unscaled/1024 if $scale eq 'kB';
			$all_logs_size += $size_unscaled;
		}
		#else{
		#	logline("debug","Domain:$domain#####     Log:$logfile#####");
		#	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
		#	
		#	if ($domain ne '') {
		#		$sorted_logs{$domain}{'access'} = $logfile;
		#		$sorted_logs{$domain}{'access_size'} = $size;
		#		$sorted_logs{$domain}{'error'} = $logfile;
		#		$sorted_logs{$domain}{'error_size'} = $size;
		#	}
		#	else{
		#		$sorted_logs{$domain_tmp}{'error'} = $logfile;
		#		$sorted_logs{$domain_tmp}{'error_size'} = $size;
		#	}
		#}
		
		if($logfile =~ /^(Access Logs)/){
			$table_data_syslog->{$logfile}{'deleteable'} = $edit_logs;
			$table_data_syslog->{$logfile}{'domain'} = 'L__Alle Domains__L';
			$table_data_syslog->{$logfile}{'logfile_name'} = $logfile;
			$table_data_syslog->{$logfile}{'logfile_size_sized'} = $size;
			$table_data_syslog->{$logfile}{'logfile_name_delete'} = 'alldomains';
			
		}
		elsif($logfile =~ /^(Error Logs)/){
			$table_data_syslog->{$logfile}{'logfile_name'} = $logfile;
			$table_data_syslog->{$logfile}{'logfile_size_sized'} = $size;
			
		}
		elsif($logfile =~ /^(Messages|Maillogs)/){
			my $all = '';
			$all = 'allsystem' unless $fb;
			$all = 'all' if $fb;
            my $downloadable = '1';
            my $deleteable = $edit_logs;
            
            if ( ! $fb && $extern_mx && $logfile =~ /Maillogs/) {
                $downloadable = '';
                $deleteable = '';
            }
                        

			$table_data_syslog->{$logfile}{'downloadable'} = $downloadable;
			$table_data_syslog->{$logfile}{'deleteable'} = $deleteable;
			$table_data_syslog->{$logfile}{'domain'} = 'L__Systemlogs__L';
			$table_data_syslog->{$logfile}{'logfile_name'} = $logfile;
			$table_data_syslog->{$logfile}{'logfile_size_sized'} = $size;
			my $logfile_encoded = encode_base64url($logfile);
			$table_data_syslog->{$logfile}{'logfile_href_download'} = qq~/cgi-bin/easytecc4/index.pl?action=download_file&amp;file=$logfile_encoded&amp;type=logfile~;
			$table_data_syslog->{$logfile}{'logfile_name_delete'} = 'allsystem';

		}
	}

	foreach(sort keys %sorted_logs){
		my $domain = $_;
		my $idn_domain = encode('utf-8', domain_to_unicode($domain));
		if($sorted_logs{$_}{'access'}){
			my $logfile = $sorted_logs{$_}{'access'};
			
			$table_data_domainlog->{$idn_domain}{'deleteable'} = $edit_logs;
			$table_data_domainlog->{$idn_domain}{'idn_domain'} = encode('utf-8', domain_to_unicode($domain));
			$table_data_domainlog->{$idn_domain}{'domain'} = $domain;
			$table_data_domainlog->{$idn_domain}{'logfile_name'} = $sorted_logs{$_}{'access'};
			$table_data_domainlog->{$idn_domain}{'logfile_size_sized'} = $sorted_logs{$_}{'access_size'};
			my $logfile_encoded = encode_base64url($logfile);
			$table_data_domainlog->{$idn_domain}{'logfile_href_download'} = qq~/cgi-bin/easytecc4/index.pl?action=download_file&amp;file=$logfile_encoded&amp;type=logfile~;
			
			#push(@logfiles, domain_to_unicode($_).'|'.$sorted_logs{$_}{'access'}.'|'.$sorted_logs{$_}{'access_size'}.'|'.
			#	qq~<a href="/cgi-bin/easytecc3/index.pl?action=download_file&amp;file=$logfile&amp;type=logfile">L__Download__L</a>~ .'|'.
			#	qq~<a href="/cgi-bin/easytecc3/index.pl?action=delete_logfiles&amp;domain=$domain">L__Löschen__L</a>~
			#);
		}
		if($sorted_logs{$_}{'error'}){
			my $logfile = $sorted_logs{$_}{'error'};
			#'z' is ugly workaround for sorted access and error log output. Nobody has seen it ;)
			$table_data_domainlog->{$idn_domain . 'z'}{'logfile_name'} = $sorted_logs{$_}{'error'};
			$table_data_domainlog->{$idn_domain . 'z'}{'logfile_size_sized'} = $sorted_logs{$_}{'error_size'};
			my $logfile_encoded = encode_base64url($logfile);
			$table_data_domainlog->{$idn_domain . 'z'}{'logfile_href_download'} = qq~/cgi-bin/easytecc4/index.pl?action=download_file&amp;file=$logfile_encoded&amp;type=logfile~;
			
			#push(@logfiles, ''.'|'.$sorted_logs{$_}{'error'}.'|'.$sorted_logs{$_}{'error_size'}.'|'.
			#	qq~<a href="/cgi-bin/easytecc3/index.pl?action=download_file&amp;file=$logfile&amp;type=logfile">L__Download__L</a>~ .'|'.
			#	''
			#);
		}
	}

	#push(@logfiles, @syslog);

	my $percentval = ($all_logs_size/$quota)*100;
	##kaufm. Rundung
	$percentval = sprintf("%.0f", $percentval);
	my $balken_usage = $percentval;
	my $balken_free = 100 - $balken_usage;

	if(($quota * .8) <= $all_logs_size){
		$template->param('logfile_size_alert' => 1);
	#	$quotabalken = qq|<img src="/easytecc3/images/red.gif" width="$balken_usage" height="15" align="bottom" alt="$balken_usage % genutzt" border="0" /><img src="/easytecc3/images/grey.gif" width="$balken_free" height="15" align="bottom" alt="$balken_free % frei" border="0" />|;
	}
	#else{
	#	$quotabalken = qq|<img src="/easytecc3/images/green.gif" width="$balken_usage" height="15" align="bottom" alt="$balken_usage % genutzt" border="0" /><img src="/easytecc3/images/grey.gif" width="$balken_free" height="15" align="bottom" alt="$balken_free % frei" border="0" />|;
	#}

	$template->param('in_use_MB' => sprintf "%.2f", $all_logs_size);
	$template->param('percent' => ' (' . $percentval . '%)');
	#$template->param('bar' => $quotabalken);

	unless(`grep 'dellogs -a' /home/web/cronfile`){
		if(!$fb){
			$template->param('add_cron_delete_logfiles' => '1');
		}
	}

	#easytecc3::table(\$template,'<td>L__Domainname__L</td><td>L__Logfile__L</td><td>L__Größe__L</td><td colspan="4">L__Aktionen__L</td>', \@logfiles, 'table1');

	easytecc3::table_e4($template, $table_data_domainlog, 'table_tr_show_logfiles_domain_template.html');
	
	if($session->param('user') eq 'admin'){
	
		easytecc3::table_e4($template, $table_data_syslog, 'table_tr_show_logfiles_syslog_template.html');
		
	}
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub domainsearch{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_domainsearch.html');
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub change_errordocs{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'change_errordocs.html');
	my $unauthorized_file = `cat $droot_prefix/error_docs/unauthorized.htm`;
	my $forbidden_file = `cat $droot_prefix/error_docs/forbidden.htm`;
	my $notfound_file = `cat $droot_prefix/error_docs/notfound.htm`;
	my $ierror_file = `cat $droot_prefix/error_docs/ierror.htm`;

	#$unauthorized_file =~ s/\n/<br />/g;
	#$forbidden_file =~ s/\n/<br />/g;
	#$notfound_file =~ s/\n/<br />/g;
	#$ierror_file =~ s/\n/<br />/g;

	$template->param('unauthorized' => $unauthorized_file);
	$template->param('forbidden' => $forbidden_file);
	$template->param('notfound' => $notfound_file);
	$template->param('ierror' => $ierror_file);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_webmailer{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_webmailer.html');
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub new_vhost{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = '';
	
	## warum gibt es hier $input{'xxxx'} Felder? Laut grep gibt es kein Form mit action=new_vhost. Woher soll $input kommen?
	## TODO: korrigieren
	
	# fehlerhafte felder sollte man auch sehen können...
	if($validation_result){
	
		my %error_fields = %$validation_result;
		
		if($error_fields{'special'} || $error_fields{'quota'} || $error_fields{'custom_tag'}){
		
			$input{'extended_options'} = '1';
			
		}
	}

	$template = HTML::Template->new(filename => 'new_vhost.html');

	my $new_ftp = '';
	my $new_db = '';
		
	my $passwd = file->new({file_name => '/etc/passwd'});
	$passwd->read_file;
	my %passwd = %{$passwd->file_parsed_hash()};	
		
	if($session->param('user') eq 'admin'){

		$new_ftp = '1';
		$new_db = '1';
		
		my $userselect='<select id="userselect" name="userselect" class="selectpicker form-control" multiple title="L__Benutzer wählen__L">';
		
		foreach my $ftpuser (sort keys %passwd){
			
			next if $passwd{$ftpuser}{'gecos'} !~ /^CUST/;
		
			$readuserregex = '#' . $ftpuser . '#';
			$writeuserregex = '#' . uc $ftpuser . '#';
			
			$userselect .= '<optgroup label="' . $ftpuser . '">';
			$userselect .= '<option id="write__' . $ftpuser . '" title="' . uc($ftpuser) . '"';
			
			if($admins =~ m/$writeuserregex/){
				$userselect .= ' selected';
			}	
			
			$userselect .= '>L__schreiben__L</option>';
						
			$userselect .= '<option id="read__' . $ftpuser . '" title="' . lc($ftpuser) . '"';
			
			if($admins =~ m/$readuserregex/){
				$userselect .= ' selected';
			}
			
			$userselect .= '>L__lesen__L</option>';
			
			$userselect .= '</optgroup>';
			
		}

		$userselect .= '</select>';
		
		$userselect .= "
<script type='text/javascript'>

	\$('#userselect').on('change', function(e){

		var arr = \$('#userselect').data('selectedids') || new Array();
		var admin_users = '';
	
		\$(this).find('option').each(function(){
		
			var id = \$(this).attr('id');
			var arr_id = id.split('__',2);
			var readwrite = arr_id[0];
			var user = arr_id[1];
			var idx = arr.indexOf(id)
		
			if(\$(this).is(':selected')){             
			
				if(idx == -1){
			
					var removeId;
					
					if(readwrite === 'write'){
					
						removeId = 'read__' + user;
									
					} else {
				
						removeId = 'write__' + user;
				
					}
														
					\$('#' + removeId).removeAttr('selected');
					var removeIdx = arr.indexOf(removeId);
				
					if(removeIdx > -1){
				
						arr.splice(removeIdx, 1);
				
					}
								
					arr.push(id);
				
				}
												
			} else {
			
				if(idx > -1){
				
					arr.splice(idx, 1);
				
				}
			
			}
		
		});

		for (var idx = 0; idx < arr.length; idx++) {
			
			var id = arr[idx];
			var arr_id = id.split('__',2);
			var readwrite = arr_id[0];
			var user = arr_id[1];
			
			if(admin_users.length > 0){
				
				admin_users += ', ';
					
			}
				
			if(readwrite === 'write'){
				
				admin_users += user.toUpperCase();
					
			} else {
				
				admin_users += user.toLowerCase();
					
			}
					
		}
		
		
		\$(this).data('selectedids',arr);
		\$(this).selectpicker('refresh');
		
		\$('#admin_users').val(admin_users);
		
	});
</script>";
		
		$template->param('userselect' => $userselect);
								
	} else {
		
		my $gecos = $passwd{$session->param('user')}{'gecos'};
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.ftp-2.db-2';
		
		}
			
		if($gecos =~ m/\.ftp-2/){
		
			$new_ftp = '1';
		
		}
		
		if($gecos =~ m/\.db-2/){
		
			$new_db = '1';
		
		}
	
	}
	
	$template->param('new_ftp' => $new_ftp);
	$template->param('new_db' => $new_db);
	
	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};
	my %config = %{$httpd_conf->config_hash()};

	if(scalar $config{'listen_80'} > 1){
		my $ip = $config{'main_ip'};
		$ip = $input{'ip_select'} if exists $input{'ip_select'};

		my $template_ip_select = HTML::Template->new(filename => 'ip_select.html');
		easytecc3::template_loop(\%input,\$template_ip_select, $config{'listen_80'}, 'ip_select', $ip);
		$template->param('ip_select' => $template_ip_select->output);
	}
	else{
		$template->param('ip_select' => $config{'main_ip'});
	}
	
	
	# ich bin fassungslos ob dessen, was ich hier kopier
	if(scalar $config{'php_versions'} > 1){
	
		logline("debug","php-versions: " . join(',',@ { $config{'php_versions'} }));
	
		my $php = $config{'server_php'};
		$php = $input{'php_select'} if exists $input{'php_select'};
		
		my $template_php_select = HTML::Template->new(filename => 'php_select.html');
		easytecc3::template_loop(\%input,\$template_php_select, $config{'php_versions'}, 'php_select', $php);
		$template->param('php_select' => $template_php_select->output);

	}
	
	#	if(-d '/home/httpd/docs/twig' && ! -d '/home/httpd/docs/zarafa'){
	#		$template->param('twig_select' => 'Twig' . '<input type="checkbox" name="webmail" value="twig" checked><br />');
	#	}
	#	elsif(-d '/home/httpd/docs/twig' && -d '/home/httpd/docs/zarafa'){
	#		$template->param('twig_select' => 'Twig' . '<input type="checkbox" name="webmail" value="twig"><br />');
	#		$template->param('zarafa_select' => 'Zarafa' . '<input type="checkbox" name="webmail" value="zarafa" checked><br />');
	#	}
	#	elsif(-d '/home/httpd/docs/zarafa'){
	#		$template->param('zarafa_select' => 'Zarafa' . '<input type="checkbox" name="webmail" value="zarafa" checked><br />');
	#	}

	#bei Entryserver keine Option für ftp- und mysqluser und Datenbank anlegen
	unless (defined easytecc3::is_ftp_limited()) {
		my $template_ftp_mysql = HTML::Template->new(filename => 'new_vhost_ftp_mysql.html');
		my $display_ftp = 'none';
		$display_ftp = 'block' if $input{'ftp'};
		my $display_mysql_db = 'none';
		$display_mysql_db = 'block' if $input{'mysql_db'};

		# wenn beim Anlegen fehlerhafte Eingabe, dann ggf. ftp und mysql erneut als cheked anzeigen
		$template_ftp_mysql->param('checked_ftp' => ' checked') if $input{'ftp'};
		$template_ftp_mysql->param('display_ftp' => $display_ftp);
		$template_ftp_mysql->param('ftpuser' => $input{'ftpuser'});
		$template_ftp_mysql->param('ftppass' => $input{'ftppass'});
		$template_ftp_mysql->param('ftpquota' => $input{'ftpquota'});
		$template_ftp_mysql->param('ftpdescription' => $input{'ftpdescription'});

		$template_ftp_mysql->param('checked_suexec' => ' checked') if $input{'suexec'};
		
		$template_ftp_mysql->param('checked_mysql_db' => ' checked') if $input{'mysql_db'};
		$template_ftp_mysql->param('display_mysql_db' => $display_mysql_db);
		$template_ftp_mysql->param('db' => $input{'db'});
		$template_ftp_mysql->param('dbuser' => $input{'dbuser'});
		$template_ftp_mysql->param('dbpass' => $input{'dbpass'});

		$template_ftp_mysql->param('new_ftp' => $new_ftp);
		$template_ftp_mysql->param('new_db' => $new_db);	
		
		# Fehlerklasse für Felder setzen, wo Validierung fehlgeschlagen ist
		%error_fields = %$validation_result;
		foreach(keys %error_fields){
			$template_ftp_mysql->param('error_class_' . $_ => qq~has-error~);
			$template_ftp_mysql->param('error_text_' . $_ => qq~<span class="help-block">~ . encode_entities($error_fields{$_}, '<>&"') . qq~</span>~);
		}
		$template_ftp_mysql->param('has_suexec' => $config{'has_suexec'});
		$template->param('new_vhost_ftp_mysql' => $template_ftp_mysql->output);
	}

	if(!defined($input{'quota'})){
		$input{'quota'} = '100000';
	}
	
	$template->param('quota' => $input{'quota'});
	
	
	# show / hide extended options
	my $display_extended_options = 'none';
	my $checked_extended_options = '';
	
	if ($input{'extended_options'}){
		$display_extended_options = 'block';
		$checked_extended_options = ' checked';
	}
		
	$template->param('display_extended_options' => $display_extended_options);
	$template->param('checked_extended_options' => $checked_extended_options);
		
#	if($input{'stats'} eq 'awstats'){
		$template->param('checked_awstats' => ' checked');
#	}
#	elsif($input{'stats'} eq 'webalizer'){
#		$template->param('checked_webalizer' => ' checked');
#	}

#	if($input{'webmail'} eq 'roundcube'){
		$template->param('checked_roundcube' => ' checked');
#	}
#	#Webmailer Zarafa
#	elsif($input{'webmail'} eq 'zarafa'){
#		$template->param('checked_zarafa' => ' checked');
#	}

	$template->param('checked_mysql' => ' checked');

	$template->param('special' => encode_entities($input{'special'})) if exists $input{'special'};
	
	#set default pop for aut to 10
	if (length($input{'pop'}) == '0') {
		$template->param('pop' => '10');
	}
	if (length($input{'for'}) == '0') {
		$template->param('for' => '10');
	}
	if (length($input{'aut'}) == '0') {
		$template->param('aut' => '10');
	}
	
	if (length($input{'custom_tag'})) {
		$template->param('custom_tag' => $input{'custom_tag'});
	}

	my $default_docroot = '';

	
	if($session->param('user') eq 'admin'){
		
		if($fb){

			$default_docroot = '/usr/local/www/apache24/noexec/';
		
		} else {
		
			$default_docroot = '/home/httpd/docs/';
		
		}
	
		if (length($input{'admin_users'})) {
			$template->param('admin_users' => $input{'admin_users'});
		}

		$template->param('show_admin_users' => '1');
		$template->param('show_ip_select' => '1');
	
	} else {
	
		$template->param('ip' => $config{'main_ip'}); 
		$input{'admin_users'} = $session->param('user');
		
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};
		
		$default_docroot = $passwd{$input{'admin_users'}}{'home'} . '/';
	
	}
	
	$template->param('show_php_select' => scalar $config{'php_versions'} >= 1 ? '1' : '');
	
	$template->param('default_docroot' => $default_docroot);
			
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub change_vhost{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = '';

	$template = HTML::Template->new(filename => 'change_vhost.html');

	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};
	my %config = %{$httpd_conf->config_hash()};

	logline("debug","Creating File Object \$passwd.");
	my $passwd = file->new({file_name => '/etc/passwd'});
	$passwd->read_file;
	my %passwd = %{$passwd->file_parsed_hash()};
	my %home_lookup =  %{$passwd->lookup2_hash()};

	my ($quotaref, $sum_ftplimit, $sum_ftpuse, $ftpserverlimit) = easytecc3::getquota_ftp();
	my %quota = %$quotaref;

	my $ftpuser = '';
	my $ftpquota = '';
	my $ftpquota_sized = '';
	my $ftpused = '';
	my $quotabalken = '';
	my $domain = $input{'domain'};
	my $domain_ssl_icon = '';
	my $domain_ip_icon = '';
	my $domain_ohne_www = $domain;
	$domain_ohne_www =~ s/^www\.//;

	$domain = 'www.' . $domain unless($domain =~ /^www\./);

	
	my $ftpdir = $domains{$domain}{'droot'};
	while(length($ftpdir) && $ftpdir !~ /\/(data|noexec)$/){
				
		if(exists $home_lookup{$ftpdir}){
			
			$ftpuser = $home_lookup{$ftpdir};
			$ftpquota = $quota{$ftpuser}{'quota'};
			$ftpquota_sized = easytecc3::getsize($ftpquota);
			$ftpused = $quota{$ftpuser}{'use'};
			$quotabalken = easytecc3::quotabar($ftpquota, $ftpused, 'all');
			last;
			
		}
		
		$ftpdir =~ s/\/[^\/]*$//;
		
	}	
		
	#if(exists $home_lookup{$domains{$domain}{'droot'}}){
	#	$ftpuser = $home_lookup{$domains{$domain}{'droot'}};
	#	$ftpquota = $quota{$ftpuser}{'quota'};
	#	$ftpquota_sized = easytecc3::getsize($ftpquota);
	#	$ftpused = $quota{$ftpuser}{'use'};
	#	$quotabalken = easytecc3::quotabar($ftpquota, $ftpused, 'all');
	#}

	logline("debug","$domain ssl_enabled=" . $config{'ssl_enabled'} . 'ssl=' . $domains{$domain}{'ssl'} . 'droot=' . $domains{$domain}{'ssl_droot'});

	# Kunde - domain specific check
	if($session->param('user') ne 'admin'){	
		my $admins = $domains{$domain}{'admin_users'};
		$admins =~ s/[\s,]+/#/g;
		$admins = '#' . $admins . '#';
		$readuserregex = '#' . $session->param('user') . '#';
		$writeuserregex = '#' . uc $session->param('user') . '#';
			
		if($admins =~ m/$writeuserregex/){
			$template->param('disabled' => '');
		} else {
			$template->param('disabled' => 'disabled');
		}
		
		$gecos = $passwd{$session->param('user')}{'gecos'};	
		
		if($gecos !~ m/^CUST/){
	
			$gecos = 'CUST.vhost-1';
				
		}
		
		if($gecos !~ m/\.vhost-[1-9]/){
			
			$template->param('no_quota' => '1');
				
		}
			
			
	} else {
		
		$template->param('disabled' => '');
		
	}
		
	# wenn SSL-Domain, dann Icon
	if($config{'ssl_enabled'} && $domains{$domain}{'ssl'}){
		$domain_ssl_icon = qq~<img src="/easytecc3/images/ssl.gif" width="15" height="15" align="bottom" alt="SSL-Domain" border="0" />~;

		my $template_ssl = HTML::Template->new(filename => 'ssl_change_vhost.html');
		$template_ssl->param('ssl_ip' => $domains{$domain}{'ssl_ip'});
		$template_ssl->param('ssl_port' => $domains{$domain}{'ssl_port'});
		$template_ssl->param('ssl_droot' => $domains{$domain}{'ssl_droot'});
		# take over value from above check
		$template_ssl->param('disabled' => $template->param('disabled'));
		
		$template_ssl->param('checked_ssl_force' => ' checked') if $domains{$domain}{'ssl_force'} == '1';

		$template_ssl->param('ssl_port' => $input{'ssl_port'}) if exists $input{'ssl_port'};
		$template_ssl->param('ssl_droot' => $input{'ssl_droot'}) if exists $input{'ssl_droot'};
		# Fehlerklasse für Felder setzen, wo Validierung fehlgeschlagen ist
		%error_fields = %$validation_result;
		foreach(keys %error_fields){
			$template_ssl->param('error_class_' . $_ => qq~class="form-error-label"~);
		}

		# evtl. haben Port80-vhost und SSL-vhost verschiedene spezielle Einstellungen.
		# daher bei SSL-Domain zwei Felder für manuelle eintrge
		my $html = '';
		foreach(@{$domains{$domain}{'special_ssl'}}){
			$html .= $_ . "\n";
		}
		$template_ssl->param('special_ssl' => encode_entities($html));
		$template_ssl->param('special_ssl' => encode_entities($input{'special_ssl'})) if exists $input{'special_ssl'};

		$template->param('ssl_change_vhost' => $template_ssl->output);
	}

	# wenn separate IP, dann Icon
	if($config{'main_ip'} ne $domains{$domain}{'ip'}){
		$domain_ip_icon = qq~<img src="/easytecc3/images/ip.gif" width="15" height="15" align="bottom" alt="SSL-Domain" border="0" />~;
	}

	# wenn webserver mehrere IPs hat, dann IPs zur Auswahl stellen, damit Kunde vhost auf andere IP ändern kann
	# Evtl. hat er mehrere IPs gemietet und will unterschiedlich aufteilen. Nach Absenden von change_vhost kommt
	# Nachfrage, ob vhost nur geändert oder Kopie von vhost mit alter IP für Propagation angelegt werden soll.
	if(scalar $config{'listen_80'} > 1){
	
		logline("debug","listen_80: " . join(',',@ { $config{'listen_80'} }));
	
		my $ip = $domains{$domain}{'ip'};
		$ip = $input{'ip_select'} if exists $input{'ip_select'};

		my $template_ip_select = HTML::Template->new(filename => 'ip_select.html');
		easytecc3::template_loop(\%input,\$template_ip_select, $config{'listen_80'}, 'ip_select', $ip);
		$template->param('ip_select' => $template_ip_select->output);

	}

	# ich bin fassungslos ob dessen, was ich hier kopier
	if(scalar $config{'php_versions'} > 1){
	
		logline("debug","php-versions: " . join(',',@ { $config{'php_versions'} }));
	
		my $php = $domains{$domain}{'php'};
		$php = $input{'php_select'} if exists $input{'php_select'};
		
		my $template_php_select = HTML::Template->new(filename => 'php_select.html');
		easytecc3::template_loop(\%input,\$template_php_select, $config{'php_versions'}, 'php_select', $php);
		$template->param('php_select' => $template_php_select->output);

	}
	
	$template->param('openbasedir' => $domains{$domain}{'openbasedir'});
	
	# .user.ini link
	my $dir_encoded = $domains{$domain}{'droot'};
	$dir_encoded =~ s#^(/home/httpd/docs/|/usr/local/www/apache24/(noexec|data)/)##;
	$dir_encoded = encode_base64url($dir_encoded);
	
	my $file_encoded = encode_base64url('.user.ini');
	$template->param('file_href_edit' => qq~modify_file&amp;type=edit&amp;dir=$dir_encoded&amp;file=$file_encoded~);	
	
	# wenn mindestens ein Scriptalias diesen als änderbares Feld anzeigen, aber nur Standard-Scriptaliase /cgi-bin/ und /cgi-local/.
	# Eigene landen in manuelle Eintrge
	my $has_cgi_bin = '';
	my $has_cgi_local = '';
	#script alias cgi-local always in data instead noexec
	my $droot_data = $domains{$domain}{'droot'};
	$droot_data =~ s/\/noexec\//\/data\//;
	if(scalar $domains{$domain}{'scriptalias'} >= 1){
		foreach(@{$domains{$domain}{'scriptalias'}}){
			if(/^ScriptAlias\s+\/cgi-bin(\/|\s)\s*\/home\/httpd\/cgi-bin[\/]{0,1}$/ && ! $fb){
				$template->param('checked_cgi-bin' => ' checked');
				$has_cgi_bin = '1';
			}
			elsif(/^ScriptAlias\s+\/cgi-bin(\/|\s)\s*\/usr\/local\/www\/apache24\/cgi-bin[\/]{0,1}$/ && $fb){
				$template->param('checked_cgi-bin' => ' checked');
				$has_cgi_bin = '1';
			}
			elsif(/^ScriptAlias\s+\/cgi-local(\/|\s)\s*$droot_data\/cgi-local[\/]{0,1}$/){
				$template->param('checked_cgi-local' => ' checked');
				$has_cgi_local = '1';
			}
			#kein Standard-Scriptalias, kommt in manuelle Eintrge
			else{
				push @{$domains{$domain}{'special'}}, $_;
			}
		}
	}

	if($domains{$domain}{'roundcube'} == '1' || $fb){
		$template->param('checked_roundcube' => ' checked');
	}

	
	
	if($domains{$domain}{'redirect_domain'}){
		$template->param('redirect_domain' => $domains{$domain}{'redirect_domain'});
	}
	
	#Alias für phpmyadmin
	if($domains{$domain}{'mysql'}){
		$template->param('checked_mysql' => ' checked');
	}

	logline("debug",qq~Log:$domains{$domain}{'access_log'}~);

	#Logs
	if($domains{$domain}{'access_log'}){
		$template->param('stats' => qq~accesslog: <input type="text" name="access_log" value="$domains{$domain}{'access_log'}" size="45"><br />
		errorlog: <input type="text" name="error_log" value="$domains{$domain}{'error_log'}" size="45"><br />~);
	}

	#awstats oder webalizer oder nix wenn change_vhost zum ersten mal aufgerufen wird
	unless($input{'stats'}){
		if(-e "$awstats_conf_prefix/awstats.$domain_ohne_www.conf"){
			$template->param('checked_awstats' => ' checked');
		}
		elsif(`grep '/usr/local/etc/$domain_ohne_www.conf' /home/web/cronfile`){
			$template->param('checked_webalizer' => ' checked');
		}
		else {
			$template->param('checked_nostats' => ' checked');
		}
						
	}
	#falls exec_change_vhost mit Fehler, dann wird change_vhost erneut aufgerufen, die Vorauswahl wieder übernehmen
	else{
		if($input{'stats'} eq 'awstats'){
			$template->param('checked_awstats' => ' checked');
		}
		elsif($input{'stats'} eq 'webalizer'){
			$template->param('checked_webalizer' => ' checked');
		}
		else {
			$template->param('checked_nostats' => ' checked');
		}
	}

	$template->param('vhost' => $domain);
	$template->param('domain' => $domain_ohne_www);
	$template->param('idn_domain' => encode('utf-8', domain_to_unicode($domain_ohne_www)));
	$template->param('domain_ssl_icon' => $domain_ssl_icon);
	$template->param('domain_ip_icon' => $domain_ip_icon);
	$template->param('ip' => $domains{$domain}{'ip'});
	$template->param('port' => $domains{$domain}{'port'});
	$template->param('quota' => $domains{$domain}{'quota'});
	$template->param('quotabar' =>  qq~<input type="hidden" name="ftpuser" value="$ftpuser" /><input type="hidden" name="ftpquota" value="$ftpquota" />&nbsp;&nbsp;L__FTP-User__L $ftpuser: $quotabalken~);
	$template->param('serveradmin' => $domains{$domain}{'serveradmin'});
	$template->param('droot' => $domains{$domain}{'droot'});
	$template->param('access_log' => $domains{$domain}{'access_log'});
	$template->param('error_log' => $domains{$domain}{'error_log'});
	$template->param('pop' => $domains{$domain}{'pop'});
	$template->param('for' => $domains{$domain}{'for'});
	$template->param('aut' => $domains{$domain}{'aut'});
	$template->param('custom_tag' => $domains{$domain}{'custom_tag'});
	
	$template->param('show_php_select' => scalar $config{'php_versions'} >= 1 ? '1' : '');
	
	$template->param('ftp_user' => $ftpuser);
	
	if($session->param('user') eq 'admin'){
	
		$template->param('admin_users' => $domains{$domain}{'admin_users'});
		
		$template->param('show_admin_users' => '1');
		$template->param('show_ip_select' => '1');
		$template->param('disabled' => '');
		
		my $admins = $domains{$domain}{'admin_users'};
		$admins =~ s/[\s,]+/#/g;
		$admins = '#' . $admins . '#';
						
		my $userselect='<select id="userselect" name="userselect" class="selectpicker form-control" multiple title="L__Benutzer wählen__L">';
		
		foreach my $ftpuser (sort keys %passwd){
			
			next if $passwd{$ftpuser}{'gecos'} !~ /^CUST/;
		
			$readuserregex = '#' . $ftpuser . '#';
			$writeuserregex = '#' . uc $ftpuser . '#';
			
			$userselect .= '<optgroup label="' . $ftpuser . '">';
			$userselect .= '<option id="write__' . $ftpuser . '" title="' . uc($ftpuser) . '"';
			
			if($admins =~ m/$writeuserregex/){
				$userselect .= ' selected';
			}	
			
			$userselect .= '>L__schreiben__L</option>';
						
			$userselect .= '<option id="read__' . $ftpuser . '" title="' . lc($ftpuser) . '"';
			
			if($admins =~ m/$readuserregex/){
				$userselect .= ' selected';
			}
			
			$userselect .= '>L__lesen__L</option>';
			
			$userselect .= '</optgroup>';
			
		}

		$userselect .= '</select>';
		
		$userselect .= "
<script type='text/javascript'>

	\$('#userselect').on('change', function(e){

		var arr = \$('#userselect').data('selectedids') || new Array();
		var admin_users = '';
	
		\$(this).find('option').each(function(){
		
			var id = \$(this).attr('id');
			var arr_id = id.split('__',2);
			var readwrite = arr_id[0];
			var user = arr_id[1];
			var idx = arr.indexOf(id)
		
			if(\$(this).is(':selected')){             
			
				if(idx == -1){
			
					var removeId;
					
					if(readwrite === 'write'){
					
						removeId = 'read__' + user;
									
					} else {
				
						removeId = 'write__' + user;
				
					}
														
					\$('#' + removeId).removeAttr('selected');
					var removeIdx = arr.indexOf(removeId);
				
					if(removeIdx > -1){
				
						arr.splice(removeIdx, 1);
				
					}
								
					arr.push(id);
				
				}
												
			} else {
			
				if(idx > -1){
				
					arr.splice(idx, 1);
				
				}
			
			}
		
		});

		for (var idx = 0; idx < arr.length; idx++) {
			
			var id = arr[idx];
			var arr_id = id.split('__',2);
			var readwrite = arr_id[0];
			var user = arr_id[1];
			
			if(admin_users.length > 0){
				
				admin_users += ', ';
					
			}
				
			if(readwrite === 'write'){
				
				admin_users += user.toUpperCase();
					
			} else {
				
				admin_users += user.toLowerCase();
					
			}
					
		}
		
		
		\$(this).data('selectedids',arr);
		\$(this).selectpicker('refresh');
		
		\$('#admin_users').val(admin_users);
		
	});
</script>";
		
		$template->param('userselect' => $userselect);
		
		
	} 
	
	
	
	#Eingabefeld für weitere Domainnamen
	my $serveralias = '';
	foreach(@{$domains{$domain}{'domains'}}){
		logline("debug","serveralias = $_");
		next if /^www\./;
		next if /^$domain_ohne_www$/;
		$serveralias .= encode('utf-8', domain_to_unicode($_)) . "\n";
	}

	$template->param('domains' => qq~$serveralias~);

	my $html = '';
	unless($input{'special'}){
		foreach(@{$domains{$domain}{'special'}}){
			$html .= $_ . "\n";
		}
	}
	else{
		$html = $input{'special'};
	}
	$template->param('special' => encode_entities($html));
	
	my $suexec='';
	
	if(!$input{'suexec'}){
			
		if($html =~ /\s*[^#]\s*SuexecUserGroup\s+$ftpuser\s+$ftpuser/){
			$suexec='1';
		}
				
	}
	$template->param('suexec' => $suexec);
	$template->param('has_suexec' => $config{'has_suexec'});	
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub new_install{
	
	if($session->param('show_inst') ne '1'){
		return start();
	}
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);

	my $template = HTML::Template->new(filename => 'new_install.html');
	
	# saving allowed_domains
		
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};
	my %allowed_domains = ();
	
	foreach my $domain (keys %domains){

		if($session->param('user') ne 'admin'){
		
			my $admins = $domains{$domain}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $session->param('user') . '#';
			
			logline("debug","admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				next;
			}
			
		}
	
		foreach my $alias_domain (@{$domains{$domain}{'domains'}}){
				
			$alias_domain =~ s/^www\.//;
			$alias_domain =~ s/^\*\.//;
			
			# deny server.han-solo.net
			if ($alias_domain =~ m/^[^\.]+\.han-solo\.net$/){
				next;
			}
			
			$allowed_domains{$alias_domain} = 1;
		
		}
				
		$domain =~ s/^www\.//;
		$domain =~ s/^\*\.//;
			
		$allowed_domains{$domain} = 1;
		
	}
	
	# hack: installer kann nicht mit langen listen
	if($session->param('user') eq 'admin'){
		
		%allowed_domains = ();
		
	} else {
	
		if(! keys %allowed_domains){

			$input{'error'} = 1;
			$template = HTML::Template->new(filename => 'index.html');
			return error("L__Der Autonistaller kann nicht geladen werden, es sind keine Domains eingerichtet__L");

		}
		
	}
	
	$session->param("allowed_domains", join(',', sort keys %allowed_domains));	
	$session->flush();
		
#	$template->param('domain_select' => '');
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub new_install_old{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'new_install.html');
	
	#first check for database connection
	my ($dbh, $mysql_connect_error) = easytecc3::mysql_connect();
	if ($mysql_connect_error == '1'){
		logline("error","<<< Leaving ".(caller(0))[3]."() by mysql connect error.");
		return(add_mysql_password());
	}
	$dbh->disconnect;
	
	my $domain = $input{'domain'};
	
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};
	
	my @idn_domains = ();
	foreach my $domain (sort keys %domains){
		logline("debug","foreach = $domain");
		#wildcard nicht für Weiterleitung anbieten
		next if(/\*/);
		#push @idn_domains, domain_to_unicode($_ . '|' . qq~value="$_"~;
		#push @idn_domains, $_;
		my $domain_ohne_www = $domain;
		$domain_ohne_www =~ s/^www\.//;
		push @idn_domains, encode('utf-8', domain_to_unicode($domain_ohne_www));
	}
	
	my $template_domain_select = HTML::Template->new(filename => 'domain_select.html');
	easytecc3::template_loop_e4(\%input,\$template_domain_select, \@idn_domains, "domain_select$forcount", $input{"domain_select$forcount"} ? encode('utf-8', domain_to_unicode($input{"domain_select$forcount"})) : encode('utf-8', domain_to_unicode($domain)));
	$template->param('domain_select' => $template_domain_select->output);
	
	if (length($input{'active_tab'})) {
		$template->param('new_install_active_tab'.$input{'active_tab'} => 1);
	}
	else{
		$template->param('new_install_active_tab1' => 1);	
	}
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub confirm_new_install{
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'confirm_new_install.html');

	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};

	$template->param('install' => $input{'install'});
	$template->param('domain' => $input{'domain'});
	$template->param('droot' => $domains{'www.'.$input{'domain'}}{'droot'});
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
	
}

sub exec_new_install{
	
}

sub change_popuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'change_popuser.html');
	$template = HTML::Template->new(filename => 'change_popuser_admin_extern_mailserver.html') if $input{'domain'} eq 'www.administrator';
	my $email = '';
	my $popcount = 1;
	my $quotabalken = '';
	my $password = '';
	my @user = ();
	my $domain = $input{'domain'};
	$domain =~ s/^www\.//;

	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};

	my %passwd = ();
	my %mailquota = ();
	my ($mailquotaref, $sum_maillimit, $sum_mailuse, $mailserverlimit);


	
	
	### Mario: Passwörter nicht mehr anzeigen ###
	logline("debug","ShowMailuserPasswords: $easytecc_custom_conf_entries{'ShowMailuserPasswords'}");
	if ( "$easytecc_custom_conf_entries{'ShowMailuserPasswords'}" eq "NO" ) {
		logline ("debug","ShowMailuserPasswords=NO");
		$template->param('do_not_show_password' => '1');
	} else {
		logline ("debug","ShowMailuserPasswords=YES");
	}


	# zum gucken, ob es FTP-User gibt, die passwd vom Webserver auslesen, und gucken ob es zum
	# document root der Domain einen FTP-User mit passendem home-Verzeichnis gibt
	logline("debug","Creating File Object \$webserver_passwd.");
	my $webserver_passwd = file->new({file_name => '/etc/passwd'});
	$webserver_passwd->read_file;
	my %webserver_passwd = %{$webserver_passwd->file_parsed_hash()};
	my %home_lookup =  %{$webserver_passwd->lookup2_hash()};

	my ($quotaref, $sum_ftplimit, $sum_ftpuse, $ftpserverlimit) = easytecc3::getquota_ftp();
	my %quota = %$quotaref;

	if (easytecc3::extern_mx() || $fb) {
		$mailpasswd = easytecc3::get_mailpasswd();
		%passwd = %{$mailpasswd->file_parsed_hash()};
		($mailquotaref, $sum_maillimit, $sum_mailuse, $mailserverlimit) = easytecc3::getquota_mail(\%passwd);
		%mailquota = %$mailquotaref;
		#%mailquota = %passwd;
	}
	#elsif (easytecc3::extern_mx()){
	#	$mailpasswd = easytecc3::get_mailpasswd();
	#	%passwd = %{$mailpasswd->file_parsed_hash()};
	#
	#	#%passwd = %{easytecc3::get_mailpasswd()};
	#	($mailquotaref, $sum_maillimit, $sum_mailuse, $mailserverlimit) = easytecc3::getquota_mail();
	#	%mailquota = %$mailquotaref;
	#}
	else{
		%passwd = %webserver_passwd;
		%mailquota = %quota;
		$sum_maillimit = $sum_ftplimit;
		$sum_mailuse = $sum_ftpuse;
		$mailserverlimit = $ftpserverlimit;
	}

	# hide mailserver domains for non admin, show edit
	
	my $show_vhost = '';
	my $disabled = '';

	my $servername = `sed 's/^.* // ; s/\$/.han-solo.net/' /etc/FQDN 2>/dev/null`;
	chomp $servername;
	
	if($session->param('user') eq 'admin'){
			
		$show_vhost = '1';
		$disabled = '';
		
		if($input{'domain'} eq $servername){
			$domains{$servername}{'pop'} = 1;
			$domains{$servername}{'for'} = 1;
			$domains{$servername}{'aut'} = 0;
		}
	
	} else {

		my $passwd_ftp = file->new({file_name => '/etc/passwd'});
		$passwd_ftp->read_file;
		my %passwd_ftp = %{$passwd_ftp->file_parsed_hash()};
			
		my $gecos = $passwd_ftp{$session->param('user')}{'gecos'};	
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.vhost-1.email-1';
		
		}
		
		if($gecos =~ m/\.vhost/){
	
			$show_vhost = '1';
	
		}
	
		if($gecos !~ m/\.email-[1-9]/){
			
			$disabled = 'disabled';
				
		}
	
	}
	
	$template->param('show_vhost' => $show_vhost);
	$template->param('disabled' => $disabled);
	
	my $splitted_domains = join '|', @{$domains{$input{'domain'}}{'domains'}};
	$splitted_domains =~ s/\*/\\*/g;
	logline("debug","splitted_domains = $splitted_domains");
	logline("debug","servername = $servername");

	my $admin_delete_disabled = ($domain eq 'administrator' || $input{'domain'} eq $servername) ? 'DISABLED': '';
	logline("debug","admin_delete_disabled = $admin_delete_disabled");
		
	my $table_data = {};
	foreach my $user(sort keys %passwd){
		if(
		   $domain eq 'administrator' && $user ne 'admin' ||
		   $input{'domain'} eq $servername && $user ne 'admin@' . $servername ||
		   $input{'domain'} ne $servername && $passwd{$user}{'gecos'} !~ /^($splitted_domains) - POP/
		){
			logline("debug","skipping user $user");
			next;
		}	
		
		my $mailquota_sized =  $mailquota{$user}{'quota'} / 1024;
		my $quotabalken = easytecc3::quotabar($mailquota{$user}{'quota'}, $mailquota{$user}{'use'}, 'used');
		$password =  value("$passwd{$user}{'dec'}", "pass$popcount") if $input{'form_submit'};
		#$password =  decode("utf8", value("$passwd{$user}{'dec'}", "pass$popcount")) if not exists $input{'form_submit'};
		$password = value("$passwd{$user}{'dec'}", "pass$popcount") if not exists $input{'form_submit'};

		push(@user, qq~<input type="hidden" name="old_user$popcount" value="$user" />
		<input type="hidden" name="old_pass$popcount" value="$passwd{$user}{'dec'}" />
		<input type="hidden" name="old_quota$popcount" value="$mailquota_sized" />
		<input  type="checkbox" name="delete$popcount" id="delete$popcount" value="$user" $admin_delete_disabled />
		<input name="user$popcount" type="text" id="user$popcount" value=~ . value("$user", "user$popcount") . qq~size="20" />~ . '|' .
		qq~<input name="pass$popcount" type="text" id="pass$popcount" value=~ . $password . qq~size="20" />~ . '|' .
		qq~<input name="quota$popcount" type="text" id="quota$popcount" value=~ . value("$mailquota_sized", "quota$popcount") . qq~size="6" /> MB~ . '|' .
		qq~$quotabalken~
		);
		
		logline("debug","change_popuser table_data user=$user");
		
		if($input{'domain'} eq $servername){
			$table_data->{$user}{'domain'} = $domain;
		} else {
			$table_data->{$user}{'domain'} = 'www.'.$domain;
		}
		
		$table_data->{$user}{'popcount'} = $popcount;
		$table_data->{$user}{"user"} = $user;
		$table_data->{$user}{"user_idn"} = encode('utf-8', email_to_unicode($user));
		$table_data->{$user}{"pass"} =  $password;
		$table_data->{$user}{"oldpass"} = $passwd{$user}{'dec'};
		#$table_data->{$user}{"quota"} = $fb ? $mailquota{$user}{'quota'} : $mailquota_sized;
		$table_data->{$user}{"quota"} = $input{"quota$popcount"} ? $input{"quota$popcount"} : $mailquota{$user}{'quota'} / 1024;
		
		$table_data->{$user}{'mailquota_used_sized'} = easytecc3::getsize($mailquota{$user}{'use'});
		$table_data->{$user}{'mailquota_used_percent'} = sprintf("%.0f", ($mailquota{$user}{'use'}/$mailquota{$user}{'quota'})*100) if $mailquota{$user}{'quota'} > 0;
		$table_data->{$user}{'alert_mailuser_quota'} = easytecc3::quota_alert($mailquota{$user}{'quota'}, $mailquota{$user}{'use'}, '.8');
		
		$table_data->{$user}{"error_class_user"} = error_class("user$popcount");
		$table_data->{$user}{"error_class_pass"} = error_class("pass$popcount");
		$table_data->{$user}{"error_class_quota"} = error_class("quota$popcount");		
		$table_data->{$user}{"error_text_user"} = qq~<span class="help-block">$error_fields{"user$popcount"}</span>~ if $error_fields{"user$popcount"};
		$table_data->{$user}{"error_text_pass"} = qq~<span class="help-block">$error_fields{"pass$popcount"}</span>~  if $error_fields{"pass$popcount"};
		$table_data->{$user}{"error_text_quota"} = qq~<span class="help-block">$error_fields{"quota$popcount"}</span>~  if $error_fields{"quota$popcount"};
		
		$table_data->{$user}{"error_text_quota"} = qq~<span class="help-block">$error_fields{"quota$popcount"}</span>~  if $error_fields{"quota$popcount"};
		
		$table_data->{$user}{'disabled'} = $disabled;
		$table_data->{$user}{'delete_disabled'} = $admin_delete_disabled;
		
		if(-x '/usr/iports/bin/imapsync' || -x '/usr/local/bin/imapsync'){
			
			$table_data->{$user}{'HAS_IMAPSYNC'} = '1';
			
			# imapsync running
			my $pidfile = "/tmp/imapsync-$user.pid";
			if(-f $pidfile){
			
				$table_data->{$user}{'IMPORT_RUNNING'} = '1';
			
			}
			
			my $logfile = "/tmp/imapsync-$user.log";
			if(-f $logfile){
			
				$table_data->{$user}{'IMPORT_DONE'} = '1';
				
				my $successfile = "/tmp/imapsync-$user.ok";
				if (! -f $successfile){
					
					$table_data->{$user}{'IMPORT_ERROR'} = '1';
					
				}
			
			
			}
			
						
		}
			
		my $easytecc_enable_file = "/usr/local/etc/easytecc/mailuser/$user";
					
		if(-e $easytecc_enable_file){
			$table_data->{$user}{'HAS_EASYTECC'} = '1';
			
			if(-e "/usr/local/etc/easytecc/2fa/$user"){
				
				$table_data->{$user}{'HAS_2FA'} = '1';
				
			}
			
		}
							
		my @keys = ('EMAILUSER',$user);
		my $note = note_from_hashfile(\@keys);
														
		if($note->{title}){
								
			$table_data->{$user}{'note_title'} = $note->{title};
			$table_data->{$user}{'note_text'} = $note->{text};
										
		}
		
		# fix perms
		`/usr/iports/bin/sudo /usr/sbin/chown.pl virtmail:vuser /home/$user`;
				
		$popcount++;
	}

	logline("debug","pop = " . $domains{$input{'domain'}}{'pop'});

	# leere Felder
	#bei freebsd dmr ist Anzahl von Emailusern 'for' da Emailuser gleichzeitig Emailadressen mit Weiterleitung auf den User sind
	#if ($fb) {
		#damit leere Felder auch auf freebsd angezeigt werden, nicht hüpsch aber egal
	#	$domains{$input{'domain'}}{'pop'} = $domains{$input{'domain'}}{'for'};
	#}
	
	
	my $add_empty_lines = `cat /usr/local/etc/easytecc/new_mail_lines 2>/dev/null`;
	chomp $add_empty_lines;
	if(!defined($add_empty_lines) || $add_empty_lines !~ m/^[0-9]+$/){
		
		$add_empty_lines = 5;
		
	}
	
	my $max_empty_lines = $popcount + $add_empty_lines;
	
	while($domains{$input{'domain'}}{'pop'} >= $popcount && $popcount < $max_empty_lines){
		push(@user, qq~<input type="hidden" name="old_user$popcount" value="" />
			<input  type="checkbox" name="delete$popcount" id="delete$popcount" value="" DISABLED />
			<input name="user$popcount" type="text" id="user$popcount" value=~ . value("", "user$popcount") . qq~size="20" />~ . '|' .
			qq~<input name="pass$popcount" type="text" id="pass$popcount" value=~ . value("", "pass$popcount") . qq~size="20" />~ . '|' .
			qq~<input name="quota$popcount" type="text" id="quota$popcount" value=~ . value("", "quota$popcount") . qq~size="6" /> MB~
		);
		
		my $user = 'zzz'.$popcount unless $input{"user$popcount"};
		$user = $input{"user$popcount"} if length($input{"user$popcount"});
		$table_data->{$user}{"newuser"} = 1;
		$table_data->{$user}{"user"} = encode('utf-8', $input{"user$popcount"});
		$table_data->{$user}{"user_idn"} = encode('utf-8', email_to_unicode($input{"user$popcount"}));
		$table_data->{$user}{"pass"} = encode('utf-8', $input{"pass$popcount"});
		
		$table_data->{$user}{"quota"} = encode('utf-8', $input{"quota$popcount"});
		
		$table_data->{$user}{"error_class_user"} = error_class("user$popcount");
		$table_data->{$user}{"error_class_pass"} = error_class("pass$popcount");
		$table_data->{$user}{"error_class_quota"} = error_class("quota$popcount");
		$table_data->{$user}{"error_text_user"} = qq~<span class="help-block">$error_fields{"user$popcount"}</span>~ if $error_fields{"user$popcount"};
		$table_data->{$user}{"error_text_pass"} = qq~<span class="help-block">$error_fields{"pass$popcount"}</span>~  if $error_fields{"pass$popcount"};
		$table_data->{$user}{"error_text_quota"} = qq~<span class="help-block">$error_fields{"quota$popcount"}</span>~  if $error_fields{"quota$popcount"};
		$table_data->{$user}{"popcount"} = $popcount;
		$table_data->{$user}{"disabled"} = $disabled;
		
		if($fb){
			$table_data->{$user}{"placeholder"} = encode('utf-8',email_to_unicode("adresse$popcount\@$domain"));
		} else {
			$table_data->{$user}{"placeholder"} = "benutzer$popcount";
		}	
		
		if($input{'domain'} eq $servername){
			$table_data->{$user}{'domain'} = $domain;
		} else {
			$table_data->{$user}{'domain'} = 'www.'.$domain;
		}
		
		$popcount++;
	}

	if(
	   $home_lookup{$domains{$input{'domain'}}{'droot'}} ne '' ||
	   $input{'domain'} eq $servername
	){
		my $ftpuser = $home_lookup{$domains{$input{'domain'}}{'droot'}};
		
		if($input{'domain'} eq $servername){
			$ftpuser = 'admin';
		}
				
		my $ftpquota = $quota{$ftpuser}{'quota'};
		my $ftpquota_sized = $ftpquota / 1024;
		my $ftpused = $quota{$ftpuser}{'use'};
		my $quotabalken = easytecc3::quotabar($ftpquota, $ftpused);
		logline("debug","change_pop mit ftp = $ftpuser");
		my @ftpuser = ($ftpuser . '|' . qq~<input type="hidden" NAME="ftpuser" value="$ftpuser" />
		<input type="hidden" name="old_ftpquota" value="$ftpquota_sized" />
		<input name="ftpquota" id="ftpquota" value=~ . value("$ftpquota_sized", "ftpquota") . qq~size="6" /> MB~);

		#easytecc3::table(\$template,'<td>L__FTP-User dieser Domain__L</td><td colspan="6">L__FTP-Quota__L</td>', \@ftpuser, 'table2');
		
		
		$template->param('ftpquota' => $ftpquota_sized);
		if($input{'domain'} eq $servername){
			$domains{$input{'domain'}}{'quota'} = $ftpquota_sized;
		}
	}


	easytecc3::table_e4($template, $table_data, 'table_tr_change_popuser_template.html');
	#easytecc3::table(\$template,'<td>L__Username__L</td><td>L__Passwort__L</td><td>L__E-Mail-Quota__L</td><td colspan="4">L__Quotanutzung__L</td>', \@user, 'table1');

	$template->param('domain' => $input{'domain'});
	$template->param('idn_domain' => encode('utf-8', domain_to_unicode($input{'domain'})));
	
	if($domains{$input{'domain'}}{'quota'}){
		
		my $mailquota;
				
		if($domain eq $servername){
			$mailquota = $quota{'admin'}{'quota'} / 1024;
		
		}
				
		else{
		
			$mailquota = $domains{$input{'domain'}}{'quota'};
				
			my $ftpdir = $domains{$input{'domain'}}{'droot'};
			while(length($ftpdir) && $ftpdir !~ /\/(data|noexec)$/){
					
				if(exists $home_lookup{$ftpdir}){
						
					my $ftpuser = $home_lookup{$ftpdir};
					$mailquota = (($domains{$input{'domain'}}{'quota'} * 1024 ) - $quota{$ftpuser}{'quota'}) / 1024;
					last;
						
				}
					
				$ftpdir =~ s/\/[^\/]*$//;
					
			}	
		
		}
		$template->param('quota' => $mailquota . ' MB');
	}

	$template->param('delete_disabled' => $admin_delete_disabled);
		
	logline("debug","change_pop action=$action input-action=" . $input{'action'});

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub show_single_edit_email{
change_forward();	
}

sub new_forward_single_edit{
change_forward();	
}

sub change_forward_single_edit{
change_forward();	
}

sub change_forward{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);

	#my $ref_fb = (caller(0))[3] . '_fb';
	#if(defined *$ref_fb{CODE}){return($ref_fb->(@args));}

	# lhs = left hand side
	# rhs = right hand side

	# weiterleitungen editieren:
	# in Freifeld Namen von Usern wenn mehrere Empfänger
	# Autoresponder anlegen/editieren/löschen
	# wenn Autoresponder, dann aus aliases Empfänger

	# Autoresponder löschen:
	# bein editieren von Weiterleitung
	# als Formularbutton beim editieren von Autoresponder

	# Autoresponderübersicht wie bisher auer anstatt Email-Copyempfänger
	# selectbox mit angelegten E-Mailadressen
	# beim editieren von Weiterleitungen anzeigen, ob Autoresponder angelegt + Link

	# in aliases ist lokaler user oder externe E-Mailadresse
	my $template = HTML::Template->new(filename => 'change_forward.html') if ($action eq 'change_forward' ||
																													 $action eq 'change_forward_single_edit' ||
																													 $action eq 'new_forward_single_edit');
	#same output expect selectboxes and non modal and all read only
	$template = HTML::Template->new(filename => 'show_single_edit_email.html') if $action eq 'show_single_edit_email';


	my $do_not_show_ascii_autoresponder = 0;
	if ( "$easytecc_custom_conf_entries{'ShowASCIIAutoresponder'}" eq "NO" ) {
		$do_not_show_ascii_autoresponder = 1;	
	}

	$template->param('do_not_show_ascii_autoresponder' => $do_not_show_ascii_autoresponder);


	my $email = '';
	my $forcount = '1';
	my $autcount = '';
	my @forward = ();
	my @popuser = ();
	my @popuser_idn = ();
	# hash zum schnelleren lokalisieren existierender pop3user
	my %popuser_lookup = undef;
	my $domain = $input{'domain'};
	$domain =~ s/^www\.//;

	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};

	return(error('L__Der Benutzer oder die Domain existiert nicht__L')) unless exists $domains{$input{'domain'}};
	#$error_fields{"non_specific"} .= "L__Der Benutzer oder die Domain existiert nicht__L"  unless exists $domains{$input{'domain'}};
	
	logline("debug","Creating File Object \$virtmaps.");
	my $virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
	$virtmaps->read_file;
	my %virtmaps = %{$virtmaps->file_parsed_hash()};

	logline("debug","Creating File Object \$aliases.");
	my $aliases = file->new({file_name => '/etc/mail/aliases'});
	$aliases->read_file;
	my %aliases = %{$aliases->file_parsed_hash()};


	$mailpasswd = easytecc3::get_mailpasswd();
	my %passwd = %{$mailpasswd->file_parsed_hash()};

	my $splitted_domains = join '|', @{$domains{$input{'domain'}}{'domains'}};
	$splitted_domains =~ s/\*/\\*/g;
	logline("debug","splitted_domains = $splitted_domains");

	my $show_vhost = '';
	my $disabled = '';
		
	if($session->param('user') eq 'admin'){
			
		$show_vhost = '1';
		$disabled = '';
	
	} else {

		my $passwd_ftp = file->new({file_name => '/etc/passwd'});
		$passwd_ftp->read_file;
		my %passwd_ftp = %{$passwd_ftp->file_parsed_hash()};
			
		my $gecos = $passwd_ftp{$session->param('user')}{'gecos'};	
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.vhost-1.email-1';
		
		}
		
		if($gecos =~ m/\.vhost/){
	
			$show_vhost = '1';
	
		}
	
		if($gecos !~ m/\.email-[1-9]/){
			
			$disabled = 'disabled';
				
		}
	
	}
	
	$template->param('show_vhost' => $show_vhost);
	$template->param('disabled' => $disabled);
	
	
	#%popuser_lookup enthält alle pop3user oder bei dmr emailadressen (welche gleichzeitig pop3user sind), die zu vhost gehören
	
	if ($fb) {
		foreach my $user(sort keys %passwd){
			next if $user !~ /@(?:$splitted_domains)$/;
			push @popuser, $user;
			push @popuser_idn, encode('utf-8', email_to_unicode($user));
			$popuser_lookup{$user} = '1';
			# fix perms
			`/usr/iports/bin/sudo /usr/sbin/chown.pl virtmail:vuser /home/$user`;
		}
	}
	else{
		foreach my $user(sort keys %passwd){
			next if $passwd{$user}{'gecos'} !~ /^$domain - POP/;
			push @popuser, $user;
			push @popuser_idn, $user;
			$popuser_lookup{$user} = '1';
		}
	}
		
	my @idn_domains = ();
		
	foreach(@{$domains{$input{'domain'}}{'domains'}}){
		logline("debug","foreach = $_");
		#wildcard nicht für Weiterleitung anbieten
		next if(/\*/);
		next if($_ eq $domain);
		#push @idn_domains, domain_to_unicode($_ . '|' . qq~value="$_"~;
		#push @idn_domains, $_;
		push @idn_domains, encode('utf-8', domain_to_unicode($_));
	}

	# wegen wildcard Domains
	@idn_domains = easytecc3::del_array_duplicates(@idn_domains);

	# hautpdomain zuerst
	unshift @idn_domains, encode('utf-8', domain_to_unicode($domain));
	
	foreach(keys %virtmaps){
		my $line = $_ . ' ' . $virtmaps{$_};
		#$line = quotemeta($line);
		logline("debug","line = $line");
		if($line =~  /@(?:$splitted_domains)(?: |\t)+[a-zA-Z_\.\-0-9]+[^_aut](.+)$/){
			logline("debug","match $1");
			if ($1 eq '_aut'){
				logline("debug","match aut");
				$autcount++;
			}
		}
	}

	my $table_data = {};
	foreach(sort keys %virtmaps){
		my $emailadress = $_;
		
		#wenn bei exec_change_forward_single_edit Fehler auftritt $input{'forward'} aus post-variablen erzeugen
		#aus exec_change_forward_single_edit wird html_error aufgerufen, welches change_forward_single_edit aufruft
		#bei single_edit ist es zwangsläufig Nr. 1:
		#<input name="old_user1" type="hidden" id="old_user1" value="userpart">
		#<input name="old_domain_select1" type="hidden" id="old_domain_select1" value="example.com">		
		if ($action eq 'change_forward_single_edit' && length($input{'old_domain_select1'})) {
			$input{'forward'} = $input{'old_user1'}  . '@' . $input{'old_domain_select1'};
		}
		
		#einzelne Emailadresse editieren
		if ($action eq 'change_forward_single_edit' && $emailadress ne $input{'forward'}) {
			next;
		}
		
		#einzelne Emailadresse neu anlegen auch über change_forward, wobei die vorhandenen Adressen nicht angezeigt werden sondern nur eine leere Zeile
		if ($action eq 'new_forward_single_edit') {
			next;
		}
				
		my $virtmaps_rhs = $virtmaps{$_};
		my $line = $emailadress . ' ' . $virtmaps_rhs;
		
		# Variable für vorausgewählten User, kann aus virtmaps oder aus aliases kommen
		#my $user_select = $virtmaps_rhs;
		my $user_select = '';
		logline("debug","virtmaps line = $line##");
		# freefield: da steht immer was drin, wenns an mehrere User geht
		my $freefield = '';
		#jeder Empfänger steht in eigenem Freifeld
		my %freefields;

		#if($line =~  /@(?:$splitted_domains)(?: |\t)+[a-zA-Z_\.\-0-9]+[^_aut|_spl](.+)$/){
		# (?!.*_aut|.*_spl) = negatives lookahead, gucken ob kein autoresponder oder Weiterleitung an mehrere Empfänger
		#if($line =~  /@(?:$splitted_domains)(?: |\t)+(?!.*_aut|.*_spl)([a-zA-Z_\.\-0-9]+)$/){
		if($line =~  /@(?:$splitted_domains)(?: |\t)+([a-zA-Z_\.\-0-9@]+)$/){
			my ($user,$domain) = split("@", $line);
			$domain =~ s/\s+.*$//;

			#einzelne Weiterleitung in virtmaps auf externe emailadresse oder bei dmr auf lokalen User
			if(is_email($virtmaps_rhs)){
				if ($fb) {
				#wenn Empfängerdomain zu vhost gehört, dann Vorauswahl in selectbox, ansonsten Freifeld,
				#auf diese Weise werden Emailaliase dargestellt
					#if ($virtmaps_rhs =~ /@(?:$splitted_domains)$/ && exists $popuser_lookup{$virtmaps_rhs}) {
					#	$user_select .=  "$virtmaps_rhs|";
					#}
					#else{
						$freefield = $virtmaps_rhs . ',';
						$freefields{$virtmaps_rhs} = 1;
					#}					
				}
				else{
				$freefield = $virtmaps_rhs . ',';
				$freefields{$virtmaps_rhs} = 1;
				$user_select = '';
				#wenn auf Nicht-DMR in virtmaps Weiterleitung an externe Emailadresse kann er keinen Autoresponder haben
				#da dieser immer über aliases angesteuert wird.
				#Icon zur Anlage von neuem Autoresponder zeigen
				
					if($disabled eq ''){
				
						$table_data->{$emailadress}{'new_autoreply'} = 1;
												
					}
				}
			}
			#wenn keine ext. emailadresse und kein lokaler POPuser, kein automreponder und keine Weiterleitung an mehrere user, dann z.B. papierkorb, dummy...
			#wegen spam
			elsif(! $popuser_lookup{$virtmaps_rhs} && $virtmaps_rhs !~ /(_aut|_spl)$/ && ! exists $aliases{$virtmaps_rhs}){
				logline("debug","virtmaps rhs dummy = " . $virtmaps_rhs . "###");
				$freefield = $virtmaps_rhs . ',';
				$freefields{$virtmaps_rhs} = 1;
				$user_select = '';
				if($disabled eq ''){
				
					$table_data->{$emailadress}{'new_autoreply'} = 1;
											
				}
			}
			elsif( ! $fb && $popuser_lookup{$virtmaps_rhs}){
			#nicht dmr, einzelne Weiterleitung auf lokalen user
				logline("debug","virtmaps rhs local user = " . $virtmaps_rhs . "###");
				$user_select .=  "$virtmaps_rhs|";
				#wenn auf Nicht-DMR in virtmaps Weiterleitung an lokalen User kann er keinen Autoresponder haben
				#da dieser immer über aliases angesteuert wird.
				#Icon zur Anlage von neuem Autoresponder zeigen
				
				if($disabled eq ''){
				
					$table_data->{$emailadress}{'new_autoreply'} = 1;
											
				}
				
			}

			my $autoresponder_icon = '';

			if ($domains{$input{'domain'}}{'aut'} >= 1 && $user && $domains{$input{'domain'}}{'aut'} > $autcount){
			# Icon für Autoresponder anlegen, aber nur wenn mindestens 1 autoresponde erlaubt und keine catchall-Weiterleitung
			$autoresponder_icon = qq~<a href="/cgi-bin/easytecc3/index.pl?action=new_autoreply&amp;forward=$_&amp;domain=$input{'domain'}">L__Neu__L</a>~;
			$table_data->{$emailadress}{'has_autoreply'} = 0;
			}
			
			# Sonderfälle Autoresponder und Weiterleitungen an mehrere User oder ext. E-Mailadressen. In diesem
			# Fall anstatt rhs aus virtmaps das Ziel aus aliases auslesen und anzeigen. Bei Autoresponder ein Icon, da Autoresponder angelegt
			# Autoresponder?
			if($virtmaps_rhs =~ /(_aut)$/){
				# Wenn Autoresponder vorhanden, dann 2 Icons: editieren, löschen
				$autoresponder_icon = qq~<a href="/cgi-bin/easytecc3/index.pl?action=change_autoreply&amp;forward=$_&amp;domain=$input{'domain'}">L__Editieren__L</a>&nbsp;&nbsp;&nbsp;~;
				$autoresponder_icon .= qq~<a href="/cgi-bin/easytecc3/index.pl?action=delete_autoreply&amp;forward=$_&amp;domain=$input{'domain'}">L__Löschen__L</a>~;

				#$table_data->{$emailadress}{'has_autoreply'} = 1;
				
				#logline("debug",qq~autoreply: virtmaps rhs=$virtmaps{$_}  aliases lhs $aliases{$virtmaps{$_} . ':'~);

				#rhs aus virtmaps ist lhs aus aliases
				if(exists $aliases{$virtmaps_rhs}){
					logline("debug","virtmaps = aliases match");

					# zur besseren Lesbarkeit temp. Variable
					my $aliases_target = $aliases{$virtmaps_rhs};
					logline("debug","aut alias target1 = $aliases_target");

					if ($aliases_target =~ /\/autoresponder/) {
						$table_data->{$emailadress}{'has_autoreply'} = 1;
					}
					else{
						if($disabled eq ''){
					
							$table_data->{$emailadress}{'new_autoreply'} = 1;	
							
						}
					}
					
					# Ziele sind durch Kommata getrennt
					my @aliases_target = split(',', $aliases_target);
					# normaler Autoresponder mit lokalem pop3user, diesen in select box vorauswählen
					if(exists $popuser_lookup{$aliases_target[0]} && $#aliases_target == 1){
						$user_select = $aliases_target[0];
						$freefield = '';
						logline("debug","aut alias match popuser $aliases_target");
					}
					elsif($#aliases_target >= 0 && length($aliases_target) > 0){
						logline("debug","aut alias aliases_target >= 1 $aliases_target");
						foreach my $aliases_target(@aliases_target){
							logline("debug","aut alias foreach $aliases_target");
							
							if ($aliases_target =~ /\/autoresponder/) {
							next;
							}
							
							logline("debug","spl alias target2 = $aliases_target");
							#trim whitespaces
							$aliases_target =~ s/^\s+//;
							$aliases_target =~ s/\s+$//;
							
							if (exists $popuser_lookup{$aliases_target}) {
								$user_select .= "$aliases_target|";
							}
							else{
								logline("debug","aut alias target2 = $aliases_target");
								$freefield .= $aliases_target . ', ' ;
								$freefields{$aliases_target} = 1;
							}
							
							#if (exists $popuser_lookup{$aliases_target}) {
							#	$user_select .= "$aliases_target|";
							#}
							#else{
							#	$freefield .= $aliases_target . ', ';
							#	$freefields{$aliases_target} = 1;
							#}
						}
						# kein vorausgewählter User wenn mehrere Empfänger
						#$user_select = '';
					}
					#else{
					#bei normalem Autoresponder ist erster Eintrag der Empfänger
					#$user_select = $aliases_target[0];
					#$freefield = '';
					#}
				}
			}
			#Weiterleitung an mehrere User?
			elsif($virtmaps_rhs =~ /_spl$/ || exists $aliases{$virtmaps_rhs}){
				#rhs aus virtmaps ist lhs aus aliases
				if(exists $aliases{$virtmaps_rhs}){
					logline("debug","virtmaps = aliases match");
					# Zeile aus aliases sieht so aus:
					# mails_wichtig_hostnet_de_spl: frank, admin
					# User rausziehen( können auch mehrere sein)

					# zur besseren Lesbarkeit temp. Variable
					my $aliases_target = $aliases{$virtmaps_rhs};
					
					if ($aliases_target =~ /\/autoresponder/) {
						$table_data->{$emailadress}{'has_autoreply'} = 1;
					}
					else{
					
						if($disabled eq ''){
				
							$table_data->{$emailadress}{'new_autoreply'} = 1;	
						
						}
										
					}

					# Ziele sind durch Kommata getrennt
					my @aliases_target = split(',', $aliases_target);

					foreach my $aliases_target(@aliases_target){
						#wenn Zeil lokaler pop3user oder bei dmr emailadresse ist welcher als User existiert,
						#dann in user select anzeigen. Mehrfachauswahl möglich. Zur Überprüfung gibt es %popuser_lookup
						
						if ($aliases_target =~ /\/autoresponder/) {
							next;
						}
						
						logline("debug","spl alias target2 = $aliases_target");
						#trim whitespaces
						$aliases_target =~ s/^\s+//;
						$aliases_target =~ s/\s+$//;
						
						my $alias_on_same_server = 0;
						
						#if ($fb) {
						#bei dmr sieht Zeile in aliases so aus:
						#test1_easytecc4.de_spl: "|/usr/iports/bin/procmail -a test1@easytecc4.de"
						#aliases_target ist "|/usr/iports/bin/procmail -a test1@easytecc4.de"
						#daraus die Empfängeremailadresse extrahieren
						#	if ($aliases_target =~ /^"\|\/usr\/iports\/bin\/procmail -a (.*)"$/) {
						#		$aliases_target = $1;
						#		$alias_on_same_server = 1;
						#		logline("debug","spl fb extracted alias target = $aliases_target");
						#	}						
						#}						
						
						if ($aliases_target =~ /fwd_as_att\s([^"]*)"/){
							$aliases_target = $1;
							
							foreach $aliases_target (split(/\s+/,$aliases_target)){
								
								if($aliases_target !~ /^\//){
									
									$freefield .= $aliases_target . ', ';
									$freefields{$aliases_target} = 1;
									logline("debug","spl fb extracted alias target = $aliases_target");
							
								}		
																
							}
																		
						}
						elsif ($aliases_target =~ /^"\|\/usr\/iports\/bin\/procmail -a (.*)"$/) {
							
							$aliases_target = $1;
							if(exists $popuser_lookup{$aliases_target}){
								
								$user_select .= "$aliases_target|";
								
							} else {
								
								push @popuser_idn, $aliases_target;
								$freefield .= $aliases_target . ', ';
								$freefields{$aliases_target} = 1;
								
							}
							
						}
						elsif ($aliases_target !~ /\@/ && exists $popuser_lookup{$aliases_target}) {
							
							$user_select .= "$aliases_target|";
						
						}
						else{
							$freefield .= $aliases_target . ', ';
							$freefields{$aliases_target} = 1;
													
						}
					}
				}
			}

			my $template_domain_select = HTML::Template->new(filename => 'domain_select.html');
			easytecc3::template_loop_e4(\%input,\$template_domain_select, \@idn_domains, "domain_select$forcount", $input{"domain_select$forcount"} ? encode('utf-8', domain_to_unicode($input{"domain_select$forcount"})) : encode('utf-8', domain_to_unicode($domain)));
			$template_domain_select->param('disabled' => $disabled);
			
			my $template_user_select = HTML::Template->new(filename => 'user_select.html');
						
			#bei change_forward kann man in selectbox mehrere User gleichzeitig selektieren, dies sind immer lokale User, beim alten
			#System pop3-user und bei dmr Emailadressen die immer gleichzeitig Emailuser sind.
			#Vorausgewählte User werden | separiert übergeben
			
			#angegebene auswahl behalten
			if(exists($input{"user_select$forcount"})){
							
				if(ord($input{"user_select$forcount"}) == '160'){
					$input{"user_select$forcount"} = '';
				}
	
				$user_select = join('|',split(/\x0/,$input{"user_select$forcount"}));
	
			}
			
			easytecc3::template_loop_e4(\%input,\$template_user_select, \@popuser_idn, "user_select$forcount", encode('utf-8', email_to_unicode($user_select)));
			$template_user_select->param('disabled' => $disabled);
			
			
			my $user_select_single_edit = $user_select;
			$user_select_single_edit =~ s/\|$//g;
			$user_select_single_edit =~ s/\|/<br>/g;
			
			my $freefields_single_edit = '';
			my @freefields;
			my $freefield_count = 1;
			my $topmargin = 0;
			foreach my $freefield(sort keys %freefields){
				logline("debug","foreach freefields key=$freefield forcount=$forcount freefield_count=$freefield_count value=".$input{'freefield'.$forcount.'_'.$freefield_count});
				my $old_freefield = $freefield;
				
				if (length $input{'freefield'.$forcount.'_'.$freefield_count}) {
					$freefield = $input{'freefield'.$forcount.'_'.$freefield_count};
				}
								
				push(@freefields,"$forcount|$freefield_count|$freefield|$topmargin|$old_freefield");
				$freefield_count++;
				$topmargin = 1;
				$freefields_single_edit .= $freefield . '<br>' if length($freefield);
			}
			
			foreach my $freefield(sort keys %input){
			next if $freefield ne 'freefield'.$forcount.'_'.$freefield_count;
			my $freefield_value = $input{$freefield};			
			push(@freefields,"$forcount|$freefield_count|" . $input{$freefield} . "|$topmargin");
			$freefield_count++;
			$topmargin = 1;
			}
			
			#wenn keine Inhalte für Freifeld vorhanden ein leeres anzeigen
			if(scalar @freefields == 0){
			push(@freefields,"$forcount|$freefield_count|||");	
			}
			
			my $template_change_forward_freefields = HTML::Template->new(filename => 'change_forward_freefields.html', global_vars => 1 );
			easytecc3::template_loop_e4(\%input,\$template_change_forward_freefields, \@freefields, "freefields");
			$template_change_forward_freefields->param('disabled' => $disabled);
				
			# read sieve
			$table_data->{$emailadress}{'emailuser'} = $emailadress;
			
			my ($forward_filter, $forward_to, $autoresponder_filter, $autoresponder_subject, $autoresponder_message) = read_sieve($emailadress);
			if(length($autoresponder_message)){
				
				$table_data->{$emailadress}{'has_autoreply'} = 1;
				$table_data->{$emailadress}{'new_autoreply'} = 0;
				
			} 
						
			#if(scalar @{$forward_to}){
			#	
			#	if(length($forward_to_list)){
			#			
			#		$forward_to_list .= "\n";
			#			
			#	}
			#	
			#	$forward_to_list .= join("\n",@{$forward_to});
			#	$forward_to_count += scalar @{$forward_to};
			#	
			#}	
						
			# freefield nur ausfllen, wenn Ziel kein regulrer pop3user der Domain ist. In %popuser_lookup befinden sich alle existierenden pop3user des vhosts
			# doch blödsinn, dann würde da _aut und _spl drinstehen
			# $freefield = $virtmaps{$_} unless exists $popuser_lookup{$user_select};

			my $forward_to_list = '';
			my $forward_to_count = 0;
			my $freefield;
			foreach $freefield (@freefields){
				
				$freefield =~ s/^[^\|]*\|[^\|]*\|//;
				$freefield =~ s/\|.*$//;
								
				if(length($freefield)){
					
					push(@{$forward_to}, $freefield);
					
					#if(length($forward_to_list)){
					#	
					#	$forward_to_list .= "\n";
					#	
					#}
					#
					#$forward_to_list .= $freefield;
					#$forward_to_count++;
					
				}
				
			}
									
			# unique
			@{$forward_to} = keys %{{ map { $_ => 1 } @{$forward_to} }};
			
			$forward_to_list = join("\n",@{$forward_to});
			$forward_to_count = scalar @{$forward_to};
			
			$table_data->{$emailadress}{'forward_to'} = $forward_to_list;
			$table_data->{$emailadress}{'forward_to_count'} = $forward_to_count;
			
			if(!$forward_to_count){
			
				$table_data->{$emailadress}{'new_forward'} = 1;
				
			}
			
			$table_data->{$emailadress}{'can_delete'} = 1;
						
			logline("debug","freefield3 = $freefield; input-freefield3 = " . $input{'freefield3'});
			
			
			$table_data->{$emailadress}{'domain'} = $input{'domain'};
			$table_data->{$emailadress}{'emailadress'} = $emailadress;
			
			if(exists($input{"user$forcount"})){
				
				$table_data->{$emailadress}{'user'} = $input{"user$forcount"}
						
			} else {
				
				$table_data->{$emailadress}{'user'} = $user;
				
			}
						
			$table_data->{$emailadress}{'old_user'} = $user;
			$table_data->{$emailadress}{'old_domain_select'} = $domain;
			$table_data->{$emailadress}{'old_user_select'} = $user_select;
			#$table_data->{$emailadress}{'old_freefield'} = $freefield;
			$table_data->{$emailadress}{'forcount'} = $forcount;
			#$table_data->{$emailadress}{'freefield'} = $input{"freefield$forcount"} ? $input{"freefield$forcount"} : $freefield;
			$table_data->{$emailadress}{'domain_select'} = $template_domain_select->output if ($action eq 'change_forward' || $action eq 'change_forward_single_edit');
			$table_data->{$emailadress}{'domain_select'} = encode('utf-8', domain_to_unicode($domain)) if $action eq 'show_single_edit_email';
			$table_data->{$emailadress}{'user_select'} = $template_user_select->output if ($action eq 'change_forward' || $action eq 'change_forward_single_edit');
			$table_data->{$emailadress}{'user_select'} = $user_select_single_edit if $action eq 'show_single_edit_email';
			$table_data->{$emailadress}{"error_class_domain_select"} = error_class("domain_select$forcount");
			$table_data->{$emailadress}{'freefields'} = $template_change_forward_freefields->output if ($action eq 'change_forward' || $action eq 'change_forward_single_edit');
			$table_data->{$emailadress}{'freefields'} = $freefields_single_edit if $action eq 'show_single_edit_email';
			$table_data->{$emailadress}{'edit_email_icons'} = 1 if $action eq 'show_single_edit_email';
			$table_data->{$emailadress}{'email_type'} = $input{'email_type'};
			$table_data->{$emailadress}{"error_class_user"} = error_class("user$forcount");		
			$table_data->{$emailadress}{"error_text_user"} = qq~<span class="help-block">$error_fields{"user$forcount"}</span>~ if $error_fields{"user$forcount"};
			$table_data->{$emailadress}{'disabled'} = $disabled;
			$table_data->{$emailadress}{'do_not_show_ascii_autoresponder'} = $do_not_show_ascii_autoresponder;
			
			my @keys = ('EMAILADDRESS',$emailadress);
			my $note = note_from_hashfile(\@keys);
															
			if($note->{title}){
									
				$table_data->{$emailadress}{'note_title'} = $note->{title};
				$table_data->{$emailadress}{'note_text'} = $note->{text};
											
			}
			
			$forcount++;
		}
	}

	# Icon für Autoresponder anlegen gibs nicht bei leeren Zeilen
	my $autoresponder_icon = '';

	my $add_empty_lines = `cat /usr/local/etc/easytecc/new_mail_lines 2>/dev/null`;
	chomp $add_empty_lines;
	if(!defined($add_empty_lines) || $add_empty_lines !~ m/^[0-9]+$/){
		
		$add_empty_lines = 5;
		
	}
		
	my $max_empty_lines = $forcount + $add_empty_lines;
	
	# leere Felder
	while($domains{$input{'domain'}}{'for'} >= $forcount && $forcount < $max_empty_lines && ($action  eq 'change_forward' || $action eq 'new_forward_single_edit')){
				
		my $template_domain_select = HTML::Template->new(filename => 'domain_select.html');
		#easytecc3::template_loop(\%input,\$template_domain_select, \@idn_domains, "domain_select$forcount", domain_to_unicode($input{"domain_select$forcount"}) . '|' . qq~value="$input{"domain_select$forcount"}"~) if exists $input{"domain_select$forcount"};
		#easytecc3::template_loop(\%input,\$template_domain_select, \@idn_domains, "domain_select$forcount", '') unless exists $input{"domain_select$forcount"};
		$template_domain_select->param('disabled' => $disabled);
		easytecc3::template_loop_e4(\%input,\$template_domain_select, \@idn_domains, "domain_select$forcount", $input{"domain_select$forcount"} ? $input{"domain_select$forcount"} : '');
		
		
		my $template_user_select = HTML::Template->new(filename => 'user_select.html');
		#easytecc3::template_loop(\%input,\$template_user_select, \@popuser, "user_select$forcount", $input{"user_select$forcount"}) if exists $input{"user_select$forcount"};
		#easytecc3::template_loop(\%input,\$template_user_select, \@popuser, "user_select$forcount", '') unless exists $input{"user_select$forcount"};
		$template_user_select->param('disabled' => $disabled);
		easytecc3::template_loop_e4(\%input,\$template_user_select, \@popuser_idn, "user_select$forcount", $input{"user_select$forcount"} ? $input{"user_select$forcount"} : '');
		
		
		undef @freefields;
		my %new_freefields;
		my $freefield_count = 1;
		my $topmargin = 0;
		foreach my $freefield(sort keys %input){
			my $regex = '^freefield'.$forcount.'_';
			next if $freefield !~ /$regex/;
			my $freefield_value = $input{$freefield};			
			$new_freefields{$freefield} = $input{$freefield};
			push(@freefields,"$forcount|$freefield_count|" . $input{$freefield} . "|$topmargin");
			$freefield_count++;
			$topmargin = 1;
		}
		
		
		
		#immer ein leeres feld anzeigen
		if (scalar @freefields < 1) {
			push(@freefields,"$forcount|$freefield_count||");
		}
		
		my $template_change_forward_freefields = HTML::Template->new(filename => 'change_forward_freefields.html', global_vars => 1);
		easytecc3::template_loop_e4(\%input,\$template_change_forward_freefields, \@freefields, "freefields");
		$template_change_forward_freefields->param('disabled' => $disabled);
				
		if(length($input{"user$forcount"}) && length($input{'domain'})){
			
			$emailadress = $input{"user$forcount"} . '@' . $input{'domain'};
#			$table_data->{$emailadress}{'newrow'} = 1;
#			$table_data->{$emailadress}{'new_forward'} = 1;
#			$table_data->{$emailadress}{'new_autoreply'} = 1;
						
		} else {
							
			$emailadress = 'zzz'.$forcount unless length($input{"user$forcount"});
			
		}
		
		$table_data->{$emailadress}{'new_forward'} = 1;
		$table_data->{$emailadress}{'new_autoreply'} = 1;
		
				
		$table_data->{$emailadress}{"error_class_user"} = error_class("user$forcount");
		#$table_data->{$emailadress}{"error_text_user"} = $error_fields{"user$forcount"};
		$table_data->{$emailadress}{"error_text_user"} = qq~<span class="help-block">$error_fields{"user$forcount"}</span>~ if $error_fields{"user$forcount"};
		$table_data->{$emailadress}{"error_class_freefield"} = error_class("freefield$forcount");
		
		$table_data->{$emailadress}{'user'} = $input{"user$forcount"};
		#$table_data->{$emailadress}{'old_domain_select'} = $domain;
		#$table_data->{$emailadress}{'old_user_select'} = $user_select;
		$table_data->{$emailadress}{'forcount'} = $forcount;
		#$table_data->{$emailadress}{'freefield'} = $input{"freefield$forcount"};
		$table_data->{$emailadress}{'freefields'} = $template_change_forward_freefields->output;
		$table_data->{$emailadress}{'domain_select'} = $template_domain_select->output;
		$table_data->{$emailadress}{'user_select'} = $template_user_select->output;
		$table_data->{$emailadress}{"error_class_domain_select"} = error_class("domain_select$forcount");
		$table_data->{$emailadress}{'domain'} = $input{'domain'};
		$table_data->{$emailadress}{'email_type'} = $input{'email_type'};
		#$table_data->{$user}{"error_class_user"} = error_class("user$forcount");		
		#$table_data->{$user}{"error_text_user"} = qq~<span class="help-block">$error_fields{"user$forcount"}</span>~ if $error_fields{"user$forcount"};
		$table_data->{$emailadress}{'disabled'} = $disabled;
		$table_data->{$emailadress}{'do_not_show_ascii_autoresponder'} = $do_not_show_ascii_autoresponder;
		$table_data->{$emailadress}{'newrow'} = 1;
		
		$forcount++;
		
		if ($action eq 'new_forward_single_edit') {
			$table_data->{$emailadress}{'newuser'} = 1;
			last;
		}		
	}
	
	if($action eq 'new_forward_single_edit'){
	
		$template->param('newuser' => 1);
			
	}
	
	
	easytecc3::table_e4($template, $table_data, 'table_tr_change_forward_template.html') if ($action eq 'change_forward' ||
																							 $action eq 'change_forward_single_edit' ||
																							 $action eq 'new_forward_single_edit');
	easytecc3::table_e4($template, $table_data, 'table_tr_show_single_edit_email_template.html') if $action eq 'show_single_edit_email';

	$template->param('action' => 'exec_' . $input{'action'});
	$template->param('domain' => $input{'domain'});
	$template->param('idn_domain' => encode('utf-8', domain_to_unicode($input{'domain'})));
	$template->param('email_type' => $input{'email_type'});

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub new_autoreply{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'new_autoreply.html');

	my $forward = $input{'forward'};
	my $idn_forward = $input{'forward'};
	#catchall, hat nix vor dem @. Domain für Anzeigein idn umwandeln
	if($idn_forward =~ /^@(.*)$/){
		$idn_forward = '@' . encode('utf-8', domain_to_unicode($1));
	}
	else{
		$idn_forward = email_to_unicode($idn_forward);
	}

	$template->param('forward' => $forward);
	$template->param('idn_forward' => $idn_forward);
	$template->param('domain' => $input{'domain'});
	$template->param('email_type' => $input{'email_type'});
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub change_autoreply{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'change_autoreply.html');

	my $autoreply = '';
	my $autoreply_subject = '';
	my $autoreply_text = '';
	my $forward = $input{'forward'};
	my $forward_aliases = $forward;
	$forward_aliases =~ s/(@|\.)/_/g;
	my $domain = $forward;
	$domain =~ s/^(.*)\@//;
	my $user = $1;

	# es gibt autoresponderdateien wo domainname mit _ oder mit. existiert:
	# c.blubb_domainshooter.at.aut
	# k.seifert_steiner_de.aut
	my $domain_reverse = reverse($domain);
	# umdrehen, den ersten _ gegen . ersetzen und dann einfach gucken was vorhanden ist, das lassen wir auch so, sonst muss beim ändern von autoresponder
	# immder die aliases ggf. geändert werden..., viel zu kompliziert
	$domain_reverse =~ s/\./_/;
	$domain_reverse = reverse($domain_reverse);

	my $idn_forward = $input{'forward'};
	# catchall, hat nix vor dem @. Domain für Anzeigein idn umwandeln
	if($idn_forward =~ /^@(.*)$/){
		$idn_forward = '@' . encode('utf-8', domain_to_unicode($1));
	}
	else{
		$idn_forward = email_to_unicode($idn_forward);
	}

	logline("debug","forward_aliases=$forward_aliases");

	if(-e '/usr/local/etc/' . $forward_aliases . '.aut'){	
	$autoreply = file->new({file_name => '/usr/local/etc/' . $forward_aliases . '.aut'});
	$autoreply->read_file;
	}
	elsif(-e '/usr/local/etc/' . $user . '_' . $domain . '.aut'){
		$autoreply = file->new({file_name => '/usr/local/etc/' . $user . '_' . $domain . '.aut'});
		$autoreply->read_file;
	}
	elsif(-e '/usr/local/etc/' . $user . '_' . $domain_reverse . '.aut'){
		$autoreply = file->new({file_name => '/usr/local/etc/' . $user . '_' . $domain_reverse . '.aut'});
		$autoreply->read_file;
	}
	elsif(-e '/usr/local/etc/easytecc/' . $forward_aliases . '.aut'){	
		$autoreply = file->new({file_name => '/usr/local/etc/easytecc/' . $forward_aliases . '.aut'});
		$autoreply->read_file;
	}
	elsif(-e '/usr/local/etc/easytecc/' . $user . '_' . $domain . '.aut'){
		$autoreply = file->new({file_name => '/usr/local/etc/easytecc/' . $user . '_' . $domain . '.aut'});
		$autoreply->read_file;
	}
	elsif(-e '/usr/local/etc/easytecc/' . $user . '_' . $domain_reverse . '.aut'){
		$autoreply = file->new({file_name => '/usr/local/etc/easytecc/' . $user . '_' . $domain_reverse . '.aut'});
		$autoreply->read_file;
	}
	else{
		return(html_error({'non_specific' => 'L__Kann Autoresponderdatei nicht öffnen__L',
						   'template' => \$template}));
	}

	
	if (defined $autoreply) {		
		foreach($autoreply->file_content){
			if(/^Subject: /){
				$autoreply_subject = $_;
				$autoreply_subject =~ s/^Subject: //;
			}
			elsif(/^From: /){
	
			}
			else {
				$autoreply_text .= $_;
			}
		}
	}

	$template->param('forward' => $forward);
	$template->param('idn_forward' => $idn_forward);
	$template->param('autoreply_subject' => encode("utf-8", $autoreply_subject));
	$template->param('autoreply_text' => encode("utf-8", $autoreply_text));
	$template->param('domain' => $input{'domain'});
	$template->param('email_type' => $input{'email_type'});
	$template->param('disabled' => $input{'disabled'});

	logline("debug","<<< Leaving ".(caller(0))[3]."().");  
	return(\$template);
}

sub delete_autoreply{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'delete_autoreply.html');

	my $forward = $input{'forward'};

	$template->param('forward' => $forward);
	$template->param('forward_idn' => email_to_unicode($forward));
	$template->param('domain' => $input{'domain'});
	$template->param('email_type' => $input{'email_type'});
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub new_ftpuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'new_ftpuser.html');
	
	if(defined easytecc3::is_ftp_limited()){
		$template = HTML::Template->new(filename => 'option_not_available.html');
	} else {
	
		my $default_home = '';
		
		if($session->param('user') ne 'admin'){
		
			my $passwd = file->new({file_name => '/etc/passwd'});
			$passwd->read_file;
			my %passwd = %{$passwd->file_parsed_hash()};

			$default_home = $passwd{$session->param('user')}{'home'};
			
		} else {
		
			if($fb){
		
				$default_home = '/usr/local/www/apache24/noexec';
				
			} else {
			
				$default_home = '/home/httpd/docs';
				
			}
		
		}
		
		$default_home .= '/benutzer';	
		$template->param('default_home' => $default_home);
		
		my $default_home_rows = sprintf("%.0f", length($default_home) / 35 + 0.5);
		$template->param('default_home_rows' => $default_home_rows);
			
	}
		
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub new_adminuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'new_adminuser.html');
	
	if(defined easytecc3::is_ftp_limited() || $session->param('user') ne 'admin'){
		$template = HTML::Template->new(filename => 'option_not_available.html');
	} else {
	
		my $default_home = '';
		
		if($fb){
		
			$default_home = '/usr/local/www/apache24/noexec';
				
		} else {
			
			$default_home = '/home/httpd/docs';
				
		}
		
		$default_home .= '/benutzer';	
		$template->param('default_home' => $default_home);
		
		my $default_home_rows = sprintf("%.0f", length($default_home) / 35 + 0.5);
		$template->param('default_home_rows' => $default_home_rows);
			
	}

	if(!$validation_result){
	
		my $gecos = 'CUST.vhost.email-1.ftp.quota.spam.fileman-1.logs-1.db-1.cron-2.inst';
		 
		if($gecos =~ m/\.vhost/){
		
			$template->param('checked_show_vhosts' => 'CHECKED');
	
			if($gecos =~ m/\.vhost-[1-9]/){
		
				$template->param('checked_new_vhosts' => 'CHECKED');
			
			}
		
		}		
		
		if($gecos =~ m/\.email/){
		
			$template->param('checked_show_email' => 'CHECKED');
		
			if($gecos =~ m/\.email-[1-9]/){
			
				$template->param('checked_edit_email' => 'CHECKED');
				
			}
		
		}
		
		if($gecos =~ m/\.ftp/){
		
			$template->param('checked_show_ftp' => 'CHECKED');
		
			if($gecos =~ m/\.ftp-[1-9]/){
			
				$template->param('checked_edit_ftp' => 'CHECKED');
				
			}
		
			if($gecos =~ m/\.ftp-2/){
						
				$template->param('checked_new_ftp' => 'CHECKED');
				
			}
		
		}	
			
		if($gecos =~ m/\.quota/){
		
			$template->param('checked_show_quota' => 'CHECKED');
			
		}	
		
		if($gecos =~ m/\.spam/){
		
			$template->param('checked_show_spam' => 'CHECKED');
			
		}	
			
		if($gecos =~ m/\.fileman/){
		
			$template->param('checked_show_fileman' => 'CHECKED');
		
			if($gecos =~ m/\.fileman-1/){
			
				$template->param('checked_edit_fileman' => 'CHECKED');
				
			}
			
		}		
			
		if($gecos =~ m/\.logs/){
		
			$template->param('checked_show_logs' => 'CHECKED');
		
			if($gecos =~ m/\.logs-1/){
			
				$template->param('checked_edit_logs' => 'CHECKED');
				
			}
			
		}			
		
		
		if($gecos =~ m/\.db/){
		
			$template->param('checked_show_db' => 'CHECKED');
		
			if($gecos =~ m/\.db-[1-9]/){
			
				$template->param('checked_edit_db' => 'CHECKED');
				
			}
		
			if($gecos =~ m/\.db-2/){
						
				$template->param('checked_new_db' => 'CHECKED');
				
			}
		
		}
		
		if($gecos =~ m/\.cron/){
		
			$template->param('checked_show_cron' => 'CHECKED');
		
			if($gecos =~ m/\.cron-[1-9]/){
			
				$template->param('checked_edit_cron' => 'CHECKED');
				
			}
		
			if($gecos =~ m/\.cron-2/){
						
				$template->param('checked_new_cron' => 'CHECKED');
				
			}
		
		}	
			
		if($gecos =~ m/\.inst/){
		
			$template->param('checked_show_inst' => 'CHECKED');
			
		}

	}	
		
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub change_ftpuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'change_ftpuser.html');
	my $domain = '';

	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};

	# Domains und deren document roots in Hash und dann mit home-Verzeuchnis des FTP-Users vergleichen
	my %domain_home;
	foreach(keys %domains){
		$domain_home{$domains{$_}{'droot'}} = $domains{$_}{'domain'};
	}
	
	logline("debug","Creating File Object \$passwd.");
	my $passwd = file->new({file_name => '/etc/passwd'});
	$passwd->read_file;
	my %passwd = %{$passwd->file_parsed_hash()};

	my ($quotaref, $sum_ftplimit, $sum_ftpuse, $ftpserverlimit) = easytecc3::getquota_ftp();
	my %quota = %$quotaref;
	my $ftpuser = $input{'ftpuser'};
	my $ftpquota = $quota{$ftpuser}{'quota'};
	my $ftpquota_sized = easytecc3::getsize($ftpquota);
	my $ftpused = $quota{$ftpuser}{'use'};
	my $quotabalken = easytecc3::quotabar($ftpquota, $ftpused, 'MB_form');

	if(exists $domain_home{$passwd{$ftpuser}{'home'}}){
		#$domain = @{$domain_home{$passwd{$ftpuser}{'home'}}};
		$domain = join '<br />', @{$domain_home{$passwd{$ftpuser}{'home'}}};
		logline("debug","exist home: $domain " . @{$domain_home{$passwd{$ftpuser}{'home'}}});
		$template->param('domain' => $domain_home{$passwd{$ftpuser}{'home'}});
		$template->param('idn_domain' => encode('utf-8', domain_to_unicode($domain_home{$passwd{$ftpuser}{'home'}})));
		$template->param('quota' => $domains{$domain_home{$passwd{$ftpuser}{'home'}}}{'quota'} . ' MB');
	}
	
	if ($passwd{$ftpuser}{'shell'} eq '/usr/sbin/nologin' || $ftpuser =~ /^(admin|cyrus|dovecot|dovenull|mysql|pgsql|virtmail|web)$/) {
		$template->param('system_user' => 1);	
	}
	
	if ($passwd{$ftpuser}{'shell'} eq '/usr/sbin/nologin' ||
		$passwd{$ftpuser}{'shell'} eq '/bin/false' ||
		$passwd{$ftpuser}{'shell'} eq '/sbin/nologin' ||
		$passwd{$ftpuser}{'shell'} eq '/nonexistent' ||
		$ftpuser eq 'web') {
		$template->param('no_password' => 1);	
	}
	

	$template->param('ftpuser' => $ftpuser);
	$template->param('gecos' => $passwd{$ftpuser}{'gecos'});
	# immer in MB angeben
	$template->param('ftpquota' => $ftpquota / 1024);
	$template->param('home' => $passwd{$ftpuser}{'home'});
	$template->param('ftpquota_used_percent' => $quota{$ftpuser}{'use'} > 0 ? sprintf("%.0f",($quota{$ftpuser}{'use'} / $quota{$ftpuser}{'quota'}) * 100) : '0');
	$template->param('alert_ftpuser_quota' => easytecc3::quota_alert($quota{$ftpuser}{'quota'}, $quota{$ftpuser}{'use'}, '.8'));
	
	if($passwd{$ftpuser}{'gecos'} =~ m/^CUST/){
		$template->param('hide_gecos' => '1');
	}
	
	if($session->param('user') eq 'admin'){
		$template->param('show_vhost' => '1');
		$template->param('disabled' => '');
		
		
		
	} else {

		my $gecos = $passwd{$session->param('user')}{'gecos'};	
		
		my $gecos = $passwd{$session->param('user')}{'gecos'};

		if($gecos !~ m/^CUST/){
			$gecos = 'CUST.vhost-1.ftp-1';
		}	
		if($gecos =~ m/\.vhost/){
			$template->param('show_vhost' => '1');
			
		}
		
		$template->param('disabled' => 'disabled');
		$template->param('no_password' => 1);
		$template->param('no_quota' => 1);
		$template->param('no_home' => 1);
				
		if($gecos =~ m/\.ftp/){
			$template->param('disabled' => '');
		}
		if($gecos =~ m/\.ftp-1/){
			$template->param('no_password' => '');
			
		}
		if($gecos =~ m/\.ftp-2/){
			$template->param('no_password' => '');
			$template->param('no_quota' => '');
		}
		
		if($session->param('user') ne $ftpuser){
			$template->param('no_home' => '');
		}
				
	}
	
	# 2fa
	if($session->param('user') eq $ftpuser){
	
		$template->param('2fa_possible' => 1);
		
		# 2fa setup
		if(-f "/usr/local/etc/easytecc/2fa/$ftpuser.setup"){
		
			$template->param('2fa_setup' => 1);
			$qrcode_url = 'data:image/png;base64,' . `cat /usr/local/etc/easytecc/2fa/$ftpuser.qr`;
			$template->param('qrcode_url' => $qrcode_url);
		
		}
			
	}
		
	# 2fa present
	if(-f "/usr/local/etc/easytecc/2fa/$ftpuser"){
		
		$template->param('2fa_active' => 1);
				
	}
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub change_adminuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'change_adminuser.html');
	my $domain = '';

	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};

	my %allowed_domains;
	
	foreach my $domain (keys %domains){

		my $admins = $domains{$domain}{'admin_users'};
		$admins =~ s/[\s,]+/#/g;
		$admins = '#' . $admins . '#';
		$userregex = '#' . $input{'ftpuser'} . '#';
		
		logline("debug","admins:$admins\nuserregex:$userregex");
		
		if($admins !~ m/$userregex/i){
			next;
		}
	
		foreach my $alias_domain (@{$domains{$domain}{'domains'}}){
				
			$alias_domain =~ s/^www\.//;
			$alias_domain =~ s/^\*\.//;
			$alias_domain = encode('utf-8', domain_to_unicode($alias_domain));	
			
			$allowed_domains{$alias_domain} = 1;
		
		}
		
	}

	logline("debug","Creating File Object \$passwd.");
	my $passwd = file->new({file_name => '/etc/passwd'});
	$passwd->read_file;
	my %passwd = %{$passwd->file_parsed_hash()};
	my $ftpuser = $input{'ftpuser'};
	
	
	my $admin_domains = join(', ',(sort keys %allowed_domains));
	$template->param('admin_domains' => $admin_domains);
				
	my $gecos = $passwd{$ftpuser}{'gecos'};	
		
	if($gecos !~ m/^CUST/){

		$gecos = 'CUST.vhost-1.email-1.ftp-2.quota.spam.fileman-1.logs-1.db-2.cron-2.inst';
		$template->param('ftp_to_admin' => 1);
		
	}
	
	if($gecos =~ m/\.vhost/){
	
		$template->param('checked_show_vhosts' => 'CHECKED');
	
		if($gecos =~ m/\.vhost-[1-9]/){
		
			$template->param('checked_new_vhosts' => 'CHECKED');
			
		}
		
	}
	
	if($gecos =~ m/\.email/){
	
		$template->param('checked_show_email' => 'CHECKED');
	
		if($gecos =~ m/\.email-[1-9]/){
		
			$template->param('checked_edit_email' => 'CHECKED');
			
		}
	
	}
	
	if($gecos =~ m/\.ftp/){
	
		$template->param('checked_show_ftp' => 'CHECKED');
	
		if($gecos =~ m/\.ftp-[1-9]/){
		
			$template->param('checked_edit_ftp' => 'CHECKED');
			
		}
	
		if($gecos =~ m/\.ftp-2/){
					
			$template->param('checked_new_ftp' => 'CHECKED');
			
		}
	
	}	
		
	if($gecos =~ m/\.quota/){
	
		$template->param('checked_show_quota' => 'CHECKED');
		
	}	
	
	if($gecos =~ m/\.spam/){
	
		$template->param('checked_show_spam' => 'CHECKED');
		
	}	
		
	if($gecos =~ m/\.fileman/){
	
		$template->param('checked_show_fileman' => 'CHECKED');
	
		if($gecos =~ m/\.fileman-1/){
		
			$template->param('checked_edit_fileman' => 'CHECKED');
			
		}
		
	}		
		
	if($gecos =~ m/\.logs/){
	
		$template->param('checked_show_logs' => 'CHECKED');
	
		if($gecos =~ m/\.logs-1/){
		
			$template->param('checked_edit_logs' => 'CHECKED');
			
		}
		
	}			
	
	
	if($gecos =~ m/\.db/){
	
		$template->param('checked_show_db' => 'CHECKED');
	
		if($gecos =~ m/\.db-[1-9]/){
		
			$template->param('checked_edit_db' => 'CHECKED');
			
		}
	
		if($gecos =~ m/\.db-2/){
					
			$template->param('checked_new_db' => 'CHECKED');
			
		}
	
	}
	
	if($gecos =~ m/\.cron/){
	
		$template->param('checked_show_cron' => 'CHECKED');
	
		if($gecos =~ m/\.cron-[1-9]/){
		
			$template->param('checked_edit_cron' => 'CHECKED');
			
		}
	
		if($gecos =~ m/\.cron-2/){
					
			$template->param('checked_new_cron' => 'CHECKED');
			
		}
	
	}	
		
	if($gecos =~ m/\.inst/){
	
		$template->param('checked_show_inst' => 'CHECKED');
		
	}		
		
	# Domains und deren document roots in Hash und dann mit home-Verzeuchnis des FTP-Users vergleichen
	my %domain_home;
	foreach(keys %domains){
		$domain_home{$domains{$_}{'droot'}} = $domains{$_}{'domain'};
	}

	logline("debug","Creating File Object \$passwd.");
	my $passwd = file->new({file_name => '/etc/passwd'});
	$passwd->read_file;
	my %passwd = %{$passwd->file_parsed_hash()};

	my ($quotaref, $sum_ftplimit, $sum_ftpuse, $ftpserverlimit) = easytecc3::getquota_ftp();
	my %quota = %$quotaref;
	my $ftpuser = $input{'ftpuser'};
	my $ftpquota = $quota{$ftpuser}{'quota'};
	my $ftpquota_sized = easytecc3::getsize($ftpquota);
	my $ftpused = $quota{$ftpuser}{'use'};
	my $quotabalken = easytecc3::quotabar($ftpquota, $ftpused, 'MB_form');

	if(exists $domain_home{$passwd{$ftpuser}{'home'}}){
		#$domain = @{$domain_home{$passwd{$ftpuser}{'home'}}};
		$domain = join '<br />', @{$domain_home{$passwd{$ftpuser}{'home'}}};
		logline("debug","exist home: $domain " . @{$domain_home{$passwd{$ftpuser}{'home'}}});
		$template->param('admin_domains' => $domain_home{$passwd{$ftpuser}{'home'}});
		$template->param('idn_domain' => encode('utf-8', domain_to_unicode($domain_home{$passwd{$ftpuser}{'home'}})));
		$template->param('quota' => $domains{$domain_home{$passwd{$ftpuser}{'home'}}}{'quota'} . ' MB');
	}
	
	if ($passwd{$ftpuser}{'shell'} eq '/usr/sbin/nologin' || $ftpuser =~ /^(admin|cyrus|dovecot|dovenull|mysql|pgsql|virtmail|web)$/) {
		$template->param('system_user' => 1);	
	}
	
	if ($passwd{$ftpuser}{'shell'} eq '/usr/sbin/nologin' ||
		$passwd{$ftpuser}{'shell'} eq '/bin/false' ||
		$passwd{$ftpuser}{'shell'} eq '/sbin/nologin' ||
		$passwd{$ftpuser}{'shell'} eq '/nonexistent' ||
		$ftpuser eq 'web') {
		$template->param('no_password' => 1);	
	}
	

	$template->param('ftpuser' => $ftpuser);
	$template->param('gecos' => $passwd{$ftpuser}{'gecos'});
	# immer in MB angeben
	$template->param('ftpquota' => $ftpquota / 1024);
	$template->param('home' => $passwd{$ftpuser}{'home'});
	$template->param('ftpquota_used_percent' => $quota{$ftpuser}{'use'} > 0 ? sprintf("%.0f",($quota{$ftpuser}{'use'} / $quota{$ftpuser}{'quota'}) * 100) : '0');
	$template->param('alert_ftpuser_quota' => easytecc3::quota_alert($quota{$ftpuser}{'quota'}, $quota{$ftpuser}{'use'}, '.8'));

	# 2fa present
	if(-f "/usr/local/etc/easytecc/2fa/$ftpuser"){
		
		$template->param('2fa_active' => 1);
				
	}
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub delete_ftpuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'delete_ftpuser.html');

	logline("debug","Creating File Object \$passwd.");
	my $passwd = file->new({file_name => '/etc/passwd'});
	$passwd->read_file;
	my %passwd = %{$passwd->file_parsed_hash()};

	my $ftpuser = $input{'ftpuser'};
	$template->param('ftpuser' => $ftpuser);

	$template->param('home' => $passwd{$ftpuser}{'home'});
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub delete_adminuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'delete_adminuser.html');

	logline("debug","Creating File Object \$passwd.");
	my $passwd = file->new({file_name => '/etc/passwd'});
	$passwd->read_file;
	my %passwd = %{$passwd->file_parsed_hash()};

	my $ftpuser = $input{'ftpuser'};
	$template->param('ftpuser' => $ftpuser);

	$template->param('home' => $passwd{$ftpuser}{'home'});
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub delete_sendmail_cw{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'delete_sendmail_cw.html');

	my %domains_to_delete = ();
	my $domains_to_delete_html = '';
	my $domains_to_delete_html_list = '';

	foreach(keys %input){
		if (/^deletecw[0-9]{1,4}$/){
			$domains_to_delete{$_} = $input{$_};
			$domains_to_delete_html .= qq~<input type="hidden" name="$_" value="$input{$_}" />~;
			$domains_to_delete_html_list .= encode('utf-8', domain_to_unicode($input{$_})) . qq~<br />~;
		}
	}

	$template->param('domains_to_delete_hidden_fields' => $domains_to_delete_html);
	$template->param('domains_to_delete_list' => $domains_to_delete_html_list);
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_delete_sendmail_cw{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	logline("debug","Creating File Object \$sendmail_cw.");    
	my $sendmail_cw = file->new({file_name => '/etc/mail/sendmail.cw'});
	$sendmail_cw->read_file;
	my %sendmail_cw = %{$sendmail_cw->file_parsed_hash()};
	my %domains_to_delete = ();
	my @new_sendmail_cw = ();

	foreach(keys %input){
		if (/^deletecw[0-9]{1,4}$/){
			logline("debug","delete sendmail.cw= $_ = $input{$_}");
			$domains_to_delete{$input{$_}} = '1';
		}
	}

	foreach(@{$sendmail_cw->file_content}){
		chomp;
		if(exists $domains_to_delete{$_}){
		
		}
		else{
			push @new_sendmail_cw, $_;
		}
	}

	@{$sendmail_cw->file_content} = @new_sendmail_cw;

	my $got = $sendmail_cw->write_file;
	return(error($got)) if $got;
	$template->param('result' => 'L__Die Domains wurden aus der Mailkonfiguration gelöscht__L') if keys %domains_to_delete > 1;
	$template->param('result' => 'L__Die Domain wurde aus der Mailkonfiguration gelöscht__L') if keys %domains_to_delete == 1;
	$success_text = 'L__Die Domains wurden aus der Mailkonfiguration gelöscht__L' if keys %domains_to_delete > 1;
	$success_text = 'L__Die Domain wurde aus der Mailkonfiguration gelöscht__L' if keys %domains_to_delete == 1;
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_email&active_tab=2&success_text=' . encode_base64url($success_text);
	return(\$template);
}

sub delete_vhost{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
    
	my $template = HTML::Template->new(filename => 'delete_vhost.html');

	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};
	my $droot = $domains{$input{'domain'}}{'droot'};

	logline("debug","Creating File Object \$passwd.");
	my $passwd = file->new({file_name => '/etc/passwd'});
	$passwd->read_file;
	my %passwd = %{$passwd->file_parsed_hash()};
	my %home_lookup =  %{$passwd->lookup2_hash()};

	my $ftpuser = '';
	if(exists $home_lookup{$domains{$input{'domain'}}{'droot'}}){
		$ftpuser = $home_lookup{$domains{$input{'domain'}}{'droot'}};
	}

	logline("debug"," MARIO SSL L9671 : @{$domains{$input{'domain'}}{'special_ssl'}} ");
	if((join ' ', @{$domains{$input{'domain'}}{'special_ssl'}}) =~ m/letsencrypt/){
        logline("debug"," MARIO SSL L9673 : @{$domains{$input{'domain'}}{'special_ssl'}} ");
		$template->param('is_letsencrypt' => '1');
	}
		
	
	$template->param('domain' => $input{'domain'});
	$template->param('idn_domain' => encode('utf-8', domain_to_unicode($input{'domain'})));
	$template->param('droot' => $droot);
	$template->param('delete_ftpuser' => qq~<div class="checkbox"><label><input type="checkbox" name="delete_ftpuser" value="$ftpuser" /> FTP-User $ftpuser L__Löschen__L</label></div>~) if $ftpuser;
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub change_spamfilter{
	
	if($session->param('show_spam') ne '1'){
		return start();
	}
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);

	my $template = HTML::Template->new(filename => 'change_spamfilter.html');
	
	my @rbl = ();
	my $whitelist_content = '';
	my $blacklist_content = '';

	logline("debug","Creating File Object \$procmailrc.");	
	my $procmailrc = file->new({file_name => '/etc/procmailrc'});
	$procmailrc->read_file;
	my %procmailrc = %{$procmailrc->file_parsed_hash()};

	logline("debug","Creating File Object \$dnsbl.");	
	my $dnsbl = file->new({file_name => '/etc/mail/dnsbl.hosts'});
	$dnsbl->read_file;
	my %dnsbl = %{$dnsbl->file_parsed_hash()};

	logline("debug","Creating File Object \$whitelist.");	
	my $whitelist = file->new({file_name => '/home/spamdef/.white.lst'});
	$whitelist->read_file;
	my %whitelist = %{$whitelist->file_parsed_hash()};

	logline("debug","Creating File Object \$blacklist.");
	my $blacklist = file->new({file_name => '/home/spamdef/.black.lst'});
	$blacklist->read_file;
	my %blacklist = %{$blacklist->file_parsed_hash()};

	logline("debug","Creating File Object \$user_prefs.");	
	my $user_prefs = file->new({file_name => '/home/spamdef/.spamd/user_prefs'});
	$user_prefs->read_file;
	my %user_prefs = %{$user_prefs->file_parsed_hash()};
	my @ok_languages = split /\s+/, $user_prefs{'ok_languages'};

	my $deliver = "/etc/.deliver";
	my $junkfolder=`sed '/^DOVECOT_JUNK=/!d ; s/^.*=//' $deliver 2>/dev/null`;
	chomp $junkfolder;
	$template->param('junkfolder' => $junkfolder);
	
	my %lang = easytecc3::spam_lang();
	my $checked_europe = '';
	my $checked_china = '';
	my $checked_russia = '';
	my $checked_other = '';

	if($session->param('user') eq 'admin'){
	
		$template->param('show_global_spamfilter' => '1');
	
	}
	
	if($input{'form_submit'} && $input{'action'} eq 'exec_change_spamfilter'){
		if($input{'action_virus'} eq 'OFF'){
			$template->param('checked_virusoff' => 'checked');
		}
		elsif($input{'action_virus'} eq 'DEL'){
			$template->param('checked_virusdel' => 'checked');
		}
		elsif($input{'action_virus'} eq 'MARK'){
			$template->param('checked_virusmark' => 'checked');
		}

		if($input{'spamd'} eq 'OFF'){
			$template->param('checked_spamdoff' => 'checked');
		}
		elsif($input{'spamd'} eq 'ON'){
			$template->param('checked_spamdon' => 'checked');
		}

		$template->param('selected_pspam' . $input{'pspam_level'} => 'selected');

		if($input{'action_pspam'} eq 'MARK'){
			$template->param('checked_mark_pspam' => 'checked');
		}
		elsif($input{'action_pspam'} eq 'HEADER'){
			$template->param('checked_header_pspam' => 'checked');
		}

		$template->param('selected_cspam' . $input{'cspam_level'} => 'selected');

		if($input{'action_cspam'} eq 'MARK'){
			$template->param('checked_cspam_mark' => 'checked');
		}
		elsif($input{'action_cspam'} eq 'HEADER'){
			$template->param('checked_cspam_header' => 'checked');
		}
		elsif($input{'action_cspam'} eq 'DEL'){
			$template->param('checked_cspam_delete' => 'checked');
		}

		if($input{'report_safe'}){
			$template->param('checked_report_safe_on' => 'checked');
		}
		else{
			$template->param('checked_report_safe_off' => 'checked');
		}

		foreach(keys %input){
			#<input name="lang_other" type="checkbox" class="languagetype="checkbox"" value="other" <TMPL_VAR NAME=checked_spamd_lang_other>
			next unless /^lang_(.*)$/;
			$template->param('checked_spamd_lang_' . $1 => 'checked');
		}
	}
	else{
		foreach(@ok_languages){
			$template->param('checked_spamd_lang_' . $_ => ' checked');
			$checked_europe = '1' if(!$checked_europe && /^($lang{'europe'})$/);
			$checked_china = '1' if(!$checked_europe && /^($lang{'china'})$/);
			$checked_russia = '1' if(!$checked_europe && /^($lang{'russia'})$/);
			$checked_other = '1' if(!$checked_europe && /^($lang{'other'})$/);
		}
		$template->param('checked_spamd_lang_europe' => ' checked') if $checked_europe;
		$template->param('checked_spamd_lang_china' => ' checked') if $checked_china;
		$template->param('checked_spamd_lang_russia' => ' checked') if $checked_russia;
		$template->param('checked_spamd_lang_other' => ' checked') if $checked_other;

		#rbl
		my @loop_data = ();
		
		foreach(sort keys %dnsbl){
			logline("debug","rbl:$_ $dnsbl{$_}");
			my %row_data;
			$row_data{'RBL_ID'} = "rbl_$_";
			$row_data{'RBL_NAME'} = $_;
			$row_data{'CHECKED_RBL_ID'} = 'checked' if $dnsbl{$_} == '1';
			push(@loop_data, \%row_data);
			
			#my $checked = 'checked' if $dnsbl{$_} == '1';
			#push(@rbl, qq~$_~ . '|' .
			#	qq~<input name="rbl_$_" type="checkbox" onClick="rbl(this)" value="1" $checked />~
			#);
		}
		$template->param('RBL_LOOP' => \@loop_data);		
		#easytecc3::table(\$template,'<td>L__Realtime Blacklists__L</td><td colspan="6">L__aktiv__L</td>', \@rbl, 'rbl');

		# Whiteliste
		foreach(sort keys %whitelist){
			$whitelist_content = $whitelist_content . $_ . "\n";
		}
		$template->param('whitelist' => $whitelist_content);

		# Blackliste
		foreach(sort keys %blacklist){
			$blacklist_content = $blacklist_content . $_ . "\n";
		}
		$template->param('blacklist' => $blacklist_content);

		# generischer Anhangsfilter
		# VIRUS=MARK      #OFF;DEL;MARK
		if($procmailrc{'VIRUS'} eq 'OFF'){
			$template->param('checked_virusoff' => 'checked');
		}
		elsif($procmailrc{'VIRUS'} eq 'DEL'){
			$template->param('checked_virusdel' => 'checked');
		}
		elsif($procmailrc{'VIRUS'} eq 'MARK'){
			$template->param('checked_virusmark' => 'checked');
		}
		$template->param('subj_virus' => $procmailrc{'SUBJ_VIRUS'});
		$template->param('postfix_virus' => $procmailrc{'POSTFIX'});

		# Spamassassin
		if($procmailrc{'SPAMD'} eq 'OFF'){
			$template->param('checked_spamdoff' => 'checked');
		}
		elsif($procmailrc{'SPAMD'} eq 'ON'){
			$template->param('checked_spamdon' => 'checked');
		}
		
		# warscheinlicher Spam
		# aus /home/spamdef/.spamd/user_prefs
		# required_hits           5.0
		$template->param('selected_pspam' .  $user_prefs{'required_hits'} => 'selected');
		# Aktion warscheinlicher Spam
		# PSPAM=MARK      #MARK;HEADER
		if($procmailrc{'PSPAM'} eq 'MARK'){
			$template->param('checked_mark_pspam' => 'checked');
		}
		elsif($procmailrc{'PSPAM'} eq 'HEADER'){
			$template->param('checked_header_pspam' => 'checked');
		}
		
		# Subjektpräfix Spamverdacht
		$template->param('subj_pspam' => $procmailrc{'SUBJ_PSPAM'});
		# sicherer Spam
		# aus /etc/procmailrc
		# CLEVEL='\*\*\*\*\*\*\*\*\*\*'
		# Wert wurde schon als Zahl beim Parsen in $procmailrc{'CLEVEL'} gespeichert
		$template->param('selected_cspam' .  $procmailrc{'CLEVEL'} => 'selected');
		# Aktion sicherer Spam
		# CSPAM=MARK      #DEL;MARK;HEADER
		if($procmailrc{'CSPAM'} eq 'MARK'){
			$template->param('checked_cspam_mark' => 'checked');
		}
		elsif($procmailrc{'CSPAM'} eq 'HEADER'){
			$template->param('checked_cspam_header' => 'checked');
		}
		elsif($procmailrc{'CSPAM'} eq 'DEL'){
			$template->param('checked_cspam_delete' => 'checked');
		}

		# Subjektpräfix sicherer Spam
		$template->param('subj_cspam' => $procmailrc{'SUBJ_CSPAM'});
		# Bericht user_prefs:
		# report_safe             1
		if($user_prefs{'report_safe'} eq '1'){
			$template->param('checked_report_safe_on' => 'checked');
		}
		else{
			$template->param('checked_report_safe_off' => 'checked');
		}
		
		# ugly unhack from score_DNSBL 10 to DNSBL 10
		my @scores = ();
		foreach(keys %user_prefs){
		
			next unless (/^score_/);
			next unless ($user_prefs{$_} =~ /[0-9\.]+/);
			
			my $rule = $_;
			$rule =~ s/^score_//;
			
			push @scores, $rule . ' ' . $user_prefs{$_}; 
		
		}
		
		$template->param('scores' => join("\n", sort @scores));
		
	}
	
	
	if($input{'action'} eq 'change_spamfilter' || $input{'action'} eq 'exec_change_spamfilter'){
	
	#preselect defaults for new special spamfilter tab
	$template->param('special_checked_virusmark' => 'checked');
	$template->param('special_subj_virus' => $procmailrc{'SUBJ_VIRUS'});
	$template->param('special_postfix_virus' => $procmailrc{'POSTFIX'});
	$template->param('special_checked_spamdon' => 'checked');
	$template->param('special_selected_pspam' .  $user_prefs{'required_hits'} => 'selected');
	$template->param('special_checked_mark_pspam' => 'checked');
	$template->param('special_subj_pspam' => $procmailrc{'SUBJ_PSPAM'});
	$template->param('special_selected_cspam' .  $procmailrc{'CLEVEL'} => 'selected');
	$template->param('special_checked_cspam_mark' => 'checked');
	$template->param('special_subj_cspam' => $procmailrc{'SUBJ_CSPAM'});
	$template->param('special_checked_report_safe_off' => 'checked');
	$template->param('special_checked_spamd_lang_europe' => ' checked') if $checked_europe;
	$template->param('special_checked_spamd_lang_china' => ' checked') if $checked_china;
	$template->param('special_checked_spamd_lang_russia' => ' checked') if $checked_russia;
	$template->param('special_checked_spamd_lang_other' => ' checked') if $checked_other;
		
		foreach(@ok_languages){
			$template->param('special_checked_spamd_lang_' . $_ => ' checked');
		}
				
		$template->param('special_scores' => join("\n", sort @scores));
		
	}
	
	if (length($input{'active_tab'})) {
		$template->param('change_spamfilter_active_tab'.$input{'active_tab'} => 1);
	}
	else{
	
		if($session->param('user') eq 'admin'){
		
			$template->param('change_spamfilter_active_tab1' => 1);	
			
		} else {
		
			$template->param('change_spamfilter_active_tab2' => 1);	
			
		}
	}
	
	
	show_special_spamfilter($template);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub new_special_spamfilter{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	#my $template = HTML::Template->new(filename => 'change_spamfilter.html');
	#Formular für neuen Spezialfilter istz in change_spamfilter als eigener tab...
	my $template_tmp = change_spamfilter();
	my $template = $$template_tmp;
	$template->param('change_spamfilter_active_tab2' => 1);
	
	logline("debug","Creating File Object \$procmailrc.");
	my $procmailrc = file->new({file_name => '/etc/procmailrc'});
	$procmailrc->read_file;
	my %procmailrc = %{$procmailrc->file_parsed_hash()};

	logline("debug","Creating File Object \$user_prefs.");
	my $user_prefs = file->new({file_name => '/home/spamdef/.spamd/user_prefs'});
	$user_prefs->read_file;
	my %user_prefs = %{$user_prefs->file_parsed_hash()};
	
	my $special_spamfilter = $input{'special_spam_user_domain'} if $input{'special_spam_user_domain'};
	my $deliver = "/home/$special_spamfilter/.deliver";
	my $junkfolder=`sed '/^DOVECOT_JUNK=/!d ; s/^.*=//' $deliver 2>/dev/null`;
	chomp $junkfolder;
	$template->param('special_junkfolder' => $junkfolder);
	
	unless($input{'form_submit'}){
		# generischer Anhangsfilter
		# VIRUS=MARK      #OFF;DEL;MARK
		if($procmailrc{'VIRUS'} eq 'OFF'){
			$template->param('special_checked_virusoff' => 'checked');
		}
		elsif($procmailrc{'VIRUS'} eq 'DEL'){
			$template->param('special_checked_virusdel' => 'checked');
		}
		elsif($procmailrc{'VIRUS'} eq 'MARK'){
			$template->param('special_checked_virusmark' => 'checked');
		}
		$template->param('special_subj_virus' => $procmailrc{'SUBJ_VIRUS'});
		$template->param('special_postfix_virus' => $procmailrc{'POSTFIX'});

		# Spamassassin
		if($procmailrc{'SPAMD'} eq 'OFF'){
			$template->param('special_checked_spamdoff' => 'checked');
		}
		elsif($procmailrc{'SPAMD'} eq 'ON'){
			$template->param('special_checked_spamdon' => 'checked');
		}
		
		# warscheinlicher Spam
		# aus /home/spamdef/.spamd/user_prefs
		# required_hits           5.0
		$template->param('special_selected_pspam' .  $user_prefs{'required_hits'} => 'selected');
		# Aktion warscheinlicher Spam
		# PSPAM=MARK      #MARK;HEADER
		if($procmailrc{'PSPAM'} eq 'MARK'){
			$template->param('special_checked_mark_pspam' => 'checked');
		}
		elsif($procmailrc{'PSPAM'} eq 'HEADER'){
			$template->param('special_checked_header_pspam' => 'checked');
		}
		
		# Subjektpräfix Spamverdacht
		$template->param('special_subj_pspam' => $procmailrc{'SUBJ_PSPAM'});
		# sicherer Spam
		# aus /etc/procmailrc
		# CLEVEL='\*\*\*\*\*\*\*\*\*\*'
		# Wert wurde schon als Zahl beim Parsen in $procmailrc{'CLEVEL'} gespeichert
		$template->param('special_selected_cspam' .  $procmailrc{'CLEVEL'} => 'selected');
		# Aktion sicherer Spam
		# CSPAM=MARK      #DEL;MARK;HEADER
		if($procmailrc{'CSPAM'} eq 'MARK'){
			$template->param('special_checked_cspam_mark' => 'checked');
		}
		elsif($procmailrc{'CSPAM'} eq 'HEADER'){
			$template->param('special_checked_cspam_header' => 'checked');
		}
		elsif($procmailrc{'CSPAM'} eq 'DEL'){
			$template->param('special_checked_cspam_delete' => 'checked');
		}
		
		# Subjektpräfix sicherer Spam
		$template->param('special_subj_cspam' => $procmailrc{'SUBJ_CSPAM'});
		# Bericht user_prefs:
		# report_safe             1
		if($user_prefs{'report_safe'} eq '1'){
			$template->param('special_checked_report_safe_on' => 'checked');
		}
		else{
			$template->param('special_checked_report_safe_off' => 'checked');
		}
		
	}
	else{
		

		$template->param('special_spam_user_domain' => $special_spamfilter);

		if($input{'special_action_virus'} eq 'OFF'){
			$template->param('special_checked_virusoff' => 'checked');
		}
		elsif($input{'special_action_virus'} eq 'DEL'){
			$template->param('special_checked_virusdel' => 'checked');
		}
		elsif($input{'special_action_virus'} eq 'MARK'){
			$template->param('special_checked_virusmark' => 'checked');
		}

		if($input{'special_spamd'} eq 'OFF'){
			$template->param('special_checked_spamdoff' => 'checked');
		}
		elsif($input{'special_spamd'} eq 'ON'){
			$template->param('special_checked_spamdon' => 'checked');
		}

		$template->param('special_selected_pspam' . $input{'special_pspam_level'} => 'selected');

		if($input{'special_action_pspam'} eq 'MARK'){
			$template->param('special_checked_mark_pspam' => 'checked');
		}
		elsif($input{'special_action_pspam'} eq 'HEADER'){
			$template->param('special_checked_header_pspam' => 'checked');
		}

		$template->param('special_selected_cspam' . $input{'special_cspam_level'} => 'selected');

		if($input{'special_action_cspam'} eq 'MARK'){
			$template->param('special_checked_cspam_mark' => 'checked');
		}
		elsif($input{'special_action_cspam'} eq 'HEADER'){
			$template->param('special_checked_cspam_header' => 'checked');
		}
		elsif($input{'special_action_cspam'} eq 'DEL'){
			$template->param('special_checked_cspam_delete' => 'checked');
		}

		if($input{'special_report_safe'}){
			$template->param('special_checked_report_safe_on' => 'checked');
		}
		else{
			$template->param('special_checked_report_safe_off' => 'checked');
		}

		# ugly unhack from score_DNSBL 10 to DNSBL 10
		my @scores = ();
		foreach(keys %user_prefs){
		
			next unless (/^score_/);
			next unless ($user_prefs{$_} =~ /[0-9\.]+/);
			
			my $rule = $_;
			$rule =~ s/^score_//;
			
			push @scores, $rule . ' ' . $user_prefs{$_}; 
		
		}
		
		$template->param('special_scores' => join("\n", sort @scores));
		
		foreach(keys %input){
			#<input name="lang_other" type="checkbox" class="language" value="other" <TMPL_VAR NAME=checked_spamd_lang_other>
			next unless /^special_lang_(.*)$/;
			$template->param('special_checked_spamd_lang_' . $1 => 'checked');
		}
	}
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub change_special_spamfilter{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'change_special_spamfilter.html');
	
	my $whitelist_content = '';
	my $blacklist_content = '';
	my $special_spamfilter = $input{'domain'} if $input{'domain'};
	my $special_spamfilter_idn = encode('utf-8', domain_to_unicode($input{'domain'})) if $input{'domain'};

	$special_spamfilter = $input{'user'} if $input{'user'};
	$special_spamfilter_idn = encode('utf-8',email_to_unicode($input{'user'})) if $input{'user'};

	$special_spamfilter = $input{'special_spam_user_domain'} if $input{'special_spam_user_domain'};
	$special_spamfilter_idn = encode('utf-8', domain_to_unicode($input{'special_spam_user_domain'})) if $input{'special_spam_user_domain'};

	logline("debug","Creating File Object \$procmailrc.");
	my $procmailrc = file->new({file_name => "/home/$special_spamfilter/.spamproc",
								user => $input{'user'},
								domain => $input{'domain'}}
	);
	$procmailrc->read_file;
	my %procmailrc = %{$procmailrc->file_parsed_hash()};

	logline("debug","Creating File Object \$whitelist.");
	my $whitelist = file->new({file_name => "/home/$special_spamfilter/.white.lst"});
	$whitelist->read_file;
	my %whitelist = %{$whitelist->file_parsed_hash()};

	logline("debug","Creating File Object \$blacklist.");
	my $blacklist = file->new({file_name => "/home/$special_spamfilter/.black.lst"});
	$blacklist->read_file;
	my %blacklist = %{$blacklist->file_parsed_hash()};

	logline("debug","Creating File Object \$user_prefs.");
	my $user_prefs = file->new({file_name => "/home/$special_spamfilter/.spamd/user_prefs"});
	$user_prefs->read_file;
	my %user_prefs = %{$user_prefs->file_parsed_hash()};
	my @ok_languages = split /\s+/, $user_prefs{'ok_languages'};
	
	my $deliver = "/home/$special_spamfilter/.deliver";
	my $junkfolder=`sed '/^DOVECOT_JUNK=/!d ; s/^.*=//' $deliver 2>/dev/null`;
	chomp $junkfolder;
	$template->param('special_junkfolder' => $junkfolder);
	

	my %lang = easytecc3::spam_lang();
	my $checked_europe = '';
	my $checked_china = '';
	my $checked_russia = '';
	my $checked_other = '';

	unless($input{'form_submit'}){
		foreach(@ok_languages){
			$template->param('special_checked_spamd_lang_' . $_ => ' checked');
			$checked_europe = '1' if(!$checked_europe && /^($lang{'europe'})$/);
			$checked_china = '1' if(!$checked_europe && /^($lang{'china'})$/);
			$checked_russia = '1' if(!$checked_europe && /^($lang{'russia'})$/);
			$checked_other = '1' if(!$checked_europe && /^($lang{'other'})$/);
		}
		$template->param('special_checked_spamd_lang_europe' => ' checked') if $checked_europe;
		$template->param('special_checked_spamd_lang_china' => ' checked') if $checked_china;
		$template->param('special_checked_spamd_lang_russia' => ' checked') if $checked_russia;
		$template->param('special_checked_spamd_lang_other' => ' checked') if $checked_other;

		# Whiteliste
		foreach(sort keys %whitelist){
			logline("debug","whitelist:$_");
			$whitelist_content = $whitelist_content . $_ . "\n";
		}
		$template->param('special_whitelist' => $whitelist_content);

		# Blackliste
		foreach(sort keys %blacklist){
			$blacklist_content = $blacklist_content . $_ . "\n";
		}
		$template->param('special_blacklist' => $blacklist_content);

		# generischer Anhangsfilter
		# VIRUS=MARK      #OFF;DEL;MARK
		if($procmailrc{'VIRUS'} eq 'OFF'){
			$template->param('special_checked_virusoff' => 'checked');
		}
		elsif($procmailrc{'VIRUS'} eq 'DEL'){
			$template->param('special_checked_virusdel' => 'checked');
		}
		elsif($procmailrc{'VIRUS'} eq 'MARK'){
			$template->param('special_checked_virusmark' => 'checked');
		}
		$template->param('special_subj_virus' => $procmailrc{'SUBJ_VIRUS'});
		$template->param('special_postfix_virus' => $procmailrc{'POSTFIX'});

		# Spamassassin
		if($procmailrc{'SPAMD'} eq 'OFF'){
			$template->param('special_checked_spamdoff' => 'checked');
		}
		elsif($procmailrc{'SPAMD'} eq 'ON'){
			$template->param('special_checked_spamdon' => 'checked');
		}
		
		# wahrscheinlicher Spam
		# aus /home/spamdef/.spamd/user_prefs
		# required_hits           5.0
		$template->param('special_selected_pspam' .  $user_prefs{'required_hits'} => 'selected');
		# Aktion warscheinlicher Spam
		# PSPAM=MARK      #MARK;HEADER
		if($procmailrc{'PSPAM'} eq 'MARK'){
			$template->param('special_checked_mark_pspam' => 'checked');
		}
		elsif($procmailrc{'PSPAM'} eq 'HEADER'){
			$template->param('special_checked_header_pspam' => 'checked');
		}
		
		# Subjektpräfix Spamverdacht
		$template->param('special_subj_pspam' => $procmailrc{'SUBJ_PSPAM'});
		# sicherer Spam
		# aus /etc/procmailrc
		# CLEVEL='\*\*\*\*\*\*\*\*\*\*'
		# Wert wurde schon als Zahl beim Parsen in $procmailrc{'CLEVEL'} gespeichert
		$template->param('special_selected_cspam' .  $procmailrc{'CLEVEL'} => 'selected');
		# Aktion sicherer Spam
		# CSPAM=MARK      #DEL;MARK;HEADER
		if($procmailrc{'CSPAM'} eq 'MARK'){
			$template->param('special_checked_cspam_mark' => 'checked');
		}
		elsif($procmailrc{'CSPAM'} eq 'HEADER'){
			$template->param('special_checked_cspam_header' => 'checked');
		}
		elsif($procmailrc{'CSPAM'} eq 'DEL'){
			$template->param('special_checked_cspam_delete' => 'checked');
		}
		
		# Subjektpräfix sicherer Spam
		$template->param('special_subj_cspam' => $procmailrc{'SUBJ_CSPAM'});
		# Bericht user_prefs:
		# report_safe             1
		if($user_prefs{'report_safe'} eq '1'){
			$template->param('special_checked_report_safe_on' => 'checked');
		}
		else{
			$template->param('special_checked_report_safe_off' => 'checked');
		}
		
		# ugly unhack from score_DNSBL 10 to DNSBL 10
		my @scores = ();
		foreach(keys %user_prefs){
		
			next unless (/^score_/);
			next unless ($user_prefs{$_} =~ /[0-9\.]+/);
			
			my $rule = $_;
			$rule =~ s/^score_//;
			
			push @scores, $rule . ' ' . $user_prefs{$_}; 
		
		}
		
		$template->param('special_scores' => join("\n", sort @scores));
		
	}
	else{
		if($input{'special_action_virus'} eq 'OFF'){
			$template->param('special_checked_virusoff' => 'checked');
		}
		elsif($input{'special_action_virus'} eq 'DEL'){
			$template->param('special_checked_virusdel' => 'checked');
		}
		elsif($input{'special_action_virus'} eq 'MARK'){
			$template->param('special_checked_virusmark' => 'checked');
		}

		if($input{'special_spamd'} eq 'OFF'){
			$template->param('special_checked_spamdoff' => 'checked');
		}
		elsif($input{'special_spamd'} eq 'ON'){
			$template->param('special_checked_spamdon' => 'checked');
		}

		$template->param('special_selected_pspam' . $input{'special_pspam_level'} => 'selected');

		if($input{'special_action_pspam'} eq 'MARK'){
			$template->param('special_checked_mark_pspam' => 'checked');
		}
		elsif($input{'special_action_pspam'} eq 'HEADER'){
			$template->param('special_checked_header_pspam' => 'checked');
		}

		$template->param('special_selected_cspam' . $input{'special_cspam_level'} => 'selected');

		if($input{'special_action_cspam'} eq 'MARK'){
			$template->param('special_checked_cspam_mark' => 'checked');
		}
		elsif($input{'special_action_cspam'} eq 'HEADER'){
			$template->param('special_checked_cspam_header' => 'checked');
		}
		elsif($input{'special_action_cspam'} eq 'DEL'){
			$template->param('special_checked_cspam_delete' => 'checked');
		}

		if($input{'special_report_safe'}  eq 'ON'){
			$template->param('special_checked_report_safe_on' => 'checked');
		}
		elsif($input{'special_report_safe'}  eq 'OFF'){
			$template->param('special_checked_report_safe_off' => 'checked');
		}

		foreach(keys %input){
			#<input name="lang_other" type="checkbox" class="language" value="other" <TMPL_VAR NAME=checked_spamd_lang_other>
			next unless /^lang_(.*)$/;
			$template->param('special_checked_spamd_lang_' . $1 => 'checked');
		}
	}

	$template->param('special_spam_user_domain' => $special_spamfilter);
	$template->param('special_spam_user_domain_idn' => $special_spamfilter_idn);
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub change_virusfilter{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'change_virusfilter.html');
	my $whitelist_content = '';

	logline("debug","Creating File Object \$clamavmilter.");
	my $clamavmilter = file->new({file_name => "/etc/sysconfig/clamav-milter"});
	$clamavmilter->read_file;
	my %clamavmilter = %{$clamavmilter->file_parsed_hash()};

	logline("debug","Creating File Object \$clamavtemplate.");
	my $clamavtemplate = file->new({file_name => "/etc/sysconfig/clamav-template"});
	$clamavtemplate->read_file;
	my %clamavtemplate = %{$clamavtemplate->file_parsed_hash()};

	logline("debug","Creating File Object \$clamavwhitelist.");
	my $clamavwhitelist = file->new({file_name => "/etc/sysconfig/clamav-whitelist"});
	$clamavwhitelist->read_file;
	my %clamavwhitelist = %{$clamavwhitelist->file_parsed_hash()};

	# Virusfilter an/aus aus /etc/sysconfig/clamav-milter ziehen
	# MILTER_ON=YES
	# MILTER_ON=
	if($clamavmilter{'MILTER_ON'} eq 'YES'){
		$template->param('checked_virusfilter_on' => 'checked');
	}
	else{
		$template->param('checked_virusfilter_off' => 'checked');
	}

	# Viruswhiteliste, diese Absender laufen nicht dirch Virenfilter
	foreach(sort keys %clamavwhitelist){
		$whitelist_content = $whitelist_content . $_ . "\n";
	}
	$template->param('virus_whitelist' => $whitelist_content);

	# Virenbericht an/aus aus /etc/sysconfig/clamav-milter ziehen
	# Bericht an: QUIET=
	# Bericht aus: QUIET=YES
	if($clamavmilter{'QUIT'} eq 'YES'){
		$template->param('checked_report_safe_off' => 'checked');
	}
	else{
		$template->param('checked_report_safe_on' => 'checked');
	}

	# Sender des Virenberichtes
	# FROM=
	# FROM=rttrtrtr@erererer.de
	$template->param('virus_found_sender' => $clamavmilter{'FROM'});

	# Subject des Virenberichtes
	# [admin@mxmxmx ~]$ cat /etc/sysconfig/clamav-template
	# Subject: Virugs gelöscht! [%s]
	# [%s] ist Original-Subject, kann optional in Berichtsmail eingebaut werden, in Easytecc {ORGSUB} anstatt [%s] anzeigen
	$template->param('virus_found_subject' => easytecc3::string_to_utf8($clamavtemplate{'subject'}));
	# und der Templateinhalt
	$template->param('virus_found_text' => easytecc3::string_to_utf8($clamavtemplate{'template'}));

	logline("debug","change_virus text:" . $clamavtemplate{'template'});

	# Headereintrag an/aus aus /etc/sysconfig/clamav-milter ziehen
	# Headereintrag an: NOXHEADER=
	# Headereintrag aus: NOXHEADER=YES
	if($clamavmilter{'NOXHEADER'} eq 'YES'){
		$template->param('checked_virusheader_off' => 'checked');
	}
	else{
		$template->param('checked_virusheader_on' => 'checked');
	}

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub new_cronjob{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'new_cronjob.html');
	my $template_cronjob_table = HTML::Template->new(filename => 'cronjob_table.html');

	my $edit_cron = '';
	
	if($session->param('user') eq 'admin'){
	
		$edit_cron = '1';
		
	} else {
	
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};

		my $gecos = $passwd{$session->param('user')}{'gecos'};
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.cron-1';
		
		}
			
		if($gecos =~ m/\.cron-2/){
		
			$edit_cron = '1';
		
		}

	}
	
	$template->param('edit_cron' => $edit_cron);
	$template_cronjob_table->param('edit_cron' => $edit_cron);


	# bei neuem cronjob zunchst zufllige Uhrzeit zwischen 00:00 - 02:00 auswhlen, damit die Spassvgel nicht immer mintlich machen
	my %cronjob = ( 'min' => int(rand('59')),
					'std' => int(rand('2')));
	easytecc3::cronjob_selected_time(\$template_cronjob_table, \%cronjob);
	$template->param('cronjob_table' => $template_cronjob_table->output);
	$template->param('job' => $input{'command'});

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub change_cronjob{


	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'change_cronjob.html');

	my $template_cronjob_table = HTML::Template->new(filename => 'cronjob_table.html');

	my $cronjob = $input{'cronjob'};
	logline("debug","Creating File Object \$cronfile.");
	my $cronfile = file->new({file_name => '/home/web/cronfile'});
	$cronfile->read_file;
	my %cronjobs = %{$cronfile->file_parsed_hash()};
	my $cronjob_html = '';
	# cronjob suchen, $cronjob ist Zeilennummer in Datei, der hash-key ist aber Befehl rückwärts
	# damit das listing von gleichen jobs mit unterschiedlichen Zeiten funktioniert
	# Also suchen wir nach $cronjobs{$cronjob}{'count'} = $cronjob
	# Es muss zwar der ganze hash durchgegangen werden aber egal...

	foreach(keys %cronjobs){
		if($cronjobs{$_}{'count'} == $cronjob){
			# encode_entities damit Zeichen wie " in Fomrularfeld dargestellt werden und nicht das html zerstören
			$cronjobs{$_}{'job'} = encode_entities($cronjobs{$_}{'job'});
			$template->param('job' => $cronjobs{$_}{'job'});
			easytecc3::cronjob_selected_time(\$template_cronjob_table, \%{$cronjobs{$_}});
		}
	}

	# $cronjobs{$cronjob}{'job'}
	# $cronjobs{$cronjob}{'min'}
	# $cronjobs{$cronjob}{'std'}
	# $cronjobs{$cronjob}{'mday'}
	# $cronjobs{$cronjob}{'mon'}
	# $cronjobs{$cronjob}{'wday'}

	my $edit_cron = '';
	my $new_cron = '';
	
	if($session->param('user') eq 'admin'){
	
		$edit_cron = '1';
		$new_cron = '1';
		
	} else {
	
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};

		my $gecos = $passwd{$session->param('user')}{'gecos'};
		
		if($gecos !~ m/^CUST/){

			$gecos = 'CUST.cron-1';
		
		}
			
		if($gecos =~ m/\.cron-[1-9]/){
		
			$edit_cron = '1';
		
		}
		
		if($gecos =~ m/\.cron-2/){
		
			$new_cron = '1';
		
		}
			
	}
	
	$template->param('edit_cron' => $edit_cron);
	$template_cronjob_table->param('edit_cron' => $edit_cron);
	
	$template->param('new_cron' => $new_cron);
	$template_cronjob_table->param('new_cron' => $new_cron);
		
	$template->param('cronjob' => $cronjob);
	$template->param('cron_key' => $input{'cron_key'});
	
	$template->param('cronjob_table' => $template_cronjob_table->output);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub delete_cronjob{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'delete_cronjob.html');
	my $cronjob = $input{'cronjob'};
	logline("debug","Creating File Object \$cronfile.");
	my $cronfile = file->new({file_name => '/home/web/cronfile'});
	$cronfile->read_file;
	my %cronjobs = %{$cronfile->file_parsed_hash()};

	# cronjob suchen, $cronjob ist Zeilennummer in Datei, der hash-key ist aber Befehl rückwärts
	# damit das listing von gleichen jobs mit unterschiedlichen Zeiten funktioniert
	# Also suchen wir nach $cronjobs{$cronjob}{'count'} = $cronjob
	# Es muss zwar der ganze hash durchgegangen werden aber egal...
	foreach(keys %cronjobs){
		if($cronjobs{$_}{'count'} == $cronjob){
			$template->param('job' => encode('utf-8',$cronjobs{$_}{'job'}));
			$template->param('cron_key' => $input{'cron_key'});
		}
	}
	$template->param('cronjob' => $cronjob);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub new_htaccess{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'new_htaccess.html');
	my $dir = $input{'dir'};	
	my $showdir = '';
	my $warning = '';
	
	unless ($dir){
		$showdir = 'L__Kein gültiges Verzeichnis ausgewählt.__L';
		$warning = 1;
	} else {
		if ($fb) {
			$showdir = '/usr/local/www/apache24/noexec/' . $dir;
		}
		else{
			$showdir = '/home/httpd/docs/' . $dir;
		}
	}
	
	$template->param('dir' => $dir);
	my $dir_encoded = encode_base64url($dir);
	$template->param('dir_encoded' => $dir_encoded);
	$template->param('showdir' => $showdir);
	$template->param('warning' => $warning);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub new_dir{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'new_dir.html');
	my $dir = $input{'dir'};
	$template->param('dir' => $dir);
	my $dir_encoded = encode_base64url($dir);
	$template->param('dir_encoded' => $dir_encoded);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_new_dir{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $result = $validation_result;

	logline("debug","exec_new_dir result:$result###");

	if($result){

	}
	else{
		
		$newdir = lc($input{'dir'} . '/' . $input{'newdir'});
		$newdir =~ s/\/\//\//;
		
		
		logline("debug","newdir: $newdir\n");
				
		if($fb){
			system("/usr/iports/bin/sudo /usr/sbin/webmkdir -p $newdir");
			system("/usr/iports/bin/sudo /usr/sbin/chown.pl " . $session->param('user') . ":vuser $newdir d");
			system("/usr/iports/bin/sudo /usr/sbin/chmod.pl 775 $newdir");
		}
		else {
			system("/usr/sbin/admmkdir -p $newdir");
		}
	}

	$result = 'L__Fehler__L: ' . $error if $error;
	
	return error($error) if $error;
	
	$result = 'L__Das Verzeichnis wurde erfolgreich angelegt__L';
	$success_text = 'L__Das Verzeichnis wurde erfolgreich angelegt__L';

	$template->param('result' => $result);
	logline("debug","result = " . $result);
	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_filemanager&dir=' . encode_base64url($newdir) . '&success_text=' . encode_base64url($success_text);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}


sub change_htaccess{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'change_htaccess.html');

		my $dir = $droot_prefix . '/' . $input{'dir'};
		my @htuser;

		open (HTPASSWD,"$dir/.htpasswd") || return(error("L__Fehler beim Lesen von .htpasswd__L:", "$!"));
			my @htpasswd = <HTPASSWD>;
		close(HTPASSWD);

		foreach(sort @htpasswd){
			next if (! /:/);
			my ($user,$pass) = split /\:/, $_;
			push @htuser, $user if $user;
		}

		my $template_user_select = HTML::Template->new(filename => 'user_select_no_multiple.html');
		easytecc3::template_loop_e4(\%input,\$template_user_select, \@htuser, 'user_select', '');

		$template->param('tableuser' => $template_user_select->output);
		$template->param('full_dir' => $dir);
		$template->param('dir' => $input{'dir'});
		my $dir_encoded = encode_base64url($input{'dir'});
		$template->param('dir_encoded' => $dir_encoded);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub delete_htaccess{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'delete_htaccess_all.html');
	$template =  HTML::Template->new(filename => 'delete_htaccess_user.html') if $input{'type'} eq 'delete_user';

	my $dir = $droot_prefix . '/' . $input{'dir'};
		$template->param('full_dir' => $dir);
		$template->param('dir' => $input{'dir'});
		my $dir_encoded = encode_base64url($input{'dir'});
		$template->param('dir_encoded' => $dir_encoded);
		# gibs nur bei user löschen, nicht wenn ganzer passwortschutz weg soll
		$template->param('htaccessuser' => $input{'user_select'});

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub new_frontpage{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'new_frontpage.html');

	# wenn von exec_new_frontpage kommt und User oder Passwort falsch, dann zunchst
	my $result = $validation_result;

	# evtl. redirect von exec_new_frontpage, wenn alte FP-Installation gefunden.
	# In deisem Fall löschen von alten FP-Dateien und Ordnern anbieten
	if($input{'action'} eq 'exec_new_frontpage' && ! $result){
		my $template_old_frontpage = HTML::Template->new(filename => 'old_frontpage.html');

		$template_old_frontpage->param('domain_select' => $input{'domain_select'});
		$template->param('domain_select' => $input{'domain_select'});
		$template->param('old_frontpage' => $template_old_frontpage->output);
		$template->param('frontpageuser' => $input{'frontpageuser'});
		$template->param('password' => $input{'password'});
	}
	else{
		my $template_domain_select = HTML::Template->new(filename => 'domain_select.html');

		logline("debug","Creating File Object \$httpd_conf.");
		my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
		$httpd_conf->read_file;
		my %domains = %{$httpd_conf->file_parsed_hash()};
		my @domains = ();

		foreach(sort keys %domains){
			#keine wildcarddomains für frontplage anbieten
			next if(/\*/);
			# damit ohne www. in selectbox angezeigt wird
			my $domain_ohne_www = $_;
			$domain_ohne_www =~ s/^www\.//;
			push @domains, encode('utf-8', domain_to_unicode($domain_ohne_www)) . '|' . qq~value="$_"~;
		}

		#wenn falsche Eingabe wird new_frontpage erneut aufgerufen. fpinstall legt grundstzlich mit führendem
		#www an. Von ausgewählter Domain domain_select das führende www entfernen und erneut als vorausgewählt
		#anzeigen sofern vorhanden.
		my $selected_domain_ohne_www = $input{'domain_select'};
		$selected_domain_ohne_www =~ s/^www\.//;

		easytecc3::template_loop(\%input,\$template_domain_select, \@domains, 'domain_select', encode('utf-8', domain_to_unicode($selected_domain_ohne_www)) . '|' . qq~value="$input{'domain_select'}"~);

		#logline("debug","template_domain_select:\n" . $template_domain_select->output);
		#my $table = $template_domain_select->output;
		#my $out = $table;

		$template->param('domain_select' => $template_domain_select->output);
		logline("debug","template_domain_select:\n" . $template_domain_select->output);
	}

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub delete_special_spamfilter{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'delete_special_spamfilter.html');

	$template->param('special_spam_user_domain' => $input{'special_spam_user_domain'});
	$template->param('special_spam_user_domain_idn' => encode('utf-8', domain_to_unicode($input{'special_spam_user_domain'})));

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub delete_frontpage{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'delete_frontpage.html');

	$template->param('domain' => $input{'domain'});
	$template->param('idn_domain' => encode('utf-8', domain_to_unicode($input{'domain'})));

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub auto_cronjob{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = '';

	if($input{'cronjob'} eq 'delete_all_logs'){
		$template = HTML::Template->new(filename => 'add_cron_delete_logfiles.html');
	}
	elsif($input{'cronjob'} eq 'delete_admin_email'){
		$template = HTML::Template->new(filename => 'add_cron_delete_admin_email.html');
	}

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub delete_logfiles{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'delete_logfiles.html');
	my $logfile = $input{'logfile'};
	my $domain = $input{'domain'};
	my $idn_domain = encode('utf-8', domain_to_unicode($domain));

	# wenn in Logfilebersicht auf "alle Logs zuknftig automatisch löschen klickt
	if($logfile eq 'add_cron'){
		$template = HTML::Template->new(filename => 'add_cron_delete_logfiles.html');
	}
	else{
		# Log einzelner Domain löschen
		if($domain){
			$template->param('log_domain' => 1);
		}
		# Logs aller Domains löschen
		elsif($logfile eq 'alldomains'){
			$template->param('log_alldomain' => 1);
		}
		# alle Systemlogs löschen
		elsif($logfile eq 'allsystem'){
			$template->param('log_allsystem' => 1);
		}
		elsif($logfile eq 'all'){
			$template->param('log_all' => 1);
		}
	}

	$template->param('domain' => $domain);
	$template->param('idn_domain' => $idn_domain);
	$template->param('logfile' => $logfile);

	return(\$template);
}

sub instant_mysqlbackup{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	if ($input{'nameofbackup'} eq '' || $input{'nameofbackup'} =~ m/[^A-Za-z\.\-\_0-9]/){
		# $action ist Funktion, die html an html_error ausliefert
		#$action = 'show_mysqlbackup_details';
		$action = 'change_mysqlbackup';
		return(html_error({'nameofbackup' => 'L__Der Dateiname ist ungültig__L'}));
	}
	
	my @databases;

	if($session->param('user') eq 'admin' && $input{'all_databases'}){
						
		logline("debug","instant_mysqlbackup:1");				
						
		my ($dbh, $mysql_connect_error) = easytecc3::mysql_connect();
		if ($mysql_connect_error == '1'){
			return(add_mysql_password());
		}				
						
		my $sth   = $dbh->prepare('SHOW DATABASES');
		$sth->execute;
		
		logline("debug","instant_mysqlbackup:2");				

		while ( my @row = $sth->fetchrow_array ){ # alle rows auslesen

			foreach my $item (@row){
		
				next if $item eq 'information_schema';
				push(@databases, $item);
				
				logline("debug","instant_mysqlbackup:$item");
				
			}
		
		}
			
	} else {
				
		push(@databases, $input{'database'});
		
	}
			
	my $backup = $input{'nameofbackup'};
	#my $user         = 'root';
	#my $db_host	= $ENV{HTTP_HOST};
	my $mysqldump = "$easytecc_prefix/mysqldumper.pl";

	#if(-e "/usr/local/etc/easytecc/.dbconf"){
	#	do "/usr/local/etc/easytecc/.dbconf";
	#}

	my $database;
	foreach $database (@databases){
	
		if( ! -d "$mysqlbackup_dir/$database"){
			mkdir("$mysqlbackup_dir/$database", 0775);
			`chmod 775 $mysqlbackup_dir/$database`;
		}
	
		`touch $mysqlbackup_dir/$database/$backup.lock`;
	
		logline("debug","instant_mysqlbackup:$mysqldump $database $backup $input{'gzip_compression'}");
	
		$| = 1;
		if(my $pid = fork){
	
		}
		else{
			#child
			close (STDIN);
			close (STDOUT);
			close (STDERR);
			open STDIN, '>/dev/null';
			open STDOUT, '>/dev/null';
			open STDERR, '>/dev/null';
			system("$mysqldump $database $backup $input{'gzip_compression'} &");
			exit(0);
		}

	}	
		
	sleep(2);

	return(show_mysqlbackup_details());
}

sub change_mysqlbackup{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'change_mysqlbackup.html');
	my ($database,$backup_days,$email_backup,$admin_email_from,$admin_email_to,$has_mysqlbackup) = '';
	
	if($input{'all_databases'}){
		
		$template->param('all_databases' => 1);
		
	} else {
	
		if(-e "/usr/local/etc/easytecc/mysqlbackup/$input{'database'}.dbb"){
			my $dbconf = `cat /usr/local/etc/easytecc/mysqlbackup/$input{'database'}.dbb`;
			($database,$backup_days,$email_backup,$admin_email_from,$admin_email_to) = split /\n/, $dbconf;
			$database =~ s/^\s*\$database='(.*)'\;/$1/;
			$backup_days =~ s/^\s*\$backup_days='(.*)'\;/$1/;
			$email_backup =~ s/^\s*\$email_backup='(.*)'\;/$1/;
			$admin_email_from =~ s/^\s*\$admin_email_from='(.*)'\;/$1/;
			$admin_email_to =~ s/^\s*\$admin_email_to='(.*)'\;/$1/;
			$has_mysqlbackup = '1';
		}
	
		if(-e "/usr/local/etc/easytecc/mysqlbackup/$input{'database'}.dbb" && $database eq ''){
			return(error("$input{'database'}: L__Backup-Konfigurationsdatei nicht lesbar__L"));
		}
	
		$template->param('database' => $input{'database'});
		
	}

	#wenn beim Ausfllen von Formular Fehler, dann wird es mit Fehlermeldung erneut angezeigt.
	#Vorauswahl wieder übernehmen.
	if(exists $input{'email_backup'}){
		$email_backup = $input{'email_backup'};
	}

	#Backup per email schicken nur für Datenbanken bis 50 MB erlauben
	my (%database_size, $datadir) = easytecc3::get_size_mysql();
	
	foreach(sort keys %database_size){
		logline("debug","database_size key=$_ value=" . $database_size{$_});
	}
	
	my $database_too_big_for_mail = '';
	if($database_size{$input{'database'}} >= '50000'){
		$database_too_big_for_mail = '1';
		$template->param('disabled_email_backup_yes' => 'disabled');
	}

	if($email_backup eq 'yes' && ! $database_too_big_for_mail){
		$template->param('checked_email_backup_yes' => 'checked="checked"');
	}
	#wenn Datenbank zu groß und es wird editiert, dann auf confirm wechseln
	elsif($email_backup eq 'yes' && $database_too_big_for_mail){
		$template->param('checked_email_backup_confirm' => 'checked="checked"');
	}
	elsif($email_backup eq 'confirm'){
		$template->param('checked_email_backup_confirm' => 'checked="checked"');
	}
	elsif($email_backup eq ''){
		$template->param('checked_email_backup_no' => 'checked="checked"');
	}

	$template->param('admin_email_to' => $admin_email_to);
	$template->param('admin_email_from' => $admin_email_from);
	$template->param('backup_days' => $backup_days);
	$template->param('has_mysqlbackup' => $has_mysqlbackup);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub confirm_delete_forward{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);

	#if ($fb) {
	#	$template = HTML::Template->new(filename => 'delete_multi_forward_fb.html');
	#}
	#else{
		$template = HTML::Template->new(filename => 'delete_multi_forward.html');
	#}

	my %delete_forward;
	foreach(sort keys %input){
		# <input  type="checkbox" name="delete2" value="frank">
		if(/^delete[0-9]{1,4}$/){
			$delete_forward{$_} = $input{$_};
		}
	}

	my $hidden_fields_delete_forward = '';
	my $delete_forward = '';
	foreach(sort keys %delete_forward){
		$hidden_fields_delete_forward .= qq~<input type="hidden" name="$_" value="$delete_forward{$_}">~;
		$delete_forward .= $delete_forward{$_} . '<br />';
	}
	$template->param('domain' => $input{'domain'});
	$template->param('hidden_fields_delete_forward' => $hidden_fields_delete_forward);
	$template->param('delete_forward' => $delete_forward);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub confirm_restore_mysqlbackup{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'confirm_restore_mysqlbackup.html');
	$template->param('database' => $input{'database'});
	$template->param('backup' => $input{'backup'});

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub confirm_delete_mysqlbackup{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'confirm_delete_mysqlbackup.html');
	$template->param('database' => $input{'database'});
	$template->param('backup' => $input{'backup'});

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub download_mysqlbackup{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $database = $input{'database'};
	my $backup = $input{'backup'};

	if(-e "$mysqlbackup_dir/$database/$backup"){
		logline("debug","pushing db backup = "."$mysqlbackup_dir/$database/$backup");	
		binmode STDOUT;
		open (IF, "$mysqlbackup_dir/$database/$backup") || dienice("open $mysqlbackup_dir/$database/$backup: $!");
			print "Content-Type: application/octet-stream\n";
			print "Content-Disposition: attachment;filename=\"$backup\"\n\n";
			print while(<IF>);
		close IF;
	}
	logline("debug","<<< Exiting ".(caller(0))[3]."().");
	exit(0);
}

sub delete_mysql_auto_backup{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $database = $input{'database'};

	# automatisches Backup löschen
	my $template = HTML::Template->new(filename => 'confirm_delete_mysql_auto_backup.html');
	$template->param('database' => $database);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_restore_mysqlbackup{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $database = $input{'database'};
	my $backup = $input{'backup'};
	my $arg = '';
	my $backup_file = "$mysqlbackup_dir/$database/$backup";
	my $db_host	= $ENV{HTTP_HOST};
	$db_host = 'localhost' if $fb;

	my ($dbh, $mysql_connect_error) = easytecc3::mysql_connect();
	if ($mysql_connect_error == '1'){
		logline("error","<<< Leaving ".(caller(0))[3]."() by mysql connect error.");
		return(add_mysql_password());
	}
	$dbh->disconnect;


	# do anstatt require, weil .dbconf schon in  easytecc3::mysql_connect() gelesen wird und zweimal require der selben Datei geht nicht
	my $dbconf = `cat /usr/local/etc/easytecc/.dbconf`;
	my ($user,$password) = split /\n/, $dbconf;
	$user =~ s/^\$user="(.*)"\;/$1/;
	$password =~ s/^\$password="(.*)"\;/$1/;
	$password = quotemeta($password);

	logline("debug","user=$user password=$password");

	if( ! -e $backup_file){
		$action = 'confirm_restore_mysqlbackup';
		logline("error","Das Backup existiert nicht = ".$backup_file);
		return(html_error({'Fehler' => 'L__Das Backup existiert nicht__L'}));
	}

	if ( ! -z $backup_file && -r $backup_file){
		# T wie Text
		if ( -T $backup_file){
			$arg = "$mysql --host=$db_host --user=$user --password=$password $database < $backup_file 2>&1";
		}
		# B wie Binär, also gzip-komprimiert
		elsif ( -B $backup_file){
			$arg = "gunzip -c $backup_file | $mysql --host=$db_host --user=$user --password=$password $database 2>&1";
		}
		else{
			$action = 'confirm_restore_mysqlbackup';
			logline("error","Der Dateityp der Backupdatei konnte nicht erkannt werden = ".$backup_file);
			return(html_error({'Fehler' => 'L__Der Dateityp der Backupdatei konnte nicht erkannt werden__L'}));
		}

		my $got = `$arg`;

		if($got && $got !~ /Using a password on the command line interface can be insecure/){
			$action = 'confirm_restore_mysqlbackup';
			logline("error","Das Backup konnte nicht eingespielt werden = ".$got);
			return(html_error({'Fehler' => "L__Das Backup konnte nicht eingespielt werden__L: $got"}));
		}
	}
	else{
		$action = 'confirm_restore_mysqlbackup';
		logline("error","Die Backupdatei durfte nicht gelesen werden oder is 0 bytes = ".$backup_file);
		return(html_error({'Fehler' => 'L__Die Backupdatei konnte nicht gelesen werden__L'}));
	}

	$template->param('result' => 'L__Das Backup wurde erfolgreich wieder hergestellt__L');
	$success_text = 'L__Das Backup wurde erfolgreich wieder hergestellt__L';
	$json_output{'success_message'} = '1';

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_delete_mysql_auto_backup{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $result = $validation_result;

	if($result){
		logline("error","exec_delete_mysql_auto_backup result = $result###");
	}
	else{
		`rm -f $mysqlbackup_dir/$input{'database'}.dbb` unless $fb;
		`/usr/iports/bin/sudo /usr/sbin/rm.pl $mysqlbackup_dir/$input{'database'}.dbb` if $fb;
		logline("debug","exec_delete_mysql_auto_backup result = $result###");
		$result = 'L__Das automatische Backup wurde deaktiviert__L';
		$success_text = 'L__Das automatische Backup wurde deaktiviert__L';
	}

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	
	$json_output{'success_message'} = '1';
	return(\$template);
}

sub new_mysqluser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'new_mysqluser.html') unless $fb;
	my $template = HTML::Template->new(filename => 'new_mysqluser_fb.html') if $fb;

	if(defined easytecc3::is_ftp_limited()){
		$template = HTML::Template->new(filename => 'option_not_available.html');
	}
	else{
		my ($dbh, $mysql_connect_error) = easytecc3::mysql_connect();
		if ($mysql_connect_error == '1'){
			return(add_mysql_password());
		}
		$template->param('dbhost' => $ENV{HTTP_HOST} );
	}

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_new_vhost{
    
    #hier gibts gehacktes!
    
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $error = '';
	my $result = $validation_result;
	
	
	if($result){
		# hm. hier kommen wir nie an...
		# wenn Datenbank mit vhost angelegt werden soll und mysql-Verbindung fehlgeschlagen ist
		# dann Formular für mysql-Passwort anzeigen
		if($results->invalid( 'dbuser' ) =~ /Datenbankverbindung/){
			logline("warning","invalid dbuser = " . $result);
			return(add_mysql_password());
		}
	}
	else{
		my %handle_hash = %{easytecc3::return_file_handler_store()};
		my $httpd_conf = $handle_hash{'/etc/httpd/conf/httpd.conf'};
		my %config = %{$httpd_conf->config_hash()};

		my $ip = $input{'ip_select'} if $input{'ip_select'};
		#ansonsten ist es Haupt-IP aus httpd.conf
		$ip = $config{'main_ip'} unless $input{'ip_select'};
		
		$input{'droot'} = lc($input{'droot'});
				
		my $newphp = $input{'php'};
		if($input{'php_select'}){
			
			$newphp = $input{'php_select'};
			
		}
		
		if(!$newphp){
			$newphp = '5.5'
		}
							
		my $newwrapper = '';
        my $newsuexec = '';
        my $suexec_copy_wrapper_from = '';
        my $suexec_copy_wrapper_to = '';
			    
        #todo: php-version aus kopiertem wrapper parsen
        
		if($fb){
		    
			if($newphp eq '5.5'){
						
				$newwrapper = '/usr/iports/bin/php-cgi';
												
			}
			else{
			
				$newwrapper = "/usr/iports/php$newphp/bin/php-cgi";
				$newwrapper =~ s/\.//g;
				
			}
						
			logline("debug","special was " . $input{'special'});
			
			if($input{'suexec'}){
				
				my $exec_droot = $input{'droot'};
				$exec_droot =~ s/\/noexec\//\/data\//;
				
				$suexec_copy_wrapper_from = $newwrapper;
				$newwrapper = "$exec_droot/php$newphp-cgi";
				$suexec_copy_wrapper_to = $newwrapper;
				
				$newsuexec = "SuexecUserGroup $input{'ftpuser'} $input{'ftpuser'}";
				
				if($input{'special'} =~ /\s*SuexecUserGroup\s*/){
									
					$input{'special'} =~ s#SuexecUserGroup\s*.*#$newsuexec#g;
					
				} else {
					
					$input{'special'} .= "\n<IfModule suexec_module>\n$newsuexec\n<\/IfModule>";
					
				}
				
				if($input{'special_ssl'} =~ /\s*SuexecUserGroup\s*/){
									
					$input{'special_ssl'} =~ s#SuexecUserGroup\s*.*#$newsuexec#g;
					
				} else {
					
					$input{'special_ssl'} .= "\n<IfModule suexec_module>\n$newsuexec\n<\/IfModule>";
					
				}
				
			}
						
			# alter indianer kennt kein iffile
			my $apache_version = `/usr/iports/sbin/httpd -v 2>/dev/null | sed '1!d ; s/[^0-9]*//g' 2>/dev/null`;
			chomp($apache_version);
				
			if($input{'openbasedir'}){
			
				if($apache_version > 2425){
			
					$newwrapper = "<IfFile $newwrapper>\nFcgidWrapper \"$newwrapper -d open_basedir=$input{'openbasedir'}\"\n<\/IfFile>";
					
				} else {
					
					$newwrapper = "FcgidWrapper \"$newwrapper -d open_basedir=$input{'openbasedir'}\"";
					
				}
				
			} else {
				
				if($apache_version > 2425){
				
					$newwrapper = "<IfFile $newwrapper>\nFcgidWrapper $newwrapper\n<\/IfFile>";
					
				} else {
					
					$newwrapper = "FcgidWrapper $newwrapper";
					
				}
				
			}	
				
			if($input{'special'} =~ /(?<!\#)FcgidWrapper/){
				
				$input{'special'} =~ s#(<IfFile[^\n]+\n+)?(?<!\#)FcgidWrapper[^\n]+(\n+</IfFile>)?#$newwrapper#;
					
			} else {
					
				$input{'special'} .= "\n<IfModule fcgid_module>\n<Location \/>\n$newwrapper\n<\/Location>\n<\/IfModule>";
					
			}
			
			if($input{'special_ssl'} =~ /(?<!\#)*FcgidWrapper/){
									
				$input{'special_ssl'} =~ s#(<IfFile[^\n]+\n+)?(?<!\#)*FcgidWrapper[^\n]+(\n+</IfFile>)?#$newwrapper#;
					
			} else {
					
				$input{'special_ssl'} .= "\n<IfModule fcgid_module>\n<Location \/>\n$newwrapper\n<\/Location>\n<\/IfModule>";
					
			}
			
		}
		
		if($input{'redirect_domain'}){
			
			my $redirect_domain = $input{'redirect_domain'};
			my $redirect_path;
						
			if(!$redirect_domain){
				
				$redirect_domain = '%{HTTP_HOST}';
				
			} else {
			
				($redirect_domain,$redirect_path) = $redirect_domain =~ m/^([^\/]+)\/*(.*)$/;
							
			}
			
			
			my $redirect_scheme = 'http';
						
			if($input{'special'} !~ /\s*RewriteRule.*REDIRECT_DOMAIN:.*/){
				
				$input{'special'} .= "\n<IfModule rewrite_module>\nRewriteEngine On\nRewriteRule ^\/?\\.well-known/.+ - [END]\nRewriteRule . - [E=REDIRECT_DOMAIN:$redirect_domain]\nRewriteRule . - [E=REDIRECT_SCHEME:$redirect_scheme]\nRewriteCond expr \"%{HTTP_HOST} != %{ENV:REDIRECT_DOMAIN} || 'http' != %{ENV:REDIRECT_SCHEME}\"\nRewriteRule ^\\/?(.*)\$ %{ENV:REDIRECT_SCHEME}:\/\/%{ENV:REDIRECT_DOMAIN}\/\$1 [R=301,L]\n<\/IfModule>";
				
			}
			else{
				
				$input{'special'} =~ s/\[E=REDIRECT_DOMAIN:.*\]/[E=REDIRECT_DOMAIN:$redirect_domain]/;
				$input{'special'} =~ s/\[E=REDIRECT_SCHEME:.*\]/[E=REDIRECT_SCHEME:$redirect_scheme]/;
				
			}
			
			if(length($redirect_path)){
				
				$input{'special'} =~ s/%\{ENV:REDIRECT_DOMAIN\}\/[^\s]+/%{ENV:REDIRECT_DOMAIN}\/$redirect_path/;
				
			}
			
									
		}
		
		# add letsencrypt
		if($input{'special'} !~ /\.well-known\//){
			
			$input{'special'} = "<IfModule rewrite_module>\nRewriteEngine On\nRewriteRule ^\/?\\.well-known/.+ - [END]\n<\/IfModule>" . $input{'special'};
						
		}
				
		
		# set admin_users for non admin
		if($session->param('user') ne 'admin'){
			$input{'admin_users'} = uc ($session->param('user'));
		}
		
		my $port = '80';
		my $awstats = '';
		my $webmail = '';
		$webmail = qq~Alias /zarafa $droot_prefix/zarafa~ if $input{'webmail'} eq 'zarafa';
		$webmail = qq~Alias /webmail $droot_prefix/roundcube~ if ($input{'webmail'} eq 'roundcube' && ! $fb);
		#$webmail = qq~Redirect /webmail /roundcube~ if ($input{'webmail'} eq 'roundcube' && $fb);

		my $cgi_bin = '';
		$cgi_bin = qq~ScriptAlias /cgi-bin/ $cgi_prefix/~ if $input{'cgi-bin'};

		my $cgi_local = '';
		if ($fb && $input{'cgi-local'}) {
			$cgi_local = qq~$input{'droot'}/cgi-local/~;
			$cgi_local =~ s/\/noexec\//\/data\//;
			$cgi_local = qq~ScriptAlias /cgi-local/  $cgi_local
<Directory "$cgi_local">
    AllowOverride None
    Options None
    Require all granted
</Directory>
~;			
		}
		elsif ( ! $fb && $input{'cgi-local'}) {
			$cgi_local = qq~ScriptAlias /cgi-local/ $input{'droot'}/cgi-local/~;
			
		}
		

		my $mysql = '';
		$mysql = qq~Alias /mysql $droot_prefix/phpMyAdmin~ if ($input{'mysql'} && ! $fb);
		$mysql = qq~Alias /mysql /usr/local/www/phpMyAdmin~ if ($input{'mysql'} && $fb);

		#pop, for, aut auf null wenn leer
		$input{'pop'} = '0' unless $input{'pop'};
		$input{'for'} = '0' unless $input{'for'};
		$input{'aut'} = '0' unless $input{'aut'};

		my $domains = $input{'domains'};
		#Zeilenumbrche aus mehrzeiligem Fomrularfeld entfernen
		$domains =~ s/\r\n/ /g;
		#lowercase
		$domains =~ tr/A-Z/a-z/;
		#erstes www. wenn vorhanden entfernen
		$domains =~ s/^www\.//;
		#wenn andere Domains mit www. dann das auch weg
		$domains =~ s/(;|:|,|\t+|\s+)www\./ /g;


		my @domains_tmp = split m(;|:|,|\t+|\s+), $domains;
		my @domains = ();

		#seriously...
		#apache2.0:
		#ServerName *.test.de
		#ServerAlias *.test.de www.*.test.de

		#apache2.4:
		#ServerName test.de
		#ServerAlias *.test.de www.*.test.de
		
		foreach(@domains_tmp){
			#bei wildcarddomains schlägt domain_to_ascii fehl, daher * abschneiden, domain_to_ascii und * wieder ranhängen
			if(/^\*\.(.*)$/){
				my $domain = $1;
				$domain = ascii_domain($domain);
				$domain = '*.' . $domain;
				push @domains, $domain;
			}
			else{
				push @domains, ascii_domain($_);
			}
		}

		#serveradmin umlautfähig
		my $serveradmin = email_to_ascii($input{'serveradmin'});

		my $servername = $domains[0];
		
		if ($fb && $servername =~ /^\*\.(.*)$/) {
			$servername = $1;
			if (! grep  $_ eq $servername, @domains) {
				push @domains, ascii_domain($servername);
			}
			
		}
		
		
		my $domain_ohne_www = $servername;
		$servername = 'www.' . $servername if($servername !~ /^www\./);

		$result .= join('#',@domains);
		logline("debug","domains = " . join(' ',@domains));

		unless($input{'ftp'}){
			
			if ($fb){
				system("/usr/iports/bin/sudo /usr/sbin/webmkdir -p $input{'droot'}")	
			}
			else{
				system("/usr/sbin/admmkdir -p $input{'droot'}");
				system("chmod 775 $input{'droot'}");
				system("$easytecc_prefix/chmod.pl 775 $input{'droot'}");
			}   
		}

		my $logfiles = '';
		#logfiles schreiben, wenn Statistikauswertung erfolgen soll
		if($input{'stats'} eq 'webalizer' || $input{'stats'} eq 'awstats'){
			$logfiles = qq~CustomLog /home/web/log/access_log_$domain_ohne_www combined~;
		}

		if($input{'stats'} eq 'awstats'){
			
			if($input{'suexec'}){
				#my $servername = `grep -m1 han-solo.net /etc/hosts | awk '{print \$2}'`;
				my $servername = `sed 's/^.* // ; s/\$/.han-solo.net/' /etc/FQDN 2>/dev/null`;
				chomp $servername;
				$awstats = qq~Redirect /stats http://$servername/awstats/awstats.pl?config=$domain_ohne_www~;
			} else {
				$awstats = qq~Redirect /stats http://$servername/awstats/awstats.pl?config=$domain_ohne_www~;
			}
										
			my $got = `$easytecc_prefix/gen_awstats.pl $domain_ohne_www newlog`;
			return(error("L__Fehler beim Anlegen der Statistik für Domain__L $domain_ohne_www : $got")) if $got;
			#awstats-cronjob anlegen, sofern noch nicht vorhanden und webalizer-cronjob entfernen sofern vorhanden
			my @new_cronfile = ();
			my $has_webalizer_cron = '';
			my $has_awstats_cron = '';
			logline("debug","Creating File Object \$cronfile.");
			my $cronfile = file->new({file_name => '/home/web/cronfile'});
			$cronfile->read_file;
			foreach($cronfile->file_content){
				#cronjob löschen
				if (/\/usr\/local\/etc\/$domain_ohne_www\.conf/){
					logline("debug","cronjob löschen = $_");
					$has_webalizer_cron = '1';
					next;
				}
				if (/awstats_updateall\.pl/){
					$has_awstats_cron = '1';
				}
				# alles andere in zu schreibendes cronfile
				push @new_cronfile, $_;
			}

			#ggf. awstatscronjob hinzufügen
			if(! $has_awstats_cron){
				my $min =  int(rand('59'));
				push @new_cronfile, qq~$min 0 * * * $awstats_updateall now 1>/dev/null 2>/dev/null\n~;		        
			}
			$cronfile->file_content(\@new_cronfile);
			my $got = $cronfile->write_file;
			return(error($got)) if $got;
		}
		elsif($input{'stats'} eq 'webalizer'){
			#ggf. vorhandene awstats-conf löschen, die Statistiken selbst löschen wir lieber nicht... cleanup kann man irgendwann immer noch abhängig von letztem Zugriff machen
			if(-e "$awstats_conf_prefix/awstats.$domain_ohne_www.conf"){
			my $got = `rm -f $awstats_conf_prefix/awstats.$domain_ohne_www.conf`;
			return(error("L__Fehler beim Löschen der AWStats-Konfigurationsdatei für Domain__L $domain_ohne_www:$got")) if $got;
			}
			#neuen webalizer-cronjob und webalizerdatei anlegen
			unless(`grep '/usr/local/etc/$domain_ohne_www.conf' /home/web/cronfile`){
				logline("debug","Creating File Object \$cronfile.");
				my $cronfile = file->new({file_name => '/home/web/cronfile'});
				my $got = $cronfile->read_file;
				my $min =  int(rand('59'));
				push @{$cronfile->file_content}, qq~$min 0 * * * /usr/local/bin/webalizer -c /usr/local/etc/$domain_ohne_www.conf 1>/dev/null 2>/dev/null\n~;
				my $got = $cronfile->write_file;
				return(error($got)) if $got;
				easytecc3::generatewebalizer($domain_ohne_www, $input{'droot'});
			}
		}

		#Serveraliaszeile
		my $serveralias = "";
		foreach(@domains){
			$serveralias .= $_ . ' www.' . $_ . ' ';
		}


		my $new_vhost = qq~
<VirtualHost $ip:$port>
ServerAdmin $serveradmin
DocumentRoot $input{'droot'}
ServerName $servername
ServerAlias $serveralias
$logfiles
$cgi_bin
$cgi_local
$webmail
$mysql
$awstats
$input{'special'}
#POP:$input{'pop'}
#FOR:$input{'for'}
#AUT:$input{'aut'}
#QUOT:$input{'quota'}
#CUSTOM_TAG:$input{'custom_tag'}
#ADMIN_USERS:$input{'admin_users'}
</VirtualHost>
~;

			push @{$httpd_conf->file_content} , split(/\n/,$new_vhost);
			logline("debug","new_vhost=$new_vhost");

			if($input{'ftp'}){
				$input{'gecos'} = $input{'ftpdescription'};
				$error = easytecc3::add_ftpuser(\%input);
				return(error('L__Konnte FTP-User nicht anlegen__L')) if $error;
                
                 if($input{'suexec'}){
            
                    #todo: cp.pl anpassen?
                    #my $got = `/usr/iports/bin/sudo /usr/sbin/cp.pl $suexec_copy_wrapper_from $suexec_copy_wrapper_to 2>&1`;
                    
                    #berechtigungen von -o wieder zurücksetzen
                    $got = `/usr/iports/bin/sudo /usr/sbin/chown.pl $input{'ftpuser'}:vuser $input{'droot'} d 2>&1`;
                    return(error("L__Fehler beim Setzen des Besitzers für__L $input{'droot'}: $got")) if $got;
                   
                    $got = `/usr/iports/bin/sudo /usr/sbin/chmod.pl 775 $input{'droot'} 2>&1`;
                    return(error("L__Fehler beim Setzen der Berechtigungen für__L $input{'droot'}: $got")) if $got;
                    
                    $got = `cp -f $suexec_copy_wrapper_from $suexec_copy_wrapper_to`;
                    return(error("L__Fehler beim Kopieren von__L $suexec_copy_wrapper_from L__zu__L $suexec_copy_wrapper_to: $got")) if $got;
                    
                    #und wieder setzen
                    $got = `/usr/iports/bin/sudo /usr/sbin/chown.pl $input{'ftpuser'}:$input{'ftpuser'} $input{'droot'} d 2>&1`;
                    return(error("L__Fehler beim Setzen des Besitzers für__L $input{'droot'}: $got")) if $got;
                    
                    $got = `/usr/iports/bin/sudo /usr/sbin/chmod.pl 755 $input{'droot'} 2>&1`;
                    return(error("L__Fehler beim Setzen der Berechtigungen für__L $input{'droot'}: $got")) if $got;
                    
                }
                
			}

			if($input{'mysql_db'}){
				$error = easytecc3::add_mysqldb(\%input);
				return(error('L__Konnte Datenbank nicht anlegen__L')) if $error;
				$error = easytecc3::add_mysqluser(\%input);
				return(error('L__Konnte mySQL-User nicht anlegen__L')) if $error;
			}

			my $got = $httpd_conf->write_file;
			return(error($got)) if $got;

			$result = qq~L__Der vHost wurde erfolgreich angelegt__L!~;
			$result .= qq~<a href="/cgi-bin/easytecc3/index.pl?action=change_popuser&amp;domain=$servername">L__Fortfahren mit E-Mail-User anlegen__L</a><br />~ if $input{'pop'};
			$result .= qq~<a href="/phpMyAdmin" target="_blank">L__Fortfahren mit phpMyAdmin__L</a><br />~ unless $fb;
			$result .= qq~<a href="/phpmyadmin" target="_blank">L__Fortfahren mit phpMyAdmin__L</a><br />~ if $fb;
			
			$success_text = qq~L__Der vHost wurde erfolgreich angelegt__L!~;

		}

	$template->param('result' => $result);
	logline("debug","result = " . $result);
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_vhosts&success_text=' . encode_base64url($success_text);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_delete_vhost{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $error = '';
	my $result = $validation_result;

	logline("debug","exec_delete_vhost result:$result###");

	if($result){

	}
	else{

		# Kunde
		if($session->param('user') ne 'admin'){	
			my $loginuser = $session->param('user');
			logline("debug","Creating File Object \$passwd.");
			my $passwd = file->new({file_name => '/etc/passwd'});
			$passwd->read_file;
			my %passwd = %{$passwd->file_parsed_hash()};

			if ($passwd{$loginuser}{'gecos'} !~ /\.vhost-[1-9]/){
				return(error("L__Sie können diese Domain nicht verändern.__L"));
			}			
		}

		# httpd.conf wurde bereits bei Validierung eingelesen und in globale Variable gespeichert, damit ersparen wir uns doppelte Arbeit
		my %handle_hash = %{easytecc3::return_file_handler_store()};
		my $httpd_conf = $handle_hash{'/etc/httpd/conf/httpd.conf'};
		my %domains = %{$httpd_conf->file_parsed_hash()};
		my $droot = $domains{$input{'domain'}}{'droot'};

		my $vhost_to_delete = $input{'domain'};
		my $vhost_to_delete_ohne_www = $vhost_to_delete;
		$vhost_to_delete_ohne_www =~ s/^www\.//;

		#vhost aus httpd.conf löschen
		my @new_httpd_conf = ();
		my $vhost = '';
		my $delete_this_vhost = '';
		my @tmp_vhost = ();

		foreach($httpd_conf->file_content){
			chomp;
			$vhost = 1 if(/^\<VirtualHost\s+([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}):/i);

			if($vhost){
				push @tmp_vhost, $_;
				my $vhost_to_delete_quoted = quotemeta("$vhost_to_delete");

				$delete_this_vhost = '1' if(/^ServerName\s+$vhost_to_delete_quoted\b/);
				

				#dieser vhost ist es nicht, also in @tmp_vhost gesammelte Zeilen unverändert übernehmen
				if(/^\<\/VirtualHost/ && ! $delete_this_vhost){
					push @new_httpd_conf, @tmp_vhost;
					$vhost = '';
					@tmp_vhost = ();
				}
				#oder match auf zu löschenden vhost, hier passiert nix und vhost wird nicht in new_httpd_conf gepushed, gleichbedeutend mit löschen
				elsif(/^\<\/VirtualHost/ && $delete_this_vhost){
					logline("debug","vhost=$vhost");
					$vhost = '';
					@tmp_vhost = ();
					# $delete_this_vhost wieder auf null setzen, da es mehrere vhost mit gleichem Namen geben kann, z.B. wegen SSL oder
					# propagationsvhost mit alter IP. Alles weghauen
					$delete_this_vhost = '';
				}
			}
			else{
				push @new_httpd_conf, $_;
			}
		}

		@{$httpd_conf->file_content} = @new_httpd_conf;

		if($input{'delete_ftpuser'}){
			# delete_droot = 0: Inhalt von home user admin zuordnen
			# delete_droot = 1: home löschen
			my $got = easytecc3::del_ftpuser($input{'delete_ftpuser'}, $input{'delete_droot'});
			return(error("L__Fehler beim Löschen von FTP-User__L: $got")) if $got;
		}

		# wenn es FTP-User zum löschen gibt und delete_droot=1, dann wurde home schon beim löschen von
		#ftpuser gelöscht
		#TODO fb
		if($input{'delete_droot'} && !$input{'delete_ftpuser'}){
			my $got = `/usr/iports/bin/sudo /usr/sbin/rm.pl $droot d` if $fb;
			my $got = `$easytecc_prefix/rm.pl $droot d` unless $fb;
			return(error("L__Fehler beim Löschen von__L $droot: $got")) if ($got || -d "$droot");
		}

		#domainspezifische Spameinstellungen löschen
		if(-e "/home/$vhost_to_delete_ohne_www/.spamd/user_prefs"){
			my $tmperror = system("/usr/sbin/delspam","-n","$vhost_to_delete_ohne_www") unless $fb;
			my $tmperror = `/usr/iports/bin/sudo /usr/sbin/delspam -n $vhost_to_delete_ohne_www` if $fb;
			return(html_error(({'L__Die Spameinstellungen konnten nicht gelöscht werden__L' => "$tmperror"}))) if $tmperror;

			my $got = easytecc3::delete_from_spamconf($vhost_to_delete_ohne_www);
			return(html_error(({'L__Die Spameinstellungen konnten nicht gelöscht werden__L' => "$got"}))) if $got;
		}

		# E-Mailuser und Weiterleitungen löschen
		if($input{'delete_email'}){
			my @new_virtmaps = ();
			my @new_aliases = ();
			my %delete_from_aliases = ();
			my $domain = $input{'domain'};
			$domain =~ s/^www\.//;

			$mailpasswd = easytecc3::get_mailpasswd();
			my %passwd = %{$mailpasswd->file_parsed_hash()};
			#my %passwd = %{easytecc3::get_mailpasswd()};

			logline("debug","Creating File Object \$virtmaps.");
			my $virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
			$virtmaps->read_file;
			my %virtmaps = %{$virtmaps->file_parsed_hash()};

			logline("debug","Creating File Object \$aliases.");
			my $aliases = file->new({file_name => '/etc/mail/aliases'});
			$aliases->read_file;
			my %aliases = %{$aliases->file_parsed_hash()};

			my $serveralias = '';
			foreach(@{$domains{$input{'domain'}}{'domains'}}){
				logline("debug","serveralias=$_");
				#wildcard gibs in emailadressen nicht
				next if /^\*\./;
				#ebenso kein www....
				next if /^www\./;
				next if /^$domain_ohne_www$/;
				$serveralias .= $_ . '|';
			}
			#das letzte | weg, daruas können wir dann regex (domain1|domain2|domain3) basteln fr
			#match auf lhs in virtmaps um Weiterleitungen zu löschen
			$serveralias =~ s/\|$//;
			my $emailadress_regex = $serveralias;
			logline("debug","emailadress_regex=$emailadress_regex");

			foreach my $user(sort keys %passwd){
				logline("debug","E-Mailuser=$user gecos=" . $passwd{$user}{'gecos'});
				next if $passwd{$user}{'gecos'} !~ /^$domain - POP/;
	
				#userspezifische Spameinstellungen löschen
				if(-e "/home/$user/.spamd/user_prefs"){
					my $tmperror = system("/usr/sbin/delspam","-n","$user") unless $fb;
					my $tmperror = `/usr/iports/bin/sudo /usr/sbin/delspam -n $user` if $fb;
					return(html_error(({'L__Die Spameinstellungen konnten nicht gelöscht werden__L' => "$tmperror"}))) if $tmperror;
	
					my $got = easytecc3::delete_from_spamconf($olduser);
						return(html_error(({'L__Die Spameinstellungen konnten nicht gelöscht werden__L' => "$got"}))) if $got;
				}
	
				#TODO fb
				if ($fb) {
					my $mailpasswd = easytecc3::get_mailpasswd();
					my @new_mailpasswd = $mailpasswd->file_content;
					#vorhandenen Eintrag entfernen
					@new_mailpasswd = grep !/^$user:/, @new_mailpasswd;
	
					@{$mailpasswd->file_content} = @new_mailpasswd;
					$got = $mailpasswd->write_file;
					logline("error","mailpasswd->write_file got = $got") if $got;
					return(error($got)) if $got;
					
				}
				else{
					my $got = `/usr/sbin/deluser -m -r -n "$user"`;
					return(error("L__Fehler beim Löschen von E-Mailuser__L: $got")) if $got;
				}
				
				# .pass datei
				`rm -f "/usr/local/etc/easytecc/$user.pass"`;
				
			}
			
			foreach($virtmaps->file_content) {
				# match auf Weiterleitung von Domain aus zu löschendem vhost
				if(/^[a-zA-Z0-9_\-\.]{0,100}\@($emailadress_regex)\s+(.*)$/){
					my $target_to_delete = $2;
					logline("debug","match emailadress=$_ target_to_delete=$target_to_delete");
					# Ziel kann Weiterleitung auf mehrere user und/oder autoresponder sein,
					# diese ebenfalls aus aliases entfernen
					if($target_to_delete =~ /_aut$/){
						$delete_from_aliases{$target_to_delete} = $forcount;
						my $autoreply_file = $target_to_delete;
						$autoreply_file =~ s/_aut/\.aut/;
						`rm -f /usr/local/etc/$autoreply_file`;
					}
					elsif($target_to_delete =~ /_spl$/){
						$delete_from_aliases{$target_to_delete} = $forcount;
					}
				}
				else{
					#alle Zeilen, die nicht auf zu löschen vhost matchen wieder in neue virtmaps übernehmen
					push @new_virtmaps, $_;
				}
			}

			@{$virtmaps->file_content} = map(lc, @new_virtmaps);
			my $got = $virtmaps->write_file;
			if ($got) {
				logline("error","virtmaps->write_file = ".$got);
				return(error($got));
			}

			# aus hash %delete_from_aliases regex basteln, um Zeilen aus aliases zu matchen die gelöscht werden sollen
			my $delete_from_aliases_regex = join('|',keys %delete_from_aliases);
			logline("debug","delete_from_aliases_regex=$delete_from_aliases_regex");

			foreach($aliases->file_content) {
				if(/^($delete_from_aliases_regex)\s*:/){
					logline("debug","match aliases=$_");
					#nix, Zeile wird gelöscht
				}
				else{
					#alles andere wieder übernehmen
					push @new_aliases, $_;
				}
			}

			if(keys %delete_from_aliases){
				@{$aliases->file_content} = @new_aliases;
				my $got = $aliases->write_file;
				if ($got) {
					logline("error","aliases->write_file = ".$got);
					return(error($got));
				}
			}
			
			my $sendmail_cw = file->new({file_name => '/etc/mail/sendmail.cw'});
			$sendmail_cw->read_file;
			my @sendmail_cw = @{$sendmail_cw->file_content()};
			my @new_sendmail_cw = grep !/^$serveralias/, @sendmail_cw;
			@{$sendmail_cw->file_content} = @new_sendmail_cw;
			$got = $sendmail_cw->write_file;
			if ($got) {
				logline("error","aliases->write_file = ".$got);
				return(error($got));
			}
			
			# .pass datei-reste
			my $passfiles = '/usr/local/etc/easytecc/*@' . $domain . '.pass';
			`rm -f $passfiles`;
			
		}

        
        ### Mario: Sobald ein SSL-VHost gelöscht wird -jedoch nicht das SSL-Zertifikat- dann wird durch den Cronjob immer wieder versucht,
        ### das SSL-Zertifikat zu verlängern. Daher müssen einige Schritte durchgeführt werden ...
        if($input{'delete_ssl_files'}){
			#my $got = `/usr/iports/bin/sudo /usr/sbin/rm.pl $droot d` if $fb;
			#my $got = `$easytecc_prefix/rm.pl $droot d` unless $fb;
                    logline("debug"," MARIO delete_ssl_files von $vhost_to_delete_ohne_www");
            system('/bin/sh -c "/usr/iports/bin/letsencrypt revoke --cert-path ' . $domains{$input{'domain'}}{'ssl_cert'} . '"');
			#return(error("L__Fehler beim Löschen von__L $droot: $got")) if ($got || -d "$droot");
		}
        
        
        
		#awstats und/oder webalizer-Statistik löschen
		if ($fb) {
			
			`rm -f /usr/local/etc/awstats/awstats.$vhost_to_delete_ohne_www.conf`;
			`rm -f /usr/local/www/awstats/cgi-bin/awstats[0-9][0-9][0-9][0-9][0-9][0-9].$vhost_to_delete_ohne_www.*`;
			
		} else {
			
			if(-e "$awstats_conf_prefix/awstats.$vhost_to_delete_ohne_www.conf"){
				logline("debug","awstats loeschen:$awstats_conf_prefix/awstats.$vhost_to_delete_ohne_www.conf");
				my $got = `$easytecc_prefix/rm.pl $awstats_conf_prefix/awstats.$vhost_to_delete_ohne_www.conf`;
				my $got = `$easytecc_prefix/rm.pl /var/lib/awstats/awstats[0-9][0-9][0-9][0-9][0-9][0-9].$vhost_to_delete_ohne_www.txt`;
				my $got = `$easytecc_prefix/rm.pl /var/lib/awstats/awstats[0-9][0-9][0-9][0-9][0-9][0-9].$vhost_to_delete_ohne_www.bak`;
			}
			
		}	
		
		if(-e "/usr/local/etc/$vhost_to_delete_ohne_www.conf"){
			logline("debug","webalizer loeschen: /usr/local/etc/$vhost_to_delete_ohne_www.conf");
			my $got = `$easytecc_prefix/rm.pl /usr/local/etc/$vhost_to_delete_ohne_www.conf`;

			logline("debug","Creating File Object \$cronfile.");
			my $cronfile = file->new({file_name => '/home/web/cronfile'});
			$cronfile->read_file;

			my @new_cronfile = ();

			foreach($cronfile->file_content){
				#cronjob löschen
				if (/webalizer -c \/usr\/local\/etc\/$vhost_to_delete_ohne_www.conf/){
					logline("debug","cronjob löschen:$_");
					next;
				}
				# alles andere in zu schreibendes cronfile
				push @new_cronfile, $_;
			}

			$cronfile->file_content(\@new_cronfile);
			my $got = $cronfile->write_file;
			if ($got) {
				logline("error","cronfile->write_file = ".$got);
				return(error($got));
			}
		}


		my $got = $httpd_conf->write_file;
		return(error($got)) if $got;

		$result = 'L__Der vHost wurde erfolgreich gelöscht!__L';
		$success_text = 'L__Der vHost wurde erfolgreich gelöscht!__L';
	}

	$template->param('result' => $result);
	logline("debug","result = " . $result);
	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_vhosts&success_text=' . encode_base64url($success_text);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_change_vhost{

	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $error = '';
	my $result = $validation_result;

	logline("debug","exec_change_vhost result:$result###");

	if($result){

	}
	else{
		# httpd.conf wurde bereits bei Validierung eingelesen und in globale Variable gespeichert, damit ersparen wir uns doppelte Arbeit
		my %handle_hash = %{easytecc3::return_file_handler_store()};
		my $httpd_conf = $handle_hash{'/etc/httpd/conf/httpd.conf'};
		my %domains = %{$httpd_conf->file_parsed_hash()};
		my %config = %{$httpd_conf->config_hash()};
		my $vhost = $input{'vhost'};
		my $domain_ohne_www = $vhost;
		$domain_ohne_www =~ s/^www\.//;
		# die alte IP des zu ändernden vhosts, wichtig falls mehrere IPs vorhanden um zu ändernden vhost eindeutig zu identifizieren
		my $oldip = $input{'ip'};
		my $port = $input{'port'};
		#optionales hiddenfeld, nur wenn vhost SSL hat
		my $old_ssl_port = $input{'old_ssl_port'};
		my $ssl_port = $input{'ssl_port'};
		# wenn vhost SSL hat, dann ist hiddenfeld ssl_port gesetzt
		my $ssl = '1' if $input{'old_ssl_port'};
		# wenn Server mehrere IPs hat, dann Formularfeld ip_select auswerten
		my $newip = $input{'ip_select'} if $input{'ip_select'};
		#ansonsten ist es hidden-Feld ip
		$newip = $input{'ip'} unless $input{'ip_select'};
		my $awstats = '';
		
		#if(!length($input{'ssl_droot'})){
			
			$input{'ssl_droot'} = $input{'droot'};
			
		#}
		
		if(!length($input{'ssl_port'})){
			
			$input{'ssl_port'} = 443;
			
		}	
					
		if($input{'stats'} eq 'awstats'){
			if($input{'suexec'}){
				#my $vhost = `grep -m1 han-solo.net /etc/hosts | awk '{print \$2}'`;
				my $vhost = `sed 's/^.* // ; s/\$/.han-solo.net/' /etc/FQDN 2>/dev/null`;
				chomp $vhost;
				$awstats = qq~Redirect /stats http://$vhost/awstats/awstats.pl?config=$domain_ohne_www~;
			} else {
				$awstats = qq~Redirect /stats http://$vhost/awstats/awstats.pl?config=$domain_ohne_www~;
			}
		}
		
		# preserve admin_users and ip for non admin
		if($session->param('user') ne 'admin'){
			$input{'admin_users'} = $domains{$vhost}{'admin_users'};
			$newip = $domains{$vhost}{'ip'};
		}
		
		my $newphp = $input{'php'};
		if($input{'php_select'}){
			
			$newphp = $input{'php_select'};
			
		}
		
		if(!$newphp){
			$newphp = '5.5'
		}
							
		my $newwrapper = '';
        my $newsuexec = '';
        my $suexec_copy_wrapper_from = '';
        my $suexec_copy_wrapper_to = '';
			    
   		if($fb){
			
			if($newphp eq '5.5'){
						
				$newwrapper = '/usr/iports/bin/php-cgi';
												
			}
			else{
			
				$newwrapper = "/usr/iports/php$newphp/bin/php-cgi";
				$newwrapper =~ s/\.//g;						# Der Punkt in der Version wird entfernt. # 
				
			}
						
			logline("debug","special was " . $input{'special'});
			
			if($input{'suexec'}){

				
				my $exec_droot = $input{'droot'};
				$exec_droot =~ s/\/noexec\//\/data\//;
				
				$suexec_copy_wrapper_from = $newwrapper;
				$newwrapper = "$exec_droot/php$newphp-cgi";
				$suexec_copy_wrapper_to = $newwrapper;
				
				$newsuexec = "SuexecUserGroup $input{'ftpuser'} $input{'ftpuser'}";
				
				if($input{'special'} =~ /\s*[^#]\s*SuexecUserGroup\s+/){
									
					$input{'special'} =~ s#SuexecUserGroup\s*.*#$newsuexec#g;
					
				} else {
					
					$input{'special'} .= "\n<IfModule suexec_module>\n$newsuexec\n<\/IfModule>";
					
				}
				
				if($input{'special_ssl'} =~ /\s*[^#]\s*SuexecUserGroup\s+/){
									
					$input{'special_ssl'} =~ s#SuexecUserGroup\s*.*#$newsuexec#g;
					
				} else {
					
					$input{'special_ssl'} .= "\n<IfModule suexec_module>\n$newsuexec\n<\/IfModule>";
					
				}
				
				# dann halt hier...
				my $passwd = file->new({file_name => '/etc/passwd'});
				$passwd->read_file;
				my %passwd = %{$passwd->file_parsed_hash()};
				my $gecos = $passwd{$input{'ftpuser'}}{'gecos'};
					
				#i hate my life
				$got = `/usr/iports/bin/sudo /usr/sbin/usermod -h '$input{'droot'}' -u '$input{'ftpuser'}' -d "'$gecos'" -o 2>&1`;
				if($got && $got !~ m/group\sname.*already\sexists/){
					return(error("L__Fehler beim Ändern des FTP-Benutzers__L $input{'ftpuser'}: $got")) if $got;	
				}
			
				#berechtigungen von -o wieder zurücksetzen
				$got = `/usr/iports/bin/sudo /usr/sbin/chown.pl $input{'ftpuser'}:vuser $input{'droot'} d 2>&1`;
				return(error("L__Fehler beim Setzen des Besitzers für__L $input{'droot'}: $got")) if $got;
			   
				$got = `/usr/iports/bin/sudo /usr/sbin/chmod.pl 775 $input{'droot'} 2>&1`;
				return(error("L__Fehler beim Setzen der Berechtigungen für__L $input{'droot'}: $got")) if $got;
				
				$got = `rm -f $suexec_copy_wrapper_to 2>/dev/null`;
				$got = `cp -f $suexec_copy_wrapper_from $suexec_copy_wrapper_to`;
				return(error("L__Fehler beim Kopieren von__L $suexec_copy_wrapper_from L__zu__L $suexec_copy_wrapper_to: $got")) if $got;
				
				#und wieder setzen
				$got = `/usr/iports/bin/sudo /usr/sbin/chown.pl $input{'ftpuser'}:$input{'ftpuser'} $input{'droot'} d 2>&1`;
				return(error("L__Fehler beim Setzen des Besitzers für__L $input{'droot'}: $got")) if $got;
				
				$got = `/usr/iports/bin/sudo /usr/sbin/chmod.pl 755 $input{'droot'} 2>&1`;
				return(error("L__Fehler beim Setzen der Berechtigungen für__L $input{'droot'}: $got")) if $got;
				
				
			} elsif ($input{'special'} =~ m/<IfModule suexec_module>[^<]*<\/IfModule>/) {
                
                
				logline("debug","exec_change_vhost undoing suexec: $input{'ftpuser'}\n");
				
				$input{'special'} =~ s/<IfModule suexec_module>[^<]*<\/IfModule>//m;
                $input{'special_ssl'} =~ s/<IfModule suexec_module>[^<]*<\/IfModule>//m;
						
				#$input{'special'} =~ s/SuexecUserGroup/#SuexecUserGroup/;
				#$input{'special_ssl'} =~ s/SuexecUserGroup/#SuexecUserGroup/;
				
				#/usr/sbin/usermod kann die gruppe leider nicht entfernen, deswegen admin und cmsfix
                
                if (length($input{'ftpuser'})){
                    
                    $got = `/usr/iports/bin/sudo /usr/sbin/chown.pl $input{'ftpuser'}:vuser $input{'droot'} d 2>&1`;
                    return(error("L__Fehler beim Setzen des Besitzers für__L $input{'droot'}: $got")) if $got;
				
                    $got = `/usr/iports/bin/sudo /usr/sbin/cms_fix.pl $input{'ftpuser'} $input{'droot'} 2>&1`;
                    return(error("L__Fehler beim Setzen der Berechtigungen für__L $input{'droot'}: $got")) if $got;
                    
                }
                

			}
			
			# alter indianer kennt kein iffile
			my $apache_version = `/usr/iports/sbin/httpd -v 2>/dev/null | sed '1!d ; s/[^0-9]*//g' 2>/dev/null`;
			chomp($apache_version);
			
			if($input{'openbasedir'}){
			
				if($apache_version > 2425){
			
					$newwrapper = "<IfFile $newwrapper>\nFcgidWrapper \"$newwrapper -d open_basedir=$input{'openbasedir'}\"\n<\/IfFile>";
					
				} else {
					
					$newwrapper = "FcgidWrapper \"$newwrapper -d open_basedir=$input{'openbasedir'}\"";
					
				}
				
			} else {
				
				if($apache_version > 2425){
				
					$newwrapper = "<IfFile $newwrapper>\nFcgidWrapper $newwrapper\n<\/IfFile>";
					
				} else {
					
					$newwrapper = "FcgidWrapper $newwrapper";
					
				}
				
			}
							
			if($input{'special'} =~ /(?<!\#)FcgidWrapper/){
				
				$input{'special'} =~ s#(<IfFile[^\n]+\n+)?(?<!\#)FcgidWrapper[^\n]+(\n+</IfFile>)?#$newwrapper#;
				
			} else {
					
				$input{'special'} .= "\n<IfModule fcgid_module>\n<Location \/>\n$newwrapper\n<\/Location>\n<\/IfModule>";
					
			}
			
			if($input{'special_ssl'} =~ /(?<!\#)FcgidWrapper/){
									
				$input{'special_ssl'} =~ s#(<IfFile[^\n]+\n+)?(?<!\#)FcgidWrapper[^\n]+(\n+</IfFile>)?#$newwrapper#;
					
			} else {
					
				$input{'special_ssl'} .= "\n<IfModule fcgid_module>\n<Location \/>\n$newwrapper\n<\/Location>\n<\/IfModule>";
					
			}
			
		}
			
		if($input{'redirect_domain'} ne $domains{$vhost}{'redirect_domain'} || $input{'ssl_force'} ne $domains{$vhost}{'ssl_force'}){
			
			my $redirect_domain = $input{'redirect_domain'};
			my $redirect_path;
			
			if(!$redirect_domain){
				
				$redirect_domain = '%{HTTP_HOST}';
				
			} else {
				
				($redirect_domain,$redirect_path) = $redirect_domain =~ m/^([^\/]+)\/*(.*)$/;
				
			}
			
			my $redirect_scheme = 'http';
			
			if($input{'ssl_force'}){
				
				$redirect_scheme = 'https';
				
			}
						
			if($input{'special'} !~ /\s*RewriteRule.*REDIRECT_DOMAIN:.*/){
				
				$input{'special'} .= "\n<IfModule rewrite_module>\nRewriteEngine On\nRewriteRule ^\/?\\.well-known/.+ - [END]\nRewriteRule . - [E=REDIRECT_DOMAIN:$redirect_domain]\nRewriteRule . - [E=REDIRECT_SCHEME:$redirect_scheme]\nRewriteCond expr \"%{HTTP_HOST} != %{ENV:REDIRECT_DOMAIN} || 'http' != %{ENV:REDIRECT_SCHEME}\"\nRewriteRule ^\\/?(.*)\$ %{ENV:REDIRECT_SCHEME}:\/\/%{ENV:REDIRECT_DOMAIN}\/\$1 [R=301,L]\n<\/IfModule>";
				
			}
			else{
				
				$input{'special'} =~ s/\[E=REDIRECT_DOMAIN:.*\]/[E=REDIRECT_DOMAIN:$redirect_domain]/;
				$input{'special'} =~ s/\[E=REDIRECT_SCHEME:.*\]/[E=REDIRECT_SCHEME:$redirect_scheme]/;
				
			}
			
			if(length($redirect_path)){
				
				$input{'special'} =~ s/%\{ENV:REDIRECT_DOMAIN\}\/[^\s]+/%{ENV:REDIRECT_DOMAIN}\/$redirect_path/;
				
			}
			
			if($input{'special_ssl'} !~ /\s*RewriteRule.*REDIRECT_DOMAIN:.*/){
				
				$input{'special_ssl'} .= "\n<IfModule rewrite_module>\nRewriteEngine On\nRewriteRule ^\/?\\.well-known/.+ - [END]\nRewriteRule . - [E=REDIRECT_DOMAIN:$redirect_domain]\nRewriteCond expr \"%{HTTP_HOST} != %{ENV:REDIRECT_DOMAIN}\"\nRewriteRule ^\\/?(.*)\$ https:\/\/%{ENV:REDIRECT_DOMAIN}\/\$1 [R=301,L]\n<\/IfModule>";
				
			}
			else{
				
				$input{'special_ssl'} =~ s/\[E=REDIRECT_DOMAIN:.*\]/[E=REDIRECT_DOMAIN:$redirect_domain]/;
				#falls kopiert!
				$input{'special_ssl'} =~ s/\[E=REDIRECT_SCHEME:.*\]/[E=REDIRECT_SCHEME:https]/;
				$input{'special_ssl'} =~ s/\'http\'\s!=\s%\{ENV:REDIRECT_SCHEME\}/\'https\' != %{ENV:REDIRECT_SCHEME}/;
												
			}
			
			if(length($redirect_path)){
				
				$input{'special_ssl'} =~ s/%\{ENV:REDIRECT_DOMAIN\}\/[^\s]+/%{ENV:REDIRECT_DOMAIN}\/$redirect_path/;
				
			}			
						
		}
			
		# add letsencrypt
		if($input{'special'} !~ /\.well-known\//){
			
			$input{'special'} = "<IfModule rewrite_module>\nRewriteEngine On\nRewriteRule ^\/?\\.well-known/.+ - [END]\n<\/IfModule>\n" . $input{'special'};
						
		}
		if($input{'special_ssl'} !~ /\.well-known\//){
			
			$input{'special_ssl'} = "<IfModule rewrite_module>\nRewriteEngine On\nRewriteRule ^\/?\\.well-known/.+ - [END]\n<\/IfModule>\n" . $input{'special_ssl'};
						
		}	
			
		if($ssl && length($input{'admin_users'})){
			
			if($input{'special_ssl'} !~ m/ProxyPass\s\/easytecc/ && $fb){
			
				# immer und immer wieder
				#my $servername = `grep -m1 '^[^#]*han-solo.net' /etc/hosts | awk '{print \$2}'`;
				my $servername = `sed 's/^.* // ; s/\$/.han-solo.net/' /etc/FQDN 2>/dev/null`;
				chomp $servername;
			
				$input{'special_ssl'} .= "\nSSLProxyEngine on";
				$input{'special_ssl'} .= "\nProxyPass /easytecc https://$servername/easytecc/";
				$input{'special_ssl'} .= "\nProxyPassReverse /easytecc https://$servername/easytecc/";
				$input{'special_ssl'} .= "\nProxyPass /cgi-bin/easytecc4/ https://$servername/cgi-bin/easytecc4/";
				$input{'special_ssl'} .= "\nProxyPassReverse /cgi-bin/easytecc4/ https://$servername/cgi-bin/easytecc4/";
				
			}
						
		} elsif($input{'special_ssl'} =~ m/ProxyPass\s\/easytecc\// && $fb){
			
			$input{'special_ssl'} =~ s/.*SSLProxyEngine\son.*//;
			$input{'special_ssl'} =~ s/.*ProxyPass\s.*easytecc.*//g;
			$input{'special_ssl'} =~ s/.*ProxyPassReverse\s.*easytecc.*//g;
			
		}
					
		logline("debug","special is " . $input{'special'});	
			
		
		# Wenn SSL-vhost geändert werden soll, gucken, ob gleiche IP + Port schon durch andere SSL-Domain besetzt ist
		# weil sonst das Zertifikat des ersten vhosts in der httpd.conf genommen wird.
		my %ip_port_used = '';
		foreach(keys %domains){
			next if $_ eq $vhost;
			$ip_port_used{$domains{$_}{'ssl_ip'}}{$domains{$_}{'ssl_port'}} = '1';
		}

		# SNI allowed on fb machines
		# nun auch auf linux ;-)
		#if(exists $ip_port_used{$newip}{$ssl_port}){
		#	# return(html_error('L__Die angegebene IP und der Port werden bereits durch eine andere SSL-Domain verwendet__L'));
		#	return(html_error(({'ip_select' => 'L__Die angegebene IP und der Port werden bereits durch eine andere SSL-Domain verwendet__L'})));
		#}

		#Auswertung für awstats entfernen wenn checkbox nicht aktiv
		if($input{'stats'} ne 'awstats' && -e "$awstats_conf_prefix/awstats.$domain_ohne_www.conf"){
			`/usr/iports/bin/sudo /usr/sbin/rm.pl "$awstats_conf_prefix/awstats.$domain_ohne_www.conf"` if $fb;
			`rm -f "$awstats_conf_prefix/awstats.$domain_ohne_www.conf"` unless $fb;
		}
		# falls von webalizer auf awstats oder umgekehrt gewechselt wird
		elsif($input{'stats'} eq 'awstats' && ! -e "$awstats_conf_prefix/awstats.$domain_ohne_www.conf"){
			
			# wenn schon log vorhanden, dann sucht es sich gen_awstats.pl selbst raus
			if($domains{$vhost}{'access_log'} ne ''){
				my $got = `$easytecc_prefix/gen_awstats.pl $domain_ohne_www`;
				$got = `$easytecc_prefix/gen_awstats.pl $domain_ohne_www`;
				return(error("L__Fehler beim Anlegen der Statistik für Domain__L $domain_ohne_www:$got")) if $got;
			}
			# wenn nicht standardpfad benutzen und gen_awstats.pl mit zweiltem Schalter mitteilen
			else{
				my $got = `$easytecc_prefix/gen_awstats.pl $domain_ohne_www newlog`;
				return(error("L__Fehler beim Anlegen der Statistik für Domain__L $domain_ohne_www:$got")) if $got;
			}

			# awstats-cronjob anlegen, sofern noch nicht vorhanden und webalizer-cronjob entfernen sofern vorhanden
			my @new_cronfile = ();
			my $has_webalizer_cron = '';
			my $has_awstats_cron = '';
			logline("debug","Creating File Object \$cronfile.");
			my $cronfile = file->new({file_name => '/home/web/cronfile'});
			$cronfile->read_file;
			foreach($cronfile->file_content){
				# cronjob löschen
				if (/\/usr\/local\/etc\/$domain_ohne_www\.conf/){
					logline("debug","cronjob löschen:$_");
					$has_webalizer_cron = '1';
					next;
				}
				if (/awstats_updateall\.pl/){
					$has_awstats_cron = '1';
				}
				# alles andere in zu schreibendes cronfile
				push @new_cronfile, $_;
			}

			# ggf. awstatscron hinzufügen
			if(! $has_awstats_cron){
				my $min =  int(rand('59'));
				push @new_cronfile, qq~$min 0 * * * $awstats_updateall now 1>/dev/null 2>/dev/null\n~;
			}
			$cronfile->file_content(\@new_cronfile);
			my $got = $cronfile->write_file;
			return(error($got)) if $got;
		}
		elsif($input{'stats'} eq 'webalizer'){
			# ggf. vorhandene awstats-conf löschen, die Statistiken selbst löschen wir lieber nicht... cleanup kann man irgendwann immer noch abhängig von letztem Zugriff machen
			if(-e "$awstats_conf_prefix/awstats.$domain_ohne_www.conf"){
				my $got = `rm -f $awstats_conf_prefix/awstats.$domain_ohne_www.conf`;
				return(error("L__Fehler beim Löschen der AWStats-Konfigurationsdatei für Domain__L $domain_ohne_www: $got")) if $got;
			}
			#neuen webalizer-cronjob und webalizerdatei anlegen
			unless(`grep '/usr/local/etc/$domain_ohne_www.conf' /home/web/cronfile`){
				logline("debug","Creating File Object \$cronfile.");
				my $cronfile = file->new({file_name => '/home/web/cronfile'});
				my $got = $cronfile->read_file;
				my $min =  int(rand('59'));
				push @{$cronfile->file_content}, qq~$min 0 * * * /usr/local/bin/webalizer -c /usr/local/etc/$domain_ohne_www.conf 1>/dev/null 2>/dev/null\n~;
				my $got = $cronfile->write_file;
				return(error($got)) if $got;
				easytecc3::generatewebalizer($domain_ohne_www, $input{'droot'});
			}
		}

		my @new_httpd_conf = ();

		#my $special = $input{'special'};
		#$special =~ s/\r\n/ /g;
		my $logfiles = '';
		#vorhandenen Pfad für Logfile immer übernehmen
		if($domains{$vhost}{'access_log'} ne ''){
			$logfiles = qq~CustomLog $domains{$vhost}{'access_log'} combined\n~;
			# sofern vorhanden auch errorlog übernehmen
			$logfiles .= qq~ErrorLog $domains{$vhost}{'error_log'}~ if $domains{$vhost}{'error_log'} ne '';
		}
		#noch kein Log vorhanden, aber Auswahl für Statistikprogramm, also Logfile anlegen
		elsif($input{'stats'} eq 'webalizer' || $input{'stats'} eq 'awstats'){
			$logfiles = qq~CustomLog /home/web/log/access_log_$domain_ohne_www combined\nErrorLog /home/web/log/error_log_$domain_ohne_www~;
		}

		my $webmail = '';
		$webmail = qq~Alias /zarafa $droot_prefix/zarafa~ if $input{'webmail'} eq 'zarafa';
		$webmail = qq~Alias /webmail $droot_prefix/roundcube~ if ($input{'webmail'} eq 'roundcube' && ! $fb);
		#$webmail = qq~Redirect /webmail /roundcube~ if ($input{'webmail'} eq 'roundcube' && $fb);

		my $cgi_bin = '';
		$cgi_bin = qq~ScriptAlias /cgi-bin/ $cgi_prefix/~ if $input{'cgi-bin'};

		my $cgi_local = '';
		if ($fb && $input{'cgi-local'}) {
			$cgi_local = qq~$input{'droot'}/cgi-local/~;
			$cgi_local =~ s/\/noexec\//\/data\//;
			$cgi_local = qq~ScriptAlias /cgi-local/  $cgi_local
<Directory "$cgi_local">
    AllowOverride None
    Options None
    Require all granted
</Directory>
~;			
		}
		elsif ( ! $fb && $input{'cgi-local'}) {
			$cgi_local = qq~ScriptAlias /cgi-local/ $input{'droot'}/cgi-local/~;
			
		}

		my $mysql = '';
		$mysql = qq~Alias /mysql $droot_prefix/phpMyAdmin~ if ($input{'mysql'} && ! $fb);
		$mysql = qq~Alias /mysql /usr/local/www/phpMyAdmin~ if ($input{'mysql'} && $fb);

		#der zu ändernde vhost
		my $vhost_to_change = $input{'vhost'};
		my $domains = $input{'domains'};
		# Zeilenumbrche aus mehrzeiligem Fomrularfeld entfernen
		$domains =~ s/\r\n/ /g;
		# lowercase
		$domains =~ tr/A-Z/a-z/;
		# erstes www. wenn vorhanden entfernen
		$domains =~ s/^www\.//;
		# wenn andere Domains mit www. dann das auch weg
		$domains =~ s/(;|:|,|\t+|\s+)www\./ /g;

		my $servername = $servername_to_alias = ascii_domain($input{'domain'});
		my $servername_to_alias = $servername;
		$servername = 'www.' . $servername if($servername !~ /^www\./);
		# Servername kommt auch in Serveralias rein
		$servername_to_alias =~ s/^www\.//;

		$domains = "$servername_to_alias " . $domains;
		my @domains = split m(;|:|,|\t+|\s+), $domains;

		logline("debug","domains=" . join(' ',@domains));

		# Serveraliaszeile
		my $serveralias = "";
		foreach(@domains){
			# bei wildcarddomains schlägt domain_to_ascii fehl, daher * abschneiden, domain_to_ascii und * wieder ranhängen
			if(/^\*\.(.*)$/){
				my $domain = $1;
				$domain = ascii_domain($domain);
				$domain = '*.' . $domain;
				$serveralias .= $domain . ' www.' . $domain . ' ';
			}
			else{
				$serveralias .= ascii_domain($_) . ' www.' . ascii_domain($_) . ' ';
			}
		}
		$serveralias =~ s/\s+$//;

		#Serveradmin E-Mailadresse umlautfähig
		my $serveradmin = email_to_ascii($input{'serveradmin'});

		my $change_this_vhost = '';
		# bei erster Zeile eines vhosts wissen wir noch nicht welcher vhost es ist
		#also erstmal zwischenspeichern
		my @tmp_vhost = ();
		my $vhost = '';
		my $ssl_vhost = '';
		my $vhost_ip = '';
		# counter für array @new_httpd_conf, falls zweiter vhost aufgrund Änderung von IP eingefgt werden muss
		my $line_vhost_port80 = '';
		my $line_vhost_ssl = '';
		# für den alten vhost wird ein neuer erstellt. Erkennung erfolgt mit /^ServerName\s+$vhost_to_change\b/
		# Alles was dann an Zeilen vom alten vhost folgt wird gelöscht
		my $discard_rest_of_old_vhost = '';
		# wenn vhost auf andere IP geändert wurde wird zweiter vhost mit alter IP wegen Propagation
		# angelegt. Wenn der vhost erneut geändert wird, wird beim ändern des ersten vhosts schon zweiter vhost mit alter
		# IP erstellt. D.h. der zweite alte vhost in httpd.conf kann ignoriert werden. variable wird bei if($oldip ne $newip) gesetzt
		my $vhost_done = '';
		my $tmp_servername;
		foreach($httpd_conf->file_content){
			#wenn Server mehrere IPs hat, dann existieren ggf. 4 vhosts, je zwei für port 80 und 443 wegen Propagationszeit
			# Änderungen dann an 4 vhosts durchführen
			#wenn die IP von vhost geändert wird, dann den alten vhost belassenund neuen vhostz mit neuer IP vor alten anlegen
			#auch wegen Propagation. Bei allen nderungen auch Änderung an vhost mit alter IP machen
			#evtl. hat SSL-vhost Spezialeintrge, diese auf jeden Fall immer mitübernehmen, es sei denn eine Änderung matcht auf
			#special line. Dabei <directory> und <ifconfig> bercksichtigen
			$vhost = 1 if(/^\<VirtualHost\s+([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}):$port/i);
			$ssl_vhost = 1 if(/^\<VirtualHost\s+([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}):(443|8444|8445|8080)/i);
			$vhost_ip = $1;

			if($vhost){
				push @tmp_vhost, $_;
				my $vhost_to_change_quoted = quotemeta("$vhost_to_change");
				$change_this_vhost = '1' if(/^ServerName\s+$vhost_to_change_quoted\b/);


				if(/^ServerName/){
					$tmp_servername = $_;
					logline("debug","tmpservername1=$tmp_servername");
				}

				#dieser vhost ist es nicht, also in @tmp_vhost gesammelte Zeilen unverändert übernehmen
				if(/^\<\/VirtualHost/ && ! $change_this_vhost){
					logline("debug","tmpservername2=$tmp_servername");
					push @new_httpd_conf, @tmp_vhost;
					$vhost = '';
					@tmp_vhost = ();
				}
				# letzte Zeile von zu änderndem vhost, hier Variablen zurcksetzen, damit nachfolgende vhosts auch
				#geschrieben werden können
				elsif(/^\<\/VirtualHost/ && $change_this_vhost){
					$change_this_vhost = '';
					$vhost = '';
					$discard_rest_of_old_vhost = '';
					@tmp_vhost = ();
					# ganz wichtig, sonst wird vhost doppelt geschrieben
					next;
				}
				#oder match auf zu ändernden vhost. $vhost_done ist für den Fall, da noch nachfolgende vhosts mit anderen IPs folgen, diese werden
				# ignoriert, da hier schon zweiter vhost mit alter IP angelegt wird, sofern die IP geändert werden soll
				elsif($change_this_vhost  && ! $vhost_done){

					#restliche Zeilen vom zu ändernden vhost nicht übernehmen
					next if $discard_rest_of_old_vhost;

					logline("debug","vhost=$vhost\tssl_vhost=$ssl_vhost\tvhost_ip=$vhost_ip\told_ssl_port=$old_ssl_port\tnewip=$newip");
					logline("debug","vhost 80 match");
					
					my $vhost_changed = qq~
<VirtualHost $newip:$port>
ServerAdmin $serveradmin
DocumentRoot $input{'droot'}
ServerName $servername
ServerAlias $serveralias
$logfiles
$cgi_bin
$cgi_local
$webmail
$mysql
$awstats
$input{'special'}
#POP:$input{'pop'}
#FOR:$input{'for'}
#AUT:$input{'aut'}
#QUOT:$input{'quota'}
#CUSTOM_TAG:$input{'custom_tag'}
#ADMIN_USERS:$input{'admin_users'}
</VirtualHost>
~;

#					$vhost_changed =~ s/\n\n/\n/g;
#					$vhost_changed =~ s/\n\n/\n/g;
#					push @new_httpd_conf, $vhost_changed;
					push @new_httpd_conf, split(/\n/,$vhost_changed);

					# ok, nun haben wir den geänderten vhost, es kann aber sein, da sich die IP geändert hat
					# in diesem Fall den gleichen vhost mit der alten IP hinter dem neuen vhost anlegen, damit es bei
					# propagation nicht zu Ausfall kommt. Domains aus vhosts hören auf beide IPs
					if($oldip ne $newip){
						logline("debug","$oldip ne $newip");
					my $vhost_oldip = qq~
<VirtualHost $oldip:$port>
ServerAdmin $serveradmin
DocumentRoot $input{'droot'}
ServerName $servername
ServerAlias $serveralias
$logfiles
$cgi_bin
$cgi_local
$webmail
$mysql
$awstats
$input{'special'}
#POP:$input{'pop'}
#FOR:$input{'for'}
#AUT:$input{'aut'}
#QUOT:$input{'quota'}
#CUSTOM_TAG:$input{'custom_tag'}
#ADMIN_USERS:$input{'admin_users'}
</VirtualHost>
~;
#						$vhost_oldip =~ s/\n\n/\n/g;
#						$vhost_oldip =~ s/\n\n/\n/g;
#						push @new_httpd_conf, $vhost_oldip;
						push @new_httpd_conf, split(/\n/,$vhost_oldip);
					}
					# die restlichen Zeilen des alten vhosts ignorieren
					$discard_rest_of_old_vhost = '1';
					# vhost mit alter IP fertig. für den Fall, da bereits vhost mit alter IP vorhanden wird dieser ignoriert, da ja hier bereits zwei vhosts
					# mit beiden IP s angelegt wurden
					$vhost_done = '1';
				}
			}
			elsif($ssl_vhost){
				push @tmp_vhost, $_;

				$change_this_vhost = '1' if(/^ServerName\s+$vhost_to_change\b/);

				#dieser vhost ist es nicht, also in @tmp_vhost gesammelte Zeilen unverändert übernehmen
				if(/^\<\/VirtualHost/ && ! $change_this_vhost){
					push @new_httpd_conf, @tmp_vhost;
					$ssl_vhost = '';
					@tmp_vhost = ();
				}
				elsif(/^\<\/VirtualHost/ && $change_this_vhost){
					$change_this_vhost = '';
					$ssl_vhost = '';
					$discard_rest_of_old_vhost = '';
					@tmp_vhost = ();
					# ganz wichtig, sonst wird vhost doppelt geschrieben
					next;
				}
				# oder match auf zu ändernden vhost
				elsif($change_this_vhost){

					#restliche Zeilen vom zu ändernden vhost nicht übernehmen
					next if $discard_rest_of_old_vhost;

					logline("debug","SSLvhost=$vhost\tssl_vhost=$ssl_vhost\tvhost_ip=$vhost_ip\told_ssl_port=$old_ssl_port\tnewip=$newip\tssl_port=$ssl_port");
					logline("debug","SSLvhost match");

my $vhost_changed = qq~
<VirtualHost $newip:$ssl_port>
ServerAdmin $serveradmin
DocumentRoot $input{'ssl_droot'}
ServerName $servername
ServerAlias $serveralias
$logfiles
$cgi_bin
$cgi_local
$webmail
$mysql
$awstats
$input{'special_ssl'}
</VirtualHost>
~;
#					$vhost_changed =~ s/\n\n/\n/g;
#					$vhost_changed =~ s/\n\n/\n/g;
#					push @new_httpd_conf, $vhost_changed;
					push @new_httpd_conf, split(/\n/,$vhost_changed);
					logline("debug","vhost_changed=$vhost_changed");

					# ok, nun haben wir den geänderten SSL-vhost, es kann aber sein, da sich die IP geändert hat
					# in diesem Fall den gleichen vhost mit der alten IP hinter dem neuen vhost anlegen, damit es bei
					# propagation nicht zu Ausfall kommt. Domains aus vhosts hören auf beide IPs

					# Nein, doch nicht...
					# Wenn Kopie von vhost mit alter IP angelegt wird und es gibt anderen SSL-vhost mit der gleichen IP dann würde das falsche Zertifikat
					# und der falsch vhost beim Aufruf der zweiten SSL-domain erfolgen. Also doch Propagation, aber nur beim SSL-Aufruf. Damit kann man aber leben

					# die restlichen Zeilen des alten vhosts ignorieren
					$discard_rest_of_old_vhost = '1';
				}
			}
			else{
				push @new_httpd_conf, $_;
			}
		}
		@{$httpd_conf->file_content} = @new_httpd_conf;
		my $got = $httpd_conf->write_file;
		return(error($got)) if $got;
		
		if($ssl && $input{'special_ssl'} =~ m/letsencrypt/){
						
			if(defined($session) && defined($session->param('ssl_expiry_dates'))){
				%ssl_expiry_dates = %{$session->param('ssl_expiry_dates')};
				delete $ssl_expiry_dates{$vhost};
			}
		
			if(
				$input{'ssl_droot'} ne $domains{$servername}{'ssl_droot'} ||
				$input{'droot'} ne $domains{$servername}{'droot'} ||
				$input{'vhost'} ne $domains{$servername}{'domain'} ||
				$serveralias ne $domains{$servername}{'serveralias'} 
			){
				
				logline("debug","ssl=$ssl\ninput_special_ssl=$input{'special_ssl'}\ninput_ssl_droot=$input{'ssl_droot'}\nvhost_ssl_droot=$domains{$servername}{'ssl_droot'}\ninput_droot=$input{'droot'}\nvhost_droot=$domains{$servername}{'droot'}\n");
				logline("debug","input_vhost=#$input{'vhost'}#\ninput_serveralias=#$serveralias#\nvhost_vhost=#$domains{$servername}{'domain'}#\nvhost_serveralias=#$domains{$servername}{'serveralias'}#\n");		
				$success_text2 = 'L__Eine Veränderung des DocumentRoot, ServerName oder ServerAlias wirkt sich auf das hinterlegte Let\'s Encrypt Zertifikat aus. Sie sollten das Zertifikat neu erstellen, falls die Änderung nicht nur temporär ist.__L';
				
			}
						
		}
		
	}

	
	my $user_context = qq~<br /><br />
	<a href="/cgi-bin/easytecc3/index.pl?action=change_forward&amp;domain=$input{'vhost'}"><b>L__gehe zu "E-Mail-Weiterleitungen anlegen"__L</b></a><br />
	<a href="/cgi-bin/easytecc3/index.pl?action=change_popuser&amp;domain=$input{'vhost'}"><b>L__gehe zu "E-Mail-User anlegen"__L</b></a>~;

	$template->param('result' => 'L__Der vhost wurde erfolgreich geändert!__L' . $user_context);
	$success_text = 'L__Der vhost wurde erfolgreich geändert!__L';
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_vhosts&success_text=' . encode_base64url($success_text);
	
	
	
	if($success_text2 ne ''){
		
		$json_output{'redirect_to'} .= '&success_text2=' . encode_base64url($success_text2);
		
	}
		
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub delete_popuser{
	$input{'action'} = 'exec_delete_popuser';
	exec_change_popuser();
}

sub exec_delete_popuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $error = '';
	my $result = $validation_result;

	logline("debug","exec_delete_popuser result:$result###");

	if($result){

	}
	else{
		# erstmal die zu löschenden user in array sammeln
		my @deluser;
		foreach(sort keys %input){
			# <input  type="checkbox" name="delete2" value="frank">
			if(/^delete[0-9]{1,4}$/){
				push @deluser, $input{$_};
			}
		}

		foreach my $olduser(@deluser) {
			
			my $easytecc_enable_file = '/usr/local/etc/easytecc/mailuser/' . $olduser;
			`test -f $easytecc_enable_file && rm $easytecc_enable_file`;
						
			if(-e "/home/$olduser/.spamd/user_prefs"){
				my $tmperror = `/usr/sbin/delspam -n $olduser` unless $fb;
				my $tmperror = `/usr/iports/bin/sudo /usr/sbin/delspam -n $olduser` if $fb;
				
				return(html_error(({'non_specific' => 'L__Die Spameinstellungen konnten nicht gelöscht werden__L'}))) if $tmperror;

				my $got = easytecc3::delete_from_spamconf($olduser);
				return(html_error(({'non_specific' => 'L__Die Spameinstellungen konnten nicht gelöscht werden__L'}))) if $got;
			}

			
			if ($fb) {
				
				logline("debug","Creating File Object \$virtmaps.");
				my $virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
				$virtmaps->read_file;
				my %virtmaps = %{$virtmaps->file_parsed_hash()};
		
				logline("debug","Creating File Object \$aliases.");
				my $aliases = file->new({file_name => '/etc/mail/aliases'});
				$aliases->read_file;
				my %aliases = %{$aliases->file_parsed_hash()};
		
				my %delete_from_aliases;
				my @new_virtmaps = ();
				my @new_aliases = ();
		
				# erstmal die zu löschenden Weiterleitungen in hash sammeln
				my %old_emailadress;
		
				foreach(sort keys %input){
					# <input  type="checkbox" name="delete2" value="frank">
					if(/^delete[0-9]{1,4}$/){
						logline("debug","key input=$_");
						$old_emailadress{$input{$_}} = '1';
					}
				}
		
				my $emailadress_regex = join('|',keys %old_emailadress);
		
				foreach($virtmaps->file_content) {
					# Wenn Domain aber kein Autoresponder
					# Domainmituser@ und direkt am Zeilenbeginn
					if(/^($emailadress_regex)\s+(.*)$/){
						# aha, match auf ein der zu löschenden E-Mailadressen, value aus %old_emailadress ist die Zeile aus Fornular, wo
						# neue Daten eingetragen wurden. $1 aus regex entspricht gespeichertem value
						my $forcount_to_delete = $1;
						my $target_to_delete = $2;
		
						logline("debug","regex match: forcount_to_delete = $1## - target_to_delete = $2##");
		
						# entweder einzelne Weiterleitung in virtmaps oder mehrere Ziele, d.h. auch aliases Zeile löschen
						if($target_to_delete =~ /(_aut|_spl)$/){
							$delete_from_aliases{$target_to_delete} = $forcount;
						}
					}
					else{
						#alles was nicht matcht unverändert übernehmen
						push @new_virtmaps, $_;
					}
				}
		
				my $delete_from_aliases_regex = join('|',keys %delete_from_aliases);
		
				if(keys %delete_from_aliases){
					foreach($aliases->file_content) {
						if(/^($delete_from_aliases_regex)\s*:/){
							# nix, Zeile wird gelöscht
						}
						else{
							push @new_aliases, $_;
						}
					}
		
					@{$aliases->file_content} = @new_aliases;
					my $got = $aliases->write_file;
					if ($got) {
						logline("error","aliases->write_file = ".$got);
						return(error($got));
					}
				}
		
				@{$virtmaps->file_content} = map(lc, @new_virtmaps);
				my $got = $virtmaps->write_file;
				if ($got) {
					logline("error","virtmaps->write_file = ".$got);
					return(error($got));
				}
				
				
				my $mailpasswd = easytecc3::get_mailpasswd();
				my @new_mailpasswd = $mailpasswd->file_content;
				#vorhandenen Eintrag entfernen
				@new_mailpasswd = grep !/^$olduser:/, @new_mailpasswd;

				@{$mailpasswd->file_content} = @new_mailpasswd;
				$got = $mailpasswd->write_file;
				logline("error","mailpasswd->write_file got = $got") if $got;
				return(error($got)) if $got;
				
				if (is_email($olduser)){
				$got = `/usr/iports/bin/sudo /usr/sbin/rm.pl /home/$olduser d`;
				logline("error","/usr/sbin/rm.pl /home/$olduser d got = $got") if $got;
				return(error($got)) if $got;
				}
				
			}
			else{
				##bei E-Mailuser Alles an Daten wech hauen...
				my $newerror = `/usr/sbin/deluser -m -r -n "$olduser"`;
					if($newerror){
					chomp($newerror);
					$error .= "deluser2: $newerror<br />\n";
					$newerror = "";
					}
				last if $error;
			}
			
			# .pass datei
			`rm -f "/usr/local/etc/easytecc/$olduser.pass"`;
				
		}

		if (! $error){
			my $user_context = qq~<br /><br />
			<a href="/cgi-bin/easytecc3/index.pl?action=change_forward&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-Weiterleitungen anlegen"__L</b></a><br />
			<a href="/cgi-bin/easytecc3/index.pl?action=change_popuser&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-User anlegen"__L</b></a>~;

			$result = qq~L__E-Mail-User erfolgreich gelöscht!__L<br /><br />~ . $user_context;
			$success_text = 'L__E-Mail-User erfolgreich gelöscht!__L';
			$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_email&success_text=' . encode_base64url($success_text);
		}
		else{
			$result = qq~L__Achtung! Die Änderungen konnten nicht vollständig übernommen werden. Bitte beachten Sie folgende Warnhinweise__L:<br />$error~;
			$json_output{'error'} = $result;
		}
	}

	$template->param('result' => $result);
	logline("debug","result = " . $result);

	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_change_popuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $error = '';
	my $anychange = '';
	my $result = $validation_result;

	logline("debug","exec_change_popuser result:$result###");

	if($result){

	}
	else{
		
		my %delete_popuser;
		my @adduser;
		my @deluser;
		my @editquota;
		my @editpass;
		my %domains;
		
		#zuerst gucken, ob popuser gelöscht werden sollen
		
		foreach(sort keys %input){
			# <input  type="checkbox" name="delete2" value="frank">
			if(/^delete[0-9]{1,4}$/){
				$delete_popuser{$_} = $input{$_};
			}
		}

		my %sendmail_cw_domains;		
		
		if(keys %delete_popuser >= 1 && !$session->param('is_mailuser')){
			
			logline("debug",'change_popuser delete');
			
			$template = HTML::Template->new(filename => 'delete_multi_popuser.html');
			my $hidden_fields_delete_popuser = '';
			my $delete_popuser = '';
			foreach(sort keys %delete_popuser){
				$hidden_fields_delete_popuser .= qq~<input type="hidden" name="$_" value="$delete_popuser{$_}">~;
				$delete_popuser .= $delete_popuser{$_} . '<br />';
				logline("debug","delete: " . $delete_popuser{$_});
				
			}
			$template->param('domain' => $input{'domain'});
			$template->param('hidden_fields_delete_popuser' => $hidden_fields_delete_popuser);
			$template->param('delete_popuser' => $delete_popuser);
			$template->param('delete_popuser_idn' => encode('utf-8', email_to_unicode($delete_popuser)));
		}
		# keine popuser explizit zum löschen, nur Änderung von Name, Passwort oder Quota
		# Änderung von Name beinhaltet natürlich auch löschen und Neuanlage von User
		else{
			
			logline("debug",'change_popuser change');
			
			# erstmal Daten sammeln:
			#  <tr><td><INPUT TYPE="HIDDEN" NAME="old_user2" VALUE="frank">
			#  <input  type="checkbox" name="delete2" value="frank">
			#  <INPUT NAME="user2" TYPE="TEXT" id="user2" VALUE="frank" SIZE="20"></td>
			#  <td><INPUT NAME="pass2" TYPE="TEXT" id="pass2" VALUE="gugl" SIZE="20"></td>
			#  <td><INPUT NAME="quota2" TYPE="TEXT" id="quota2" VALUE="1000" SIZE="6"> MB</td>
			
			
			# darf nicht mehr als vhost-Quota sein
			my $vhost_quota_sum = '';

			my $popused = '';
			foreach(keys %input){
				next unless /^old_user(.*)$/;
				$popused++;
			}

			#if ($fb) {
			#$domains{$input{'domain'}}{'pop'} = $domains{$input{'domain'}}{'for'};
			#logline("debug",qq~fb pop=for=$domains{$input{'domain'}}{'for'}~);
			#}
			
			# mailuser hack
			if($session && $session->param('is_mailuser')){
			
				logline("debug","is_mailuser=1, setting template=mailuser_interface");
				$template = ${mailuser_interface()};
				$action = $input{'action'} = 'mailuser_interface';
				$input{'active_tab'} = '_password';
										
				if(length($input{"pass1"})){
			
					push(@editpass,1);
					$anychange = 1;
					
				}
								
			} else { 
			
				my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
				$httpd_conf->read_file;
				%domains = %{$httpd_conf->file_parsed_hash()};
			
				my $servername = `sed 's/^.* // ; s/\$/.han-solo.net/' /etc/FQDN 2>/dev/null`;
				chomp $servername;
				
				#$input{'domain'} ne 'www.administrator' damit admin auf externem Mailserver geändert werden kann
				if($popused > $domains{$input{'domain'}}{'pop'} && $input{'domain'} ne 'www.administrator' && $input{'domain'} ne $servername){
					
					logline("debug","popused = $popused, domain = $input{'domain'}, popmax = $domains{$input{'domain'}}{'pop'}");
					
					return(html_error(({'non_specific' => 'L__Der vHost enthält mehr E-Mail-User als der vHost erlaubt. Bitte editieren Sie den vHost und erhöhen die Anzahl der E-Mail-Accounts um Änderungen vornehmen zu können__L'})));
				}
	
				#Damit admin auf externem Mailserver geändert werden kann, admin ist keiner domain zugeordnet
				$domains{$input{'domain'}}{'pop'} = '1' if ($input{'domain'} eq 'www.administrator' || $input{'domain'} eq $servername);
	
				my $domain = $input{'domain'};
				$domain =~ s/^www\.//;
	
	
				foreach my $count (0..$domains{$input{'domain'}}{'pop'}){
					
					$input{"user$count"} = email_to_ascii($input{"user$count"});
									
					my $easytecc_enable_file;
					if($input{"easytecc$count"} && length($input{"user$count"})){
						
						$easytecc_enable_file = '/usr/local/etc/easytecc/mailuser/' . $input{"user$count"};
						`test -f $easytecc_enable_file || touch $easytecc_enable_file`;
						$anychange = 1;
				
					} elsif(length($input{"old_user$count"})) {
					
						$easytecc_enable_file = '/usr/local/etc/easytecc/mailuser/' . $input{"old_user$count"};
						`test -f $easytecc_enable_file && rm $easytecc_enable_file`;
						$anychange = 1;
						
					}
					
					if(!$input{"2fa$count"}){
						
						my $two_fa_enable_file = '/usr/local/etc/easytecc/2fa/' . $input{"old_user$count"};
						`test -f $two_fa_enable_file && rm $two_fa_enable_file`;
						$anychange = 1;
						
					}
														
					if($input{"old_user$count"} ne $input{"user$count"} ||
					   $input{"old_pass$count"} ne $input{"pass$count"} ||
					   $input{"old_quota$count"} ne $input{"quota$count"}){
						
						logline("debug","###exec_change_popuser###" . $input{"old_pass$count"} . "##" . $input{"pass$count"} . "##");
						
						# AHA :) also was geändert.....
						# nur was?!?!?!? ;)
						if($input{"old_user$count"} eq ""){
							logline("debug",qq~popuser anlegen: $input{"user$count"}~);
							
							#gabs nich - also neu
							push(@adduser,$count);
							$anychange = 1;
						}
						elsif($input{"user$count"} eq ""){
							logline("debug",qq~popuser löschen: $input{"user$count"}~);
							#gabs vorher - jetzt weg
							push(@deluser,$count);
							$anychange = 1;
							# Quota eines zu löschenden Users aus der für E-Mailuser vergebenen Quota herausrechnen
							$vhost_quota_sum -= $input{"quota$count"}
						}
						elsif($input{"user$count"} eq $input{"old_user$count"} &&
							  $input{"old_pass$count"} eq $input{"pass$count"} &&
							  $input{"old_quota$count"} ne $input{"quota$count"}){
							logline("debug",qq~popuser quota ändern: $input{"user$count"}~);
	
							#user gabs vorher - immernoch GLEICH
							#quota geändert
							push(@editquota,$count);
							$anychange = 1;
						}
						elsif($input{"user$count"} eq $input{"old_user$count"} &&
							  $input{"old_pass$count"} ne $input{"pass$count"} &&
							  $input{"old_quota$count"} eq $input{"quota$count"}){
							logline("debug",qq~popuser pass ändern: $input{"user$count"}~);
							#user gabs vorher - immernoch GLEICH
							#pass geändert
							push(@editpass,$count);
							$anychange = 1;
						}
						elsif($input{"user$count"} eq $input{"old_user$count"} &&
							  $input{"old_pass$count"} ne $input{"pass$count"} &&
							  $input{"old_quota$count"} ne $input{"quota$count"}){
							logline("debug",qq~popuser pass und quota ändern: $input{"user$count"}~);
							#user gabs vorher - immernoch GLEICH
							#pass UND quota geändert
							push(@editpass,$count);
							push(@editquota,$count);
							$anychange = 1;
						}
						elsif($input{"user$count"} ne $input{"old_user$count"}){
							logline("debug",qq~popuser löschen und anlegen: $input{"old_user$count"} $input{"user$count"}~);
							# user gabs vorher - ABER geändert (also einen gelöscht neuen in gleiche id
							# pass UND/ODER quota muss uns egal sein - alles andere klappt wg. web rechten nicht - also nehmen wir neuen user an
							
							push(@deluser,$count); ##mit altem user
							push(@adduser,$count); ##mit neuem user
							$anychange = 1;
						}
					}
					$vhost_quota_sum += $input{"quota$count"};
				}
	
				if($input{'ftpquota'} ne $input{'old_ftpquota'}){
					$anychange = 1;
				}
	
				if($input{'ftpquota'}){
					$vhost_quota_sum += $input{'ftpquota'};
				}
	
				if($domains{$input{'domain'}}{'quota'} < $vhost_quota_sum  && $input{'domain'} ne 'www.administrator' && $input{'domain'} ne $servername){
					my $max_pop_quota = $domains{$input{'domain'}}{'quota'} - $input{'ftpquota'};
					#return(html_error(({'quota' => 'L__Die vergebene Quota darf die Gesamtquota des vHosts nicht übersteigen__L'})));
					$error_fields{"non_specific"} .= "L__Die vergebene Quota darf die Gesamtquota des vHosts nicht übersteigen__L L__Für E-Mail-Benutzer stehen zur Verfügung:__L $max_pop_quota MB";
				}

			}	
				
			# user zählen und wenn doppelt dann Fehlermeldung
			my %popusers;
			my $domainpart = '';
			
			

			# Validierung der Formularfelder, bei Fehler wieder change_popuser anzeigen und css klasse setzen, damit Felder markiert sind
			# In hash error_fields wird feldname und Fehlermeldung gesetzt, dadurch wei html_error welches Feld markiert werden muß.
			if($anychange){
				logline("debug","exec_change_popuser validation");
				# die arrays
				# @adduser = $input{"user$count"}
				# @editquota = $input{"quota$count"}
				# @editpass = $input{"pass$count"}
				# enthalten die Änderungen, wenn z.B. in @adduser eine "2" steht, dann muss $input{"user2"} überprft werden.
				foreach my $count(@adduser){
					undef $domain_part;
					# hash of arrays um Usernamen dem Formularfeld user$count zuordnen zu können und fehlerhaftes Feld CSS-Klasse setzen zu können
					# In anonymen array landen nummern von $count. Wenn mehr als eine, dann wurde Username doppelt angegeben.
					push @{$popusers{$input{"user$count"}}}, $count;
					
					$domain_part = $input{"user$count"};
					$domain_part =~ s/^.*@//;
					$domain_part = ascii_domain($domain_part);
					logline("debug","domainpart=$domain_part");
					
					
					my %password_chars;
					my @password_chars = split //, $input{"pass$count"};
					foreach(@password_chars){
						$password_chars{$_} = '1';
					}
					logline("debug","user = $count; "."pass = " . $input{"pass$count"});

					if(easytecc3::mailuser_exists($input{"user$count"})){
						$error_fields{"user$count"} = "L__Der Benutzer existiert bereits__L";
					}
					if($input{"user$count"} =~ /^(mail|kontakt|support|info|webmaster|administrator|office|admin|httpd)$/){
						$error_fields{"user$count"} = "L__Dieser Name kann nicht als E-Mail-User verwendet werden. Bitte wählen Sie einen anderen Namen.__L";
					}
					if(! $input{"user$count"}){
						$error_fields{"user$count"} = "L__Bitte geben Sie einen Benutzernamen an__L";
					}
					if($input{"user$count"} =~ /[^a-zA-Z0-9\-\_]/ && ! $fb){
						$error_fields{"user$count"} = "L__Der Benutzername enthält ungültige Zeichen__L";
					}
					
					if(is_domain($domain_part) && ! is_email(email_to_ascii($input{"user$count"})) && $fb){
						$error_fields{"user$count"} = "L__Die E-Mail-Adresse hat ein falsches Format__L";
					}					
					elsif(! is_domain($domain_part) && $fb){
						$error_fields{"user$count"} = "$domain_part: L__Ungültiger Domainname__L";
						logline("debug","domainpart=$domain_part Ungültiger Domainname");	
					}
					elsif( (! grep $_ eq $domain_part, @{$domains{$input{'domain'}}{'domains'}}) && $fb){
						$error_fields{"user$count"} = "$domain_part L__gehört nicht zur Domain__L $input{'domain'}";
						logline("debug","domainpart=$domain_part falsche Domain");
					}
					
					if(length $input{"user$count"} < 2){
						$error_fields{"user$count"} = "L__Der Benutzername ist zu kurz__L";
					}
					if(length $input{"user$count"} > 16 && ! $fb){
						$error_fields{"user$count"} = "L__Der Benutzername ist zu lang. Bitte geben Sie höchstens 16 Zeichen an.__L";
					}
					if(length $input{"user$count"} > 250 && $fb){
						$error_fields{"user$count"} = "L__Der Benutzername ist zu lang. Bitte geben Sie höchstens 250 Zeichen an.__L";
					}
					if(! $input{"quota$count"}){
						$error_fields{"quota$count"} = "L__Bitte geben Sie eine Speicherbegrenzung an__L";
					}
					if($input{"quota$count"} =~ /\D/){
						logline("warning","quota ungültig");
						$error_fields{"quota$count"} = "L__Die Mengenangabe für die Speicherbegrenzung darf nur aus Zahlen bestehen__L";
					}

					if(! $input{"pass$count"}){
						$error_fields{"pass$count"} = "L__Bitte geben Sie ein Passwort an__L";
					}
					elsif($input{"pass$count"} =~ /^[0-9]{1,}$/){
						$error_fields{"pass$count"} = "L__Das Passwort darf nicht ausschliesslich aus Zahlen bestehen__L";
					}
					elsif($input{"pass$count"} =~ /[äöüÄÖÜß]/){
						$error_fields{"pass$count"} = "L__Das Passwort enthält ungültige Zeichen__L";
					}
					elsif($input{"pass$count"} !~ /[A-Za-z0-9\%\+\*\~\-\_\@\#\$\&\=\?\!]/){
						$error_fields{"pass$count"} = "L__Das Passwort enthält ungültige Zeichen__L";
					}
					elsif($input{"user$count"} eq $input{"pass$count"}){
						$error_fields{"pass$count"} = ('L__Das Passwort darf nicht gleich dem Benutzernamen sein__L');
					}
					elsif(length($input{"pass$count"}) < 10){
						$error_fields{"pass$count"} = ('L__Das Passwort ist zu kurz__L');
					}
					elsif(keys(%password_chars) < 2){
						logline("debug","change popuser chars:" . $input{"pass$count"} . '=' . keys(%password_chars));
						$error_fields{"pass$count"} = ('L__Das Passwort muss mindestens zwei verschiedene Zeichen enthalten__L');
					} else {
						$sendmail_cw_domains{$domain_part} = 1;
					}
					
				}
				foreach(@editquota){
					logline("debug",qq~quota=$_ $input{"quota$_"}~);
					if(! $input{"quota$_"}){
						$error_fields{"quota$_"} = "L__Bitte geben Sie eine Speicherbegrenzung an__L";
					}
					elsif($input{"quota$_"} =~ /\D/){
						logline("warning","quota ungültig");
						$error_fields{"quota$_"} = "L__Die Mengenangabe für die Speicherbegrenzung darf nur aus Zahlen bestehen__L";
					} else {
						
						undef $domain_part;
						$domain_part = $input{"user$_"};
						$domain_part =~ s/^.*@//;
						$domain_part = ascii_domain($domain_part);
						$sendmail_cw_domains{$domain_part} = 1;
					
					}
						
						
				}
				foreach(@editpass){
					my %password_chars;
					my @password_chars = split //, $input{"pass$_"};
					foreach(@password_chars){
						logline("debug","char=$_ ord=" . ord($_));
						$password_chars{$_} = '1';
					}

					logline("debug",$input{"pass$_"}." = editpass = $_\nchars = ".keys(%password_chars));
					if(! $input{"pass$_"}){
						$error_fields{"pass$_"} = "L__Bitte geben Sie ein Passwort an__L";
					}
					elsif($input{"pass$_"} =~ /^[0-9]{1,}$/){
						$error_fields{"pass$_"} = "L__Das Passwort darf nicht ausschliesslich aus Zahlen bestehen__L";
					}
					elsif($input{"pass$_"} =~ /[äöüÄÖÜß]/){
						$error_fields{"pass$_"} = "L__Das Passwort enthält ungültige Zeichen__L";
					}
					elsif($input{"pass$_"} !~ /[A-Za-z0-9\%\+\*\~\-\_\@\#\$\&\=\?\!]/){
						$error_fields{"pass$_"} = "L__Das Passwort enthält ungültige Zeichen__L";
					}
					elsif($input{"user$_"} eq $input{"pass$_"}){
						$error_fields{"pass$_"} = ('L__Das Passwort darf nicht gleich dem Benutzernamen sein__L');
					}
					elsif(length($input{"pass$_"}) < 10){
						$error_fields{"pass$_"} = ('L__Das Passwort ist zu kurz__L');
					}
					elsif(keys(%password_chars) < 2){
						$error_fields{"pass$_"} = ('L__Das Passwort muss mindestens zwei verschiedene Zeichen enthalten__L');
					}
					elsif(exists ($input{"rep_pass$_"}) && !length($input{"rep_pass$_"})){
						$error_fields{"rep_pass$_"} = "L__Bitte wiederholen Sie das Passwort__L";
					}
					elsif(exists ($input{"rep_pass$_"}) && $input{"rep_pass$_"} ne $input{"pass$_"}){
						$error_fields{"rep_pass$_"} = "L__Die Passwörter stimmen nicht überein__L";
					}
										
					else {
						
						undef $domain_part;
						$domain_part = $input{"user$_"};
						$domain_part =~ s/^.*@//;
						$domain_part = ascii_domain($domain_part);
						$sendmail_cw_domains{$domain_part} = 1;
					
					}
				}

				# doppelte Usernamen?
				foreach(sort keys %popusers){
					# $popusers{$_} enthält anonymes array von user$count. Wenn mehr als einer, dann wurde user doppelt angegeben.
					# Mit Hilfe von user$count CSS-Klasse setzen
					if(scalar @{$popusers{$_}} > 1){
						foreach(@{$popusers{$_}}){
							$error_fields{"user$_"} = $input{"user$_"} . ": L__Der Benutzername wurde doppelt angegeben__L";
						}
					}
				}
			}
						
			if(keys(%error_fields)){
			
				return(html_error(\%error_fields))
							
			}

			my $newerror = '';
			#um Code übersichtlicher zu halten kann mailpasswd ggf. mehrmals geschrieben werden,
			#macht in der Praxis aber nur ein paar Millisekunden aus
			my $virtmaps = '';
			my $aliases = '';
			my $mailpasswd = '';
			my @new_mailpasswd;
			my @new_virtmaps;
			my @new_aliases;
			if($anychange){
				#In easytecc4 können bei change_popuser keine Emailuser mehr gelöscht werden, indem der Name des Users geändert wird.
				#easytecc3:
				#-Kd ändert Namen von Benutzer
				#-exec_change_popuser löscht alten User und legt neuen an. Dadurch werden auch alle Emails des alten Users gelöscht
				#und einige Kunden dachten diese werden mit übernommen.
				#
				#easytecc4:
				#-zu löschende User werden mit checkbox marktiert und es gibt separaten Löschungsdialog
				#dadurch entstehen keine Missverständnisse
				#das Feld des Emailbenutzers ist auch readonly und kann nicht geändert werden
				#
				#den Code lassen wir erstmal drin und setzen @deluser zurück, vielleicht kann man es für andere Zwecke nochmal gebrauchen
				undef @deluser;
				## @deluser - single - Wird nicht mehr verwendet
				foreach my $count (@deluser) {
					# old_ Namen holen von id
					my $olduser = $input{"old_user$count"};

					if(-e "/home/$olduser/.spamd/user_prefs"){
						my $tmperror = system("/usr/sbin/delspam","-n","$olduser");
						return(html_error(({'L__Die Spameinstellungen konnten nicht gelöscht werden__L' => "$tmperror"}))) if $tmperror;

						my $got = easytecc3::delete_from_spamconf($olduser);
						return(html_error(({'L__Die Spameinstellungen konnten nicht gelöscht werden__L' => "$got"}))) if $got;
					}

					##bei E-Mailuser Alles an Daten wech hauen...
					$newerror = `/usr/sbin/deluser -m -r -n "$olduser"` unless $error;
					if($newerror){
						chomp($newerror);
						$error .= "deluser2: $newerror<br />\n";
						$newerror = "";
					}
					last if $error;
				}

				## @adduser - single
				my $domain = $input{'domain'};
				$domain =~ s/^www\.//;
				unless($error){

					if ($fb && scalar @adduser > 0) {
						logline("debug","Creating File Object \$mailpasswd.");
						$mailpasswd = easytecc3::get_mailpasswd();
						@new_mailpasswd = $mailpasswd->file_content;
						
						logline("debug","Creating File Object \$virtmaps.");
						$virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
						$virtmaps->read_file;
						my %virtmaps = %{$virtmaps->file_parsed_hash()};
						@new_virtmaps = $virtmaps->file_content;
				
						logline("debug","Creating File Object \$aliases.");	
						$aliases = file->new({file_name => '/etc/mail/aliases'});
						$aliases->read_file;
						my %aliases = %{$aliases->file_parsed_hash()};
						@new_aliases = $aliases->file_content;
					}
									
					##Neue Daten anhängen
					foreach my $count (@adduser) {
						##user prüfen und schreiben
						#auf altem System wird nur ein Systemuser angelegt, sonst nix
						if($input{"user$count"} && ! $fb) {
							logline("debug",qq~vor adduser pop3: $input{"user$count"}~);
							# usernamen immer klein
							$input{"user$count"} = lc($input{"user$count"});
							##Nur Mail da kein -f(tp) Schalter
							$newerror = `/usr/sbin/adduser -h '/home/$input{"user$count"}' -d '$domain - POP' -q $input{"quota$count"}M -p '$input{"pass$count"}' -n '$input{"user$count"}'`;
							$error .= qq~adduser $input{"user$count"},$input{"quota$count"}M: $newerror<br />\n~ if $newerror;
							logline("debug",qq~nach adduser pop3: $newerror  /usr/sbin/adduser -h /home/$input{"user$count"} -d '$domain - POP' -q $input{"quota$count"}M -p $input{"pass$count"} -n $input{"user$count"}~);
							easytecc3::encrypt("/usr/local/etc/easytecc/" . $input{"user$count"} . ".pass", $input{"pass$count"});
						}
						elsif($input{"user$count"} && $fb) {
						#auf freebsd dmr ist Emailuser=Emailadresse und es wird User in /etc/mail/mailuser
						#und auch auch eine Weiterleitung angelegt.
						#virtmaps: blubb@example.com    blubb_example.com_spl
						#aliases: blubb_example.com_spl:   "|/usr/iports/bin/procmail -a blubb@example.com"
							my $email_address = email_to_ascii($input{"user$count"});
							my $virtmaps_rhs = $email_address . '_spl';
							$virtmaps_rhs =~ s/@/_/;
							my $aliases_lhs = $virtmaps_rhs;
							my $aliases_rhs = qq~"|/usr/iports/bin/procmail -a $email_address"~;
							push @new_virtmaps, qq~$email_address\t\t$virtmaps_rhs~;
							push @new_aliases, qq~$aliases_lhs:\t$aliases_rhs~;
							my $password = $input{"pass$count"};
							$password = encode('iso-8859-1', "$password");
							$password = `/usr/iports/bin/sudo /usr/sbin/doveadm pw -s SHA512-CRYPT -p '$password' | sed s/\{SHA512-CRYPT\}//`;
							chomp $password;
							#TODO: get real 'virtmail' UID from passwd
							push @new_mailpasswd, qq~$email_address:$password:1008:1005:$domain - POP:/home/~ . $email_address . '::userdb_quota_rule=*:storage=' . $input{"quota$count"} . 'M';
							my $got = `/usr/iports/bin/sudo /usr/sbin/webmkmhome -u $email_address` if ($email_address && ! -d "/home/$email_address");
							logline("debug","webmkmhome got = $got\nemail_address = $email_address");
							logline("error","webmkmhome got = $got") if $got;	
							return(error($got)) if $got;
							easytecc3::encrypt("/usr/local/etc/easytecc/$email_address.pass", $input{"pass$count"});
						}
						last if $error;
					}
					
					if ($fb && scalar @adduser > 0) {
						@{$virtmaps->file_content} = map(lc, @new_virtmaps);
						my $got = $virtmaps->write_file;
						logline("error","virtmaps->write_file got = $got") if $got;
						undef @new_virtmaps;
						return(error($got)) if $got;
				
						@{$aliases->file_content} = map(lc, @new_aliases);
						$got = $aliases->write_file;
						logline("error","aliases->write_file got = $got") if $got;
						undef @new_aliases;
						return(error($got)) if $got;
				
						@{$mailpasswd->file_content} = @new_mailpasswd;
						$got = $mailpasswd->write_file;
						logline("error","mailpasswd->write_file got = $got") if $got;
						undef @new_mailpasswd;
						return(error($got)) if $got;
					}
					
				}

				## @editpass - multi
				unless($error){
					
					if ($fb && scalar @editpass > 0) {
						logline("debug","Creating File Object \$mailpasswd.");
						$mailpasswd = easytecc3::get_mailpasswd();
						@new_mailpasswd = $mailpasswd->file_content;
					}
					
					foreach my $count (@editpass) {
						##user prüfen und pass ändern
						if($input{"user$count"} && ! $fb) {
							$newerror = `/usr/sbin/chps -p '$input{"pass$count"}' -n '$input{"user$count"}' -m`;
							$error .= qq~<B>$input{"user$count"}</B>: $newerror<br />~ if $newerror;
							easytecc3::encrypt("/usr/local/etc/easytecc/" . $input{"user$count"} . ".pass", $input{"pass$count"});
						}
						elsif($input{"user$count"} && $fb) {
							my $password = $input{"pass$count"};
							logline("debug","doveadm password1=$password");
							$password = encode('iso-8859-1', "$password");
							logline("debug","doveadm password2=$password");
							$password = `/usr/iports/bin/sudo /usr/sbin/doveadm pw -s SHA512-CRYPT -p '$password' | sed s/\{SHA512-CRYPT\}//`;
							chomp $password;
							
							my $emailadress = $input{"user$count"};
							@new_mailpasswd = grep !/^$emailadress:/, @new_mailpasswd;
							#TODO: get real 'virtmail' UID from passwd
							push @new_mailpasswd, qq~$emailadress:$password:1008:1005:$domain - POP:/home/~ . $emailadress . '::userdb_quota_rule=*:storage=' . $input{"quota$count"} . 'M';
							easytecc3::encrypt("/usr/local/etc/easytecc/$emailadress.pass", $input{"pass$count"});
						}
						last if $error;
					}
					
					if ($fb && scalar @editpass > 0) {
				
						@{$mailpasswd->file_content} = @new_mailpasswd;
						$got = $mailpasswd->write_file;
						logline("error","mailpasswd->write_file got = $got") if $got;
						undef @new_mailpasswd;
						return(error($got)) if $got;
					}
					
				}
				# @editquota - multi
				unless($error){
					
					if ($fb && scalar @editquota > 0) {
						logline("debug","Creating File Object \$mailpasswd.");
						$mailpasswd = easytecc3::get_mailpasswd();
						@new_mailpasswd = $mailpasswd->file_content;
					}
					
					foreach my $count (@editquota) {
						# User prüfen und quota ändern, gibs auf freebsd nicht wegen virtuell
						if($input{"user$count"} && ! $fb) {
							$newerror = `/usr/sbin/quotuser -q $input{"quota$count"}M -n $input{"user$count"} -m  2>&1`;
							logline("debug",qq~editquota:/usr/sbin/quotuser -q $input{"quota$count"}M -n $input{"user$count"}~);
							$error .= qq~<B>$input{"user$count"}</B>: $newerror<br />~ if $newerror;
						}
						elsif($input{"user$count"} && $fb) {
							my $emailadress = $input{"user$count"};
							
							logline("debug","changing quota for $emailadress");
							
							my $password = $input{"pass$count"};
							
							# resuse existing pwd
							if(!length($password) || $password eq $input{"old_pass$count"}){
								
								($password) = grep /^$emailadress:/, @new_mailpasswd;
								$password =~ s/^[^:]+://;
								$password =~ s/:.*$//;
								
								logline("debug","editquota reusing pwdhash $password");
																
							} else {
								
								$password = encode('iso-8859-1', "$password");
								$password = `/usr/iports/bin/sudo /usr/sbin/doveadm pw -s SHA512-CRYPT -p '$password' | sed s/\{SHA512-CRYPT\}//`;
															
							}
							
							chomp $password;
							
							@new_mailpasswd = grep !/^$emailadress:/, @new_mailpasswd;
							#TODO: get real 'virtmail' UID from passwd
													
							
							if($input{'domain'} ne $servername){
								push @new_mailpasswd, qq~$emailadress:$password:1008:1005:$domain - POP:/home/~ . $emailadress . '::userdb_quota_rule=*:storage=' . $input{"quota$count"} . 'M';
							} else {
								push @new_mailpasswd, qq~$emailadress:$password:1008:1005::/home/~ . $emailadress . '::userdb_quota_rule=*:storage=' . $input{"quota$count"} . 'M';
							}
						}
						
						last if $error;
					}
					
					if ($fb && scalar @editquota > 0) {
				
						@{$mailpasswd->file_content} = @new_mailpasswd;
						$got = $mailpasswd->write_file;
						logline("error","mailpasswd->write_file got = $got") if $got;
						undef @new_mailpasswd;
						return(error($got)) if $got;
					}
					
				}

				unless($error){
					# ftp quota neu setzen, nicht freebsd
					if($input{'old_ftpquota'} != $input{'ftpquota'}){
						logline("debug",qq~vor ftpquota ändern: $input{"ftpuser"}~);
						# M hinter $input{'quotaftp'}steht für MB
						$newerror = `/usr/sbin/quotuser -q $input{'ftpquota'}M -n '$input{'ftpuser'}'  2>&1`;
						$error .= qq~<B>$input{'ftpuser'}</B>: ".$newerror."<br />~ if $newerror;
						logline("debug",qq~nach ftpquota ändern: /usr/sbin/quotuser -q $input{'ftpquota'}M -n $input{'ftpuser'}~);
					}
				}
			}
		}

		logline("debug","error = $error");
		logline("debug","anychange = $anychange");
		
		#wenn checkboxen für zu löschende User ausgewählt anderes Template anzeigen und kein redirect,
		#ist ganz am Anfang dieser Funktion.
		if (! $error && keys(%delete_popuser) == 0 && $anychange){
			my $user_context = qq~<br /><br />
			<a href="/cgi-bin/easytecc3/index.pl?action=change_forward&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-Weiterleitungen anlegen"__L</b></a><br />
			<a href="/cgi-bin/easytecc3/index.pl?action=change_popuser&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-User anlegen"__L</b></a>~;

			#<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
			$result = qq~L__Die Änderung wurde erfolgreich durchgeführt__L!<br /><br />~ . $user_context;
			$success_text = 'L__Die Änderung wurde erfolgreich durchgeführt__L!';
			
			
			my $domainlist = '';
				
			my $sendmail_cw = file->new({file_name => '/etc/mail/sendmail.cw'});
			$sendmail_cw->read_file;
			my %domains = %{$sendmail_cw->file_parsed_hash()};
			
			if($fb && keys %sendmail_cw_domains){
				
				my $domain;
				foreach $domain (keys %sendmail_cw_domains){
					
					if(!exists $domains{$domain}){
						
						if($domainlist ne ''){
							$domainlist .= ', ';
						}
						$domainlist .= $domain;
												
					}
					
				}
				
			} else {
				
				my $domainlist = $input{'domain'};
				$domainlist =~ s/^www\.//;
				
				
			}
			
			
			if($domainlist ne ''){
					
				$success_text .= '<br><br><span style="color: #a94442;">Die Domain';
									
				if($domainlist =~ m/,/){
						
					$success_text .= "s $domainlist sind";
						
				} else {
					
					$success_text .= " $domainlist ist";
					
				}	
										
				$success_text .= ' noch nicht als Mailserver-Domain eingetragen und für den Mailempfang nicht aktiv!</span>';
					
			}
			
			#$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_email&success_text=' . encode_base64url($success_text);
			$json_output{'redirect_to'} = '&success_text=' . encode_base64url($success_text);
				
		}	
					
		elsif($error){
			$result = qq~L__Achtung! Die Änderungen konnten nicht vollständig übernommen werden. Bitte beachten Sie folgende Warnhinweise__L:<br />$error~;
			$json_output{'error'} = $result;
		}
	}

	$template->param('result' => $result);
	
	logline("debug","result = " . $result);
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_delete_forward{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $error = '';
	my $result = $validation_result;

	logline("debug","exec_delete_forward result = $result###");

	if($result){
		logline("error","exec_delete_forward result = $result###");
		$result .= 'error';
	}
	else{
		logline("debug","Creating File Object \$virtmaps.");
		my $virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
		$virtmaps->read_file;
		my %virtmaps = %{$virtmaps->file_parsed_hash()};

		logline("debug","Creating File Object \$aliases.");
		my $aliases = file->new({file_name => '/etc/mail/aliases'});
		$aliases->read_file;
		my %aliases = %{$aliases->file_parsed_hash()};

		my %delete_from_aliases;
		my @new_virtmaps = ();
		my @new_aliases = ();

		# erstmal die zu löschenden Weiterleitungen in hash sammeln
		my %old_emailadress;

		foreach(sort keys %input){
			# <input  type="checkbox" name="delete2" value="frank">
			if(/^delete[0-9]{1,4}$/){
				logline("debug","key input=$_");
				$old_emailadress{$input{$_}} = '1';
			}
		}

		my $emailadress_regex = join('|',keys %old_emailadress);

		foreach($virtmaps->file_content) {
			# Wenn Domain aber kein Autoresponder
			# Domainmituser@ und direkt am Zeilenbeginn
			if(/^($emailadress_regex)\s+(.*)$/){
				# aha, match auf ein der zu löschenden E-Mailadressen, value aus %old_emailadress ist die Zeile aus Fornular, wo
				# neue Daten eingetragen wurden. $1 aus regex entspricht gespeichertem value
				my $forcount_to_delete = $1;
				my $target_to_delete = $2;

				logline("debug","regex match: forcount_to_delete = $1## - target_to_delete = $2##");

				# entweder einzelne Weiterleitung in virtmaps oder mehrere Ziele, d.h. auch aliases Zeile löschen
				if($target_to_delete =~ /(_aut|_spl)$/){
					$delete_from_aliases{$target_to_delete} = $forcount;
				}
			}
			else{
				#alles was nicht matcht unverändert übernehmen
				push @new_virtmaps, $_;
			}
		}

		my $delete_from_aliases_regex = join('|',keys %delete_from_aliases);

		if(keys %delete_from_aliases){
			foreach($aliases->file_content) {
				if(/^($delete_from_aliases_regex)\s*:/){
					# nix, Zeile wird gelöscht
				}
				else{
					push @new_aliases, $_;
				}
			}

			@{$aliases->file_content} = @new_aliases;
			my $got = $aliases->write_file;
			if ($got) {
				logline("error","aliases->write_file = ".$got);
				return(error($got));
			}
		}

		@{$virtmaps->file_content} = map(lc, @new_virtmaps);
		my $got = $virtmaps->write_file;
		if ($got) {
			logline("error","virtmaps->write_file = ".$got);
			return(error($got));
		}
				
	}

	my $user_context = '';

	if ($fb) {
		$user_context = qq~<br /><br />
		<a href="/cgi-bin/easytecc3/index.pl?action=change_forward&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-Adressen anlegen"__L</b></a><br />~;
		$template->param('result' => 'L__Die E-Mail-Adressen wurden erfolgreich geändert__L' . $user_context);
		$success_text = 'L__Die E-Mail-Adressen wurden erfolgreich geändert__L';
		
		if ($input{'email_type'} eq 'single_edit') {
			$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_single_edit_email&domain=' . $input{'domain'} . '&success_text=' . encode_base64url($success_text);
		}
		else{
			$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_email&success_text=' . encode_base64url($success_text);
		}
	}
	else{
		$user_context = qq~<br /><br />
		<a href="/cgi-bin/easytecc3/index.pl?action=change_forward&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-Weiterleitungen anlegen"__L</b></a><br />
		<a href="/cgi-bin/easytecc3/index.pl?action=change_popuser&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-User anlegen"__L</b></a>~;
		$template->param('result' => 'L__Die Weiterleitungen wurden erfolgreich geändert__L' . $user_context);
		$success_text = 'L__Die Weiterleitungen wurden erfolgreich geändert__L';
		
		if ($input{'email_type'} eq 'single_edit') {
			$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_single_edit_email&domain=' . $input{'domain'} . '&success_text=' . encode_base64url($success_text);
		}
		else{
			$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_email&success_text=' . encode_base64url($success_text);
		}
	}

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_new_forward_single_edit{
exec_change_forward();
}

sub exec_change_forward_single_edit{
exec_change_forward();
}

sub exec_change_forward{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $error = '';
	my $result = $validation_result;
	my %delete_forward;
	my %sendmail_cw_domains;
	
	logline("debug","exec_change_forward result:$result###");

	if($result){

	}
	else{

	
		#zuerst gucken, ob Weiterleitungen gelöscht werden sollen
		foreach(sort keys %input){
			# <input  type="checkbox" name="delete2" value="frank">
			if(/^delete[0-9]{1,4}$/){
				$delete_forward{$_} = $input{$_};
			}
		}

		if(keys %delete_forward >= 1){
			$template = HTML::Template->new(filename => 'delete_multi_forward.html');
			my $hidden_fields_delete_forward = '';
			my $delete_forward = '';
			foreach(sort keys %delete_forward){
				$hidden_fields_delete_forward .= qq~<input type="hidden" name="$_" value="$delete_forward{$_}">~;
				$delete_forward .= $delete_forward{$_} . '<br />';
			logline("debug","exec_change_forward delete_forward=$_");
			}
			$template->param('domain' => $input{'domain'});
			$template->param('hidden_fields_delete_forward' => $hidden_fields_delete_forward);
			$template->param('delete_forward' => $delete_forward);
			$template->param('email_type' => $input{'email_type'});
		}
		else{

			my $forcount = '1';
			my @forcount_change=();
			# wenn bei Weiterleitung Änderung an aliases notwendig, dann ist $aliases_forcount{$forcount} gesetzt und enthlt Array mit Zielen
			my %aliases_forcount;
			# Hash um zu berprüfen, ob E-Mailadressen doppelt angegeben wurden
			my %emailadress;
			# wird bentigt, um in vorhandener virtmaps die zu ändernde E-Mailadresse zu finden
			my %old_emailadress;
			my $domain = $input{'domain'};
			$domain =~ s/^www\.//;
			my %freefields;
			my %user_select;
			
			my %handle_hash = %{easytecc3::return_file_handler_store()};
			# httpd_conf wurde schon von Validator geöffnet, also nicht nochmal öffnen, sondern vorhandene Datenstruktur nehmen
			my $httpd_conf = $handle_hash{'/etc/httpd/conf/httpd.conf'};
			my %domains = %{$httpd_conf->file_parsed_hash()};

			logline("debug","Creating File Object \$virtmaps.");
			my $virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
			$virtmaps->read_file;
			my %virtmaps = %{$virtmaps->file_parsed_hash()};

			logline("debug","Creating File Object \$aliases.");
			my $aliases = file->new({file_name => '/etc/mail/aliases'});
			$aliases->read_file;
			my %aliases = %{$aliases->file_parsed_hash()};

			$mailpasswd = easytecc3::get_mailpasswd();
			%passwd = %{$mailpasswd->file_parsed_hash()};

			my $splitted_domains = join '|', @{$domains{$input{'domain'}}{'domains'}};
			$splitted_domains =~ s/\*/\\*/g;
			logline("debug","splitted_domains=$splitted_domains");

			#my %error_fields = ();
			# es gibt pro Weiterleitung acht Felder, 4 für die vorhandenen und 4 für die neuen Eintrge:
			# old_user1
			# old_domain_select1
			# old_user_select1
			# old_freefield1
			# user1
			# domain_select1
			# user_select1
			# freefield1
			#
			# user1 + domain_select1 = E-Mailadresse
			
			while($domains{$input{'domain'}}{'for'} >= $forcount){
				$input{"domain_select$forcount"} = ascii_domain($input{"domain_select$forcount"});
				$input{"user_select$forcount"} = email_to_ascii($input{"user_select$forcount"});
				
						
				my %user_select_compare;
				my %old_user_select;
				# user- und domainselect haben &nbsp; wenn keine Domain ausgewählt, &nbsp; wird an Script als Sonderzeichen ord(194) übertragen
				# das muss in "nix" umgewandelt werden, damit Stringvergleich mit vorhandenen Weiterleitungen funktioniert
				# und erkannt werden kann ob sich was geändert hat.
				if(ord($input{"domain_select$forcount"}) == '160'){
					$input{"domain_select$forcount"} = '';
				}
				if(ord($input{"user_select$forcount"}) == '160'){
					$input{"user_select$forcount"} = '';
				}

				logline("debug","user_select$forcount=".$input{"user_select$forcount"});
				
				##split multiple user_select ord($char== 0)
				my @arr = split /\x0/, $input{"user_select$forcount"};
				@{$user_select{$forcount}} = @arr;
				foreach(@arr){
					logline("debug","arr###$_###\n");
					$user_select_compare{$_} = 1;
				}
				
				# E-Mailadressen in Hash inkrementieren
				## wenn mehr als 1 rauskommt wurde E-Mailadresse doppelt angegeben
				# aber nur wenn mindestens ein Formularfeld ausgefüllt wurde, sonst würde @ als doppelte E-Mailadresse erkannt werden
				if ($input{"domain_select$forcount"} && ($input{"user$forcount"} || $input{"user_select$forcount"} || $input{"freefield$forcount"."_1"} )){
					my $email_tmp = $input{"user$forcount"} . '@' . $input{"domain_select$forcount"};
					$emailadress{$email_tmp}++;
				}

				## bei oldfreefield muss letzes Komma weggetrimmt werden, da dies bei freefield auch gemacht wird.
				##ansonsten wird fälschlicherweise erkannt, daß sich etwas geändert hat
				##wenn autoresponder mit weiterleitung an User, dann gibt es am Ende Leerzeichen, in dem Fall Leerzeichen und Komma am Ende weg
				#$input{"old_freefield$forcount"} =~ s/\s+$//;
				#$input{"old_freefield$forcount"} =~ s/,$//;
				#$input{"freefield$forcount"} =~ s/[(\;|\,|\:|\s+)]{2,}/,/gc;
				#$input{"freefield$forcount"} =~ s/^[(\s*\;\s*|\s*\,\s*|\s*\:\s*|\s+)]{0,}//;
				#$input{"freefield$forcount"} =~ s/[(\s*\;\s*|\s*\,\s*|\s*\:\s*|\s+)]{0,}$//;
				#my @targetsarray = split /\s*\;\s*|\s*\,\s*|\s*\:\s*|\s+/, $input{"freefield$forcount"};
				## im Freifeld sind z.B. pupupu und blubber als Weiterleitung auf 2 user drin und user_select ist leer
				## kd ändert user_select auf pupupu, da user schon in freefield drin ergibt sich keine nderung
				#if(grep (/^$input{"user_select$forcount"}$/, @targetsarray)){
				#	my $target_string = join(',', @targetsarray);
				#	logline("debug",qq~clear $input{"user_select$forcount"} from #$target_string#~);
				#	$input{"user_select$forcount"} = '';
				#}
				
				my $freefield_changed = '';
				#foreach(grep {/^freefield$forcount_/} sort keys %input){
				foreach(sort keys %input){
					my $freefield = $_;
					my $regex = '^freefield'.$forcount.'_';
					next if $freefield !~ /$regex/;
					my $freefield_value = $input{$freefield};
					my $freefield_count = 1;
					
					logline("debug","forcount=$forcount freefield=$freefield value=".$input{$freefield});
					
					if ($input{"old_$freefield"} ne $input{"$freefield"}) {
						push @forcount_change, $forcount;
						$freefields{$forcount}{$freefield} = $freefield_value;
						$freefield_changed = 1;
						logline("debug","$forcount old_freefield != freefield freefield=$freefield ".$input{"old_$freefield"}.'!='.$input{"$freefield"});
					}
					elsif(length($freefield_value) > 0){
					#vorhandene Freifelder übernehmen
					$freefields{$forcount}{$freefield} = $freefield_value;
					}					
					
				}
			
				# hack to throw error
				if(exists($input{"user$forcount"}) && exists($input{"domain_select$forcount"})){
					
					if(
					   	$input{"old_user$forcount"} ne '' ||
						$input{"old_domain_select$forcount"} ne '' ||
						$input{"old_user_select$forcount"} ne '' ||
						$input{"old_freefield_select$forcount"} ne ''
					) {
						
						if(! $input{"user_select$forcount"} && keys %{$freefields{$forcount}} < 1 && !length($input{"forward_to_text$forcount"})){
							push @forcount_change, $forcount;
						}
																		
					}
				}
				
				#irgendeine nderung?
				#multiple user select is stored as | separated hidden field, compare with user_select hash
				#<input name="old_user_select1" type="hidden" id="old_user_select1" value="test1@test2.de|test2@test1.de">
				my $user_select_changed = '';
				my @old_user_select = split /\|/, $input{"old_user_select$forcount"};
				foreach(@old_user_select){
					$old_user_select{$_} = 1;
				}
				
				if (%old_user_select != %user_select_compare) {
					
					foreach(sort keys %old_user_select){
						logline("debug","$forcount old_user_select $_=" . $old_user_select{$_} . "##");	
					}
					foreach(sort keys %user_select_compare){
						logline("debug","$forcount user_select_compare $_=" . $user_select_compare{$_} . "##");	
					}
					
					$user_select_changed = 1;
					logline("debug","$forcount old_user_select != user_select_compare");
				}
				else {
					my %cmp = map { $_ => 1 } keys %old_user_select;
					for my $key (keys %user_select_compare) {
						last unless exists $cmp{$key};
						last unless $old_user_select{$key} eq $user_select_compare{$key};
						delete $cmp{$key};
					}
					if (%cmp) {
						$user_select_changed = 1;
						logline("debug","$forcount cmp old_user_select != user_select_compare");
					}
					else{
						#print "they have the same keys or values\n";
					}
				}

				
				if($input{"old_user$forcount"} ne $input{"user$forcount"} ||
				   $user_select_changed ||
				   $freefield_changed)
				{
					logline("debug","Weiterleitung ändern1:$forcount user_select_changed=$user_select_changed freefield_changed=$freefield_changed");
					logline("debug",qq~$forcount, neu:$input{"user$forcount"}\@$input{"domain_select$forcount"} alt:$input{"old_user$forcount"}\@$input{"old_domain_select$forcount"}~);
					push @forcount_change, $forcount unless (grep  $_ eq $forcount, @forcount_change);
					$old_emailadress{qq~$input{"old_user$forcount"}\@$input{"old_domain_select$forcount"}~} = $forcount;
				}
				
				if($input{"old_domain_select$forcount"} ne '' &&
				   $input{"old_domain_select$forcount"} ne $input{"domain_select$forcount"}
				   )
				{
					logline("debug","Weiterleitung ändern2 domain_select:$forcount user_select_changed=$user_select_changed freefield_changed=$freefield_changed");
					logline("debug",qq~$forcount, neu:$input{"user$forcount"}\@$input{"domain_select$forcount"} alt:$input{"old_user$forcount"}\@$input{"old_domain_select$forcount"}~);
					push @forcount_change, $forcount unless (grep  $_ eq $forcount, @forcount_change);
					$old_emailadress{qq~$input{"old_user$forcount"}\@$input{"old_domain_select$forcount"}~} = $forcount;
				}
				
				
				$forcount++;
			}

			#keine Änderung, hat nur aus Spass geklickt
			if(scalar @forcount_change == '0'){
				#$template->param('result' => 'L__Es wurde keine Änderung durchgeführt__L');
				$success_text = 'L__Es wurde keine Änderung durchgeführt__L';
	
				$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_email&success_text=' . encode_base64url($success_text);
				return(\$template);
			}

			# doppelte E-Mailadressen?
			foreach(sort keys %emailadress){
				if($emailadress{$_} > 1){
					$error_fields{"Emailfehler"} = "$_: L__Die E-Mail-Adresse wurde doppelt angegeben__L";
				}
			}

			# weitere Überprüfungen der Eingabefelder nur durchführen, wenn überhaupt eine Änderung und nix doppelt
			if(scalar @forcount_change >= 1 && ! $error){
				foreach my $forcount(@forcount_change){
					# hier stehen ein oder mehrere lokale User und/oder externe E-Mailadressen drin
					#my @targetsarray = split /\s*\;\s*|\s*\,\s*|\s*\:\s*|\s+/, $input{"freefield$forcount"};
					my @targetsarray = ();
					my %freefield_hash = %{$freefields{$forcount}};
					logline("debug",qq~vor foreach freefield hash~);
					
					#gon on here add aliases
					
					foreach(sort keys %freefield_hash){
						push @targetsarray, $freefield_hash{$_};
						logline("debug",qq~foreach freefield hash=$_ value=~.$freefield_hash{$_});
					}
					foreach(@{$user_select{$forcount}}){
						if ($fb) {
							push @targetsarray, qq~"|/usr/iports/bin/procmail -a $_"~;
						}
						else{
							push @targetsarray, $_;	
						}							
					}
					
					my $mailuser = $input{"user$forcount"} . '@' . $input{"domain_select$forcount"};
					my $forward_filter;
					
					# external
					my $sendmail_target = $mailuser;
	
					# add random local part to catch all
					if($mailuser =~ m/^@/){
						
						$sendmail_target = 'catchall' . $$ . $sendmail_target;
						
					}
					
					my $sendmail_forward = `/usr/sbin/sendmail -d27 -bv $sendmail_target 2>/dev/null | grep -m 1 'aliased to' 2>/dev/null  | sed 's/^.*aliased to // ; s/"//g' 2>/dev/null`;
					chomp($sendmail_forward);
					
					# single virtmaps line
					if(!length($sendmail_forward)){
						
						$sendmail_forward = `/usr/sbin/sendmail -d60 -bv $sendmail_target 2>/dev/null | grep -m 1 'map_lookup(virtuser' 2>/dev/null | sed 's/.*> // ; s/ .*//' 2>/dev/null`;
						
					}
					
					$sendmail_forward = get_sendmail_forward($mailuser);
										
					my $forward_target;
					foreach $forward_target (split(/,\s*/,$sendmail_forward)){
						
						# email
						if($forward_target =~ m/^([^\@\s]+\@[^\@]+)$/){
							
							push(@{$forward_to}, $1);
							
							if($forward_filter ne 'att'){
								
								$forward_filter = 'off';
								
							}
							
						}
						# fwd_as_att
						elsif($forward_target =~ m/fwd_as_att\s([^"]*)"/){
							
							$forward_target = $1;
							foreach $forward_target (split(/\s+/,$forward_target)){
								
								if($forward_target !~ /^\//){
							
									push(@{$forward_to}, $forward_target);
																
								}		
																
							}
							$forward_filter = 'att';
							
						}
							
						
					}
								
					#all targets from form submit
					$aliases_forcount{$forcount} = \@targetsarray;
															
					if($input{"user$forcount"} ne '' && $input{"user$forcount"} !~ /[a-zA-Z0-9_\-\.]/ ){
						$error_fields{"user$forcount"}  = $input{"user$forcount"} . '@' . $input{"domain_select$forcount"} . ": L__Die E-Mail-Adresse enthält ungültige Zeichen__L";
					}
					#E-Mailadresse berprüfen, aber nur wenn $input{"user$forcount"} existiert.  Wenn leer dann ist es catchallweiterleitung
					elsif($input{"user$forcount"} ne '' && ! is_email($input{"user$forcount"} . '@' . $input{"domain_select$forcount"})){
						$error_fields{"user$forcount"}  = $input{"user$forcount"} . '@' . $input{"domain_select$forcount"} . ": L__Keine gültige E-Mail-Adresse__L";
					}

					if(! is_domain($input{"domain_select$forcount"})){
						$error_fields{"domain_select$forcount"}  = $input{"domain_select$forcount"} . " L__Bitte wählen Sie einen Domainnamen__L";
					}
					elsif($input{"domain_select$forcount"} !~ /^($splitted_domains)$/){
						$error_fields{"domain_select$forcount"} = $input{"domain_select$forcount"} . ": L__Der Domainname ist für diesen vHost nicht erlaubt__L";
					}

					# Wenn neue Weiterleitung angelegt wird, dann mu auch Ziel angegeben sein
					logline("debug",qq~userforcount=$input{"user$forcount"} input_domain_select=$input{"domain_select$forcount"} user_select_forcount=$input{"user_select$forcount"} keys freefields=~ . keys %{$freefields{$forcount}});
					if(exists($input{"user$forcount"}) && exists($input{"domain_select$forcount"})){
						if(! $input{"user_select$forcount"} && keys %{$freefields{$forcount}} < 1 && !length($input{"forward_to_text$forcount"})){
							$error_fields{"user_select$forcount"} = $input{"user$forcount"} . '@' . $input{"domain_select$forcount"} . ": L__Bitte geben Sie einen Benutzer oder eine Weiterleitung an__L";
						}
					}
															
					# ausgewählten E-Mailuser berprüfen, wenn keiner ausgewählt, dann freefield prüfen
					foreach my $user_select(@{$user_select{$forcount}}){
						# User wurde ausgewählt, gucken ob es den gibt
						if(not exists $passwd{$user_select}){
							$error_fields{"user_select$forcount"}  = $user_select . ": L__Der E-Mail-User existiert nicht__L";
						}
						# ist ausgewählter User der Domain zugeordnet?
						# hmpf, wenn er einmal drin ist, laesst es sich so nicht mehr speichern
						#elsif($passwd{$user_select}{'gecos'} !~ /^$domain - POP$/){
						#	$error_fields{"user_select$forcount"} = $user_select . ": L__Der E-Mail-User ist einem anderen vHost zugeordnet__L";
						#}
					}
										
					# freefield prüfen
					#my %freefield_hash = $freefields{$forcount};
					logline("debug",qq~old_freefield $input{"old_freefield$forcount"} new_freefield $input{"freefield$forcount"}~);
					my $freefieldcount = '1';
					foreach my $targetaddress_fieldname (sort keys %freefield_hash){
						my $targetaddress = $freefield_hash{$targetaddress_fieldname};
						logline("debug","targetaddress:$targetaddress targetaddress_fieldname=$targetaddress_fieldname");
						# wenn Ziel ein @ beinhaltet gehen wir davon aus, da eine E-Mailadresse gemeint ist
						# Usernamen nicht berprüfen, da es Weiterleitungen nach muell, papierkorb o.. gibt
						# damit Mails schon auf SMTP-Ebene abgelehnt werden
						if($targetaddress =~ /@/  && $targetaddress =~ /^.*[^a-zA-Z0-9_\-\.]{1,100}.*\@.*/ ){
							$error_fields{"$targetaddress_fieldname"}  = $input{"freefield$forcount"} . ": L__Ungültige Zeichen__L";
						}
						elsif( $targetaddress =~ /@/  && !is_email($targetaddress)){
							$error_fields{"$targetaddress_fieldname"} = $targetaddress . ": L__Keine korrekte E-Mail-Adresse__L";
						}
						elsif( is_domain($targetaddress)){
							$error_fields{"$targetaddress_fieldname"} = "L__Eine Domain kann kein Ziel sein__L";
							logline("debug","error_fields freefield=$targetaddress_fieldname");
						}
						elsif( $targetaddress !~ /@/  && $targetaddress =~ /[^a-zA-Z0-9_\-\.\/]/){
							$error_fields{"$targetaddress_fieldname"} = $targetaddress . ": L__Ungültige Zeichen__L";
						}
						elsif( $fb && ( length($targetaddress) > 4 && $targetaddress !~ /@/  && $targetaddress ne '/dev/null')){
							$error_fields{"$targetaddress_fieldname"} = $targetaddress . ": L__Keine korrekte E-Mail-Adresse__L";
						}
					$freefieldcount++;
					}										
				}
			}

			logline("debug","forcount_change:" .  scalar @forcount_change);
			if(scalar @forcount_change >= 1 && keys %error_fields >= 1){
				return(html_error(\%error_fields));
			}

			if(scalar @forcount_change >= 1 && ! $error){
				my @new_virtmaps;
				my @new_aliases;
				# wenn eine Weiterleitung von zwei oder meheren Usern auf einen User geändert wird
				# kann die _spl-Zeile aus aliases gelöscht werden
				my %delete_from_aliases;
				my %add_to_aliases;
				my %modify_aliases;

				my $emailadress_regex = join('|',keys %old_emailadress);

				foreach($virtmaps->file_content) {
					# Wenn Domain aber kein Autoresponder
					# Domainmituser@ und direkt am Zeilenbeginn
					if(/^($emailadress_regex)\s+(.*)$/){
						# aha, match auf ein der zu ändernden E-Mailadressen, value aus %old_emailadress ist die Zeile aus Fornular, wo
						# neue Daten eingetragen wurden. $1 aus regex entspricht gespeichertem value
						my $virtmaps_lhs = $1;
						my $virtmaps_rhs = $2;
						#$forcount_to_change ist lhs in virtmaps, was in hash %old_emailadress als key gespeichert ist
						# der entsprechende value ist die zu ändernde Weiterleitung aus den Formularfeldern, $forcount=Formularfeldnummer
						my $forcount = $old_emailadress{$virtmaps_lhs};
						my @aliases_forcount = @{$aliases_forcount{$forcount}};
						
						logline("debug","regex match:virtmaps_lhs=$1##virtmaps_rhs=$2##forcount=$forcount##aliases_forcount=$aliases_forcount{$forcount}");
						# entweder einzelne Weiterleitung in virtmaps oder mehrere Ziele, d.h. auch aliases ändern
						if($virtmaps_rhs =~ /_(spl|aut)$/){
							# nur ein Ziel auf externe E-Mailadresse was vorher Weiterleitung auf mindstens 2 mit _spl war, ist in %aliases_forcount weil externe E-Mailadresse
							# in freefield angegeben wurde. ext. emailadresse landet in virtmaps und _spl aus aliases löschen
							if(scalar @aliases_forcount == '1'  && ! $input{"user_select$forcount"} && ! $input{"has_autoreply$forcount"}){
								logline("debug",qq~auf extern aliases_forcount=$aliases_forcount{$forcount}~);
								push @new_virtmaps, qq~$input{"user$forcount"}\@$input{"domain_select$forcount"}\t\t$aliases_forcount[0]~;
								$delete_from_aliases{$virtmaps_rhs} = '1';
							}
							#alles andere über _spl mit aliases
							else{
								push @new_virtmaps, qq~$input{"user$forcount"}\@$input{"domain_select$forcount"}\t\t$input{"user$forcount"}_$input{"domain_select$forcount"}_spl~;
								# aliases modifizieren, Verknpfung von aliaszeile lhs zur zu ändernden Zeile aus Formular herstellen
								$modify_aliases{$virtmaps_rhs} = $forcount;
								# todo: in $modify_aliases das array von $aliases_forcount{$forcount} rein
							}
						}
						else{
							# nur ein Ziel auf externe E-Mailadresse, ist in %aliases_forcount weil externe E-Mailadresse
							# in freefield angegeben wurde
							if(scalar @aliases_forcount == '1' && ! $input{"user_select$forcount"} && $aliases_forcount[0] ne '/dev/null'){
								logline("debug",qq~auf extern aliases_forcount=$aliases_forcount{$forcount}~);
								push @new_virtmaps, qq~$input{"user$forcount"}\@$input{"domain_select$forcount"}\t\t$aliases_forcount[0]~;
							}
							else{
								logline("debug",qq~aliases_forcount=$aliases_forcount{$forcount}~);
								push @new_virtmaps, qq~$input{"user$forcount"}\@$input{"domain_select$forcount"}\t\t$input{"user$forcount"}_$input{"domain_select$forcount"}_spl~;
								$add_to_aliases{$forcount} = qq~$input{"user$forcount"}_$input{"domain_select$forcount"}_spl~;
							}
						}
					}
					else{
						push @new_virtmaps, $_;
					}
				}

				#Neue Weiterleitung anhängen
				foreach my $forcount(@forcount_change){
				my @aliases_forcount = @{$aliases_forcount{$forcount}};
				
				logline("debug","new forward: aliases_forcount=" . join(',', @aliases_forcount));
				
					if( $input{"old_user$forcount"} eq '' &&
						$input{"old_domain_select$forcount"} eq '' &&
						$input{"old_user_select$forcount"} eq '' &&
						$input{"old_freefield_select$forcount"} eq '')
						{
						if(scalar @aliases_forcount == '1' && ! $input{"user_select$forcount"} && $aliases_forcount[0] ne '/dev/null'){
							#einzelne externe emailadresse
							push @new_virtmaps, qq~$input{"user$forcount"}\@$input{"domain_select$forcount"}\t\t$aliases_forcount[0]~;
						}
						else {
							#alles andere über _spl mit aliases
							push @new_virtmaps, qq~$input{"user$forcount"}\@$input{"domain_select$forcount"}\t\t$input{"user$forcount"}_$input{"domain_select$forcount"}_spl~;
							$add_to_aliases{$forcount} = qq~$input{"user$forcount"}_$input{"domain_select$forcount"}_spl~;
						}
						
						$sendmail_cw_domains{$input{"domain_select$forcount"}} = 1;
					}
				}

				my $modify_aliases_regex = join('|',keys %modify_aliases);
				my $delete_from_aliases_regex = join('|',keys %delete_from_aliases);

				logline("debug","modify_aliases_regex: #$modify_aliases_regex#");
				logline("debug","delete_from_aliases_regex: #$delete_from_aliases_regex#");

				# modifizieren und alte löschen
				foreach($aliases->file_content) {
					my $line = $_;
					#der erste matcht auf alle ziele + autoresponder oder Programm, der zweite auf Ziele ohne Programm, z.B. externe Emailadresse und/oder lokaler User
					#if(/^($modify_aliases_regex)\s*:\s*(.*),\s*("{0,}.*)$/ || /^($modify_aliases_regex)\s*:\s*(.*)$/){
					if( /^($modify_aliases_regex)\s*:\s*(.*)$/ ){
						logline("debug","match auf modify_aliases_regex:1=$1 2=$2");
						# Zeile modifizieren
						my $aliases_lhs = $1;
						my $aliases_rhs_targets = $2;
						my $forcount = $modify_aliases{$aliases_lhs};
						$input{"user$forcount"} = lc($input{"user$forcount"});
						my @targetsarray = @{$aliases_forcount{$forcount}};
						@targetsarray = easytecc3::del_array_duplicates(@targetsarray);
						my $target_string = join(',', @targetsarray);
						
						
						logline("debug","#####################target_string = $target_string");
						
						
						#in $aliases_forcount{$forcount} sind nur Ziele aus Formular, Autoresponder hinzufügen wenn vorhanden
						#und Dateinamen ändern wenn sich Emailadresse geändert hat
						if ($input{"has_autoreply$forcount"}) {
							$target_string .=  qq~, "|$autoresponder /usr/local/etc/easytecc/$input{"user$forcount"}_$input{"domain_select$forcount"}.aut"~;
						}
						
						#spezielle Einträge übernehmen, alles was in Anführungszeichen und kein Autoresponder ist können
						#pipes an kundeneigene Programme sein
						my @aliases_rhs_targets_array = split /,\s*/, $aliases_rhs_targets;
						foreach my $string(@aliases_rhs_targets_array){
							
							logline("debug","#####################string = $string");
							
							if ($string =~ /"/ && $string !~ /\/autoresponder/ && $string !~ /\|\/usr\/iports\/bin\/procmail -a/) {
								
								$target_string .=  qq~, $string~;
							}
							elsif($string =~ /^[^\|\/\s\"]+$/ && !exists($passwd{$string})){
							
								logline("debug","#####################string is no user");
								
								$target_string .=  qq~, $string~;
								
							}
							
						}
						
						$target_string =~ s/^,//;
						$target_string =~ s/,$//;
						$target_string =~ s/,,/,/g;
						if($aliases_lhs =~ /_(aut|spl)$/){
							# wenn sich die E-Mailadresse einer Weiterleitung mit Auroresponder ändert, muss sich auch der Name der
							# Autoresponderdatei ändern, der immer eine bestimmte Syntax hat, z.B.
							# auto@krusator.de = auto_krusator.de.aut
							# Wenn auto@krusator.de auf doofauto@krusator.de geändert wird muss sie doofauto_krusator.de.aut heissen, also vorhandene Datei umbenennen
							# vorhandene Autoresponderdatei:
							if ($input{"has_autoreply$forcount"}) {
								my $autoreply_file = $aliases_rhs_targets;
								$autoreply_file =~ m/\/(.*\.aut)/;
								$autoreply_file = $1;
								my $new_autoreply_file = qq~$input{"user$forcount"}_$input{"domain_select$forcount"}.aut~;
								logline("debug","has_autoreply=1 autoreply_file=$autoreply_file");
								my $got = `$easytecc_prefix/mv.pl /usr/local/etc/$autoreply_file /usr/local/etc/$new_autoreply_file 2>&1` unless $fb;
								my $got = `/usr/iports/bin/sudo /usr/sbin/mv.pl /usr/local/etc/easytecc/$autoreply_file /usr/local/etc/easytecc/$new_autoreply_file 2>&1` if $fb;
								
								# autoresponderdatei nochmal einlesen und schreiben, damit ggf. auf externen Mailserver übertragen wird
								logline("debug","Creating File Object /usr/local/etc/easytecc/$new_autoreply_file.");
								my $file = file->new({file_name => "/usr/local/etc/easytecc/$new_autoreply_file"});
								$file->read_file;
								$got = $file->write_file;
								if ($got) {
								logline("error","/usr/local/etc/$new_autoreply_file ->write_file = ".$got);
								return(error($got));
								}
							}
							push @new_aliases, qq~$input{"user$forcount"}_$input{"domain_select$forcount"}_spl:\t$target_string~;
						}
						else{
							push @new_aliases, qq~$aliases_lhs:\t$target_string~;
						}
					}
					elsif(/^($delete_from_aliases_regex)\s*:\s*(.*)$/){
						# nix, Zeile wird gelöscht
					}
					else{
						push @new_aliases, $_;
					}
				}

				foreach my $forcount(sort keys %add_to_aliases){
					my @targetsarray = @{$aliases_forcount{$forcount}};
					@targetsarray = easytecc3::del_array_duplicates(@targetsarray);
					my $target_string = join(',', @targetsarray);
					$target_string =~ s/^,//;
					$target_string =~ s/,$//;
					push @new_aliases, qq~$input{"user$forcount"}_$input{"domain_select$forcount"}_spl:\t$target_string~;
				}

				@{$virtmaps->file_content} = map(lc, @new_virtmaps);
							
				my $got = $virtmaps->write_file;
				if ($got) {
					logline("error","virtmaps->write_file = ".$got);
					return(error($got));
				}


				if(keys %modify_aliases || keys %delete_from_aliases || keys %add_to_aliases){
					@{$aliases->file_content} = map(lc, @new_aliases);
					my $got = $aliases->write_file;
					if ($got) {
						logline("error","aliases->write_file = ".$got);
						return(error($got));
					}
				}
			}
		}
	}

	if (! $error && keys %delete_forward == 0){
		logline("debug","exec_change_forward error=0 delete_forward=0");
	my $user_context = qq~<br /><br />
	<a href="/cgi-bin/easytecc3/index.pl?action=change_forward&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-Weiterleitungen anlegen"__L</b></a><br />
	<a href="/cgi-bin/easytecc3/index.pl?action=change_popuser&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-User anlegen"__L</b></a>~;

	$template->param('result' => 'L__Die E-Mail-Weiterleitungen wurden erfolgreich geändert__L' . $user_context);
	$success_text = 'L__Die E-Mail-Weiterleitungen wurden erfolgreich geändert__L';
		
		my $domainlist = '';
				
		my $sendmail_cw = file->new({file_name => '/etc/mail/sendmail.cw'});
		$sendmail_cw->read_file;
		my %domains = %{$sendmail_cw->file_parsed_hash()};
		
		if(keys %sendmail_cw_domains){
			
			my $domain;
			foreach $domain (keys %sendmail_cw_domains){
				
				if(!exists $domains{$domain}){
					
					if($domainlist ne ''){
						$domainlist .= ', ';
					}
					$domainlist .= $domain;
											
				}
				
			}
			
		} 
				
		if($domainlist ne ''){
				
			$success_text .= '<br><br><span style="color: #a94442;">Die Domain';
								
			if($domainlist =~ m/,/){
					
				$success_text .= "s $domainlist sind";
					
			} else {
				
				$success_text .= " $domainlist ist";
				
			}	
									
			$success_text .= ' noch nicht als Mailserver-Domain eingetragen und für den Mailempfang nicht aktiv!</span>';
				
		}	
		
		
		if ($input{'email_type'} eq 'single_edit') {
			$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_single_edit_email&domain=' . $input{'domain'} . '&success_text=' . encode_base64url($success_text);
		}
		else{
		$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_email&success_text=' . encode_base64url($success_text);
		}
		
	}
	elsif($error){
	$json_output{'error'} = 'L__Ein Fehler ist aufgetreten__L';	
	}
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_new_autoreply{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $error = '';
	my $result = $validation_result;

	logline("debug","exec_new_autoreply result:$result###");

	if($result){

	}
	else{
		my $forward = $input{'forward'};
		logline("debug","Creating File Object \$virtmaps.");
		my $virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
		$virtmaps->read_file;
		my %virtmaps = %{$virtmaps->file_parsed_hash()};

		logline("debug","Creating File Object \$aliases.");
		my $aliases = file->new({file_name => '/etc/mail/aliases'});
		$aliases->read_file;
		my %aliases = %{$aliases->file_parsed_hash()};

		my @new_virtmaps = ();
		my @new_aliases = ();
		my $aliases_lhs = '';
		# $domain und $user um autoreplydateinamen zu erstellen
		my $domain = $forward;
		$domain =~ s/^(.*)\@//;
		my $user = $1;
		# Wenn einzelner Empfänger in virtmaps, dann muss er in aliases bernommen werden
		my $virtmaps_to_aliases_target = '';
		# wenn mehrere Empfänger, dann rhs aus virtmaps sichern, diese entspricht lhs aus aliases die modifiziert werden muss
		my $old_virtmaps_rhs = '';
		#Die Weiterleitung kann auf einen Empfänger in virtmaps oder schon auf mehrere Empfänger mit "_spl"
		#in aliases angelegt sein
		foreach($virtmaps->file_content){
			# die zu ändernde E-Mailadresse, entweder ist es normale Weiterleitung oder es gibt _spl-Verweis auf aliases.
			# wenn _spl dann existiert bereits Weiterleitung an mehrere User
			if(/^$forward\s+(.*)$/){
				my $virtmaps_rhs = $1;

				if($virtmaps_rhs =~ /_(spl|aut)$/){
					# virtmaps_rhs sichern, weil diese Zeile in aliases geändert werden muss
					$old_virtmaps_rhs = $virtmaps_rhs;
					#obsolet, kein Nutzen
					#$virtmaps_rhs =~ s/_spl$/_aut/;
					push @new_virtmaps, qq~$forward\t$virtmaps_rhs~;
					$aliases_lhs = $virtmaps_rhs;
				}
				else{
					# Weiterleitungsziel sichern, der kommt mit in aliases als Empfänger
					$virtmaps_to_aliases_target = $virtmaps_rhs;
					# anschliessend rhs von virtmaps auf _aut ändern
					$virtmaps_rhs = $user . '_' . $domain . '_aut';
					push @new_virtmaps, qq~$forward\t$virtmaps_rhs~;
					# virtmaps_rhs z.B. blubber_hostnet.de_aut
					$aliases_lhs = $virtmaps_rhs;
				}
			}
			else{
				push @new_virtmaps, $_;
			}
		}

		# wenn $virtmaps_to_aliases_target gesetzt, dann wissen wir, da es vorher noch keinen eintrag in aliases gab.
		# D.h. neue Zeile in aliases anhängen
		if($virtmaps_to_aliases_target){
			push @{$aliases->file_content}, $aliases_lhs . ":\t" . $virtmaps_to_aliases_target . ',' . qq~"|$autoresponder /usr/local/etc/easytecc/$user~ . '_' . qq~$domain.aut"~;
			@new_aliases = @{$aliases->file_content};
		}
		#ansonmsten Zeile suchen und modifizieren
		else{
			foreach($aliases->file_content){
				# vorhandene Weiterleitung in aliases an mehrere User gefunden
				if(/^$old_virtmaps_rhs\s*:\s*(.*)$/){
					push @new_aliases, $aliases_lhs . ":\t" . $1 . ',' . qq~"|$autoresponder /usr/local/etc/easytecc/$user~ . '_' . qq~$domain.aut"~;
				}
				else{
					push @new_aliases, $_;
				}
			}
		}

		$aliases->file_content(\@new_aliases);
		my $got = $aliases->write_file;
		if ($got) {
			logline("error","aliases->write_file = ".$got);
			return(error($got));
		}

		@new_virtmaps = map(lc, @new_virtmaps);
		$virtmaps->file_content(\@new_virtmaps);
		my $got = $virtmaps->write_file;
		if ($got) {
			logline("error","virtmaps->write_file = ".$got);
			return(error($got));
		}

		logline("debug","Creating File Object /usr/local/etc/easytecc/" . $user . '_' . $domain . '.aut');
		my $autoreply = file->new({	file_name => '/usr/local/etc/easytecc/' . $user . '_' . $domain . '.aut',
									user => $user,
									domain => $domain});

		my @autoreply_content = ("From: $forward", "Subject: $input{'autoreply_subject'}\n", "$input{'autoreply_text'}");
		$autoreply->file_content(\@autoreply_content);
		my $got = $autoreply->write_file;
		if ($got) {
			logline("error","autoreply->write_file = ".$got);
			return(error($got));
		}
	}

	my $user_context = qq~<br /><br />
	<a href="/cgi-bin/easytecc3/index.pl?action=change_forward&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-Weiterleitungen anlegen"__L</b></a><br />
	<a href="/cgi-bin/easytecc3/index.pl?action=change_popuser&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-User anlegen"__L</b></a>~;

	$template->param('result' => 'L__Der Autoresponder wurde erfolgreich angelegt!__L' . $user_context);
	$success_text = 'L__Der Autoresponder wurde erfolgreich angelegt!__L';

	if ($input{'email_type'} eq 'single_edit') {
		$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_single_edit_email&domain=' . $input{'domain'} . '&success_text=' . encode_base64url($success_text);
	}
	else{
		$json_output{'modal_action'} = 'change_forward';
		$json_output{'modal_action_args'} = '&amp;domain=' . $input{'domain'};
	}
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_change_autoreply{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $error = '';
	my $result = $validation_result;

	logline("debug","exec_change_autoreply result: $result###");

	if($result){

	}
	else{
		my $domain = $input{'forward'};
		my $forward = $input{'forward'};
		my $forward_aliases = $forward;
		$forward_aliases =~ s/(@|\.)/_/g;
		$domain =~ s/^(.*)\@//;
		my $user = $1;
		my $autoreply_file = '';

		# es gibt autoresponderdateien wo domainname mit _ oder mit. existiert:
		# c.blubb_domainshooter.at.aut
		# k.seifert_steiner_de.aut
		my $domain_reverse = reverse($domain);
		# umdrehen, den ersten _ gegen . ersetzen und dann einfach gucken was vorhanden ist, das lassen wir auch so, sonst muss beim Ändern von autoresponder
		# immder die aliases ggf. geändert werden..., viel zu kompliziert
		$domain_reverse =~ s/\./_/;
		$domain_reverse = reverse($domain_reverse);

		if(-e '/usr/local/etc/' . $forward_aliases . '.aut'){	
			$autoreply_file = '/usr/local/etc/' . $forward_aliases . '.aut';
		}
		elsif(-e '/usr/local/etc/' . $user . '_' . $domain . '.aut'){
			$autoreply_file = '/usr/local/etc/' . $user . '_' . $domain . '.aut';
		}
		elsif(-e '/usr/local/etc/' . $user . '_' . $domain_reverse . '.aut'){
			$autoreply_file = '/usr/local/etc/' . $user . '_' . $domain_reverse . '.aut';
		}
		elsif(-e '/usr/local/etc/easytecc/' . $forward_aliases . '.aut'){
			$autoreply_file = '/usr/local/etc/easytecc/' . $forward_aliases . '.aut';
		}
		elsif(-e '/usr/local/etc/easytecc/' . $user . '_' . $domain . '.aut'){
			$autoreply_file =  '/usr/local/etc/easytecc/' . $user . '_' . $domain . '.aut';
		}
		elsif(-e '/usr/local/etc/easytecc/' . $user . '_' . $domain_reverse . '.aut'){
			$autoreply_file =  '/usr/local/etc/easytecc/' . $user . '_' . $domain_reverse . '.aut';
		}
		else{
			return(html_error({'non_specific' => 'L__Kann Autoresponderdatei nicht öffnen__L'}));
		}

		logline("debug","Creating File Object \$autoreply_file.");
		my $autoreply = file->new({	file_name => $autoreply_file,
									user => $user,
									domain => $domain});

		my @autoreply_content = ("From: $input{'forward'}", "Subject: $input{'autoreply_subject'}\n", "$input{'autoreply_text'}");
		$autoreply->file_content(\@autoreply_content);
		my $got = $autoreply->write_file;
		return(error($got)) if $got;
	}

	my $user_context = qq~<br /><br />
	<a href="/cgi-bin/easytecc3/index.pl?action=change_forward&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-Weiterleitungen anlegen"__L</b></a><br />
	<a href="/cgi-bin/easytecc3/index.pl?action=change_popuser&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-User anlegen"__L</b></a>~;

	$template->param('result' => 'L__Der Autoresponder wurde erfolgreich geändert!__L' . $user_context);
	$success_text = 'L__Der Autoresponder wurde erfolgreich geändert!__L';
	
	if ($input{'email_type'} eq 'single_edit') {
		$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_single_edit_email&domain=' . $input{'domain'} . '&success_text=' . encode_base64url($success_text);
	}
	else{
		$json_output{'modal_action'} = 'change_forward';
		$json_output{'modal_action_args'} = '&amp;domain=' . $input{'domain'} . '&amp;success_text=' . encode_base64url($success_text);
	}
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_delete_alert{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	
	if(length($input{'database'}) && length($input{'error'}) && -e "$mysqlbackup_dir/" . $input{'database'} . "/" . $input{'error'}){
	my $to_remove = "$mysqlbackup_dir/" . $input{'database'} . "/" . $input{'error'};
	logline("debug","to_remove=$to_remove");
	my $got = `rm -f $to_remove`;	
	}
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	exit(0);
}

sub exec_delete_autoreply{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $error = '';
	my $result = $validation_result;

	logline("debug","exec_delete_autoreply result:$result###");

	if($result){

	}
	else{
		my $forward = $input{'forward'};
		logline("debug","Creating File Object \$virtmaps.");
		my $virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
		$virtmaps->read_file;
		my %virtmaps = %{$virtmaps->file_parsed_hash()};

		logline("debug","Creating File Object \$aliases.");
		my $aliases = file->new({file_name => '/etc/mail/aliases'});
		$aliases->read_file;
		my %aliases = %{$aliases->file_parsed_hash()};

		my @new_virtmaps = ();
		my @new_aliases = ();
		my $aliases_lhs = '';
		# $domain und $user um autoreplydateinamen zu erstellen
		my $domain = $forward;
		$domain =~ s/^(.*)\@//;
		my $user = $1;
		# Wenn einzelner Empfänger in virtmaps, dann muss er in aliases bernommen werden
		my $virtmaps_to_aliases_target = '';
		# wenn mehrere Empfänger, dann rhs aus virtmaps sichern, diese entspricht lhs aus aliases die modifiziert werden muss
		my $old_virtmaps_rhs = '';
		#Die Weiterleitung kann auf einen Empfänger in virtmaps oder schon auf mehrere Empfänger mit "_spl"
		#in aliases angelegt sein
		foreach($virtmaps->file_content){
			# die zu ändernde E-Mailadresse, entweder ist es normale Weiterleitung oder es gibt _spl-Verweis auf aliases.
			# wenn _spl dann existiert bereits Weiterleitung an mehrere User
			if(/^$forward\s+(.*)$/){
				# virtmaps_rhs sichern, weil diese Zeile in aliases geändert werden muss
				# wenn es Autoreply mit nur einem Weiterleitungszeil war, dann alten Eintrag aus aliases raus und Ziel als normale
				# Weiterleitung in virtmaps rein, nachdem aliases ausgelesen wurde wissen wir was in virtmaps reinmuss
				$old_virtmaps_rhs = $1;
			}
			else{
				push @new_virtmaps, $_;
			}
		}

		foreach($aliases->file_content){
			if(/^$old_virtmaps_rhs\s*:\s*(.*),\s*(".*)$/){
				logline("debug","match auf modify_aliases_regex:$1 $2");
				my $aliases_targets = $1;
				my @targetsarray = split /,/, $aliases_targets;

				# wenn mehr als ein Empfänger wird alaises-Eintrag weiterhin gebraucht und virtmapseintrag wird von aut in spl geändert
				#if(scalar @targetsarray > 1){
					my $aliases_lhs = $old_virtmaps_rhs;
					#obsolet, kein Nutzen
					#$aliases_lhs =~ s/_aut$/_spl/;
					push @new_aliases, $aliases_lhs . ":\t" . $aliases_targets;
					# nun wissen wir auch was in virtmaps rein muss: Weiterleitung an mehrere User
					push @new_virtmaps, "$forward\t$aliases_lhs";
				#}
				#else{
					# oder Weiterleitung an nur einen Empfänger
					# zeile nicht übernehmen und Empfänger wandert in virtmaps. Da nur ein Empfänger ist es erstes Feld in targetsarray
				#	push @new_virtmaps, "$forward\t$targetsarray[0]";
				#}
			}
			else{
				push @new_aliases, $_;
			}
		}

		$aliases->file_content(\@new_aliases);
		my $got = $aliases->write_file;
		return(error($got)) if $got;

		@new_virtmaps = map(lc, @new_virtmaps);
		$virtmaps->file_content(\@new_virtmaps);
		my $got = $virtmaps->write_file;
		return(error($got)) if $got;

		my $file = '/usr/local/etc/easytecc/' . $user . '_' . $domain . '.aut';
		easytecc3::del_autoreply_file($file);
	}

	my $user_context = qq~<br /><br />
	<a href="/cgi-bin/easytecc3/index.pl?action=change_forward&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-Weiterleitungen anlegen"__L</b></a><br />
	<a href="/cgi-bin/easytecc3/index.pl?action=change_popuser&amp;domain=$input{'domain'}"><b>L__gehe zu "E-Mail-User anlegen"__L</b></a>~;

	$template->param('result' => 'L__Der Autoresponder wurde erfolgreich gelöscht__L' . $user_context);
	$success_text = 'L__Der Autoresponder wurde erfolgreich gelöscht__L';
	
	if ($input{'email_type'} eq 'single_edit') {
		$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_single_edit_email&domain=' . $input{'domain'} . '&success_text=' . encode_base64url($success_text);
	}
	else{
		$json_output{'modal_action'} = 'change_forward';
		$json_output{'modal_action_args'} = '&amp;domain=' . $input{'domain'};
	}
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_new_ftpuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $error = '';
	my $result = $validation_result;

	logline("debug","exec_new_ftpuser result:$result###");

	if($result){

	}
	else{
		$error .= easytecc3::add_ftpuser(\%input);
	}

	$result = 'L__Fehler__L: ' . $error if $error;
	
	return(html_error({'non_specific' => "$error"})) if $error;
	
	$result = 'L__Der FTP-User wurde erfolgreich angelegt__L';
	$success_text = 'L__Der FTP-User wurde erfolgreich angelegt__L';

	$template->param('result' => $result);
	logline("debug","result = " . $result);

	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_ftpuser&success_text=' . encode_base64url($success_text);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_new_adminuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $error = '';
	my $result = $validation_result;

	logline("debug","exec_new_adminuser result:$result###");
	
	my $gecos = 'CUST';
	
	if($input{'new_vhosts'} ne ''){
		
		$gecos .= '.vhost-1';
			
	} elsif($input{'show_vhosts'} ne ''){
	
		$gecos .= '.vhost';
		
	}
	
	if($input{'edit_email'} ne ''){
		
		$gecos .= '.email-1';
					
	} elsif($input{'show_email'} ne ''){
	
		$gecos .= '.email';
				
	}
		
	if($input{'new_ftp'} ne ''){
		
		$gecos .= '.ftp-2';
				
	} elsif($input{'edit_ftp'} ne ''){
	
		$gecos .= '.ftp-1';
					
	} elsif($input{'show_ftp'} ne ''){
	
		$gecos .= '.ftp';
				
	}
	
	if($input{'show_quota'} ne ''){
	
		$gecos .= '.quota';
		
	}
	
	if($input{'show_spam'} ne ''){
	
		$gecos .= '.spam';
				
	}
		
	if($input{'edit_fileman'} ne ''){
	
		$gecos .= '.fileman-1';
					
	} elsif($input{'show_fileman'} ne ''){
	
		$gecos .= '.fileman';
				
	}
		
	if($input{'edit_logs'} ne ''){
	
		$gecos .= '.logs-1';
					
	} elsif($input{'show_logs'} ne ''){
	
		$gecos .= '.logs';
				
	}
	
	if($input{'new_db'} ne ''){
		
		$gecos .= '.db-2';
					
	} elsif($input{'edit_db'} ne ''){
	
		$gecos .= '.db-1';
					
	} elsif($input{'show_db'} ne ''){
	
		$gecos .= '.db';
				
	}
	
	if($input{'new_cron'} ne ''){
		
		$gecos .= '.cron-2';
					
	} elsif($input{'edit_cron'} ne ''){
	
		$gecos .= '.cron-1';
					
	} elsif($input{'show_cron'} ne ''){
	
		$gecos .= '.cron';
				
	}
		
	if($input{'show_inst'} ne ''){
	
		$gecos .= '.inst';
				
	}
		
	if($result){
		
	}
	else{
	
		$input{'gecos'} = $gecos;
		$error .= easytecc3::add_ftpuser(\%input);
		
	}
	
	$result = 'L__Fehler__L: ' . $error if $error;
	
	return(html_error({'non_specific' => "$error"})) if $error;
	
	$result = 'L__Der Kunde wurde erfolgreich angelegt__L';
	$success_text = 'L__Der Kunde wurde erfolgreich angelegt__L';

	$template->param('result' => $result);
	logline("debug","result = " . $result);

	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_adminuser&success_text=' . encode_base64url($success_text);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_delete_ftpuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $error = '';
	my $result = $validation_result;

	if($result){

	}
	elsif($input{'ftpuser'} eq 'admin' || $input{'ftpuser'} eq 'web' || $input{'ftpuser'} eq 'ftp' || $input{'ftpuser'} eq 'mail'){
		$error = "$input{'ftpuser'}: L__User darf NICHT gelöscht werden__L";
	}
	else{
		$error .= easytecc3::del_ftpuser($input{'ftpuser'}, $input{'delete_home'});
		return(error(qq~L__Fehler beim Löschen von__L $input{'ftpuser'}: $error~)) if $error;
	}

	$result = 'L__Der FTP-User wurde erfolgreich gelöscht__L';
	$success_text = 'L__Der FTP-User wurde erfolgreich gelöscht__L';

	$template->param('result' => $result);
	logline("debug","result = " . $result);
	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_ftpuser&success_text=' . encode_base64url($success_text);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_delete_adminuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $error = '';
	my $result = $validation_result;

	if($result){

	}
	elsif($input{'ftpuser'} eq 'admin' || $input{'ftpuser'} eq 'web' || $input{'ftpuser'} eq 'ftp' || $input{'ftpuser'} eq 'mail'){
		$error = "$input{'ftpuser'}: L__User darf NICHT gelöscht werden__L";
	}
	else{
		$error .= easytecc3::del_ftpuser($input{'ftpuser'}, $input{'delete_home'});
		return(error(qq~L__Fehler beim Löschen von__L $input{'ftpuser'}: $error~)) if $error;
	}

	$result = 'L__Der Kunde wurde erfolgreich gelöscht__L';
	$success_text = 'L__Der Kunde wurde erfolgreich gelöscht__L';

	$template->param('result' => $result);
	logline("debug","result = " . $result);
	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_adminuser&success_text=' . encode_base64url($success_text);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_change_adminuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $error = '';
	my $result = $validation_result;

	logline("debug","exec_change_adminuser result:$result###");

	if($result){

	}
	else{
		
		my $ftpuser = $input{'ftpuser'};
		
		if(defined($input{'2fa'}) && $input{'2fa'} eq 'del'){
			
				`rm -f /usr/local/etc/easytecc/2fa/$ftpuser`;
				$result = 'L__Die Zwei-Faktor-Authentifizierung wurde deaktiviert__L!';
				$success_text = 'L__Die Zwei-Faktor-Authentifizierung wurde deaktiviert__L!';
		
				$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_adminuser&success_text=' . encode_base64url($success_text);
				return(\$template);
				
		} 
			
		logline("debug","Creating File Object \$passwd.");
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};
		

		
		logline("debug","Creating File Object \$passwd.");
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};
		my $ftpuser = $input{'ftpuser'};
				
		my $gecos = 'CUST';
	
		if($input{'new_vhosts'} ne ''){
			
			$gecos .= '.vhost-1';
				
		} elsif($input{'show_vhosts'} ne ''){
		
			$gecos .= '.vhost';
			
		}
		
		if($input{'edit_email'} ne ''){
			
			$gecos .= '.email-1';
				
		} elsif($input{'show_email'} ne ''){
		
			$gecos .= '.email';
			
		}
		
		if($input{'new_ftp'} ne ''){
			
			$gecos .= '.ftp-2';
				
		} elsif($input{'edit_ftp'} ne ''){
		
			$gecos .= '.ftp-1';
				
		} elsif($input{'show_ftp'} ne ''){
		
			$gecos .= '.ftp';
			
		}
		
		if($input{'show_quota'} ne ''){
		
			$gecos .= '.quota';
			
		}
		
		if($input{'show_spam'} ne ''){
		
			$gecos .= '.spam';
			
		}
		
		if($input{'edit_fileman'} ne ''){
		
			$gecos .= '.fileman-1';
				
		} elsif($input{'show_fileman'} ne ''){
		
			$gecos .= '.fileman';
			
		}
		
		if($input{'edit_logs'} ne ''){
		
			$gecos .= '.logs-1';
				
		} elsif($input{'show_logs'} ne ''){
		
			$gecos .= '.logs';
			
		}
		
		if($input{'new_db'} ne ''){
			
			$gecos .= '.db-2';
				
		} elsif($input{'edit_db'} ne ''){
		
			$gecos .= '.db-1';
				
		} elsif($input{'show_db'} ne ''){
		
			$gecos .= '.db';
			
		}
		
		if($input{'new_cron'} ne ''){
			
			$gecos .= '.cron-2';
				
		} elsif($input{'edit_cron'} ne ''){
		
			$gecos .= '.cron-1';
				
		} elsif($input{'show_cron'} ne ''){
		
			$gecos .= '.cron';
			
		}
		
		if($input{'show_inst'} ne ''){
		
			$gecos .= '.inst';
			
		}

		# wenn home geändert werden soll, nachfragen was mit Dateien im alten home passieren soll
		# Optionen:
		# -alten home-Ordner löschen
		# -alten home-Ordner beibehalten und user admin zuordnen
		# -Inhalt von alten nach neuen home-Ordner kopieren
		# -Inhalt von alten nach neuen home verschieben
		if($input{'home'} ne $passwd{$ftpuser}{'home'} && not exists $input{'home_action'}){
			$template = HTML::Template->new(filename => 'change_ftpuser_home_options.html');
			$template->param('ftpuser' => $ftpuser);
			$template->param('ftpquota' => $input{'ftpquota'});
			$template->param('gecos' => $gecos);
			$template->param('home' => $input{'home'});
			$template->param('old_home' => $passwd{$ftpuser}{'home'});
			$template->param('change_adminuser' => '1');
			logline("debug","Leaving (changed home path) ".(caller(0))[3]."().");
			return(\$template);
		}
		
		if($input{'gecos'}){
			$gecos = $input{'gecos'};
		}
		
		if($gecos ne $passwd{$ftpuser}{'gecos'} || $input{'home'} ne $passwd{$ftpuser}{'home'}){
		
			my $got = '';	
			if ($fb) {
				$got= `/usr/iports/bin/sudo /usr/sbin/usermod -h '$input{'home'}' -u '$ftpuser' -d '$gecos' 2>&1`;
				if ($got =~ /WARNING: home/) {
					$got = '';
				}
				
			}
			else{
				$got= `/usr/sbin/moduser -h '$input{'home'}' -u '$ftpuser' -d '$gecos' 2>&1`;	
			}
			return(error("L__Fehler beim Ändern von__L $ftpuser: $got")) if $got;
		}
		
		# Quota ändern falls notwendig
		my ($quotaref, $sum_ftplimit, $sum_ftpuse, $ftpserverlimit) = easytecc3::getquota_ftp();
		my %quota = %$quotaref;
		my $ftpquota = $quota{$ftpuser}{'quota'} / 1024;
		if($input{'ftpquota'} ne $ftpquota){
			my $got = '';
			if ($fb) {
				$got = `/usr/iports/bin/sudo /usr/sbin/setquota $ftpuser $input{"ftpquota"}M`;	
			}
			else{
				$got = `/usr/sbin/quotuser -q $input{'ftpquota'}M -n '$ftpuser' 2>&1`;	
			}

			return(error("L__Fehler beim Ändern der Quota von__L $ftpuser: $got")) if $got;
		}


		$input{'ftppass'} =~ s/\s//g;
		# Paswort ändern, wenn Formularfeld für Passwort ausgefüllt
		if($input{'ftppass'}){
			logline("debug","change ftp pass=" . $input{'ftppass'} . "###");
			my $got = '';
			if ($fb) {
				$got = `/usr/iports/bin/sudo /usr/sbin/chps -p '$input{'ftppass'}' -n '$ftpuser' 2>&1`;
				$got = '' if $got =~ /user information updated/;
			}
			else{
				$got = `/usr/sbin/chps -p '$input{'ftppass'}' -n '$ftpuser' 2>&1`;	
			}

			return(error("L__Fehler beim Ändern des Passwortes von__L $ftpuser: $got")) if $got;
		}
		
		# entweder soll home geändert werden und es wurde angegeben was passieren soll oder keine Änderung von home
		if($input{'home'} ne $passwd{$ftpuser}{'home'}){
			# wenn neus home, dann wurde home-Verzeichnis vorher mit moduser geändert
			# das neue home auf chmod 775 setzen, weil moduser das nicht macht
			my $got = `$easytecc_prefix/chmod.pl 775 $input{'home'} 2>&1` unless $fb;
			$got = `/usr/iports/bin/sudo /usr/sbin/chmod.pl 775 $input{'home'} 2>&1` if $fb;
			return(error("L__Fehler beim CHMOD von__L $input{'home'}: $got")) if $got;

			if($input{'home_action'} eq 'delete'){
				my $got = `$easytecc_prefix/rm.pl $passwd{$ftpuser}{'home'} d 2>&1` unless $fb;
				$got = `/usr/iports/bin/sudo /usr/sbin/rm.pl $passwd{$ftpuser}{'home'} d 2>&1` if $fb;
				return(error("L__Fehler beim Löschen von__L $passwd{$ftpuser}{'home'}: $got")) if $got;
				$result = "L__Das Verzeichnis wurde erfolgreich gelöscht__L!";
			}
			elsif($input{'home_action'} eq 'keep'){
				my $got = `$easytecc_prefix/chown.pl admin $passwd{$ftpuser}{'home'} d 2>&1` unless $fb;
				$got = `/usr/iports/bin/sudo /usr/sbin/chown.pl admin $passwd{$ftpuser}{'home'} d 2>&1` if $fb;
				return(error("L__Fehler bei CHOWN von__L $passwd{$ftpuser}{'home'}: $got")) if $got;
				$result = 'L__Das home-Verzeichnis des FTP-Users wurde erfolgreich geändert und das alte home-Verzeichnis wurde beibehalten__L!';
			}
			elsif($input{'home_action'} eq 'cp'){
				# Dateien in neues home kopieren
				my $got = `$easytecc_prefix/cp.pl $passwd{$ftpuser}{'home'} $input{'home'} d 2>&1` unless $fb;
				$got = `/usr/iports/bin/sudo /usr/sbin/cp.pl $passwd{$ftpuser}{'home'} $input{'home'} d 2>&1` if $fb;
				return(error("L__Fehler beim Kopieren von__L $passwd{$ftpuser}{'home'} L__zu__L $input{'home'}: $got")) if $got;
				# Dateien im alten home admin zuordnen
				$got = `$easytecc_prefix/chown.pl admin $passwd{$ftpuser}{'home'} d 2>&1` unless $fb;
				$got = `/usr/iports/bin/sudo /usr/sbin/chown.pl admin $passwd{$ftpuser}{'home'} d 2>&1` if $fb;
				return(error("L__Fehler bei CHOWN von__L $passwd{$ftpuser}{'home'}: $got")) if $got;
				$result = 'L__Das Verzeichnis wurde erfolgreich kopiert__L!';
			}
			elsif($input{'home_action'} eq 'mv'){
				my $got = `$easytecc_prefix/mv.pl $passwd{$ftpuser}{'home'} $input{'home'} d 2>&1` unless $fb;
				$got = `/usr/iports/bin/sudo /usr/sbin/mv.pl $passwd{$ftpuser}{'home'} $input{'home'} d 2>&1` if $fb;
				return(error("L__Fehler beim Umbenennen von__L $passwd{$ftpuser}{'home'} L__zu__L $input{'home'}: $got")) if $got;
				$result = 'L__Das Verzeichnis wurde erfolgreich umbenannt__L!';
			}
		}
		

		if($input{'ftp_to_admin'}){
			
			$result = 'L__Der Kunde wurde erfolgreich angelegt__L!';
			$success_text = 'L__Der Kunde wurde erfolgreich angelegt__L!';
		
		} else {
			
			$result = 'L__Der Kunde wurde erfolgreich geändert__L!';
			$success_text = 'L__Der Kunde wurde erfolgreich geändert__L!';
			
		}
	
	}

	$template->param('result' => $result);
	logline("debug","result = " . $result);
	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_adminuser&success_text=' . encode_base64url($success_text);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_change_ftpuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $error = '';
	my $result = $validation_result;

	logline("debug","exec_change_ftpuser result:$result###");

	if($result){

	}
	else{
		logline("debug","Creating File Object \$passwd.");
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};
		my $ftpuser = $input{'ftpuser'};

		# force reading from passwd if gecos is not given at all
		# could be an admin user edited by an admin
		$input{'gecos'} = $passwd{$ftpuser}{'gecos'} unless $input{'gecos'};

		
		# 2fa
		if(defined($input{'2fa'}) && $input{'2fa'} ne 'noop'){
	
			if($input{'2fa'} eq 'new'){
	
				my $label = $ftpuser;
				
				if($ftpuser eq 'admin'){
					
					my $servername = `sed 's/^.* // ; s/\$/.han-solo.net/' /etc/FQDN 2>/dev/null`;
					chomp $servername;
					$label .= '@' . $servername;
					
				}
							
				my $qrcode_url = `/usr/local/bin/google-authenticator -C -t -d -f -l $label -i easyTECC -Q UTF8 -r 3 -R 30 -s /usr/local/etc/easytecc/2fa/$ftpuser.setup -S 30 -w 3`;
				($qrcode_url) = $qrcode_url =~ m/(https:\/\/www\.google\.com\/chart[^\s]+)/;
				#$qrcode_url =~ s/https:\/\/www\.google\.com/https:\/\/chart.googleapis.com/;
				`wget -q -O - '$qrcode_url' | openssl base64 | tr -d '\n' > /usr/local/etc/easytecc/2fa/$ftpuser.qr`;
			
				$template = ${ change_ftpuser() };
				return(\$template);
						
			}
			elsif($input{'2fa'} eq 'ok'){
			
				`mv /usr/local/etc/easytecc/2fa/$ftpuser.setup /usr/local/etc/easytecc/2fa/$ftpuser`;
				`rm /usr/local/etc/easytecc/2fa/$ftpuser.qr`;
				$result = 'L__Die Zwei-Faktor-Authentifizierung wurde aktiviert__L!';
				$success_text = 'L__Die Zwei-Faktor-Authentifizierung wurde aktiviert__L!';	
			
			}
			elsif($input{'2fa'} eq 'del'){
			
				`rm -f /usr/local/etc/easytecc/2fa/$ftpuser*`;
				$result = 'L__Die Zwei-Faktor-Authentifizierung wurde deaktiviert__L!';
				$success_text = 'L__Die Zwei-Faktor-Authentifizierung wurde deaktiviert__L!';	
			
			}
		
		}	
			
		# wenn home geändert werden soll, nachfragen was mit Dateien im alten home passieren soll
		# Optionen:
		# -alten home-Ordner löschen
		# -alten home-Ordner beibehalten und user admin zuordnen
		# -Inhalt von alten nach neuen home-Ordner kopieren
		# -Inhalt von alten nach neuen home verschieben
		elsif($input{'home'} ne $passwd{$ftpuser}{'home'} && not exists $input{'home_action'}){
			$template = HTML::Template->new(filename => 'change_ftpuser_home_options.html');
			$template->param('ftpuser' => $ftpuser);
			$template->param('ftpquota' => $input{'ftpquota'});
			$template->param('gecos' => $input{'gecos'});
			$template->param('home' => $input{'home'});
			$template->param('old_home' => $passwd{$ftpuser}{'home'});
			logline("debug","Leaving (changed home path) ".(caller(0))[3]."().");
			return(\$template);
		}
		else{
		
logline("error","exec_change_ftpuser \$input{'home'}: " . $input{'home'});
logline("error","exec_change_ftpuser \$passwd{$ftpuser}{'home'}: " . $passwd{$ftpuser}{'home'});
logline("error","exec_change_ftpuser \$input{'gecos'}: " . $input{'gecos'});
logline("error","exec_change_ftpuser \$passwd{$ftpuser}{'gecos'}: " . $passwd{$ftpuser}{'gecos'});
	
	
			# moduser nur, wenn description oder home geändert werden soll
			if($input{'home'} ne $passwd{$ftpuser}{'home'} || $input{'gecos'} ne $passwd{$ftpuser}{'gecos'}){
				my $got = '';	
				if ($fb) {
					$got= `/usr/iports/bin/sudo /usr/sbin/usermod -h '$input{'home'}' -u '$ftpuser' -d "'$input{'gecos'}'" 2>&1`;
					if ($got =~ /WARNING: home/) {
						$got = '';
					}
					
				}
				else{
					$got= `/usr/sbin/moduser -h '$input{'home'}' -u '$ftpuser' -d '$input{'gecos'}' 2>&1`;	
				}
				return(error("L__Fehler beim Ändern von__L $ftpuser: $got")) if $got;
			}

			# Quota ändern falls notwendig
			my ($quotaref, $sum_ftplimit, $sum_ftpuse, $ftpserverlimit) = easytecc3::getquota_ftp();
			my %quota = %$quotaref;
			my $ftpquota = $quota{$ftpuser}{'quota'} / 1024;
			if($input{'ftpquota'} ne $ftpquota){
				my $got = '';
				if ($fb) {
					$got = `/usr/iports/bin/sudo /usr/sbin/setquota $ftpuser $input{"ftpquota"}M`;	
				}
				else{
					$got = `/usr/sbin/quotuser -q $input{'ftpquota'}M -n '$ftpuser' 2>&1`;	
				}

				return(error("L__Fehler beim Ändern der Quota von__L $ftpuser: $got")) if $got;
			}


			$input{'ftppass'} =~ s/\s//g;
			# Paswort ändern, wenn Formularfeld für Passwort ausgefüllt
			if($input{'ftppass'}){
				logline("debug","change ftp pass=" . $input{'ftppass'} . "###");
				my $got = '';
				if ($fb) {
					$got = `/usr/iports/bin/sudo /usr/sbin/chps -p '$input{'ftppass'}' -n '$ftpuser' 2>&1`;
					$got = '' if $got =~ /user information updated/;
				}
				else{
					$got = `/usr/sbin/chps -p '$input{'ftppass'}' -n '$ftpuser' 2>&1`;	
				}

				return(error("L__Fehler beim Ändern des Passwortes von__L $ftpuser: $got")) if $got;
			}

			#TODO fb
			# entweder soll home geändert werden und es wurde angegeben was passieren soll oder keine Änderung von home
			if($input{'home'} ne $passwd{$ftpuser}{'home'}){
				# wenn neus home, dann wurde home-Verzeichnis vorher mit moduser geändert
				# das neue home auf chmod 775 setzen, weil moduser das nicht macht
				my $got = `$easytecc_prefix/chmod.pl 775 $input{'home'} 2>&1` unless $fb;
				$got = `/usr/iports/bin/sudo /usr/sbin/chmod.pl 775 $input{'home'} 2>&1` if $fb;
				return(error("L__Fehler beim CHMOD von__L $input{'home'}: $got")) if $got;

				if($input{'home_action'} eq 'delete'){
					my $got = `$easytecc_prefix/rm.pl $passwd{$ftpuser}{'home'} d 2>&1` unless $fb;
					$got = `/usr/iports/bin/sudo /usr/sbin/rm.pl $passwd{$ftpuser}{'home'} d 2>&1` if $fb;
					return(error("L__Fehler beim Löschen von__L $passwd{$ftpuser}{'home'}: $got")) if $got;
					$result = "L__Das Verzeichnis wurde erfolgreich gelöscht__L!";
				}
				elsif($input{'home_action'} eq 'keep'){
					my $got = `$easytecc_prefix/chown.pl admin $passwd{$ftpuser}{'home'} d 2>&1` unless $fb;
					$got = `/usr/iports/bin/sudo /usr/sbin/chown.pl admin $passwd{$ftpuser}{'home'} d 2>&1` if $fb;
					return(error("L__Fehler bei CHOWN von__L $passwd{$ftpuser}{'home'}: $got")) if $got;
					$result = 'L__Das home-Verzeichnis des FTP-Users wurde erfolgreich geändert und das alte home-Verzeichnis wurde beibehalten__L!';
				}
				elsif($input{'home_action'} eq 'cp'){
					# Dateien in neues home kopieren
					my $got = `$easytecc_prefix/cp.pl $passwd{$ftpuser}{'home'} $input{'home'} d 2>&1` unless $fb;
					$got = `/usr/iports/bin/sudo /usr/sbin/cp.pl $passwd{$ftpuser}{'home'} $input{'home'} d 2>&1` if $fb;
					return(error("L__Fehler beim Kopieren von__L $passwd{$ftpuser}{'home'} L__zu__L $input{'home'}: $got")) if $got;
					# Dateien im alten home admin zuordnen
					$got = `$easytecc_prefix/chown.pl admin $passwd{$ftpuser}{'home'} d 2>&1` unless $fb;
					$got = `/usr/iports/bin/sudo /usr/sbin/chown.pl admin $passwd{$ftpuser}{'home'} d 2>&1` if $fb;
					return(error("L__Fehler bei CHOWN von__L $passwd{$ftpuser}{'home'}: $got")) if $got;
					$result = 'L__Das Verzeichnis wurde erfolgreich kopiert__L!';
				}
				elsif($input{'home_action'} eq 'mv'){
					my $got = `$easytecc_prefix/mv.pl $passwd{$ftpuser}{'home'} $input{'home'} d 2>&1` unless $fb;
					$got = `/usr/iports/bin/sudo /usr/sbin/mv.pl $passwd{$ftpuser}{'home'} $input{'home'} d 2>&1` if $fb;
					return(error("L__Fehler beim Umbenennen von__L $passwd{$ftpuser}{'home'} L__zu__L $input{'home'}: $got")) if $got;
					$result = 'L__Das Verzeichnis wurde erfolgreich umbenannt__L!';
				}
			}
			else{
				
				if ($passwd{$ftpuser}{'shell'} eq '/usr/sbin/nologin' || $ftpuser =~ /^(admin|cyrus|dovecot|dovenull|mysql|pgsql|virtmail|web)$/) {
					$result = 'L__Der System-User wurde erfolgreich geändert__L!';
					$success_text = 'L__Der System-User wurde erfolgreich geändert__L!';	
				} else {
					$result = 'L__Der FTP-User wurde erfolgreich geändert__L!';
					$success_text = 'L__Der FTP-User wurde erfolgreich geändert__L!';
				}
			}
		}
	}

	if( -f "/usr/local/etc/easytecc/2fa/$ftpuser"){
		
		$template->param('2fa' => 1);
		
	}
	
	$template->param('result' => $result);
	logline("debug","result = " . $result);
	
	$json_output{'redirect_to'} = '&success_text=' . encode_base64url($success_text);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_change_spamfilter{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $result = $validation_result;

	logline("debug","exec_change_spamfilter result: $result###");

	if($result){

	}
	else{
		my %new_dnsbl;
		my $whitelist_content = '';
		my $blacklist_content = '';

		logline("debug","Creating File Object \$procmailrc.");
		my $procmailrc = file->new({file_name => '/etc/procmailrc'});
		$procmailrc->read_file;

		logline("debug","Creating File Object \$dnsbl.");
		my $dnsbl = file->new({file_name => '/etc/mail/dnsbl.hosts'});
		$dnsbl->read_file;
		my %dnsbl = %{$dnsbl->file_parsed_hash()};

		logline("debug","Creating File Object \$whitelist.");
		my $whitelist = file->new({file_name => '/home/spamdef/.white.lst'});
		$whitelist->read_file;

		logline("debug","Creating File Object \$blacklist.");
		my $blacklist = file->new({file_name => '/home/spamdef/.black.lst'});
		$blacklist->read_file;

		logline("debug","Creating File Object \$user_prefs.");
		my $user_prefs = file->new({file_name => '/home/spamdef/.spamd/user_prefs'});
		$user_prefs->read_file;

		# rbl schreiben, zuerst die vorhandenen Listen auslesen, und mit $input{'rbl_...'} vergleichen und dann schreiben
		my $line_yes = "YES\t";
		my $line_no = "NO\t";
		foreach(sort keys %dnsbl){
			$line_yes .= "$_ " if($input{"rbl_$_"} == 1);
			$line_no .= "$_ " if($input{"rbl_$_"} != 1);
		}
		my @rbl_file_content = ("$line_yes", "$line_no");
		$dnsbl->file_content(\@rbl_file_content);
		my $got = $dnsbl->write_file;
		if ($got) {
			logline("error","dnsbl->write_file = ".$got);
			return(error($got));
		}

		# whitelist schreiben
		my @whitelist_content =  split m(\r\n|;|:|,|\t+|\s+), $input{'whitelist'};
		$whitelist->file_content(\@whitelist_content);
		$got = $whitelist->write_file;
		if ($got) {
			logline("error","whitelist->write_file = ".$got);
			return(error($got));
		}

		# blacklist schreiben
		my @blacklist_content =  split m(\r\n|;|:|,|\t+|\s+), $input{'blacklist'};
		$blacklist->file_content(\@blacklist_content);
		$got = $blacklist->write_file;
		if ($got) {
			logline("error","blacklist->write_file = ".$got);
			return(error($got));
		}

		# /etc/procmailrc schreiben
		# VIRUS=MARK
		# SPAMD=ON
		# PSPAM=MARK
		# CSPAM=MARK
		# SUBJ_VIRUS='*VIRUSVERDACHTT*:'
		# SUBJ_PSPAM='*SPAMVERDACHT*:'
		# SUBJ_CSPAM='*SPAM ERKANNT*:'
		# CLEVEL='\*\*\*\*\*\*'
		# POSTFIX='bat|com|dll|exe|pif|scr|vbs|zip'
		my @new_procmailrc;
		my $clevel = '\*' x $input{'cspam_level'};
		my @postfix = split(/\s+|\;|\,|\n/,$input{"postfix_virus"});
		my ($line,$name,$val);

		foreach(@{$procmailrc->file_content}){
			if(/^VIRUS=/){
				push @new_procmailrc, "VIRUS=$input{'action_virus'}";
			}
			elsif(/^SPAMD=/){
				push @new_procmailrc, "SPAMD=$input{'spamd'}";
			}
			elsif(/^PSPAM=/){
				push @new_procmailrc, "PSPAM=$input{'action_pspam'}";
			}
			elsif(/^CSPAM=/){
				push @new_procmailrc, "CSPAM=$input{'action_cspam'}";
			}
			elsif(/^CLEVEL=/){
				push @new_procmailrc, "CLEVEL='$clevel'";
			}
			# veränderbare
			elsif(/^POSTFIX=/){
				my $postfix = "";
				foreach my $item (sort @postfix){
					next unless($item);
					next if($item eq $lastitem);
					$postfix .= "$item|";
					$lastitem = $item;
				}
				chop $postfix;
				push @new_procmailrc, "POSTFIX='$postfix'";
			}
			elsif(/^SUBJ_CSPAM\s*=/){
				push @new_procmailrc, "SUBJ_CSPAM='$input{'subj_cspam'}'";
			}
			elsif(/^SUBJ_PSPAM\s*=/){
				push @new_procmailrc, "SUBJ_PSPAM='$input{'subj_pspam'}'";
			}
			elsif(/^SUBJ_VIRUS\s*=/){
				push @new_procmailrc, "SUBJ_VIRUS='$input{'subj_virus'}'";
			}
			else {
				push @new_procmailrc, $_;
			}
		}

		$procmailrc->file_content(\@new_procmailrc);
		$got = $procmailrc->write_file;
		logline("debug","write procmail:$got");
		if ($got) {
			logline("error","procmailrc->write_file = ".$got);
			return(error($got));
		}

		# user_prefs schreiben
		my $new_user_prefs_ref = easytecc3::prepare_user_prefs($user_prefs, \%input);
		my @new_user_prefs = @$new_user_prefs_ref;
		$user_prefs->file_content(\@new_user_prefs);
		$got = $user_prefs->write_file;
		if ($got) {
			logline("error","user_prefs->write_file = ".$got);
			return(error($got));
		}
		
		# .deliver - sed -i hat unter bsd leider einen bug und legt immer temp-dateien im selben dir an, deswegen das gecatte
		my $deliver = "/etc/.deliver";
		my $junkfolder = $input{'junkfolder'};
		$got = `[ -s $deliver ] || echo 'DOVECOT_JUNK=' > $deliver 2>/dev/null; sed 's/^DOVECOT_JUNK=.*/DOVECOT_JUNK=\'$junkfolder\'/' $deliver > /tmp/.deliver.$$ && cat /tmp/.deliver.$$ > $deliver && rm /tmp/.deliver.$$`;
		if ($got) {
			logline("error",".deliver->write_file = ".$got);
			return(error($got));
		}
	}

	$template->param('result' => 'L__Die globalen Spameinstellungen wurden erfolgreich geändert__L!');
	$success_text = 'L__Die globalen Spameinstellungen wurden erfolgreich geändert__L!';

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	undef %input;
	$input{'action'} = 'change_spamfilter';
	change_spamfilter();
	
		
	#return(\$template);
}

sub exec_new_special_spamfilter{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $result = $validation_result;

	logline("debug","exec_new_special_spamfilter result: $result###");

	if($result){

	}
	else{
		$special_spamfilter = ascii_domain($input{'special_spam_user_domain'});

		logline("debug","exec_new_special_spamfilter vor genspam: $special_spamfilter");

		system("/usr/sbin/genspam","-n",$special_spamfilter) unless $fb;
		my $got = `/usr/iports/bin/sudo /usr/sbin/genspam -n $special_spamfilter` if $fb;
		logline("debug","genspam got: $got");

		my $whitelist_content = '';
		my $blacklist_content = '';

		logline("debug","Creating File Object \$procmailrc.");
		my $procmailrc = file->new({file_name => "/home/$special_spamfilter/.spamproc",
		user => "$special_spamfilter"});
		$procmailrc->read_file;

		logline("debug","Creating File Object \$whitelist.");
		my $whitelist = file->new({file_name => "/home/$special_spamfilter/.white.lst",
		user => "$special_spamfilter"});
		#$whitelist->read_file;

		logline("debug","Creating File Object \$blacklist.");
		my $blacklist = file->new({file_name => "/home/$special_spamfilter/.black.lst",
		user => "$special_spamfilter"});
		#$blacklist->read_file;

		logline("debug","Creating File Object \$user_prefs.");
		my $user_prefs = file->new({file_name => "/home/$special_spamfilter/.spamd/user_prefs",
		user => "$special_spamfilter"});
		$user_prefs->read_file;

		# whitelist schreiben
		my @whitelist_content_tmp =  split m(\r\n|;|:|,|\t+|\s+), $input{'special_whitelist'};
		my @whitelist_content = ();
		foreach(@whitelist_content_tmp){
			if(/@/){
				push @whitelist_content, email_to_ascii($_);
			}
			else{
				push @whitelist_content, ascii_domain($_);
			}
		}
		$whitelist->file_content(\@whitelist_content);
		$got = $whitelist->write_file;
		if ($got) {
			logline("error","whitelist->write_file = ".$got);
			return(error($got));
		}

		# blacklist schreiben
		my @blacklist_content_tmp =  split m(\r\n|;|:|,|\t+|\s+), $input{'special_blacklist'};
		my @blacklist_content = ();
		foreach(@blacklist_content_tmp){
			if(/@/){
				push @blacklist_content, email_to_ascii($_);
			}
			else{
				push @blacklist_content, ascii_domain($_);
			}
		}
		$blacklist->file_content(\@blacklist_content);
		$got = $blacklist->write_file;
		if ($got) {
			logline("error","blacklist->write_file = ".$got);
			return(error($got));
		}

		# /etc/procmailrc schreiben
		# VIRUS=MARK
		# SPAMD=ON
		# PSPAM=MARK
		# CSPAM=MARK
		# SUBJ_VIRUS='*VIRUSVERDACHTT*:'
		# SUBJ_PSPAM='*SPAMVERDACHT*:'
		# SUBJ_CSPAM='*SPAM ERKANNT*:'
		# CLEVEL='\*\*\*\*\*\*'
		# POSTFIX='bat|com|dll|exe|pif|scr|vbs|zip'
		my @new_procmailrc;
		my $clevel = '\*' x $input{'special_cspam_level'};
		my @postfix = split(/\s+|\;|\,|\n/,$input{"special_postfix_virus"});
		my ($line,$name,$val);

		foreach(@{$procmailrc->file_content}){
			if(/^VIRUS=/){
				push @new_procmailrc, "VIRUS=$input{'special_action_virus'}";
			}
			elsif(/^SPAMD=/){
				push @new_procmailrc, "SPAMD=$input{'special_spamd'}";
			}
			elsif(/^PSPAM=/){
				push @new_procmailrc, "PSPAM=$input{'special_action_pspam'}";
			}
			elsif(/^CSPAM=/){
				push @new_procmailrc, "CSPAM=$input{'special_action_cspam'}";
			}
			elsif(/^CLEVEL=/){
				push @new_procmailrc, "CLEVEL='$clevel'";
			}
			# veränderbare
			elsif(/^POSTFIX=/){
				my $postfix = "";
				foreach my $item (sort @postfix){
					next unless($item);
					next if($item eq $lastitem);
					$postfix .= "$item|";
					$lastitem = $item;
				}
				chop $postfix;
				push @new_procmailrc, "POSTFIX='$postfix'";
			}
			elsif(/^SUBJ_CSPAM\s*=/){
				push @new_procmailrc, "SUBJ_CSPAM='$input{'special_subj_cspam'}'";
			}
			elsif(/^SUBJ_PSPAM\s*=/){
				push @new_procmailrc, "SUBJ_PSPAM='$input{'special_subj_pspam'}'";
			}
			elsif(/^SUBJ_VIRUS\s*=/){
				push @new_procmailrc, "SUBJ_VIRUS='$input{'special_subj_virus'}'";
			}
			else {
				push @new_procmailrc, $_;
			}
		}

		$procmailrc->file_content(\@new_procmailrc);
		$got = $procmailrc->write_file;
		if ($got) {
			logline("error","procmailrc->write_file = ".$got);
			return(error($got));
		}

		# user_prefs schreiben
		my $new_user_prefs_ref = easytecc3::prepare_user_prefs($user_prefs, \%input);
		my @new_user_prefs = @$new_user_prefs_ref;
		$user_prefs->file_content(\@new_user_prefs);
		$got = $user_prefs->write_file;
		if ($got) {
			logline("error","user_prefs->write_file = ".$got);
			return(error($got));
		}

		$mailpasswd = easytecc3::get_mailpasswd();
		my %mailpasswd = %{$mailpasswd->file_parsed_hash()};	
		#my %mailpasswd = %{easytecc3::get_mailpasswd()};

		my $domain = $mailpasswd{$special_spamfilter}{'gecos'};
		$domain =~ s/ - POP$//;

		# wenn Domain in mailpasswd nicht gefunden wird, dann ist es eine Domain
		$domain = $special_spamfilter unless $domain;

		#spamconf ändern
		logline("debug","Creating File Object /usr/local/etc/easytecc/spamuser.conf.");
		my $file = file->new({file_name => '/usr/local/etc/easytecc/spamuser.conf', append => '1', file_content => [qq~$special_spamfilter=$domain~]});
		$got = $file->write_file;
		if ($got) {
			logline("error","/usr/local/etc/easytecc/spamuser.conf->write_file = ".$got);
			return(error($got));
		}
		
		# .deliver - sed -i hat unter bsd leider einen bug und legt immer temp-dateien im selben dir an, deswegen das gecatte
		my $deliver = "/home/$special_spamfilter/.deliver";
		my $junkfolder = $input{'special_junkfolder'};
		$got = `[ -s $deliver ] || echo 'DOVECOT_JUNK=' > $deliver 2>/dev/null; sed 's/^DOVECOT_JUNK=.*/DOVECOT_JUNK=\'$junkfolder\'/' $deliver > /tmp/.deliver.$$ && cat /tmp/.deliver.$$ > $deliver && rm /tmp/.deliver.$$`;
		if ($got) {
			logline("error",".deliver->write_file = ".$got);
			return(error($got));
		}
		
	}

	$template->param('result' => 'L__Die speziellen Spameinstellungen wurden erfolgreich angelegt__L!');
	$success_text = 'L__Die speziellen Spameinstellungen wurden erfolgreich angelegt__L!';
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	
	# mailuser hack
	if($session && $session->param('is_mailuser')){
		
		logline("debug","is_mailuser=1, setting template=mailuser_interface");
		$template = ${mailuser_interface()};
		$action = $input{'action'} = 'mailuser_interface';
		$input{'active_tab'} = '_spamfilter';
		
	} else {	
			
		#direct call to change_spamfilter with active tab 3
		undef %input;
		$input{'active_tab'} = '3';
		$template = ${change_spamfilter()};
	
	}
	return(\$template);
}

sub exec_change_special_spamfilter{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $result = $validation_result;

	logline("debug","exec_change_special_spamfilter result:$result###");

	if($result){
		
	}
	else{
		$special_spamfilter = ascii_domain($input{'special_spam_user_domain'});

		my $whitelist_content = '';
		my $blacklist_content = '';

		logline("debug","Creating File Object \$procmailrc.");
		my $procmailrc = file->new({file_name => "/home/$special_spamfilter/.spamproc",
		user => "$special_spamfilter"});
		$procmailrc->read_file;

		logline("debug","Creating File Object \$whitelist.");
		my $whitelist = file->new({file_name => "/home/$special_spamfilter/.white.lst",
		user => "$special_spamfilter"});
		#$whitelist->read_file;

		logline("debug","Creating File Object \$blacklist.");
		my $blacklist = file->new({file_name => "/home/$special_spamfilter/.black.lst",
		user => "$special_spamfilter"});
		#$blacklist->read_file;

		logline("debug","Creating File Object \$user_prefs.");
		my $user_prefs = file->new({file_name => "/home/$special_spamfilter/.spamd/user_prefs",
		user => "$special_spamfilter"});
		$user_prefs->read_file;

		# whitelist schreiben
		my @whitelist_content_tmp =  split m(\r\n|;|:|,|\t+|\s+), $input{'special_whitelist'};
		my @whitelist_content = ();
		foreach(@whitelist_content_tmp){
			if(/@/){
				push @whitelist_content, email_to_ascii($_);
			}
			else{
				push @whitelist_content, ascii_domain($_);
			}
		}
		$whitelist->file_content(\@whitelist_content);
		my $got = $whitelist->write_file;
		return(error($got)) if $got;

		# blacklist schreiben
		my @blacklist_content_tmp =  split m(\r\n|;|:|,|\t+|\s+), $input{'special_blacklist'};
		my @blacklist_content = ();
		foreach(@blacklist_content_tmp){
			if(/@/){
				push @blacklist_content, email_to_ascii($_);
			}
			else{
				push @blacklist_content, ascii_domain($_);
			}
		}
		$blacklist->file_content(\@blacklist_content);
		$got = $blacklist->write_file;
		return(error($got)) if $got;

		# /etc/procmailrc schreiben
		# VIRUS=MARK
		# SPAMD=ON
		# PSPAM=MARK
		# CSPAM=MARK
		# SUBJ_VIRUS='*VIRUSVERDACHTT*:'
		# SUBJ_PSPAM='*SPAMVERDACHT*:'
		# SUBJ_CSPAM='*SPAM ERKANNT*:'
		# CLEVEL='\*\*\*\*\*\*'
		# POSTFIX='bat|com|dll|exe|pif|scr|vbs|zip'
		my @new_procmailrc;
		my $clevel = '\*' x $input{'special_cspam_level'};
		my @postfix = split(/\s+|\;|\,|\n/,$input{"special_postfix_virus"});
		my ($line,$name,$val);

		foreach(@{$procmailrc->file_content}){
			if(/^VIRUS=/){
				push @new_procmailrc, "VIRUS=$input{'special_action_virus'}";
			}
			elsif(/^SPAMD=/){
				push @new_procmailrc, "SPAMD=$input{'special_spamd'}";
			}
			elsif(/^PSPAM=/){
				push @new_procmailrc, "PSPAM=$input{'special_action_pspam'}";
			}
			elsif(/^CSPAM=/){
				push @new_procmailrc, "CSPAM=$input{'special_action_cspam'}";
			}
			elsif(/^CLEVEL=/){
				push @new_procmailrc, "CLEVEL='$clevel'";
			}
			# veränderbare
			elsif(/^POSTFIX=/){
				my $postfix = "";
				foreach my $item (sort @postfix){
					next unless($item);
					next if($item eq $lastitem);
					$postfix .= "$item|";
					$lastitem = $item;
				}
				chop $postfix;
				push @new_procmailrc, "POSTFIX='$postfix'";
			}
			elsif(/^SUBJ_CSPAM\s*=/){
				push @new_procmailrc, "SUBJ_CSPAM='$input{'special_subj_cspam'}'";
			}
			elsif(/^SUBJ_PSPAM\s*=/){
				push @new_procmailrc, "SUBJ_PSPAM='$input{'special_subj_pspam'}'";
			}
			elsif(/^SUBJ_VIRUS\s*=/){
				push @new_procmailrc, "SUBJ_VIRUS='$input{'special_subj_virus'}'";
			}
			else {
				push @new_procmailrc, $_;
			}
		}

		$procmailrc->file_content(\@new_procmailrc);
		$got = $procmailrc->write_file;
		if ($got) {
			logline("error","procmailrc->write_file = ".$got);
			return(error($got));
		}

		# user_prefs schreiben
		my $new_user_prefs_ref = easytecc3::prepare_user_prefs($user_prefs, \%input);
		my @new_user_prefs = @$new_user_prefs_ref;
		$user_prefs->file_content(\@new_user_prefs);
		$got = $user_prefs->write_file;
		if ($got) {
			logline("error","user_prefs->write_file = ".$got);
			return(error($got));
		}
		
		# .deliver - sed -i hat unter bsd leider einen bug und legt immer temp-dateien im selben dir an, deswegen das gecatte
		my $deliver = "/home/$special_spamfilter/.deliver";
		my $junkfolder = $input{'special_junkfolder'};
		$got = `[ -s $deliver ] || echo 'DOVECOT_JUNK=' > $deliver 2>/dev/null; sed 's/^DOVECOT_JUNK=.*/DOVECOT_JUNK=\'$junkfolder\'/' $deliver > /tmp/.deliver.$$ && cat /tmp/.deliver.$$ > $deliver && rm /tmp/.deliver.$$`;
		if ($got) {
			logline("error",".deliver->write_file = ".$got);
			return(error($got));
		}
	}
	
	$success_text = 'L__Die speziellen Spameinstellungen wurden erfolgreich geändert__L!';
	
	# mailuser hack
	if($session && $session->param('is_mailuser')){
		
		logline("debug","is_mailuser=1, setting template=mailuser_interface");
		$template = ${mailuser_interface()};
		$action = $input{'action'} = 'mailuser_interface';
		$input{'active_tab'} = '_spamfilter';
		
	} else {	
			
		$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=change_spamfilter&active_tab=3&success_text=' . encode_base64url($success_text);
	
	}
	
	$template->param('result' => 'L__Die speziellen Spameinstellungen wurden erfolgreich geändert__L!');
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_delete_special_spamfilter{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $result = $validation_result;
	my $success_text = '';

	if($result){

	}
	else{
		my $special_spamfilter = $input{'special_spam_user_domain'};
		my $tmperror = system("/usr/sbin/delspam","-n","$special_spamfilter") unless $fb;
		my $tmperror = `/usr/iports/bin/sudo /usr/sbin/delspam -n $special_spamfilter` if $fb;
		return(html_error(({'L__Die Spameinstellungen konnten nicht gelöscht werden__L' => "$tmperror"}))) if $tmperror;

		if(-e "/etc/cshost"){
			$tmperror = `/usr/sbin/spamconf -d $special_spamfilter 2>&1` unless $fb;
			$tmperror = `/usr/sbin/spamconf -d $special_spamfilter 2>&1` if $fb;
			return(html_error(({'L__Die Spameinstellungen konnten nicht gelöscht werden__L' => "can't delete spamconfs for user $special_spamfilter at spamd: $tmperror"}))) if $tmperror;
		}

		my $got = easytecc3::delete_from_spamconf($special_spamfilter);
		if ($got) {
			logline("error","delete_from_spamconf($special_spamfilter) = ".$got);
			return(error($got));
		}

		$result = "L__Die Spameinstellungen für__L $special_spamfilter L__wurden erfolgreich gelöscht__L";
		$success_text = "L__Die Spameinstellungen für__L $special_spamfilter L__wurden erfolgreich gelöscht__L";
	}

	$template->param('result' => $result);
	logline("debug","result = " . $result);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=change_spamfilter&active_tab=3&success_text=' . encode_base64url($success_text);
	return(\$template);
}

sub exec_change_virusfilter{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $result = $validation_result;

	logline("debug","exec_change_virusfilter result: $result###");

	if($result){

	}
	else{
		my $whitelist_content = '';

		logline("debug","Creating File Object \$clamavmilter.");
		my $clamavmilter = file->new({file_name => "/etc/sysconfig/clamav-milter"});
		$clamavmilter->read_file;
		
		logline("debug","Creating File Object \$clamavtemplate.");
		my $clamavtemplate = file->new({file_name => "/etc/sysconfig/clamav-template"});
		$clamavtemplate->read_file;

		logline("debug","Creating File Object \$clamavwhitelist.");
		my $clamavwhitelist = file->new({file_name => "/etc/sysconfig/clamav-whitelist"});
		$clamavwhitelist->read_file;

		my $quit = '';
		my $noxheader = '';
		my $from = '';
		my $milter_on = '';

		unless($input{'report_safe'}){
			$quit = 'YES';
		}
		unless($input{'virusheader'}){
			$noxheader = 'YES';
		}
		if($input{'virus_found_sender'}){
			$from = $input{'virus_found_sender'};
		}
		if($input{'virusfilter'}){
			$milter_on = 'YES';
		}

		my @clamav_milter = qq~QUIET=$quit
NOXHEADER=$noxheader
TEMPLATE=YES
WHITELIST=YES
FROM=$from
MILTER_ON=$milter_on~;

		$clamavmilter->file_content(\@clamav_milter);
		my $got = $clamavmilter->write_file;
		if ($got) {
			logline("error","clamavmilter->write_file = ".$got);
			return(error($got));
		}

		logline("debug","virus_whitelist:\n$input{'virus_whitelist'}\n");

		#my @virus_whitelist = split/(\s+|;|:|,|\t)/, $input{'virus_whitelist'};
		my @virus_whitelist = split m(\r\n|;|:|,|\t+|\s+), $input{'virus_whitelist'};

		foreach(@virus_whitelist){
			logline("debug","wl:$_##");
		}

		$clamavwhitelist->file_content(\@virus_whitelist);
		my $got = $clamavwhitelist->write_file;
		if ($got) {
			logline("error","clamavwhitelist->write_file = ".$got);
			return(error($got));
		}


		my @clamav_template = ("Subject: $input{'virus_found_subject'}\n\n", "$input{'virus_found_text'}");
		$clamavtemplate->file_content(\@clamav_template);
		my $got = $clamavtemplate->write_file;
		if ($got) {
			logline("error","clamavtemplate->write_file = ".$got);
			return(error($got));
		};
	}

	$template->param('result' => 'L__Die Virenfilter-Voreinstellungen wurden erfolgreich geändert__L!');
	$success_text = 'L__Die Virenfilter-Voreinstellungen wurden erfolgreich geändert__L!';

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_scan_antivirus{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $result = $validation_result;

	if($result){

	}
	else{
		open DAT,">/tmp/scan.$$" or dienice( 'Error processing file: '.$!);
		my $cgi = new CGI;
		my $file = $cgi->upload("filename");

		binmode $file;
		binmode DAT;

		my $data;
		while(read $file,$data,1024) {
			print DAT $data;
		}
		close DAT;

		my $answer = `/usr/sbin/clamdscan --config-file=/etc/clamd.conf --stdout --verbose - < /tmp/scan.$$`;
		my @answer = split(/\n/,$answer);

		`rm -f /tmp/scan.$$`;

		foreach my $item (@answer) {
			$item =~ s/stream/\<STRONG\>$input{'filename'}\<\/STRONG\>/;
			$item =~ s/\sOK$/\<SPAN class\=\"green\">&nbsp;OK\<\/SPAN\>/;
			$item =~ s/\sFOUND$/\<SPAN class\=\"red\">&nbsp;FOUND\<\/SPAN\>/;
			if($item =~ /^Infected files/){
				$dummy = $item;
				$dummy =~ s/^.*\:\s+//;
				if($dummy > 0){
					$item =~ s/^(.*)$/\<SPAN class\=\"red\">$1\<\/SPAN\>/;
				}
				else {
					$item =~ s/^(.*)$/\<SPAN class\=\"green\">$1\<\/SPAN\>/;
				}
			}
			$result .= "$item<br />";
		}
	}
	$template->param('result' => $result);
	logline("debug","result = " . $result);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_new_cronjob{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $result = $validation_result;

	logline("debug","exec_new_cronjob result:$result###");

	if($result){

	}
	else{
		my %handle_hash = %{easytecc3::return_file_handler_store()};
		my $cronfile = $handle_hash{'/home/web/cronfile'};
		my $new_cronjob = '';

		my %form_to_cron = %{easytecc3::form_to_cron()};

		$input{'min'} = $form_to_cron{$input{'min'}} unless $input{'min'} =~ /^\d+$/;
		$input{'std'} = $form_to_cron{$input{'std'}} unless $input{'std'} =~ /^\d+$/;
		$input{'mday'} = $form_to_cron{$input{'mday'}} unless $input{'mday'} =~ /^\d+$/;
		$input{'mon'} = $form_to_cron{$input{'mon'}} unless $input{'mon'} =~ /^\d+$/;
		$input{'wday'} = $form_to_cron{$input{'wday'}} unless $input{'wday'} =~ /^\d+$/;

		if($fb){

			$input{'command'} =~ s#/apache24/noexec/#/apache24/data/#;
					
		}		
		
		push @{$cronfile->file_content}, qq~$input{'min'} $input{'std'} $input{'mday'} $input{'mon'} $input{'wday'} $input{'command'}\n~;
		logline("debug",qq~cronjob modifiziert:$input{'min'} $input{'std'} $input{'mday'} $input{'mon'} $input{'wday'} $input{'command'}~);
		$new_cronjob = qq~$input{'min'} $input{'std'} $input{'mday'} $input{'mon'} $input{'wday'} $input{'command'}\n~;

		my $got = $cronfile->write_file;
		if ($got) {
			logline("error","cronfile->write_file = ".$got);
			return(error($got));
		}
		$result = qq~L__Der cronjob wurde erfolgreich angelegt__L~;
		$success_text = qq~L__Der cronjob wurde erfolgreich angelegt__L~;
	}

	$template->param('result' => $result);
	logline("debug","result = " . $result);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_cronjobs&success_text=' . encode_base64url($success_text);
	return(\$template);
}

sub exec_auto_cronjob{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $result = $validation_result;
	my $cronjob = '';

	logline("debug","exec_auto_cronjob result:$result###");

	if($result){
		$template->param('result' => $result);
	}
	else{
		my %handle_hash = %{easytecc3::return_file_handler_store()};
		my $cronfile = $handle_hash{'/home/web/cronfile'};

		if($input{'type'} eq 'delete_all_logs'){
			$cronjob = qq~05 01 * * * /usr/sbin/dellogs -a~ unless $fb;
			$cronjob = qq~05 01 * * * /usr/iports/bin/sudo /usr/sbin/dellogs -a~ if $fb;
		}
		elsif($input{'type'} eq 'delete_admin_email'){
			if(easytecc3::extern_mx()){
				my $socket = easytecc3::make_socket();
				logline("debug","nach make_socket() = $socket");
				print $socket "cron_delete_admin_email=\n";
			}
			
			if ($fb) {
				#my $servername = `grep -m1 han-solo.net /etc/hosts | awk '{print \$2}'`;
				my $servername = `sed 's/^.* // ; s/\$/.han-solo.net/' /etc/FQDN 2>/dev/null`;
				chomp $servername;
				my $dir = '/home/admin@' . $servername . '/mail/*';
				$cronjob = qq~05 01 * * * rm -rf $dir~;
				logline("debug","dir=$dir");
			}
			else{
				$cronjob = qq~05 01 * * * rm -rf /root/mail/*~;	
			}
		}

		push @{$cronfile->file_content}, qq~$cronjob\n~;
		my $got = $cronfile->write_file;
		return(error($got)) if $got;
		$result = qq~L__Der cronjob wurde erfolgreich angelegt__L~;
		$success_text = qq~L__Der cronjob wurde erfolgreich angelegt__L~;
	}

	$template->param('result' => $result);
	logline("debug","result = " . $result);
	
	#if($input{'type'} eq 'delete_all_logs'){
	#$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_logfiles&success_text=' . encode_base64url($success_text);
	#}
	#else{
	#$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=start&success_text=' . encode_base64url($success_text);
	#}
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_cronjobs&success_text=' . encode_base64url($success_text);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_delete_cronjob{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $result = $validation_result;
	my $deleted_cronjob = '';

	logline("debug","exec_delete_cronjob result:$result###");

	if($result){

	}
	else{
		my %handle_hash = %{easytecc3::return_file_handler_store()};
		my $cronfile = $handle_hash{'/home/web/cronfile'};
		my $count = '';
		my @new_cronfile = ();

		foreach($cronfile->file_content){
			$count++ unless /^#/ || /^$/;
			logline("debug","content cronfile $count:$_");
			s/\s+$//;

			#cronjob löschen
			if ($input{'cronjob'} == $count && ! /^#/ || /^$/){
				$deleted_cronjob = $_;
				logline("debug","cronjob löschen:$_");
				next;
			}
			# alles andere in zu schreibendes cronfile
			push @new_cronfile, $_;
		}

		$cronfile->file_content(\@new_cronfile);
		my $got = $cronfile->write_file;
		if ($got) {
			logline("error","cronfile->write_file = ".$got);
			return(error($got));
		}
		
		# change note key
		my $old_cron_key = $input{'cron_key'};
		my @old_keys = ('CRONJOB',$old_cron_key);
				
		my $note = note_from_hashfile(\@old_keys);
		if($note->{title}){
		
			note_to_hashfile(\@old_keys,'','');
			
		}
		
		
		my $cronjob_string_no_dev_null = encode('utf-8',$deleted_cronjob);
		$cronjob_string_no_dev_null =~ s/(1|2)*\s*>\s*\/dev\/null//;
		$cronjob_string_no_dev_null =~ s/(1|2)\s*>\s*&(1|2)//;
			
		$result = qq~cronjob $cronjob_string_no_dev_null L__wurde erfolgreich gelöscht__L~;
		$success_text = qq~cronjob $cronjob_string_no_dev_null L__wurde erfolgreich gelöscht__L~;
	}

	$template->param('result' => $result);
	logline("debug","result = " . $result);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_cronjobs&success_text=' . encode_base64url($success_text);
	return(\$template);
}

sub exec_change_cronjob{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $result = $validation_result;

	logline("debug","exec_delete_cronjob result:$result###");

	if($result){

	}
	else{
		my %handle_hash = %{easytecc3::return_file_handler_store()};
		my $cronfile = $handle_hash{'/home/web/cronfile'};
		my $count = '';
		my @new_cronfile = ();
		my $modified_cronjob = '';

		my %form_to_cron = %{easytecc3::form_to_cron()};

		foreach($cronfile->file_content){
			$count++ unless /^#/ || /^$/;
			logline("debug","content cronfile $count:$_");
			s/\s+$//;

			#cronjob modifizieren
			if ($input{'cronjob'} == $count && ! /^#/ || /^$/){
								
				$input{'min'} = $form_to_cron{$input{'min'}} unless $input{'min'} =~ /^\d+$/;
				$input{'std'} = $form_to_cron{$input{'std'}} unless $input{'std'} =~ /^\d+$/;
				$input{'mday'} = $form_to_cron{$input{'mday'}} unless $input{'mday'} =~ /^\d+$/;
				$input{'mon'} = $form_to_cron{$input{'mon'}} unless $input{'mon'} =~ /^\d+$/;
				$input{'wday'} = $form_to_cron{$input{'wday'}} unless $input{'wday'} =~ /^\d+$/;
				
				# change note key
				my $old_cron_key = $input{'cron_key'};
				my @old_keys = ('CRONJOB',$old_cron_key);
				
				# new key 
				my $cron_key = encode_base64url(encode('utf-8',$input{'command'}) . $input{'min'} . $input{'std'} . $input{'mday'} . $input{'mon'} . $input{'wday'});
				my @keys = ('CRONJOB',$cron_key);
												
				my $note = note_from_hashfile(\@old_keys);
				if($note->{title}){
					
					note_to_hashfile(\@keys,decode('utf-8',$note->{title}),decode('utf-8',$note->{text}));
					note_to_hashfile(\@old_keys,'','');
					
				}
				
				push @new_cronfile, qq~$input{'min'} $input{'std'} $input{'mday'} $input{'mon'} $input{'wday'} $input{'command'}\n~;
				logline("debug",qq~cronjob modifiziert:$input{'min'} $input{'std'} $input{'mday'} $input{'mon'} $input{'wday'} $input{'command'}~);
				$modified_cronjob = qq~$input{'min'} $input{'std'} $input{'mday'} $input{'mon'} $input{'wday'} $input{'command'}\n~;
				next;
			}
			# alles andere in zu schreibendes cronfile
			push @new_cronfile, $_;
		}

		$cronfile->file_content(\@new_cronfile);
		my $got = $cronfile->write_file;
		if ($got) {
			logline("error","cronfile->write_file = ".$got);
			return(error($got));
		}
		$result = qq~L__Der cronjob wurde erfolgreich modifiziert__L~;
		$success_text = qq~L__Der cronjob wurde erfolgreich modifiziert__L~;
	}

	$template->param('result' => $result);
	logline("debug","result = " . $result);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_cronjobs&success_text=' . encode_base64url($success_text);
	return(\$template);
}

sub exec_change_errordocs{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $result = $validation_result;

	logline("debug","exec_change_errordocs result:$result###");

	if($result){

	}
	else{
		if (! -e "$droot_prefix/error_docs" ) {
			`mkdir $droot_prefix/error_docs`;
		}
		
		logline("debug","Creating File Object $droot_prefix/error_docs/unauthorized.htm.");
		my $errordoc = file->new({file_name => "$droot_prefix/error_docs/unauthorized.htm"});
		my @new_errordoc = qq~$input{'unauthorized'}~;
		$errordoc->file_content(\@new_errordoc);
		my $got = $errordoc->write_file;
		if ($got) {
			logline("error","$droot_prefix/error_docs/unauthorized.htm->write_file = ".$got);
			return(error($got));
		}
		
		logline("debug","Creating File Object $droot_prefix/error_docs/forbidden.htm.");
		$errordoc = file->new({file_name => "$droot_prefix/error_docs/forbidden.htm"});
		@new_errordoc = qq~$input{'forbidden'}~;
		$errordoc->file_content(\@new_errordoc);
		$got = $errordoc->write_file;
		if ($got) {
			logline("error","$droot_prefix/error_docs/forbidden.htm->write_file = ".$got);
			return(error($got));
		}

		logline("debug","Creating File Object $droot_prefix/error_docs/notfound.htm.");
		$errordoc = file->new({file_name => "$droot_prefix/error_docs/notfound.htm"});
		@new_errordoc = qq~$input{'notfound'}~;
		$errordoc->file_content(\@new_errordoc);
		$got = $errordoc->write_file;
		if ($got) {
			logline("error","$droot_prefix/error_docs/notfound.htm->write_file = ".$got);
			return(error($got));
		}

		logline("debug","Creating File Object $droot_prefix/error_docs/ierror.htm.");
		$errordoc = file->new({file_name => "$droot_prefix/error_docs/ierror.htm"});
		@new_errordoc = qq~$input{'ierror'}~;
		$errordoc->file_content(\@new_errordoc);
		$got = $errordoc->write_file;
		if ($got) {
			logline("error","$droot_prefix/error_docs/ierror.htm->write_file = ".$got);
			return(error($got));
		}
	}

	#$template->param('result' => 'L__Die error-docs wurden erfolgreich geändert__L!');
	$success_text = 'L__Die error-docs wurden erfolgreich geändert__L!';
	
	undef %input;
	$input{'action'} = 'change_errordocs';
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	change_errordocs();
	#return(\$template);
}

sub exec_new_htaccess{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $result = $validation_result;

	logline("debug","exec_new_htaccess result: $result###");

	if($result){

	}
	else{
		my $directory = $input{'dir'};
		$directory = $droot_prefix . '/' . $directory;
#		if($fb){
#			$directory = $droot_prefix . '/' . $directory if $directory !~ /\/usr\/local\/www\/apache24\/noexec/;
#		} else {
#			$directory = $droot_prefix . '/' . $directory if $directory !~ /\/home\/httpd\/docs/;
#		}
		
		my $username = $input{'htaccessuser'};
		my $password = $input{'htaccesspass'};

		my ($fileperm, $fileuid, $filegid) = (stat($directory))[2,4,5];
		$fileperm = sprintf "%lo", ($fileperm & 07777);
		# evtl. ist da schon eine .htaccess mit rewrite-Regeln o..
		# Passwortschutz anhängen um vorhandene Inhalte nicht zu löschen
	
		
		my $new_file_content = qq~#####EASYTECC GENERATED, DO NOT EDIT#####
AuthUserFile $directory/.htpasswd
AuthGroupFile $directory/.htgroup
AuthName \"login\"
AuthType Basic

<Limit POST GET>
require group $username
</Limit>
#####END EASYTECC GENERATED#####~;

		if ( ! -f "$directory/.htaccess" || ! -f "$directory/.htgroup" || ! -f "$directory/.htpasswd" ){
			
			# open dir
			$got = `/usr/iports/bin/sudo /usr/sbin/chown.pl $fileuid:vuser $directory 2>&1`;
			return(error("L__Fehler beim Setzen des Besitzers für__L $directory: $got")) if $got;
						
			$got = `/usr/iports/bin/sudo /usr/sbin/chmod.pl 775 $directory 2>&1`;
			return(error("L__Fehler beim Setzen der Berechtigungen für__L $directory: $got")) if $got;
			
			
			if ( ! -f "$directory/.htaccess" ){
			
				system "touch","$directory/.htaccess";
			
			}
			if ( ! -f "$directory/.htgroup" ){
			
				system "touch","$directory/.htgroup";
			
			}
			if ( ! -f "$directory/.htpasswd" ){
			
				system "touch","$directory/.htpasswd";
			
			}
			
			# close dir
			$got = `/usr/iports/bin/sudo /usr/sbin/chown.pl $fileuid:$filegid $directory 2>&1`;
			return(error("L__Fehler beim Setzen des Besitzers für__L $directory: $got")) if $got;
			
			$got = `/usr/iports/bin/sudo /usr/sbin/chmod.pl $fileperm $directory 2>&1`;
			return(error("L__Fehler beim Setzen der Berechtigungen für__L $directory: $got")) if $got;
			
			
		}

		logline("debug","Creating File Object $directory/.htaccess.");
		my $file = file->new({file_name => "$directory/.htaccess", append => '1', file_content => [$new_file_content]});
		my $got = $file->write_file;
		if ($got) {
			logline("error","$directory/.htaccess->write_file = ".$got);
			return(error($got));
		}

		##jetzt auf den richtigen User und richtige chmod
		#system "/usr/bin/chown", "$fileuid"."."."$filegid", "$directory/.htaccess";
		#system "chmod", "664", "$directory/.htaccess";
		$got = `/usr/iports/bin/sudo /usr/sbin/chown.pl $fileuid:$filegid $directory/.htaccess 2>&1`;
		$got = `/usr/iports/bin/sudo /usr/sbin/chmod.pl 664 $directory/.htaccess 2>&1`;
		
		logline("debug","Creating File Object $directory/.htgroup.");
		$file = file->new({file_name => "$directory/.htgroup", file_content => ["$username: $username"]});
		my $got = $file->write_file;
		if ($got) {
			logline("error","$directory/.htgroup->write_file = ".$got);
			return(error($got));
		}

		##jetzt auf den richtigen User und richtige chmod
		#system "/usr/bin/chown", "$fileuid"."."."$filegid", "$directory/.htgroup";
		#system "chmod", "664", "$directory/.htgroup";
		$got = `/usr/iports/bin/sudo /usr/sbin/chown.pl $fileuid:$filegid $directory/.htgroup 2>&1`;
		$got = `/usr/iports/bin/sudo /usr/sbin/chmod.pl 664 $directory/.htgroup 2>&1`;

		my $content = '';
		if($fb){
			
			$content = `/usr/iports/bin/htpasswd -nb "$username" "$password" 2>/dev/null`;
			
		}
		# fallback
		if(!length($content)){
			
			$content = $username . ':' . easytecc3::encrypt_htpasswd($password);
			
		}
		
		logline("debug","Creating File Object $directory/.htpasswd.");
		$file = file->new({file_name => "$directory/.htpasswd", file_content => ["$content"]});
		my $got = $file->write_file;
		if ($got) {
			logline("error","$directory/.htpasswd->write_file = ".$got);
			return(error($got));
		}

		# jetzt auf den richtigen User und richtige chmod
		#system "/usr/bin/chown", "$fileuid"."."."$filegid", "$directory/.htpasswd";
		#system "chmod", "664", "$directory/.htpasswd";
		$got = `/usr/iports/bin/sudo /usr/sbin/chown.pl $fileuid:$filegid $directory/.htpasswd 2>&1`;
		$got = `/usr/iports/bin/sudo /usr/sbin/chmod.pl 664 $directory/.htpasswd 2>&1`;
	}

	$success_text = 'L__Die .htaccess-Einstellungen wurden erfolgreich angelegt__L!';
	
	my $dir_encoded = encode_base64url($input{'dir'});
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_filemanager&dir=' . $dir_encoded . '&success_text=' . encode_base64url($success_text);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_delete_htaccess{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $result = $validation_result;

	logline("debug","exec_delete_htaccess result:$result###");

	if($result){

	}
	else{
		my $directory = $droot_prefix . '/' . $input{'dir'};
		my $custom_htaccess = '';
		# user kann entweder durch Eingabefeld oder selectbox übermittelt werden
		my $username = $input{'htaccessuser'};

		# in .htaccess gucken, ob eigene Eintrge vorhanden und Passwortschutz ggf. nur ausschneiden:
		#    #####EASYTECC GENERATED, DO NOT EDIT#####
		#    AuthUserFile /home/httpd/docs/dav/.htpasswd
		#    AuthGroupFile /home/httpd/docs/dav/.htgroup
		#    AuthName "/home/httpd/docs/dav"
		#    AuthType Basic

		#    <Limit POST GET>
		#    require group rrr
		#    </Limit>
		#    #####END EASYTECC GENERATED#####

		open(HTACCESS,"$directory/.htaccess") || return(error("L__Fehler beim Lesen von__L $directory/.htaccess:", "$!"));
			my @htaccess = ();
			while(<HTACCESS>){
				push @htaccess, $_;
			}
		close(HTPASSWD);

		$custom_htaccess = '1' if $#htaccess > '10';

		if($input{'type'} eq 'delete_user'){
			open(HTPASSWD,"$directory/.htpasswd") || return(error("L__Fehler beim Lesen von__L $directory/.htpasswd:", "$!"));
			my @data = ();
			while(<HTPASSWD>){
				next if (/^$/);
				push @data, $_;
			}
			close(HTPASSWD);

			#wenn nur ein User vorhanden dann ganzen Passwortschutz weghauen
			if(scalar @data <= 1){
				
				my $got = `$easytecc_prefix/rm.pl "$directory/.htpasswd"` unless $fb;
				$got = `/usr/iports/bin/sudo /usr/sbin/rm.pl "$directory/.htpasswd"` if $fb;
				return(error("L__Fehler beim Entfernen von__L $htpasswd: $got")) if $got;
				
				#system "rm", "-f", "$directory/.htpasswd" || return(error("L__Fehler beim Entfernen von__L $htpasswd:", "$!"));
				
				$got = `$easytecc_prefix/rm.pl "$directory/.htgroup"` unless $fb;
				$got = `/usr/iports/bin/sudo /usr/sbin/rm.pl "$directory/.htgroup"` if $fb;
				return(error("L__Fehler beim Entfernen von__L $htgroup: $got")) if $got;
							
				#system "rm", "-f", "$directory/.htgroup" || return(error("L__Fehler beim Entfernen von__L $htgroup:", "$!"));

				if($custom_htaccess){
					my @new_file_content;
					logline("debug","Creating File Object $directory/.htaccess.");
					my $file = file->new({file_name => "$directory/.htaccess", file_content => \@new_file_content});

					my $remove = '';
					foreach(@htaccess){
						$remove = '1' if(/#####EASYTECC GENERATED/);
						push @new_file_content, $_ unless $remove;
						$remove = '' if(/#####END EASYTECC GENERATED/);
					}

					
					`/usr/iports/bin/sudo /usr/sbin/chmod.pl 666 $directory/.htaccess 2>&1`;
					my $got = $file->write_file;
					`/usr/iports/bin/sudo /usr/sbin/chmod.pl 664 $directory/.htaccess 2>&1`;
					if ($got) {
						logline("error","$directory/.htaccess->write_file = ".$got);
						return(error($got));
					}
				}
				else{
					
					my $got = `$easytecc_prefix/rm.pl "$directory/.htaccess"` unless $fb;
					$got = `/usr/iports/bin/sudo /usr/sbin/rm.pl "$directory/.htaccess"` if $fb;
					return(error("L__Fehler beim Entfernen von__L $htaccess: $got")) if $got;
					
					#system "rm", "-f", "$directory/.htaccess" || return(error("L__Fehler beim Entfernen von__L $htaccess:", "$!"));
					
				}
			}
			else{
				my @new_file_content;
				logline("debug","Creating File Object $directory/.htpasswd.");
				my $file = file->new({file_name => "$directory/.htpasswd", file_content => \@new_file_content});

				foreach(@data){
					next if (/^$username:/);
					push @new_file_content, $_;
				}

				`/usr/iports/bin/sudo /usr/sbin/chmod.pl 666 $directory/.htpasswd 2>&1`;	
				my $got = $file->write_file;
				`/usr/iports/bin/sudo /usr/sbin/chmod.pl 664 $directory/.htpasswd 2>&1`;	
				if ($got) {
					logline("error","$directory/.htpasswd->write_file = ".$got);
					return(error($got));
				}

				open(HTGROUP,"$directory/.htgroup") || return(error("L__Fehler beim Lesen von__L $directory/.htgroup:", "$!"));
					@data = <HTGROUP>;
				close(HTGROUP);

				if ($data[0] =~ /$username/) { $data[0] =~ s/$username //g || $data[0] =~ s/ $username//g; }
				logline("debug","Creating File Object $directory/.htgroup.");
				$file = file->new({file_name => "$directory/.htgroup", file_content => [$data[0]]});
				
				`/usr/iports/bin/sudo /usr/sbin/chmod.pl 666 $directory/.htgroup 2>&1`;	
				my $got = $file->write_file;
				`/usr/iports/bin/sudo /usr/sbin/chmod.pl 664 $directory/.htgroup 2>&1`;	
				if ($got) {
					logline("error","$directory/.htgroup->write_file = ".$got);
					return(error($got));
				}
			}
		}
		elsif($input{'type'} eq 'delete_all'){
			
			my $got = `$easytecc_prefix/rm.pl "$directory/.htpasswd"` unless $fb;
			$got = `/usr/iports/bin/sudo /usr/sbin/rm.pl "$directory/.htpasswd"` if $fb;
			return(error("L__Fehler beim Entfernen von__L $htpasswd: $got")) if $got;
			
			#system "rm", "-f", "$directory/.htpasswd" || return(error("L__Fehler beim Entfernen von__L $htpasswd:", "$!"));
			
			$got = `$easytecc_prefix/rm.pl "$directory/.htgroup"` unless $fb;
			$got = `/usr/iports/bin/sudo /usr/sbin/rm.pl "$directory/.htgroup"` if $fb;
			return(error("L__Fehler beim Entfernen von__L $htgroup: $got")) if $got;
						
			#system "rm", "-f", "$directory/.htgroup" || return(error("L__Fehler beim Entfernen von__L $htgroup:", "$!"));
							
			if($custom_htaccess){
				my @new_file_content;
				logline("debug","Creating File Object $directory/.htaccess.");
				my $file = file->new({file_name => "$directory/.htaccess", file_content => \@new_file_content});

				my $remove = '';
				foreach(@htaccess){
					$remove = '1' if(/#####EASYTECC GENERATED/);
					push @new_file_content, $_ unless $remove;
					$remove = '' if(/#####END EASYTECC GENERATED/);
				}

				`/usr/iports/bin/sudo /usr/sbin/chmod.pl 666 $directory/.htaccess 2>&1`;
				my $got = $file->write_file;
				`/usr/iports/bin/sudo /usr/sbin/chmod.pl 664 $directory/.htaccess 2>&1`;
				if ($got) {
					logline("error","$directory/.htaccess->write_file = ".$got);
					return(error($got));
				}
			}
			else{
				
				my $got = `$easytecc_prefix/rm.pl "$directory/.htaccess"` unless $fb;
				$got = `/usr/iports/bin/sudo /usr/sbin/rm.pl "$directory/.htaccess"` if $fb;
				return(error("L__Fehler beim Entfernen von__L $htaccess: $got")) if $got;
							
				#system "rm", "-f", "$directory/.htaccess" || return(error("L__Fehler beim Entfernen von__L $htaccess:", "$!"));
			}
		}
	}

	$success_text = 'L__Die .htaccess-Einstellungen wurden erfolgreich gelöscht__L!';
	
	my $dir_encoded = encode_base64url($input{'dir'});
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_filemanager&dir=' . $dir_encoded . '&success_text=' . encode_base64url($success_text);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
		
}

sub exec_change_htaccess{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $result = $validation_result;

	logline("debug","exec_change_htaccess result:$result###");

	if($result){

	}
	else{
		my $directory = $droot_prefix . '/' . $input{'dir'};

		if($input{'type'} eq 'newuser'){
			my $username = $input{'htaccessuser_newuser'};
			my $password = $input{'htaccesspass_newuser'};
			
			logline("debug","Creating File Object $directory/.htgroup");
			my $file = file->new({file_name => "$directory/.htgroup"});
			$file->read_file;
			#chomp ist gaaanz wichtig, da die user nebeneinander stehen. Der neue User landet am Ende der Zeile
			#ohne chomp würde er in neue Zeile eingefügt werden
			chomp ${$file->file_content}[0];
			${$file->file_content}[0] .= qq~ $username~;
			
			`/usr/iports/bin/sudo /usr/sbin/chmod.pl 666 $directory/.htgroup 2>&1`;
			my $got = $file->write_file;
			`/usr/iports/bin/sudo /usr/sbin/chmod.pl 664 $directory/.htgroup 2>&1`;
			if ($got) {
				logline("error","$directory/.htgroup->write_file = ".$got);
				return(error($got));
			}
			my $encrypted = easytecc3::encrypt_htpasswd($password);

			logline("debug","Creating File Object $directory/.htpasswd");
			$file = file->new({file_name => "$directory/.htpasswd", append => '1', file_content => [qq~$username:$encrypted~]});
			`/usr/iports/bin/sudo /usr/sbin/chmod.pl 666 $directory/.htpasswd 2>&1`;
			my $got = $file->write_file;
			`/usr/iports/bin/sudo /usr/sbin/chmod.pl 664 $directory/.htpasswd 2>&1`;
			if ($got) {
				logline("error","$directory/.htpasswd->write_file = ".$got);
				return(error($got));
			}
		}
		elsif($input{'type'} eq 'changepass'){
			my $username = $input{'user_select'};
			my $password = $input{'htaccesspass_changepass'};
			
			open(HTPASSWD,"$directory/.htpasswd") || return(error("L__Fehler beim Lesen von__L $directory/.htpasswd:", "$!"));
				my @data = <HTPASSWD>;
			close(HTPASSWD);

			my $encrypted = easytecc3::encrypt_htpasswd($password);

			for (my $i=0; $i<=$#data; $i++) { if ($data[$i] =~ /^$username:/) { $data[$i] = "$username:$encrypted"; } }
			logline("debug","Creating File Object $directory/.htpasswd");
			$file = file->new({file_name => "$directory/.htpasswd", file_content => \@data});
			`/usr/iports/bin/sudo /usr/sbin/chmod.pl 666 $directory/.htpasswd 2>&1`;
			my $got = $file->write_file;
			`/usr/iports/bin/sudo /usr/sbin/chmod.pl 664 $directory/.htpasswd 2>&1`;
			if ($got) {
				logline("error","$directory/.htpasswd->write_file = ".$got);
				return(error($got));
			}
		}
	}
	
	$success_text = 'L__Die .htaccess-Einstellungen wurden erfolgreich geändert__L!';

	my $dir_encoded = encode_base64url($input{'dir'});	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_filemanager&dir=' . $dir_encoded . '&success_text=' . encode_base64url($success_text);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_new_frontpage{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $result = $validation_result;

	logline("debug","exec_new_frontpage result:$result###");

	if($result){

	}
	else{
		# neues Frontpageweb anlegen
		if($input{'with_old_frontpage_form'}){
			# ggf. altes FP-Web löschen und dann erst neues anlegen
			if($input{'delete_old_frontpage'}){
				logline("debug","Creating File Object \$httpd_conf.");
				my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
				$httpd_conf->read_file;
				my %domains = %{$httpd_conf->file_parsed_hash()};
				my $document_root = $domains{$input{'domain_select'}}{'droot'};
				my $out = `$easytecc_prefix/delete_frontpage.pl $document_root`;
				return(error("L__Das Frontpage-Web konnte nicht gelöscht werden__L: $out")) if $out;
			}

			# fpinstall -u eee -p eee -d easytecc.at
			# das www. vom Domainnamen weg, weil FP sonst für www.www angelegt wird
			# $input{'domain_select'} ist immer Servername des vhosts in httpd.conf um eindeutige Zuordnung zu haben
			my $domain_ohne_www = $input{'domain_select'};
			$domain_ohne_www =~ s/^www\.//;
			my $got = `/usr/sbin/fpinstall -u $input{'frontpageuser'} -p $input{'password'} -d $domain_ohne_www`;
			if($got =~ /Install completed/){
				$result = qq~$domain_ohne_www: L__Das Frontpageweb wurde erfolgreich angelegt__L~;
			}
			else{
				my @got = split /\n/, $got;
				my $fp_error = '';
				foreach(@got){
					$fp_error .= $_ . '<br />';
				}
				return(error($fp_error));
			}
		}
		else{
			# erstmaliger Aufruf von exec_new_frontpage
			# erstmal gucken ob noch Reste von alter Installation, wenn ja dann wieder zu new_frontpage mit Option
			# die Reste zu löschen
			# aus httpd.conf das Document root ziehen und da gucken, ob was da
			logline("debug","Creating File Object \$httpd_conf.");
			my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
			$httpd_conf->read_file;
			my %domains = %{$httpd_conf->file_parsed_hash()};
			my $document_root = $domains{$input{'domain_select'}}{'droot'};

			logline("debug","exec_new_frontpage droot:$document_root");

			if(	-d "$document_root/_private/" ||
				-d "$document_root/_vti_bin/" ||
				-d "$document_root/_vti_cnf/" ||
				-d "$document_root/_vti_log/" ||
				-d "$document_root/_vti_pvt/" ||
				-d "$document_root/_vti_txt/" )
			{
				return(new_frontpage());
			}
			else{
				# neues Frontpageweb anlegen
				# fpinstall -u eee -p eee -d easytecc.at
				# das www. vom Domainnamen weg, weil FP sonst für www.www angelegt wird
				# $input{'domain_select'} ist immer Servername des vhosts in httpd.conf um eindeutige Zuordnung zu haben
				my $domain_ohne_www = $input{'domain_select'};
				$domain_ohne_www =~ s/^www\.//;
				my $got = `/usr/sbin/fpinstall -u $input{'frontpageuser'} -p $input{'password'} -d $domain_ohne_www`;
				if($got =~ /Install completed/){
					$result = qq~$domain_ohne_www: L__Das Frontpageweb wurde erfolgreich angelegt__L~;
				}
				else{
					my @got = split /\n/, $got;
					my $fp_error = '';
					foreach(@got){
						$fp_error .= $_ . '<br />';
					}
					return(error($fp_error));
				}
			}
		}
	}

	$template->param('result' => $result);
	logline("debug","result = " . $result);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_delete_frontpage{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $result = $validation_result;

	logline("debug","exec_new_frontpage result:$result###");

	if($result){

	}
	else{
		# fpuninstall -d easytecc.at
		# das www. vom Domainnamen weg
		# $input{'domain_select'} ist immer Servername des vhosts in httpd.conf um eindeutige Zuordnung zu haben
		my $domain_ohne_www = $input{'domain'};
		$domain_ohne_www =~ s/^www\.//;
		my $got = `/usr/sbin/fpuninstall -d $domain_ohne_www`;
		if($got =~ /Uninstall completed/){
			$result = qq~$domain_ohne_www: L__Das Frontpageweb wurde erfolgreich gelöscht__L~;
		}
		else{
			my @got = split /\n/, $got;
			my $fp_error = '';
			foreach(@got){
				$fp_error .= $_ . '<br />';
			}
			return(error($fp_error));
		}

		if($input{'delete_old_frontpage'}){
			logline("debug","exec_delete_frontpage altes web löschen");
			logline("debug","Creating File Object \$httpd_conf.");
			my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
			$httpd_conf->read_file;
			my %domains = %{$httpd_conf->file_parsed_hash()};
			my $document_root = $domains{$input{'domain'}}{'droot'};
			my $out = `$easytecc_prefix/delete_frontpage.pl $document_root`;
			return(error("L__Das Frontpage-Web konnte nicht gelöscht werden__L: $out")) if $out;
		}
	}

	$template->param('result' => $result);
	logline("debug","result = " . $result);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_delete_logfiles{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $logfile = $input{'logfile'};
	my $domain = $input{'domain'};

	# Log einzelner Domain löschen
	if($domain){
		`/usr/sbin/dellogs -d $domain` unless $fb;
		`/usr/iports/bin/sudo /usr/sbin/dellogs -d $domain` if $fb;
	}
	# Logs aller Domains löschen
	elsif($logfile eq 'alldomains'){
		logline("debug","Creating File Object \$httpd_conf.");
		my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
		$httpd_conf->read_file;
		my %domains = %{$httpd_conf->file_parsed_hash()};
		foreach(keys %domains){
			if($domains{$_}{'access_log'}){
				`cat /dev/null > $domains{$_}{'access_log'}`;
			}
			if($domains{$_}{'error_log'}){
				`cat /dev/null > $domains{$_}{'error_log'}`;
			}
		}
	}
	# alle Systemlogs löschen
	elsif($logfile eq 'allsystem'){
		`/usr/sbin/admlogs` unless $fb;
		`/usr/iports/bin/sudo /usr/sbin/dellogs -a` if $fb;
	}
	# alle Logs löschen
	elsif($logfile eq 'all'){
		`/usr/sbin/dellogs -a` unless $fb;
		`/usr/iports/bin/sudo /usr/sbin/dellogs -a` if $fb;
	}

	$result = 'L__Die Logs wurden gelöscht__L';
	$success_text = 'L__Die Logs wurden gelöscht__L';

	$template->param('result' => $result);
	logline("debug","result = " . $result);
	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_logfiles&success_text=' . encode_base64url($success_text);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_delete_mysqlbackup{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	#my $template = HTML::Template->new(filename => 'result.html');
	my $database = $input{'database'};
	my $backup = $input{'backup'};

	my $result = $validation_result;

	logline("debug","exec_delete_mysqlbackup result: $result###");

	if($result){
		#$template->param('result' => $result);
	}
	else{
		
		if ($fb) {
			`/usr/iports/bin/sudo /usr/sbin/rm.pl $mysqlbackup_dir/$database/$backup`;
			`/usr/iports/bin/sudo /usr/sbin/rm.pl $mysqlbackup_dir/$database/$backup.error` if ($input{'has_error'});
		}
		else{
			`rm -f $mysqlbackup_dir/$database/$backup`;
			`rm -f $mysqlbackup_dir/$database/$backup.error` if ($input{'has_error'});
		}
		
		$success_text = "$backup: L__Das Datenbankbackup wurde erfolgreich gelöscht__L";
	}

	my $html_tmp = $success_text;
	my $template = HTML::Template->new(scalarref => \$html_tmp);	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	#return(show_mysqlbackup_details());
	#$json_output{'ajax_html'} = 'success';
	$json_output{'success_message'} = '1';
	return(\$template);
}

sub exec_change_mysqlbackup{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $result = $validation_result;

	logline("debug","exec_change_mysqlbackup result:$result###");

	if($result){

	}
	# neue mysql-Backup-Konfigurationsdatei schreiben:
	# $database='ajaxfb';
	# $backup_days='5';
	# $email_backup='yes';
	# $admin_email_to='frank@krusator.de';
	# $admin_email_from='dbadmin@krusator.de';
	else{
		
		if ($input{'backup_days'} eq '0' || ! length($input{'backup_days'})) {
			return(exec_delete_mysql_auto_backup());
		}
		
		my @databases;

		if($session->param('user') eq 'admin' && $input{'all_databases'}){
							
			logline("debug","instant_mysqlbackup:1");				
							
			my ($dbh, $mysql_connect_error) = easytecc3::mysql_connect();
			if ($mysql_connect_error == '1'){
				return(add_mysql_password());
			}				
							
			my $sth   = $dbh->prepare('SHOW DATABASES');
			$sth->execute;
			
			logline("debug","instant_mysqlbackup:2");				
	
			while ( my @row = $sth->fetchrow_array ){ # alle rows auslesen
	
				foreach my $item (@row){
			
					next if $item eq 'information_schema';
					push(@databases, $item);
					
					logline("debug","instant_mysqlbackup:$item");
					
				}
			
			}
				
		} else {
					
			push(@databases, $input{'database'});
			
		}
		
		foreach $database(@databases){
			
		
			my $conf = qq~\$database='$database';
\$backup_days='$input{'backup_days'}';
\$email_backup='$input{'email_backup'}';
\$admin_email_from='$input{'admin_email_from'}';
\$admin_email_to='$input{'admin_email_to'}';\n~;
	
			logline("debug","Creating File Object /usr/local/etc/easytecc/mysqlbackup/$database.dbb");
			my $file = file->new({file_name => "/usr/local/etc/easytecc/mysqlbackup/$database.dbb", file_content => [qq~$conf~]});
			my $got = $file->write_file;
			if ($got) {
				logline("error","/usr/local/etc/easytecc/mysqlbackup/$database.dbb->write_file = ".$got);
				return(error($got));
			}
			#
			#unless(`grep dobackup.pl /home/web/cronfile`){
			#	logline("debug","Creating File Object \$cronfile.");
			#	my $cronfile = file->new({file_name => '/home/web/cronfile'});
			#	$cronfile->read_file;
			#	my $min =  int(rand('59'));
			#	my $std =  int(rand('1'));
			#	push @{$cronfile->file_content}, qq~$min $std * * * $easytecc_prefix/dobackup.pl -a 1>/dev/null 2>/dev/null\n~;
			#	my $got = $cronfile->write_file;
			#	if ($got) {
			#		logline("error","cronfile->write_file = ".$got);
			#		return(error($got));
			#	}
			#}
	
			add_dobackup_cron();
		
		}
			
		$result = 'L__Das automatische Backup wurde erfolgreich angelegt__L<br />' .
		qq~<a href="/cgi-bin/easytecc3/index.pl?action=show_mysqlbackup_details&database=$input{'database'}">L__Zurück zu Datenbankbackupdetails__L</a>~;
		
		$success_text = 'L__Das automatische Backup wurde erfolgreich angelegt__L';
	}

	#$template->param('result' => $result);
	logline("debug","result = " . $result);
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_dbbackup' . '&success_text=' . encode_base64url($success_text);
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub add_dobackup_cron{
	
	unless(`grep dobackup.pl /home/web/cronfile`){
			logline("debug","Creating File Object \$cronfile.");
			my $cronfile = file->new({file_name => '/home/web/cronfile'});
			$cronfile->read_file;
			my $min =  int(rand('59'));
			my $std =  int(rand('1'));
			push @{$cronfile->file_content}, qq~$min $std * * * $easytecc_prefix/dobackup.pl -a 1>/dev/null 2>/dev/null\n~;
			my $got = $cronfile->write_file;
			if ($got) {
				logline("error","cronfile->write_file = ".$got);
				return(error($got));
			}
		}
}

sub exec_new_mysqluser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	#my $template = HTML::Template->new(filename => 'result.html');
	my $result = $validation_result;

	logline("debug","exec_new_mysqluser result: $result###");

	if($result){

	}
	else{
		
		if($input{'db'}){
			$error = easytecc3::add_mysqldb(\%input);
			return(error("L__Konnte Datenbank nicht anlegen__L: $error")) if $error;
			$result .= "<br />L__Die Datenbank wurde erfolgreich angelegt__L";
			$success_text = "L__Die Datenbank wurde erfolgreich angelegt__L";
		}
		$error = easytecc3::add_mysqluser(\%input);
		return(error("L__Konnte mySQL-User nicht anlegen__L: $error")) if $error;
		$result .= '<br />L__Der mysqluser wurde erfolgreich angelegt__L';
		$success_text2 = 'L__Der mysqluser wurde erfolgreich angelegt__L';
	}
	#$template->param('result' => $result);
	logline("debug","result = " . $result);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	undef %input;
	$input{'active_tab'} = '2';
	show_dbbackup();
	#return(\$template);
}

sub exec_domainsearch{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'whois_result.html');

	my $result = $validation_result;

	logline("debug","exec_domainsearch result: $result###");

	if($result){

	}
	else{
		my $cgi = new CGI;
		my $ua = LWP::UserAgent->new();
		my $anf = HTTP::Request->new();
		my ($names,$i);
		my (@names) = $cgi->param;

		$anf->method('POST');
		$anf->uri('http://83.138.67.7/cgi-bin/library/iwhois/elookup_easytecc3.pl');

		foreach $names(@names){
			$anf->header($names[$i] => $cgi->param($names[$i]));
			$i++;
		}

		my $response = $ua->request($anf);

		if($response->is_success){
			$result = $response->content;
		}
		else{
			$result = 'L__Die Domainabfrage ist z.Z. nicht erreichbar__L';
		}
		$template->param('whois_result' => decode(utf8, $result));
	}
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub get_files {
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);

	my $dir = $input{'dir'};
	$dir =~ s#^$droot_prefix/?##;
		
	#if($dir eq $droot_prefix){
	#	$dir = '';
	#}
		
	my @allfiles = ();
	my @directories = ();
	my @files = ();
	my $allowed_primary = 1;
	my $allowed_expanded = 1;
	
	# gather allowed dirs
	my %allowed_dirs;
	my %allowed_dirs_expanded;
	if($session->param('user') ne 'admin'){
	
		my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
		$httpd_conf->read_file;
		my %domains = %{$httpd_conf->file_parsed_hash()};
		
		foreach my $domain (keys %domains){

			my $admins = $domains{$domain}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $session->param('user') . '#';
			
			logline("debug","admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				next;
			}
		
			$allowed_dirs{$domains{$domain}{'droot'}} = '1';
			
			logline("debug","allowed dir: $domains{$domain}{'droot'}");
			
		}
		
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};

		$allowed_dirs{$passwd{$session->param('user')}{'home'}} = '1';
		
		logline("debug","allowed dir: $passwd{$session->param('user')}{'home'}");
		
		
		foreach my $allowed_dir (keys %allowed_dirs){
		
			$allowed_dir =~ s/\/data\//\/noexec\//;
			
			if($allowed_dir =~ m#^$droot_prefix/?#){
				
				$allowed_dirs_expanded{$allowed_dir} = 1;
				
				$allowed_dir =~ s#^$droot_prefix/?##;
				my @subdirs = split(/\//,$allowed_dir);
				$allowed_dir = $droot_prefix;
				
				foreach my $subdir (@subdirs){
					$allowed_dir .= '/' . $subdir;
					$allowed_dirs_expanded{$allowed_dir} = 1;
				}
			
			}	
							
		}
		
		logline("debug","allowed dirs:" . Data::Dumper->Dump([\%allowed_dirs]));
		
		logline("debug","allowed dirs:" . Data::Dumper->Dump([\%allowed_dirs_expanded]));
		
				
		if(length($dir)){
			
		
			my $path = $droot_prefix . '/' . $dir;
			
			$allowed_primary = exists($allowed_dirs{$path});
			if(!$allowed_primary){
			
				foreach my $allowed_dir (keys %allowed_dirs){
				
					if($path =~ m#^$allowed_dir/.+#){
						$allowed_primary = 1;
						last;
					}
				}
								
			}
			
			$allowed_expanded = exists($allowed_dirs_expanded{$path}) || $allowed_primary;
			
		
		} else {
			
			$allowed_primary = 0;
			
		}
		
	} 
	
	my $chdir = $droot_prefix . '/' . $dir;
	
	#if($input{'dir'} !~ m#/snapshots/#){
	#	
	#	$chdir =  $droot_prefix . '/' . $dir;
	#	
	#} else {
	#	
	#	$chdir =  $dir;
	#
	#}
	
	
	if($allowed_expanded){
		opendir (DIR, $chdir) || dienice("opendir $chdir: $!");
		@allfiles = readdir(DIR);
		closedir (DIR);
	}
	
	foreach (@allfiles) {
		if(-d "$chdir/$_"){
			next if /^\.$/;
			logline("debug","directory=$_");
			
			if($session->param('user') ne 'admin' && $_ ne '..'){
				my $path = $droot_prefix;
				
				if(length($dir)){
					$path .= '/' . $dir;
				}
				
				$path .= '/' . $_;
								
				if(
					exists($allowed_dirs{$path}) ||
					exists($allowed_dirs_expanded{$path})
				){
					push(@directories, $_);
					logline("debug","path=$path dir=$dir\n");
				} else {
					foreach my $allowed_dir (keys %allowed_dirs){
				
						if($path =~ m#^$allowed_dir/.+#){
							push(@directories, $_);
							logline("debug","path=$path dir=$dir\n");
							last;
						}
					}
				}				
					
				
			} else {
			
				push(@directories, $_);
			
			}
			
		}
		else{
			logline("debug","file=$_");
			if($session->param('user') eq 'admin' || $allowed_primary){
				push(@files,$_);
			}
		}
	}

	@directories = sort { lc($a) cmp lc($b) } @directories;
	@files = sort { lc($a) cmp lc($b) } @files;

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\@directories, \@files, $allowed_primary);
}


sub add_mysql_password{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'add_mysql_password.html');

	# Entryserver hat admin als Hauptuser, den vorausgewählt zeigen
	if(defined easytecc3::is_ftp_limited()){
		$template->param('dbuser' => 'admin');
	}
	else{
		$template->param('dbuser' => 'root');
	}

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_add_mysql_password{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $dbuser = $input{'dbuser'};
	my $dbpass = $input{'dbpass'};
	logline("debug","Creating File Object /usr/local/etc/easytecc/.dbconf");
	my $file = file->new({file_name => '/usr/local/etc/easytecc/.dbconf', file_content => [qq~\$user=\"$dbuser\";\n\$password=\"$dbpass\";\n~]});
	my $got = $file->write_file;
	if ($got) {
		logline("error","/usr/local/etc/easytecc/.dbconf->write_file = ".$got);
		#second try, quick and dirty
		my $got2 = `$easytecc_prefix/chmod.pl 666 /usr/local/etc/easytecc/.dbconf` unless $fb;
		$got2 = `/usr/iports/bin/sudo /usr/sbin/chmod.pl 666 /usr/local/etc/easytecc/.dbconf` if $fb;
		$got = '';
		$got = $file->write_file;
		return(error($got)) if $got;
	}

	$template->param('result' => 'L__Der mySQL-User wurde erfolgreich gespeichert__L');
	$success_text = 'L__Der mySQL-User wurde erfolgreich gespeichert__L';

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(show_dbbackup());
	#return(\$template);
}

sub modify_dir{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	# Verzeichnis chown, chmod, löschen, umbenennen
	my $type = $input{'type'};
	my $dir = $input{'dir'};
	my $chdir = $droot_prefix . '/' . $dir;
	my $dir_without_path = $dir;
	$dir_without_path =~ s/^.*\///;
	my $template = '';

	unless(-d "$droot_prefix/$dir"){
		error("$dir: L__Das Verzeichnis existiert nicht__L");
	}
	# für Österreicher, Apple-User und Frauen:
	# Jimmy: tztztz, wer kommentiert sich denn hier so weit aus dem Fenster??? ;)
	elsif($dir =~ /^easytecc/){
		error('L__Am easyTECC-Tool sollten Sie keine Änderungen vornehmen__L');
	}

	# User für select-Box für chown und cms-fix auslesen
	logline("debug","Creating File Object \$passwd.");
	my $passwd = file->new({file_name => '/etc/passwd'});
	$passwd->read_file;
	my %passwd = %{$passwd->file_parsed_hash()};
	my %username_lookup = %{$passwd->lookup_hash()};
	my @user = ();
	my @groups = ();
	
	# gather allowed dirs
	my %allowed_dirs;
	if($session->param('user') ne 'admin'){
	
		my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
		$httpd_conf->read_file;
		my %domains = %{$httpd_conf->file_parsed_hash()};
		
		foreach my $domain (keys %domains){

			my $admins = $domains{$domain}{'admin_users'};
			$admins =~ s/[\s,]+/#/g;
			$admins = '#' . $admins . '#';
			$userregex = '#' . $session->param('user') . '#';
			
			logline("debug","admins:$admins\nuserregex:$userregex");
			
			if($admins !~ m/$userregex/i){
				next;
			}
		
			$allowed_dirs{$domains{$domain}{'droot'}} = '1';
		}
		
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};

		$allowed_dirs{$passwd{$session->param('user')}{'home'}} = '1';

	} 
	
	foreach my $user (sort keys %passwd){
		# chown nicht an POP-User ermöglichen
		next if $passwd{$user}{'gecos'} =~ / - POP/;
		
		if($session->param('user') ne 'admin'){
		
			my $allowed = 0;
			
			if($user eq 'web'){
			
				### Mario: Auf Wunsch von einem Kunden bei Matthias am Telefon, habe ich $allowed = 1; auf = 0; gesetzt, damit sich Enkunden nicht Ihrer Quota mit beliebigen FTP-Benutzern entziehen können. Man kann nun als Kunde eingeloggt nicht mehr die Dateien dem Benutzer web zuweisen. ###
				$allowed = 0;
			
			} else {
			
				my $home = $passwd{$user}{'home'};
				
				foreach my $dir (keys %allowed_dirs){
		
					if($home eq $dir || $home =~ m#^$dir/#){
			
						$allowed = 1;
				
					}
					
				}
		
			}
			
			if($allowed == 1){
			
				push(@user,$user);
				push(@groups, @{$passwd{$user}{'groups'}});
				
			}
		
		} else {
		
			push(@user,$user);
			push(@groups, @{$passwd{$user}{'groups'}});
			
		}
		
	}
		
	@groups = keys %{{ map { $_ => 1 } @groups }};
	
	### Mario: [04.05.2020] Seit einigen Wochen werden beim CMS-Fix Systemgruppen angezeigt.
	###			Diese werden mit den folgenden Zeilen entfernt. ###
	my @groups_temp = ();
	foreach ( @groups ) {
	
		my $tempgroup = $_;
		my $gid = `getent group $tempgroup | cut -d: -f3`;
		chomp ($gid);
		if ( $gid >= 1000 ) {
			push (@groups_temp, $tempgroup);
		}
	}
	@groups = @groups_temp;
	
	logline("debug","groups: @groups");

	if($type eq 'chmod'){
		$template = HTML::Template->new(filename => 'chmod_dir.html');
		
		my ($owner, $group, $fileperm) = (stat($chdir))[4,5,2];
		my $chmod = sprintf "%lo", ($fileperm & 07777);
		
		my $groupname = `/usr/bin/grep ':$group:' /etc/group | sed 's/:.*//'`;
		chomp($groupname);

		my $template_user_select = HTML::Template->new(filename => 'user_select_no_multiple.html');
		easytecc3::template_loop_e4(\%input,\$template_user_select, \@user, 'user_select', $username_lookup{$owner});
		$template->param('user_select' => $template_user_select->output);
		
		my $template_group_select = HTML::Template->new(filename => 'group_select_no_multiple.html');
		easytecc3::template_loop_e4(\%input,\$template_group_select, \@groups, 'group_select', $groupname);
		$template->param('group_select' => $template_group_select->output);
				
		$template->param('dir_chmod' => $chmod);
	}
	elsif($type eq 'cms_fix'){
		$template = HTML::Template->new(filename => 'cms_fix.html');
		my ($owner, $group, $fileperm) = (stat($chdir))[4,5,2];
		
		my $groupname = `/usr/bin/grep ':$group:' /etc/group | sed 's/:.*//'`;
		chomp($groupname);
		
		my $template_user_select = HTML::Template->new(filename => 'user_select_no_multiple.html');
		easytecc3::template_loop_e4(\%input,\$template_user_select, \@user, 'user_select', $username_lookup{$owner});
		$template->param('user_select' => $template_user_select->output);
		
		my $template_group_select = HTML::Template->new(filename => 'group_select_no_multiple.html');
		easytecc3::template_loop_e4(\%input,\$template_group_select, \@groups, 'group_select', $groupname);
		$template->param('group_select' => $template_group_select->output);
	}
	elsif($type eq 'mv'){
		$template = HTML::Template->new(filename => 'mv_dir.html');
	}
	elsif($type eq 'cp'){
		$template = HTML::Template->new(filename => 'cp_dir.html');
	}
	elsif($type eq 'rm'){
		$template = HTML::Template->new(filename => 'rm_dir.html') ;
	}

	$template->param('chdir' => $chdir);
	
	$template->param('dir' => $dir);
	my $dir_encoded = encode_base64url($dir);
	$template->param('dir_encoded' => $dir_encoded);
		
	$template->param('dir_without_path' => $dir_without_path);
	#falls formular mit ungültigen Pfadangaben abgeschickt, diese wieder einfügen
	$template->param('dir_without_path' => $input{'dir_cp'}) if exists $input{'dir_cp'};
	$template->param('dir_without_path' => $input{'dir_mv'}) if exists $input{'dir_mv'};

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_modify_dir{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $type = $input{'type'};
	# $dir wird relativ von /home/httpd/docs übergeben
	my $dir = $droot_prefix . '/' . $input{'dir'};
	my $parent_dir = $dir;
	$parent_dir =~ s/\/[^\/]{1,}$//;
	my $dir_mv = "$parent_dir/" .  $input{'dir_mv'};
	my $dir_cp = "$parent_dir/" . $input{'dir_cp'};

	my $result = $validation_result;

	logline("debug","exec_modify_dir result:$result###");

	if($result){

	}
	else{
		# wenn neuer Dateiname bereits vorhanden nachfragen ob überschrieben werden soll
		if($type eq 'cp' && -d "$dir_cp" && ! $input{'overwrite'}){
			$template = HTML::Template->new(filename => 'overwrite_dir.html');
			$template->param('dir' => $input{'dir'});
			my $dir_encoded = encode_base64url($input{'dir'});
			$template->param('dir_encoded' => $dir_encoded);
			# alles im arsch hier
			$template->param('dir_cp' => $input{'dir_cp'});
			$template->param('dir_mv' => $input{'dir_cp'});
			return(\$template);
		}

		# Änderungen durchführen: mv, rm, edit
		if($type eq 'mv'){
			my $got = `$easytecc_prefix/mv.pl $dir $dir_mv d` unless $fb;
			$got = `/usr/iports/bin/sudo /usr/sbin/mv.pl $dir $dir_mv d` if $fb;
			return(error("L__Fehler beim Umbenennen von__L $dir L__zu__L $dir_mv: $got")) if $got;
			$success_text = "L__Das Verzeichnis wurde erfolgreich umbenannt__L";
		}
		if($type eq 'cp'){
			my $got = `$easytecc_prefix/cp.pl $dir $dir_cp` unless $fb;
			$got = `/usr/iports/bin/sudo /usr/sbin/cp.pl $dir $dir_cp` if $fb;
			return(error("L__Fehler beim Kopieren von__L $dir L__zu__L $dir_cp: $got")) if $got;
			$success_text = "L__Das Verzeichnis wurde erfolgreich kopiert__L";
		}
		elsif($type eq 'rm'){
			my $got = `$easytecc_prefix/rm.pl $dir d` unless $fb;
			$got = `/usr/iports/bin/sudo /usr/sbin/rm.pl $dir d` if $fb;
			return(error("L__Fehler beim Löschen von__L $dir: $got")) if $got;
			$success_text = "L__Das Verzeichnis wurde erfolgreich gelöscht__L";
		}
		elsif($type eq 'chmod'){
			logline("debug",qq~newowner:$input{'user_select'} newchmod:$input{'dir_chmod'}~);
			my $got = `$easytecc_prefix/chown.pl $input{'user_select'}:$input{'group_select'} $dir` unless $fb;
			$got = `/usr/iports/bin/sudo /usr/sbin/chown.pl $input{'user_select'}:$input{'group_select'} $dir` if $fb;
			return(error("L__Fehler bei CHOWN von__L $dir: $got")) if $got;
			
			my $got = `$easytecc_prefix/chmod.pl $input{'dir_chmod'} $dir` unless $fb;
			$got = `/usr/iports/bin/sudo /usr/sbin/chmod.pl $input{'dir_chmod'} $dir` if $fb;
			return(error("L__Fehler bei CHMOD von__L $dir: $got")) if $got;
			
			$success_text = "L__Das Verzeichnis wurde erfolgreich geändert.__L";
		}
		elsif($type eq 'cms_fix'){
			logline("debug",qq~cms_fix:$input{'user_select'}~);

			my $got = `$easytecc_prefix/cms_fix.pl $input{'user_select'}:$input{'group_select'} $dir` unless $fb;
			$got = `/usr/iports/bin/sudo /usr/sbin/cms_fix.pl $input{'user_select'}:$input{'group_select'} $dir` if $fb;
			return(error("L__Fehler bei cms_fix von__L $dir: $got")) if $got;

			$success_text = 'L__Das Verzeichnis wurde erfolgreich geändert__L';
		}
	}

	#    mv

	#  rm

	#    cms fix:
	#    find melanie/ -not -user admin|xargs du -sc
	#7256    melanie
	#4       melanie/stats/.htaccess
	#.
	#.
	#.
	#12      melanie/logo.gif
	#7616    insgesamt

	#7616 - 7256 = Quotabedarf + ~256kB für Verzeichnis-Inodes
	my $dir_back = $input{'dir'};
	$dir_back = '' if($dir_back !~ /\//);
	$dir_back =~ s/\/[^\/]{0,100}$// if $dir_back;
	
	
	
	#$result = $result . qq~<br /><br /><a href="/cgi-bin/easytecc3/index.pl?action=show_filemanager&amp;dir=~ . $dir_back . qq~">L__Zurück zum Filemanager__L</a>~;
	#$template->param('result' => $result);
	#logline("debug","result = " . $result);

	my $dir_encoded = encode_base64url($dir_back);	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_filemanager&amp;dir=' . $dir_encoded . '&success_text=' . encode_base64url($success_text);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub modify_file{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $type = $input{'type'};
	my $dir = $input{'dir'};
	my $chdir = '';
	# wenn kein $dir, dann kein /, weil sonst bei full_file 2 slashes da wären
	$chdir = $droot_prefix . '/' . $dir if $dir;
	$chdir = $droot_prefix unless $dir;
	my $file = $input{'file'};
	my $template = '';
	
	logline("debug","chdir=$chdir\ndir=$dir\nfile=$file");

	if($type eq 'edit' && $file eq '.user.ini' &&  !-e "$droot_prefix/$dir/$file"){
	
		`touch $droot_prefix/$dir/$file`;
						
		if(!-e "$droot_prefix/$dir/$file"){
			
			`/usr/iports/bin/sudo /usr/sbin/chmod.pl 777 $droot_prefix/$dir`;
			`touch $droot_prefix/$dir/$file`;
			`/usr/iports/bin/sudo /usr/sbin/chmod.pl 755 $droot_prefix/$dir`;
			
		}
		
		if(!-e "$droot_prefix/$dir/$file"){
			
			return(modal_error('L__Die Datei konnte nicht angelegt werden.__L'));
			
		} else {
		
			`/usr/iports/bin/sudo /usr/sbin/chmod.pl 644 $droot_prefix/$dir/$file`;	
			my($fileuid, $filegid) = (stat("$droot_prefix/$dir"))[4,5];
			`/usr/iports/bin/sudo /usr/sbin/chown.pl $fileuid:$filegid $droot_prefix/$dir/$file 2>&1`;
			
		}
		
	}
	
	unless(-e "$droot_prefix/$dir/$file"){
		return(modal_error('L__Die Datei existiert nicht__L'));
	}
	# für Österrreicher, Apple-User und Frauen:
	elsif($dir =~ /^easytecc/){
		return(modal_error('L__Am easyTECC-Tool sollten Sie keine Änderungen vornehmen__L'));
	}

	if($type eq 'chmod'){
		$template = HTML::Template->new(filename => 'chmod_file.html');
		# User für select-Box für chown auslesen
		logline("debug","Creating File Object \$passwd.");
		my $passwd = file->new({file_name => '/etc/passwd'});
		$passwd->read_file;
		my %passwd = %{$passwd->file_parsed_hash()};
		my %username_lookup = %{$passwd->lookup_hash()};
		
		my @user = ();
		my @groups = ();
		
		# gather allowed dirs
		my %allowed_dirs;
		if($session->param('user') ne 'admin'){
		
			my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
			$httpd_conf->read_file;
			my %domains = %{$httpd_conf->file_parsed_hash()};
			
			foreach my $domain (keys %domains){
	
				my $admins = $domains{$domain}{'admin_users'};
				$admins =~ s/[\s,]+/#/g;
				$admins = '#' . $admins . '#';
				$userregex = '#' . $session->param('user') . '#';
				
				logline("debug","admins:$admins\nuserregex:$userregex");
				
				if($admins !~ m/$userregex/i){
					next;
				}
			
				$allowed_dirs{$domains{$domain}{'droot'}} = '1';
			}
			
			my $passwd = file->new({file_name => '/etc/passwd'});
			$passwd->read_file;
			my %passwd = %{$passwd->file_parsed_hash()};
	
			$allowed_dirs{$passwd{$session->param('user')}{'home'}} = '1';
	
		} 
		
		foreach my $user(sort keys %passwd){
			# chown nicht an POP-User ermöglichen
			next if $passwd{$user}{'gecos'} =~ / - POP/;
			
			if($session->param('user') ne 'admin'){
			
				my $allowed = 0;
				
				if($user eq 'web'){
				
					### Mario: $allowed = 0; gesetzt, damit eingeloggte Kunden nicht mehr die Möglichkeit haben, die Quota zu umgehen, indem Sie Dateien dem Benutzer web zuordnen. ###
					$allowed = 0;
				
				} else {
				
					my $home = $passwd{$user}{'home'};
					
					foreach my $dir (keys %allowed_dirs){
			
						if($home eq $dir || $home =~ m#^$dir/#){
				
							$allowed = 1;
					
						}
						
					}
			
				}
				
				if($allowed == 1){
				
					push(@user,$user);
					push(@groups, @{$passwd{$user}{'groups'}});
					
				}
			
			} else {
			
				push(@user,$user);
				push(@groups, @{$passwd{$user}{'groups'}});
				
			}
			
		}
			
		@groups = keys %{{ map { $_ => 1 } @groups }};
		
		
		my ($owner, $group, $fileperm) = (stat("$chdir/$file"))[4,5,2];
		my $chmod = sprintf "%lo", ($fileperm & 07777);
		
		my $groupname = `/usr/bin/grep ':$group:' /etc/group | sed 's/:.*//'`;
		chomp($groupname);
				
		logline("debug","owner=$owner\nchmod=$chmod");
		
#		foreach my $user(sort keys %passwd){
#			# chown nicht an POP-User ermöglichen
#			next if $passwd{$user}{'gecos'} =~ / - POP/;
#			push(@user,$user);
#		}

		my $template_user_select = HTML::Template->new(filename => 'user_select_no_multiple.html');
		easytecc3::template_loop_e4(\%input,\$template_user_select, \@user, 'user_select', $username_lookup{$owner});
		$template->param('user_select' => $template_user_select->output);
		
		my $template_group_select = HTML::Template->new(filename => 'group_select_no_multiple.html');
		easytecc3::template_loop_e4(\%input,\$template_group_select, \@groups, 'group_select', $groupname);
		$template->param('group_select' => $template_group_select->output);
				
		$template->param('file_chmod' => $chmod);
		$template->param('old_owner' => $username_lookup{$owner});
	}
	elsif($type eq 'mv'){
		$template = HTML::Template->new(filename => 'mv_file.html');
	}
	elsif($type eq 'cp'){
		$template = HTML::Template->new(filename => 'cp_file.html');
	}
	elsif($type eq 'rm'){
		$template = HTML::Template->new(filename => 'rm_file.html') ;
	}
	elsif($type eq 'edit'){
		$template = HTML::Template->new(filename => 'edit_file.html') ;
		if(-s "$chdir/$file" && -B "$chdir/$file"){
			logline("warning","bin $chdir/$file");
			return(modal_error('L__Binärdateien können nicht editiert werden__L.'));
			
		}

		my $file_content = `cat $chdir/$file`;
		my $decoder = Encode::Guess->guess($file_content, qw/ascii utf8 latin1/);
		# die $decoder unless ref($decoder);
		my $utf8 = $file_content;

		if(ref($decoder) && $decoder->name =~ /utf8/){
			#nix, ist schon utf8
		}
		else{
			$utf8 = $decoder->decode($file_content) if ref($decoder);
		}

		logline("debug","decoder = " . $decoder->name) if $debug && ref($decoder);

		$utf8 =~ s/&/\&amp;/g;
		$utf8 =~ s/\</\&lt;/g;
		$utf8 =~ s/\>/\&gt;/g;
		$template->param('file_content' => $utf8);
	}

	$template->param('chdir' => $chdir);
	$template->param('dir' => $dir);
	my $dir_encoded = encode_base64url($dir);
	$template->param('dir_encoded' => $dir_encoded);
	$template->param('file' => $file);
	my $file_encoded = encode_base64url($file);
	$template->param('file_encoded' => $file_encoded);
	$template->param('file_mv' => $file);
	$template->param('file_cp' => $file);
	$template->param('full_file' => $chdir . '/'. $file);
	my $full_file_encoded = encode_base64url($chdir . '/'. $file);
	$template->param('full_file_encoded' => $full_file_encoded);
		
	$template->param('encoding' => $decoder->name) if ref($decoder);
	#falls formular mit ungültigen Pfadangaben abgeschickt, diese wieder einfügen
	$template->param('file_cp' => $input{'file_cp'}) if exists $input{'file_cp'};
	$template->param('file_mv' => $input{'file_mv'}) if exists $input{'file_mv'};
		
	if($input{'parent'}){
		$template->param('parent' => $input{'parent'});
	}

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_modify_file{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $type = $input{'type'};
	my $file = $input{'file'};
	my $dir = $droot_prefix;
	$dir .= '/' . $input{'dir'} if $input{'dir'};
	my $fullfile = $input{'full_file'};
	if(!$fullfile){
		$fullfile = $dir ."/" . $file;
	}
	
	my $file_mv = $input{'file_mv'};
	my $file_cp = $input{'file_cp'};
	# $dir wird relativ von /home/httpd/docs übergeben

	my $result = $validation_result;

	logline("debug","exec_modify_file result:$result###");

	if($result){

	}
	else{
		# wenn neuer Dateiname bereits vorhanden nachfragen ob überschrieben werden soll
		if($type eq 'mv' && -f "$dir/$file_mv" && ! $input{'overwrite'}){
			$template = HTML::Template->new(filename => 'overwrite_file_mv.html');
			$template->param('file' => $file);
			my $file_encoded = encode_base64url($file);
			$template->param('file_encoded' => $file_encoded);
			$template->param('file_mv' => $file_mv);
			$template->param('dir' => $input{'dir'});
			my $dir_encoded = encode_base64url($input{'dir'});
			$template->param('dir_encoded' => $dir_encoded);
			return(\$template);
		}
		elsif($type eq 'cp' && -f "$dir/$file_cp" && ! $input{'overwrite'}){
			$template = HTML::Template->new(filename => 'overwrite_file_cp.html');
			$template->param('file' => $file);
			my $file_encoded = encode_base64url($file);
			$template->param('file_encoded' => $file_encoded);
			$template->param('file_cp' => $file_cp);
			$template->param('dir' => $input{'dir'});
			my $dir_encoded = encode_base64url($input{'dir'});
			$template->param('dir_encoded' => $dir_encoded);
			return(\$template);
		}

		# Änderungen durchführen: mv, rm, edit
		if($type eq 'mv'){
			my $got = `$easytecc_prefix/mv.pl $dir/$file $dir/$file_mv` unless $fb;
			$got = `/usr/iports/bin/sudo /usr/sbin/mv.pl $dir/$file $dir/$file_mv` if $fb;
			return(error("L__Fehler beim Umbenennen von__L $dir/$file zu $dir/$file_mv: $got")) if $got;
			$success_text = 'L__Die Datei wurde erfolgreich umbenannt__L';
		}
		if($type eq 'cp'){
			my $got = `$easytecc_prefix/cp.pl $dir/$file $dir/$file_cp` unless $fb;
			$got = `/usr/iports/bin/sudo /usr/sbin/cp.pl $dir/$file $dir/$file_cp` if $fb;
			return(error("L__Fehler beim Kopieren von__L $dir/$file zu $dir/$file_cp: $got")) if $got;
			$success_text = 'L__Die Datei wurde erfolgreich kopiert__L';
		}
		elsif($type eq 'rm'){
			my $got = `$easytecc_prefix/rm.pl $fullfile` unless $fb;
			$got = `/usr/iports/bin/sudo /usr/sbin/rm.pl $fullfile` if $fb;
			return(error("L__Fehler beim Löschen von__L $fullfile: $got")) if $got;

			$success_text = 'L__Die Datei wurde erfolgreich gelöscht__L';
		}
		elsif($type eq 'edit'){
			my $file_content = $input{'file_content'};
			my $encoding = $input{'encoding'};
			# etwas herumcodieren und dann speichern
			# Content kommt als utf8, wenn vorher ascii oder latin1, dann umkodieren

			$file_content =~ s/\&amp;/&/g;
			$file_content =~ s/\&lt;/\</g;
			$file_content =~ s/\&gt;/\>/g;

			$file_content = encode("ascii", $file_content) if ($encoding eq 'ascii');
			$file_content = encode("iso-8859-1", $file_content) if ($encoding eq 'latin1');
			
			logline("debug","Creating File Object $fullfile");
			my $file = file->new({file_name => "$fullfile", file_content => [qq~$file_content\n~]});
			my $got = $file->write_file;
			if($got){
								
				`/usr/iports/bin/sudo /usr/sbin/chown.pl admin:vuser $fullfile 2>&1`;
				
				my $got = $file->write_file;
				
				my($fileuid, $filegid) = (stat("$dir"))[4,5];
				`/usr/iports/bin/sudo /usr/sbin/chown.pl $fileuid:$filegid $fullfile 2>&1`;
				
				if ($got) {
					logline("error","$fullfile->write_file = ".$got);
					return(error($got));
				}
				
			}
			
			$success_text = 'L__Die Datei wurde erfolgreich geändert__L';
		}
		elsif($type eq 'chmod'){
			logline("debug",qq~newowner:$input{'user_select'} newchmod:$input{'file_chmod'}~);
			#if($input{'old_owner'} ne  $input{'user_select'}){
				my $got = `$easytecc_prefix/chown.pl $input{'user_select'}:$input{'group_select'} $fullfile` unless $fb;
				$got = `/usr/iports/bin/sudo /usr/sbin/chown.pl $input{'user_select'}:$input{'group_select'} $fullfile` if $fb;
				return(error("L__Fehler bei CHOWN von__L $fullfile: $got")) if $got;
			#}
			#if($input{'old_chmod'} !=  $input{'file_chmod'}){
				my $got = `$easytecc_prefix/chmod.pl $input{'file_chmod'} $fullfile` unless $fb;
				$got = `/usr/iports/bin/sudo /usr/sbin/chmod.pl $input{'file_chmod'} $fullfile` if $fb;
				return(error("L__Fehler bei CHMOD von__L $fullfile: $got")) if $got;
			#}
			$success_text = 'L__Die Datei wurde erfolgreich geändert__L';
		}
	}

	my $dir_encoded = encode_base64url($input{'dir'});
	
	if(!$input{'parent'}){
		$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_filemanager&amp;dir=' . $dir_encoded . '&success_text=' . encode_base64url($success_text);
	}
	
	#$result = $result . qq~<br /><br /><a href="/cgi-bin/easytecc3/index.pl?action=show_filemanager&amp;dir=~ . $input{'dir'} . qq~">L__Zurück zum Filemanager__L</a>~;
	#$template->param('result' => $result);
	logline("debug","result = " . $result);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub download_file{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $dir = $input{'dir'};
	my $file = $input{'file'};

	logline("debug","download file [$input{'type'}]: ".$dir."/".$file);

	if(exists $input{'type'} && $input{'type'} eq 'logfile'){
		binmode STDOUT;
		if($file eq 'Messages'){
			open (IF, "/var/log/messages") || dienice("open /var/log/messages: $!");
			$file = 'messages';
		}
		elsif($file eq 'Maillogs'){
			open (IF, "/var/log/maillog") || dienice("open /var/log/maillog: $!");
			$file = 'maillog';
		}
		else{
			open (IF, "/home/web/log/$file") || dienice("open /home/web/log/$file: $!");
		}
		print "Content-Type: application/octet-stream\n";
		print "Content-Disposition: attachment;filename=\"$file.txt\"\n\n";
		print while(<IF>);
		close IF;
	}
	elsif(-e "$droot_prefix/$dir/$file"){
		binmode STDOUT;
		open (IF, "$droot_prefix/$dir/$file") || dienice("open $droot_prefix/$dir/$file: $!");
		print "Content-Type: application/octet-stream\n";
		print "Content-Disposition: attachment;filename=\"$file\"\n\n";
		print while(<IF>);
		close IF;
	}
	logline("debug","<<< Exiting ".(caller(0))[3]."().");
	exit(0);
}

sub new_sendmail_cw{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	
	#included by show_email() second tab
	my $template = shift;
	
	my @sendmail_cw = ();

	logline("debug","Creating File Object \$sendmail_cw.");
	my $sendmail_cw = file->new({file_name => '/etc/mail/sendmail.cw'});
	$sendmail_cw->read_file;
	my %sendmail_cw = %{$sendmail_cw->file_parsed_hash()};

	foreach(keys %sendmail_cw){
		delete ($sendmail_cw{$_}) if /\.han-solo\.net/;
	}

	my @sendmail_cw_entries = sort keys %sendmail_cw;
	
	#dkim
	my $dkim_available = 0;
	if(-f '/etc/opendkim.conf'){
		
		$dkim_available = 1;
		
	}
	
	my $table_data = {};
	for(my $count = 0; $count <= $#sendmail_cw_entries; $count++){
		push @sendmail_cw, qq~<input  type="checkbox" name="delete$count" id="delete$domaincount" value="$sendmail_cw_entries[$count]" />~ . encode('utf-8', domain_to_unicode($sendmail_cw_entries[$count]));
		$table_data->{$sendmail_cw_entries[$count]}{'idn_domain'} = encode('utf-8', domain_to_unicode($sendmail_cw_entries[$count]));
		$table_data->{$sendmail_cw_entries[$count]}{'domain'} = $sendmail_cw_entries[$count];
		$table_data->{$sendmail_cw_entries[$count]}{'count'} = $count+1;
		
		#dkim
		if( -e "/etc/dkim/keys/$sendmail_cw_entries[$count]"){
			$table_data->{$sendmail_cw_entries[$count]}{'dkim'} = '1';
		}
		
		$table_data->{$sendmail_cw_entries[$count]}{'dkim_available'} = $dkim_available;
	}
	
	my $table_data_sorted = {};
	foreach $domain (keys %{$table_data}){
        $table_data_sorted->{$table_data->{$domain}{'idn_domain'}} = $table_data->{$domain};
    }	
	easytecc3::table_e4($template, $table_data_sorted, 'table_tr_sendmail_cw_domains_template.html');
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_new_sendmail_cw{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $result = $validation_result;

	logline("debug","exec_new_sendmail_cw result:$result###");

	if($result){

	}
	else{
		my %handle_hash = %{easytecc3::return_file_handler_store()};
		my $sendmail_cw = $handle_hash{'/etc/mail/sendmail.cw'};

		push @{$sendmail_cw->file_content} , $input{'domain'};
		my $got = $sendmail_cw->write_file;
		if ($got) {
			logline("error","sendmail_cw->write_file = ".$got);
			return(error($got));
		}
		$result .= encode('utf-8', domain_to_unicode($input{'domain'})) . ": L__Erfolgreich in Mailkonfiguration eingetragen__L";
		$success_text = $result;
		#$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_email&active_tab=2&success_text=' . encode_base64url($success_text);
		
	}
	$template->param('result' => $result);
	logline("debug","result = " . $result);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
		
	#direct call to show_email with active tab 2
	undef %input;
	$input{'active_tab'} = '2';
	$action = 'show_email';
	return(show_email());
	
	#return(\$template);
}

sub exec_new_quotamessage{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $result = $validation_result;

	logline("debug","exec_new_quotamessage result:$result###");

	if($result){

		#todo:validieren!
	
	}
	else{
		
		my $file_content = "From: " . $input{'quotasender'} . "\nSubject: " . $input{'quotasubject'} . "\n\n" . $input{'quotamessage'};
		$file_content = encode('utf8', $file_content);
		
		my $file = file->new({file_name => '/etc/mail/quotamessage', file_content => [qq~$file_content\n~]});
		
		my $got = $file->write_file;
		if ($got) {
			logline("error","/etc/mail/quotamessage->write_file = ".$got);
			return(error($got));
		}

		$file = file->new({file_name => '/etc/mail/quotafrom', file_content => [qq~$input{'quotasender'}~]});
		$got = $file->write_file;
		if ($got) {
			logline("error","/etc/mail/quotafrom->write_file = ".$got);
			return(error($got));
		}
				
		$result = 'L__Die Emailquota-Warnung wurde erfolgreich geändert.__L';
		$success_text = $result;
		#$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_email&active_tab=3&success_text=' . encode_base64url($success_text);
		
	}
	$template->param('result' => $result);
	logline("debug","result = " . $result);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
		
	#direct call to show_email with active tab 3
	undef %input;
	$input{'active_tab'} = '3';
	$action = 'show_email';
	return(show_email());
		
	#return(\$template);
}

sub exec_new_mailserver_cert{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');

	my $result = $validation_result;

	logline("debug","exec_new_mailserver_cert result:$result###");

	if($result){

		#todo:validieren!
	
	}
	else{
		
		my $mailserver_cert = $input{'mailserver_cert_select'};
			
		$result = `/usr/iports/bin/sudo /usr/sbin/setmailcert $mailserver_cert 2>&1 1>/dev/null`;
		if(length($result)){
		
			#$result = encode_entities($result);
			return(error("L__Beim Setzen des Mailserver-Zertifikates ist ein Fehler aufgetreten:__L <pre>$result</pre>"));
				   
		}
							
		$result = 'L__Das Mailserver-Zertifikat wurde erfolgreich geändert.__L';
		$success_text = $result;
		#$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_email&active_tab=3&success_text=' . encode_base64url($success_text);
		
	}
	$template->param('result' => $result);
	logline("debug","result = " . $result);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
		
	#direct call to show_email with active tab 3
	undef %input;
	$input{'active_tab'} = '4';
	$action = 'show_email';
	return(show_email());
		
	#return(\$template);
}

sub add_ssl_vhost{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'add_ssl_vhost.html');
		
	my $domain = $input{'domain'};
	$template->param('domain' => $domain);
	$template->param('action' => 'exec_add_ssl_vhost');
	$template->param('newcert' => '1');
		
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub change_ssl_vhost{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'add_ssl_vhost.html');
			
	my $domain = $input{'domain'};
	$template->param('domain' => $domain);
	$template->param('action' => 'exec_change_ssl_vhost');
	
	logline("debug","Creating File Object \$httpd_conf.");
	my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
	$httpd_conf->read_file;
	my %domains = %{$httpd_conf->file_parsed_hash()};
	
	$template->param('cert' => $domains{$domain}{'ssl_cert'});
	$template->param('key' => $domains{$domain}{'ssl_key'});
	$template->param('chain' => $domains{$domain}{'ssl_chain'});
	
	if($domains{$domain}{'ssl_cert'} =~ m/letsencrypt/){
		$template->param('is_letsencrypt' => '1');
	}
	
	if($domains{$domain}{'ssl_force'} == '1'){
		$template->param('has_ssl_redirect' => '1');
	}
		
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_add_ssl_vhost{
	
	my $template = HTML::Template->new(filename => 'result.html');
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $result = $validation_result;
	my $success_text = '';

	if($result){
	
	}
	else{
		
		my $domain = $input{'domain'};
		
		if($domain !~ m/^www\./){
			
			$domain = 'www.' . $domain;
			
		}
		
		my $install_apache_cert = '';
		if($fb){
			
			$install_apache_cert = '/usr/iports/bin/sudo /usr/sbin/install_apache_cert.pl';
			
		} else {
			
			$install_apache_cert = '/home/httpd/cgi-bin/easytecc4/install_apache_cert.pl';
			
		}
		
		if($input{'letsencrypt'}){
		
			if(!$fb){
				
				return(error("L__Let's Encrypt steht auf diesem Servertyp nicht zur Verfügung__L"));
				
			}
		
			$result = `/bin/sh -c '$install_apache_cert $domain LETSENCRYPT 2>&1'`;
			
			if($result =~ m/^ok/){
				
				$result = "L__Das Let's Encrypt Zertifikat wurde erfolgreich erstellt.__L";
				
			} else {
				
				$result = encode_entities($result);
				return(error("L__Beim Erstellen des Let's Encrypt Zertifikates ist ein Fehler aufgetreten:__L <pre>$result</pre><br>L__Eventuell verweist eine der Domains nicht auf Ihren Server oder der Zugriff auf /.well-known/acme-challenge wurde durch eine Rewrite-Regel verhindert.__L"));
		
			}	
						
		}
		
		elsif($input{'csr'}){
					
			my $openssl_create_csr = 'openssl req -nodes -newkey rsa:2048 -sha256 -keyout ' . $input{'key_file'} . ' -out ' . $input{'csr_file'} . ' -subj "/C=' . $input{'csr_country'} . '/ST=' . $input{'csr_state'} . '/L=' . $input{'csr_city'} . '/O=' . $input{'csr_company'} . '/OU=' . $input{'csr_section'} . '/CN=' . $input{'domain'} . '/emailAddress=' . $input{'csr_email'} . '" && cat ' . $input{'csr_file'};
			if(-e '/usr/local/bin/openssl'){
				$openssl_create_csr = '/usr/local/bin/' . $openssl_create_csr;
			}
			
			$result = `$openssl_create_csr 2>&1`;
			
			if($result =~ m/problems/){
				
				return(error("L__Beim Erstellen des CSR ist ein Fehler aufgetreten:__L $result"));
				
			}
			else {
				
				return(modal_message('L__Zertifikatsanfrage (CSR)__L','L__Bitte geben Sie diesen Textblock bei der Bestellung des Zertifikates an:__L<br><br><pre>' . $result . '</pre>'));
				
			}	
							
		}
		
		else {
	
			logline("debug","running $install_apache_cert $domain $input{'cert'} $input{'key'} $input{'chain'} 2>&1");
			
			$result = `$install_apache_cert $domain $input{'cert'} $input{'key'} $input{'chain'} 2>&1`;
						
			if($result =~ m/^ok/){
				
				$result = "L__Das Zertifikat wurde erfolgreich eingerichtet.__L";
				
			}
			else {
				
				return(error("L__Beim Einrichten des Zertifikates ist ein Fehler aufgetreten:__L $result"));
				
			}
			
		}
		
		$success_text = $result;
		
	}

	$template->param('result' => $result);
	logline("debug","result = " . $result);

	if($session && $session->param('ssl_expiry_dates')){
		$session->clear('ssl_expiry_dates');
	}
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_vhosts&success_text=' . encode_base64url($success_text);
	return(\$template);
		
}

sub exec_change_ssl_vhost{
	
	my $template = HTML::Template->new(filename => 'result.html');
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $result = $validation_result;
	my $success_text = '';

	if($result){
	
	}
	else{
		
		my $domain = $input{'domain'};
		
		if($domain !~ m/^www\./){
			
			$domain = 'www.' . $domain;
			
		}
		
		my $install_apache_cert = '';
		if($fb){
			
			$install_apache_cert = '/usr/iports/bin/sudo /usr/sbin/install_apache_cert.pl';
			
		} else {
			
			$install_apache_cert = '/home/httpd/cgi-bin/easytecc4/install_apache_cert.pl';
			
		}
		
		if($input{'letsencrypt'}){
		
			if(!$fb){
				
				return(error("L__Let's Encrypt steht auf diesem Servertyp nicht zur Verfügung__L"));
				
			}
		
			$result = `/bin/sh -c '$install_apache_cert $domain 443 LETSENCRYPT 2>&1'`;
			
			if($result =~ m/^ok/){
				
				$result = "L__Das Let's Encrypt Zertifikat wurde erfolgreich erstellt.__L";
				
			} else {
				
				$result = encode_entities($result);
				return(error("L__Beim Erstellen des Let's Encrypt Zertifikates ist ein Fehler aufgetreten:__L <pre>$result</pre><br>L__Eventuell verweist eine der Domains nicht auf Ihren Server oder der Zugriff auf /.well-known/acme-challenge wurde durch eine Rewrite-Regel verhindert.__L"));
				
			}	
						
		}
		
		elsif($input{'delete'}){
			
			logline("debug","Creating File Object \$httpd_conf.");
			my $httpd_conf = file->new({file_name => '/etc/httpd/conf/httpd.conf'});
			$httpd_conf->read_file;
			my %domains = %{$httpd_conf->file_parsed_hash()};
				
			my $vhost_to_delete = $domain;
			my $vhost_to_delete_ohne_www = $vhost_to_delete;
			$vhost_to_delete_ohne_www =~ s/^www\.//;
	
			#vhost aus httpd.conf löschen
			my @new_httpd_conf = ();
			my $vhost = '';
			my $delete_this_vhost = '';
			my @tmp_vhost = ();
			my $ssl = '';
	
			foreach($httpd_conf->file_content){
				chomp;
				$vhost = 1 if(/^\<VirtualHost\s+([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}):/i);
				$ssl = 1 if(/^\<VirtualHost\s+([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}):443/i);
	
				if($vhost){
										
					if(/^ServerName\s+$vhost_to_delete_quoted\b/){
						s/E=REDIRECT_SCHEME:https/E=REDIRECT_SCHEME:http/g;
					}
					
					push @tmp_vhost, $_;
					my $vhost_to_delete_quoted = quotemeta("$vhost_to_delete");
	
					if(/^ServerName\s+$vhost_to_delete_quoted\b/ && $ssl){
						$delete_this_vhost = '1'
					}
						
					#dieser vhost ist es nicht, also in @tmp_vhost gesammelte Zeilen unverändert übernehmen
					if(/^\<\/VirtualHost/ && ! $delete_this_vhost){
						push @new_httpd_conf, @tmp_vhost;
						$vhost = '';
						$ssl = '';
						@tmp_vhost = ();
					}
					#oder match auf zu löschenden vhost, hier passiert nix und vhost wird nicht in new_httpd_conf gepushed, gleichbedeutend mit löschen
					elsif(/^\<\/VirtualHost/ && $delete_this_vhost){
						logline("debug","vhost=$vhost");
						$vhost = '';
						$ssl = '';
						@tmp_vhost = ();
						# $delete_this_vhost wieder auf null setzen, da es mehrere vhost mit gleichem Namen geben kann, z.B. wegen SSL oder
						# propagationsvhost mit alter IP. Alles weghauen
						$delete_this_vhost = '';
					}
				}
				else{
					push @new_httpd_conf, $_;
				}
			}
	
			@{$httpd_conf->file_content} = @new_httpd_conf;
			
			my $got = $httpd_conf->write_file;
			return(error($got)) if $got;
			
			### Mario: Sobald ein SSL-VHost gelöscht wird -jedoch nicht das SSL-Zertifikat- dann wird durch den Cronjob immer wieder versucht,
			### das SSL-Zertifikat zu verlängern. Daher müssen einige Schritte durchgeführt werden ...
			if($domains{$domain}{'ssl_cert'} =~ m/letsencrypt/){
				#my $got = `/usr/iports/bin/sudo /usr/sbin/rm.pl $droot d` if $fb;
				#my $got = `$easytecc_prefix/rm.pl $droot d` unless $fb;
						logline("debug"," MARIO delete_ssl_files von $vhost_to_delete_ohne_www");
				system('/bin/sh -c "/usr/iports/bin/letsencrypt revoke --cert-path ' . $domains{$domain}{'ssl_cert'} . '"');
				#return(error("L__Fehler beim Löschen von__L $droot: $got")) if ($got || -d "$droot");
			}
				
			$result = "L__Der SSL-Vhost wurde erfolgreich gelöscht__L";
				
		}
		
		else {
	
			logline("debug","running $install_apache_cert $domain $input{'cert'} $input{'key'} $input{'chain'} 2>&1");
			
			$result = `$install_apache_cert $domain 443 $input{'cert'} $input{'key'} $input{'chain'} 2>&1`;
						
			if($result =~ m/^ok/){
				
				$result = "L__Das Zertifikat wurde erfolgreich eingerichtet.__L";
				
			}
			else {
				
				return(error("L__Beim Einrichten des Zertifikates ist ein Fehler aufgetreten:__L $result"));
				
			}
			
		}
				
	}

	$success_text = $result;		
	$template->param('result' => $result);
	logline("debug","result = " . $result);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_vhosts&success_text=' . encode_base64url($success_text);
	return(\$template);
		
}

sub hash_to_file{
	
	my ($file, $hashref) = @_;
	
	if(!open(HASHFILE,'>:encoding(UTF-8)',$file)){
		
		return 0;
		
	}
	
	
	use Data::Dumper;
	print HASHFILE Data::Dumper->Dump([$hashref],['$hashref']);
	close HASHFILE;
	
	return 1;
	
}

sub hash_from_file{
	
	my ($file) = @_;
	
	if(!open(HASHFILE,'<:encoding(UTF-8)',$file)){
		
		return 0;
		
	}
	
    local($/) = '';
	
	my $hashref = {};
	my $hashdef = <HASHFILE>;
	eval $hashdef;
	close HASHFILE;
		
	return $hashref;
	
}

sub note_to_hashfile{
	
	my ($keys, $title, $text) = @_;
	
	my $user_hash_file = '/usr/local/etc/easytecc/note/' . $session->param('user') . '.data';
	my $user_hashref = hash_from_file($user_hash_file);
	
	if(ref($user_hashref) ne 'HASH'){
		
		$user_hashref = {};
		
	}
	
	my $target_hashref = $user_hashref;
	foreach (@{$keys}){
	
		if(!exists($target_hashref->{$_})){
			
			$target_hashref->{$_} = {};
			
		}
			
		$target_hashref = $target_hashref->{$_};
		
	}
	
	$target_hashref->{note}->{title} = $title;
	$target_hashref->{note}->{text} = $text;
	
	return hash_to_file($user_hash_file,$user_hashref );
	
}

sub note_from_hashfile{
	
	my ($keys) = @_;
	
	my $user_hash_file = '/usr/local/etc/easytecc/note/' . $session->param('user') . '.data';
	my $user_hashref = hash_from_file($user_hash_file);
		
	my $target_hashref = $user_hashref;
	foreach (@{$keys}){
	
		if(!exists($target_hashref->{$_})){
			
			last;
						
		}
			
		$target_hashref = $target_hashref->{$_};
		
	}
	
	my $result = {};
	$result->{title} = encode('utf-8',$target_hashref->{note}->{title});
	$result->{text} = encode('utf-8',$target_hashref->{note}->{text});
			
	return $result;
		
}

sub show_save_note{
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'show_note.html');
		
	my @keys = split(/\//, $input{'note_key'});
	my $note = note_from_hashfile(\@keys);
		
	$template->param('title' => $input{'title'});
	$template->param('note_key' => $input{'note_key'});
			
	$template->param('note_title' => $note->{title});
	$template->param('note_text' => $note->{text});
	
	if(! $note->{title} && $input{'note_title'}){
		
		$template->param('note_title' => $input{'note_title'});
		
	}
	
	if($input{'parent'}){
		$template->param('parent' => $input{'parent'});
	}
						
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);

}

sub exec_show_save_note{
	
	my $template = HTML::Template->new(filename => 'show_note.html');
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $result = $validation_result;
	my $success_text = '';

	if($result){
	
	}
	else{
		
		my @keys = split(/\//, $input{'note_key'});
		my $title = $input{'note_title'};
		my $text = $input{'note_text'};
	
		if(!note_to_hashfile(\@keys,$title,$text)){
			
			return(error("L__Beim Speichern der Notiz ist ein Fehler aufgetreten.__L"));
			
		} else {
			
			$result = "L__Die Notiz wurde gespeichert.__L";
			
		}
		
		$success_text = $result;
		
	}

	$template->param('result' => $result);
	logline("debug","result = " . $result);

	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	
	if(!$input{'parent'}){
		$json_output{'redirect_to'} = '&success_text=' . encode_base64url($success_text);
	}
	
	return(\$template);
		
}

sub change_firewall{
	
	my $error = '';
	
	if($session->param('show_firewall') ne '1'){
		return start();
	}
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	
	if(! -d '/usr/local/etc/easytecc/shell2ban'){
		
		system("mkdir -p /usr/local/etc/easytecc/shell2ban");
		system("touch /usr/local/etc/easytecc/shell2ban/.disabled");
		
	}
		
	my $template = HTML::Template->new(filename => 'change_firewall.html');
	
	# enable
	if($input{'enable'}){
		
		$input{'active_tab'} = 1;
		system("rm -f /usr/local/etc/easytecc/shell2ban/.disabled");
		system("touch /usr/local/etc/easytecc/shell2ban/WHITELIST");
		system("touch /usr/local/etc/easytecc/shell2ban/BLACKLIST");
		$result = 'L__Die Firewall wurde aktiviert.__L';
				
	}
	elsif($input{'disable'}){
		
		$input{'active_tab'} = 1;
		system("touch /usr/local/etc/easytecc/shell2ban/.disabled");
		$result = 'L__Die Firewall wurde deaktiviert.__L';
		
	}
	elsif($input{'enable_web2ban'}){
		
		$input{'active_tab'} = 2;
		system("rm -f /usr/local/etc/easytecc/shell2ban/.web2ban.disabled");
		$result = 'L__Das Webserver-Plugin wurde aktiviert.__L';
					
	}
	elsif($input{'disable_web2ban'}){
		
		$input{'active_tab'} = 2;
		system("touch /usr/local/etc/easytecc/shell2ban/.web2ban.disabled");
		$result = 'L__Das Webserver-Plugin wurde deaktiviert.__L';
				
	}
	elsif($input{'enable_scan2ban'}){
		
		$input{'active_tab'} = 3;
		system("rm -f /usr/local/etc/easytecc/shell2ban/.scan2ban.disabled");
		$result = 'L__Das Portscan-Plugin wurde aktiviert.__L';
					
	}
	elsif($input{'disable_scan2ban'}){
		
		$input{'active_tab'} = 1;
		system("touch /usr/local/etc/easytecc/shell2ban/.scan2ban.disabled");
		$result = 'L__Das Portscan-Plugin wurde deaktiviert.__L';
				
	}
	elsif($input{'enable_share2ban'}){
		
		$input{'active_tab'} = 1;
		system("rm -f /usr/local/etc/easytecc/shell2ban/.share2ban.disabled");
		$result = 'L__Das Community-Plugin wurde aktiviert.__L';
					
	}
	elsif($input{'disable_share2ban'}){
		
		$input{'active_tab'} = 1;
		system("touch /usr/local/etc/easytecc/shell2ban/.share2ban.disabled");
		$result = 'L__Das Community-Plugin wurde deaktiviert.__L';
				
	}
	elsif($input{'whitelist_remove'}){
		
		$input{'active_tab'} = 1;
		
		my @keys = split(/\//, 'FIREWALL/WHITELIST/' . $input{'whitelist_remove'});
		note_to_hashfile(\@keys,'','');
		
		$input{'whitelist_remove'} =~ s/\//\\\//;
		system("sed -i '.bak' '/^" . $input{'whitelist_remove'} . "/d' /usr/local/etc/easytecc/shell2ban/WHITELIST");
				
		$result = 'L__Die IP / das Netzwerk wurde entfernt.__L';
		
		
	}	
	elsif($input{'blacklist_remove'}){
		
		$input{'active_tab'} = 1;
				
		my @keys = split(/\//, 'FIREWALL/BLACKLIST/' . $input{'blacklist_remove'});
		note_to_hashfile(\@keys,'','');
		
		$input{'blacklist_remove'} =~ s/\//\\\//;
		system("sed -i '.bak' '/^" . $input{'blacklist_remove'} . "/d' /usr/local/etc/easytecc/shell2ban/BLACKLIST");
		
		$result = 'L__Die IP / das Netzwerk wurde entfernt.__L';
		
	}
	elsif($input{'web2ban_delete_rule'}){
		
		$input{'active_tab'} = 2;
		$error = web2ban_add_edit_delete_rule('delete');
		
		if(!$error){
			$result = 'L__Die Regel wurde entfernt.__L';
		}
	
	}	
	elsif($input{'scan2ban_remove_port'}){
		
		$input{'active_tab'} = 3;
		$input{'port'} =~ s/\s+//g;
		system("sed -i '.bak' '/^" . $input{'port'} . "/d' /usr/local/etc/easytecc/shell2ban/SCAN2BAN_WHITELIST");
		
		$input{'port'} =~ s/[^0-9]//g;
		my @keys = split(/\//, 'FIREWALL/SCAN2BAN_WHITELIST/' . $input{'port'});
		note_to_hashfile(\@keys,'','');
		
		$result = 'L__Ports wurden entfernt.__L';
		
	} elsif(length($input{'scan2ban_block_not_whitelisted'})){
		
		$input{'active_tab'} = 3;
		
		if($input{'scan2ban_block_not_whitelisted'}){
					
			system("touch /usr/local/etc/easytecc/shell2ban/.scan2ban.block.not.whitelisted");
			
		} else {
			
			system("rm -f /usr/local/etc/easytecc/shell2ban/.scan2ban.block.not.whitelisted");
			
		}
		
		$result = 'L__Portscan-Einstellungen geändert.__L';
						
	} else {
		
		$template->param('change_firewall_active_tab2' => '0');
		$template->param('change_firewall_active_tab3' => '0');
		
	}
	
	if(!length($input{'active_tab'})){
		
		$input{'active_tab'} = 1;
		
	}
		
	$template->param('change_firewall_active_tab' . $input{'active_tab'} => '1');	
					
	if(-e '/usr/local/etc/easytecc/shell2ban/.disabled'){
		
		$template->param('disabled' => '1');
		
	} else {
		
		my @whitelist;
		if(-s '/usr/local/etc/easytecc/shell2ban/WHITELIST'){
			
			open WHITELIST, '</usr/local/etc/easytecc/shell2ban/WHITELIST';
			while (<WHITELIST>){
				
				my ($ip,$ttl,$note) = $_ =~ m/^([^\s]+)\s+([0-9]+)\s*#*(.*)$/;
				if(defined($ip)){
					
					logline("debug","###ip: $ip ### ttl: $ttl ### note: $note ###");
					
					if(!defined($ttl)){
						$ttl = 0;
					}
					elsif($ttl > 0){
						#$ttl = `/bin/sh -c "date -j -f '%s' '$ttl' '+%d.%m.%Y %H:%M:%S'"`;
						#chomp $ttl;
						$ttl = $strftime{"%d.%m.%Y %H:%M", $ttl};
					}
					
					my @keys = split(/\//, 'FIREWALL/WHITELIST/' . $ip);
					
					if(defined($note) && length($note)){
						
						note_to_hashfile(\@keys,'WHITELIST',$note);
					
					} else {
											
						$note = note_from_hashfile(\@keys);
						$note = $note->{text};
						
					}
									
					push @whitelist, { ip => $ip, ttl => $ttl, note => $note };
					
				}
				
			}
			close WHITELIST;
		}
		$template->param('whitelist' => \@whitelist);
		
		my @blacklist;
		if(-s '/usr/local/etc/easytecc/shell2ban/BLACKLIST'){
			
			open BLACKLIST, '</usr/local/etc/easytecc/shell2ban/BLACKLIST';
			while (<BLACKLIST>){
				
				my ($ip,$ttl,$note) = $_ =~ m/^([^\s]+)\s+([0-9]+)\s*#*(.*)$/;
				if(defined($ip)){
					
					logline("debug","###ip: $ip ### ttl: $ttl ### note: $note ###");
					
					if(!defined($ttl)){
						$ttl = 0;
					}
					elsif($ttl > 0){
						#$ttl = `/bin/sh -c "date -j -f '%s' '$ttl' '+%d.%m.%Y %H:%M:%S'"`;
						#chomp $ttl;
						$ttl = $strftime{"%d.%m.%Y %H:%M", $ttl};
					}
					
					my @keys = split(/\//, 'FIREWALL/BLACKLIST/' . $ip);
					
					if(defined($note) && length($note)){
						
						note_to_hashfile(\@keys,'WHITELIST',$note);
					
					} else {
											
						$note = note_from_hashfile(\@keys);
						$note = $note->{text};
						
					}
									
					push @blacklist, { ip => $ip, ttl => $ttl, note => $note };
										
				}
				
			}
			close BLACKLIST;
		}
		$template->param('blacklist' => \@blacklist);
		
		my @dyn_whitelist;
		if(-s '/usr/local/etc/easytecc/shell2ban/DYN_WHITELIST'){
			
			open DYN_WHITELIST, '</usr/local/etc/easytecc/shell2ban/DYN_WHITELIST';
			while (<DYN_WHITELIST>){
				
				my ($ip,$ttl,$hits) = $_ =~ m/^([^\/]+)\/32\s+([0-9]+)([0-9])$/;
				if(defined($ip)){
					
					if(!defined($ttl)){
						$ttl = 0;
					}
					elsif($ttl > 0){
						$ttl *= 10;
						#$ttl = `/bin/sh -c "date -j -f '%s' '$ttl' '+%d.%m.%Y %H:%M:%S'"`;
						#chomp $ttl;
						$ttl = $strftime{"%d.%m.%Y %H:%M", $ttl};
					}
					
					push @dyn_whitelist, { ip => $ip, ttl => $ttl, hits => $hits };
				}
				
			}
			close DYN_WHITELIST;
		}
		@dyn_whitelist = sort { inet_aton($a->{'ip'}) cmp inet_aton($b->{'ip'}) } @dyn_whitelist;
		$template->param('dyn_whitelist' => \@dyn_whitelist);
		
		my @dyn_blacklist;
		if(-s '/usr/local/etc/easytecc/shell2ban/DYN_BLACKLIST'){
			
			open DYN_BLACKLIST, '</usr/local/etc/easytecc/shell2ban/DYN_BLACKLIST';
			while (<DYN_BLACKLIST>){
				
				my ($ip,$ttl,$hits) = $_ =~ m/^([^\/]+)\/32\s+([0-9]+)([0-9])$/;
				if(defined($ip)){
					
					if(!defined($ttl)){
						$ttl = 0;
					}
					elsif($ttl > 0){
						$ttl *= 10;
						#$ttl = `/bin/sh -c "date -j -f '%s' '$ttl' '+%d.%m.%Y %H:%M:%S'"`;
						#chomp $ttl;
						$ttl = $strftime{"%d.%m.%Y %H:%M", $ttl};
					}
					
					push @dyn_blacklist, { ip => $ip, ttl => $ttl, hits => $hits };
				}
				
			}
			close DYN_BLACKLIST;
		}
		@dyn_blacklist = sort { inet_aton($a->{'ip'}) cmp inet_aton($b->{'ip'}) } @dyn_blacklist;
		$template->param('dyn_blacklist' => \@dyn_blacklist);
		
		if(-e '/usr/local/etc/easytecc/shell2ban/.web2ban.disabled'){
		
			$template->param('web2ban_disabled' => '1');
			
		} else {
			
			my @web2ban_whitelist;
			if(-s '/usr/local/etc/easytecc/shell2ban/WEB2BAN_WHITELIST'){
				
				open WEB2BAN_WHITELIST, '</usr/local/etc/easytecc/shell2ban/WEB2BAN_WHITELIST';
				
				my $index = 1;
				my ($name,$note,$list,$key,$rule);
								
				while (<WEB2BAN_WHITELIST>){
					
					# name or note
					if($_ =~ m/^#\s*(.*)$/){
						
						if(!defined($name)){
							$name = $1;
						} elsif(!defined($note)){
							$note = $1;
						} else {
							$note .= $1;
						}
						
					}
					# LogMessage line
					elsif($_ =~ m/^LogMessage\s\"#shell2ban\.web2ban#(5|6|8|9)#([^#]+)#[^#]+#\"\s\"expr=\s\\$/){
						
						($list,$key) = ($1,$2);
					
					}	
					# rule
					elsif($_ =~ m/^(.+)\\$/){
						
						if(!defined($rule)){
							$rule = $1;
						} else {
							$rule .= '<br>' . $1;
						}
					
					}
					# end
					elsif($_ =~ m/^\"$/){
						
						if(defined($name) && defined($note) && defined($list) && defined($key) && defined($rule)){
							
							push @web2ban_whitelist, { index => $index, name => $name, note => $note, key => $key, rule => $rule, testmode => $list > 7 ? 1 : 0 };
							$name = undef;
							$note = undef;
							$rule = undef;
							$index++;
							
						}
						
					}
		
															
				}
				close WEB2BAN_WHITELIST;
			}
			$template->param('web2ban_whitelist' => \@web2ban_whitelist);
			
			my @web2ban_blacklist;
			if(-s '/usr/local/etc/easytecc/shell2ban/WEB2BAN_BLACKLIST'){
				
				open WEB2BAN_BLACKLIST, '</usr/local/etc/easytecc/shell2ban/WEB2BAN_BLACKLIST';
				
				my $index = 1;
				my ($name,$note,$key,$rule);
				
				while (<WEB2BAN_BLACKLIST>){
					
					# name or note
					if($_ =~ m/^#\s*(.*)$/){
						
						if(!defined($name)){
							$name = $1;
						} elsif(!defined($note)){
							$note = $1;
						} else {
							$note .= $1;
						}
						
					}
					# LogMessage line
					elsif($_ =~ m/^LogMessage\s\"#shell2ban\.web2ban#(5|6|8|9)#([^#]+)#[^#]+#\"\s\"expr=\s\\$/){
						
						($list,$key) = ($1,$2);
					
					}	
					# rule
					elsif($_ =~ m/^(.+)\\$/){
						
						if(!defined($rule)){
							$rule = $1;
						} else {
							$rule .= '<br>' . $1;
						}
					
					}
					# end
					elsif($_ =~ m/^\"$/){
						
						if(defined($name) && defined($note) && defined($key) && defined($rule)){
							
							#$key =~ s/(.{16})/$1<span style="display:block;"><\/span>/g;
							
							push @web2ban_blacklist, { index => $index, name => $name, note => $note, key => $key, rule => $rule, testmode => $list > 7 ? 1 : 0 };
							$name = undef;
							$note = undef;
							$rule = undef;
							$index++;
							
						}
						
					}
		
															
				}
				close WEB2BAN_BLACKLIST;
			}
			$template->param('web2ban_blacklist' => \@web2ban_blacklist);
			
			my @web2ban_test_whitelist;
			if(-s '/usr/local/etc/easytecc/shell2ban/WEB2BAN_TEST_WHITELIST'){
				
				open WEB2BAN_TEST_WHITELIST, '</usr/local/etc/easytecc/shell2ban/WEB2BAN_TEST_WHITELIST';
				while (<WEB2BAN_TEST_WHITELIST>){
					
					my ($ip,$ttl,$hits) = $_ =~ m/^([^\/]+)\/32\s+([0-9]+)([0-9])$/;
					if(defined($ip)){
						
						if(!defined($ttl)){
							$ttl = 0;
						}
						elsif($ttl > 0){
							$ttl *= 10;
							#$ttl = `/bin/sh -c "date -j -f '%s' '$ttl' '+%d.%m.%Y %H:%M:%S'"`;
							#chomp $ttl;
							$ttl = $strftime{"%d.%m.%Y %H:%M", $ttl};
						}
						
						push @web2ban_test_whitelist, { ip => $ip, ttl => $ttl, hits => $hits };
					}
					
				}
				close WEB2BAN_TEST_WHITELIST;
			}
			@web2ban_test_whitelist = sort { inet_aton($a->{'ip'}) cmp inet_aton($b->{'ip'}) } @web2ban_test_whitelist;
			$template->param('web2ban_test_whitelist' => \@web2ban_test_whitelist);
			
			my @web2ban_test_blacklist;
			if(-s '/usr/local/etc/easytecc/shell2ban/WEB2BAN_TEST_BLACKLIST'){
				
				open WEB2BAN_TEST_BLACKLIST, '</usr/local/etc/easytecc/shell2ban/WEB2BAN_TEST_BLACKLIST';
				while (<WEB2BAN_TEST_BLACKLIST>){
					
					my ($ip,$ttl,$hits) = $_ =~ m/^([^\/]+)\/32\s+([0-9]+)([0-9])$/;
					if(defined($ip)){
						
						if(!defined($ttl)){
							$ttl = 0;
						}
						elsif($ttl > 0){
							$ttl *= 10;
							#$ttl = `/bin/sh -c "date -j -f '%s' '$ttl' '+%d.%m.%Y %H:%M:%S'"`;
							#chomp $ttl;
							$ttl = $strftime{"%d.%m.%Y %H:%M", $ttl};
						}
						
						push @web2ban_test_blacklist, { ip => $ip, ttl => $ttl, hits => $hits };
					}
					
				}
				close WEB2BAN_TEST_BLACKLIST;
			}
			@web2ban_test_blacklist = sort { inet_aton($a->{'ip'}) cmp inet_aton($b->{'ip'}) } @web2ban_test_blacklist;
			$template->param('web2ban_test_blacklist' => \@web2ban_test_blacklist);
					
		}
		
		if(-e '/usr/local/etc/easytecc/shell2ban/.scan2ban.disabled'){
		
			$template->param('scan2ban_disabled' => '1');
			
		} else {
			
			my @scan2ban_whitelist;
			
			if(-s '/usr/local/etc/easytecc/shell2ban/SCAN2BAN_WHITELIST'){
				
				open SCAN2BAN_WHITELIST, '</usr/local/etc/easytecc/shell2ban/SCAN2BAN_WHITELIST';
				while (<SCAN2BAN_WHITELIST>){
					
					my ($port,$note) = split(/#/,$_,2);
					if(defined($port)){
						
						$port =~ s/,/, /g;
						push @scan2ban_whitelist, { port => $port, note => $note };

					}
				
				}
				close SCAN2BAN_WHITELIST;
			}
											
			$template->param('scan2ban_whitelist' => \@scan2ban_whitelist);
			
			if(-e '/usr/local/etc/easytecc/shell2ban/.scan2ban.block.not.whitelisted'){
				
				$template->param('scan2ban_block_not_whitelisted' => '1');
				
			} else {
				
				$template->param('scan2ban_block_not_whitelisted' => '0');
				
			}
			
		}
		
		if(-e '/usr/local/etc/easytecc/shell2ban/.share2ban.disabled'){
		
			$template->param('share2ban_disabled' => '1');
							
		} else {
			
			$template->param('share2ban_disabled' => '0');
			
		}
	}
	
	
	if($error){
		
		my $subtemplate = error($error);
		my $errorhtml = $$subtemplate->output;
		
		if($input{'active_tab'} eq 2){
			$template->param('error_tab2' => $errorhtml);
		} else {
			$template->param('error' => $errorhtml);
		}	
		
	}
	$template->param('result' => $result);
	logline("debug","result = " . $result);
	
	$success_text = $result;
	#$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=change_firewall&success_text=' . encode_base64url($success_text);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub list_add_ip{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'list_add_ip.html');
	$template->param('whitelist' => $input{'whitelist'});
	$template->param('blacklist' => $input{'blacklist'});
	$template->param('ip' => $input{'ip'});
	$template->param('ttl' => $input{'ttl'});
	$template->param('ttl' => $input{'note'});
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_list_add_ip{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $result = $validation_result;

	logline("debug","exec_list_add_ip result:$result###");

	if($result){

	}
	else{
		
		#$input{'ip'} =~ s/\//\\\//;
		
		if(defined($input{'ttl'}) && $input{'ttl'} > 0){
			
			my $timestamp = `/bin/sh -c "date -j '+%s'"`;
			chomp $timestamp;
			
			$input{'ttl'} = $timestamp + ($input{'ttl'}*60*60);
			
		} else {
			
			$input{'ttl'} = 0;
			
		}
		
		my $list = $input{'whitelist'} ? 'WHITELIST' : 'BLACKLIST';
		my $listfile = '/usr/local/etc/easytecc/shell2ban/' . $list;
		#system("echo '" . $input{'ip'} . " " . $input{'ttl'} . "  1' >> " . $listfile);
		system("echo '" . $input{'ip'} . " " . $input{'ttl'} . " #" . $input{'note'} . "' >> " . $listfile);
				
		my @keys = split(/\//, 'FIREWALL/' . $list . '/' . $input{'ip'});
		my $title = $list;
		my $text = $input{'note'};
	
		if(!note_to_hashfile(\@keys,$title,$text)){
			
			$error = "L__Beim Speichern der Notiz ist ein Fehler aufgetreten.__L";
			
		} 
		
	}

	$result = 'L__Fehler__L: ' . $error if $error;
	
	return error($error) if $error;
	
	$result = 'L__Die IP / das Netzwerk wurde hinzugefügt.__L';
	$success_text = $result;

	$template->param('result' => $result);
	logline("debug","result = " . $result);
	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=change_firewall&success_text=' . encode_base64url($success_text);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub scan2ban_add_port{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'scan2ban_add_port.html');
	$template->param('whitelist' => $input{'whitelist'});
	$template->param('blacklist' => $input{'blacklist'});
	$template->param('port' => $input{'port'});
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_scan2ban_add_port{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $result = $validation_result;

	logline("debug","exec_scan2ban_add_port result:$result###");

	if($result){

	}
	else{
				
		my $list = $input{'whitelist'} ? 'WHITELIST' : 'BLACKLIST';
		my $listfile = '/usr/local/etc/easytecc/shell2ban/SCAN2BAN_' . $list;
		
		#my $port;
		#foreach $port (split(/[,\s]+/,$input{'port'})){
			
		#	system("echo '" . $port . " #" . $input{'note'} . "' >> " . $listfile);
						
		#}

		$input{'port'} =~ s/\s+//g;
				
		system("echo '" . $input{'port'} . " #" . $input{'note'} . "' >> " . $listfile);
		
		my $portstring = $input{'port'};
		$portstring =~ s/[^0-9]//g;
						
		my @keys = split(/\//, 'FIREWALL/SCAN2BAN_' . $list . '/' . $portstring);
		my $title = $list;
		my $text = $input{'note'};
	
		if(!note_to_hashfile(\@keys,$title,$text)){
			
			$error = "L__Beim Speichern der Notiz ist ein Fehler aufgetreten.__L";
			
		} 
		
	}

	$result = 'L__Fehler__L: ' . $error if $error;
	
	return error($error) if $error;
	
	$result = 'L__Ports wurden hinzugefügt.__L';
	$success_text = $result;

	$template->param('result' => $result);
	logline("debug","result = " . $result);
	
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=change_firewall&active_tab=3&success_text=' . encode_base64url($success_text);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}


sub web2ban_add_edit_delete_rule{
	
	my $action = shift;
		
	my $listname = $input{'whitelist'} ? 'WHITELIST' : 'BLACKLIST';
	my $listfile = '/usr/local/etc/easytecc/shell2ban/WEB2BAN_' . $listname;
	my $listfile_new = '/tmp/WEB2BAN_' . $listname . '.' . $$;
	my $logextra = '[%{SERVER_NAME}] %{REQUEST_SCHEME}://%{HTTP_HOST} %{THE_REQUEST} %{REQUEST_STATUS} \"%{HTTP_REFERER}\" \"%{HTTP_USER_AGENT}\"';
	
	
	my $error = '';	
	my $errortext;
	
	if($action eq 'add'){
		
		$errortext = "L__Beim Hinzufügen der Regel ist ein Fehler aufgetreten.__L";
		
	} elsif($action eq 'edit'){
		
		$errortext = "L__Beim Editieren der Regel ist ein Fehler aufgetreten.__L";
		
		if(! -s $listfile){
			
			return $errortext;
			
		}
		
	} elsif($action eq 'delete'){
		
		$errortext = "L__Beim Löschen der Regel ist ein Fehler aufgetreten.__L";
		
		if(! -s $listfile){
			
			return $errortext;
			
		}
				 
	}				 
					
	open WEB2BAN_LIST, "<$listfile";
	open WEB2BAN_LIST_NEW, ">$listfile_new";
			
	my $index = 1;
	my ($name,$note,$list,$ttl,$rule,$rule_rows);
			
	while (<WEB2BAN_LIST>){
					
		chomp;
		
		if($action eq 'add'){
			
			print WEB2BAN_LIST_NEW $_ . "\n";
			next;
			
		} else {
		
			if($index ne $input{'index'}){
			
				print WEB2BAN_LIST_NEW $_ . "\n";
			
				if($index gt $input{'index'}){
			
					next;
			
				}
			
			}
		
		}	
											
		# name or note
		if($_ =~ m/^#\s*(.*)$/){
			
			if(!defined($name)){
				$name = $1;
			} elsif(!defined($note)){
				$note = $1;
			} else {
				$note .= $1;
			}
			
		}
		# LogMessage line
		elsif($_ =~ m/^LogMessage\s\"#shell2ban\.web2ban#(5|6|8|9)#([^#]+)#[^#]+#\"\s\"expr=\s\\$/){
			
			($list,$key) = ($1,$2);
		
		}	
		# rule
		elsif($_ =~ m/^(.+)\\$/){
			
			if(!defined($rule)){
				$rule = $1;
				$rule_rows = 1;
			} else {
				$rule .= "\n" . $1;
				$rule_rows++;
			}
		
		}
		# end
		elsif($_ =~ m/^\"$/){
							
			if($index eq $input{'index'}){
				
				if($action eq 'edit'){
				
					$name=$input{'name'};
					$note=encode('utf-8',$input{'note'});
					$note =~ s/^#//mg;
					$note =~ s/^/# /mg;
					$list = $input{'whitelist'} ? 5 : 6;
					if($input{'testmode'}){
						$list += 3;
					}	
					$rule=$input{'rule'};
					$rule =~ s/[\\\s]+$//mg;
					$rule =~ s/$/ \\/mg;
					$key=md5_hex($rule);
										
					print WEB2BAN_LIST_NEW "# $name\n$note\n";
					print WEB2BAN_LIST_NEW "LogMessage \"#shell2ban\.web2ban#$list#$key#$logextra#\" \"expr= \\\n";
					print WEB2BAN_LIST_NEW "$rule\n\"\n";
					
				}
									
			} 
			
			$name = undef;
			$note = undef;
			$rule = undef;
			$index++;
							
		}
													
	}
	
	close WEB2BAN_LIST;
	
	if($action eq 'add'){
	
		$name=$input{'name'};
		$note=encode('utf-8',$input{'note'});
		$note =~ s/^#//mg;
		$note =~ s/^/# /mg;
		$list = $input{'whitelist'} ? 5 : 6;
		if($input{'testmode'}){
			$list += 3;
		}	
		$rule=$input{'rule'};
		$rule =~ s/[\\\s]+$//mg;
		$rule =~ s/$/ \\/mg;
		$key=md5_hex($rule);
							
		print WEB2BAN_LIST_NEW "# $name\n$note\n";
		print WEB2BAN_LIST_NEW "LogMessage \"#shell2ban\.web2ban#$list#$key#$logextra#\" \"expr= \\\n";
		print WEB2BAN_LIST_NEW "$rule\n\"\n";
		
	}
	
	close WEB2BAN_LIST_NEW;
	
	my $got = `/usr/iports/bin/sudo /usr/iports/sbin/httpd -C "LoadModule mpm_prefork_module libexec/apache24/mod_mpm_prefork.so" -C "LoadModule log_debug_module libexec/apache24/mod_log_debug.so" -t -f $listfile_new 2>&1`;
	chomp $got;
		
	if($got !~ m/^Syntax OK$/s){
		
		$error = $got;
		$error =~ s/^AH[0-9]+:[^:]+:/$errortext\n /;
				
	} else {
		
		# bsd cat is buggy as it does not throw all errors to stderr
		$got = `cp $listfile_new $listfile 2>&1 && rm -f $listfile_new && /usr/iports/bin/sudo /usr/sbin/reload_apache 2>&1`;
		chomp $got;
		
		if(length($got)){
			
			$error = "$errortext\n$got";
			
		} else {
			
			system("cd /usr/local/etc/easytecc/shell2ban && rm -f WEB2BAN_HTTPDERRORLOG.regex && /usr/bin/grep '#shell2ban.web2ban#' WEB2BAN_*LIST | sed 's/^.*#shell2ban.web2ban#[5689]#// ; s/#.*//' | while read UID ; do NAME=`grep -h -B 2 \"\$UID\" WEB2BAN_*LIST | sed '1!d; s/^# *//'` ; echo \"s/\$UID/\$NAME/\" >> WEB2BAN_HTTPDERRORLOG.regex; done;");
			
		}
		
	}
	
	return $error;
		
}

sub web2ban_edit_rule{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'web2ban_add_edit_rule.html');
	$template->param('whitelist' => $input{'whitelist'});
	$template->param('blacklist' => $input{'blacklist'});
	$template->param('edit' => 1);
	$template->param('add' => 0);
	
	my $listname = $input{'whitelist'} ? 'WEB2BAN_WHITELIST' : 'WEB2BAN_BLACKLIST';
	my $listfile = '/usr/local/etc/easytecc/shell2ban/' . $listname;
		
	if(! -s $listfile){
		
		return modal_error("L__Beim Lesen der Regel ist ein Fehler aufgetreten.__L");
					 
	}				 
				
	open WEB2BAN_LIST, "<$listfile";
				
	my $index = 1;
	my ($name,$note,$list,$key,$rule,$rule_rows);
				
	while (<WEB2BAN_LIST>){
					
		chomp;			
					
		# name or note
		if($_ =~ m/^#\s*(.*)$/){
			
			if(!defined($name)){
				$name = $1;
			} elsif(!defined($note)){
				$note = $1;
			} else {
				$note .= $1;
			}
			
		}
		# LogMessage line
		elsif($_ =~ m/^LogMessage\s\"#shell2ban\.web2ban#(5|6|8|9)#([^#]+)#[^#]+#\"\s\"expr=\s\\$/){
			
			($list,$key) = ($1,$2);
		
		}	
		# rule
		elsif($_ =~ m/^(.+)\\$/){
			
			if(!defined($rule)){
				$rule = $1;
				$rule_rows = 1;
			} else {
				$rule .= "\n" . $1;
				$rule_rows++;
			}
		
		}
		# end
		elsif($_ =~ m/^\"$/){
			
			if(defined($name) && defined($note) && defined($list) && defined($key) && defined($rule)){
				
				push @web2ban_blacklist, { index => $index, name => $name, note => $note, key => $key, rule => $rule, rule_rows => $rule_rows < 3 ? 3 : $rule_rows, testmode => $list > 7 ? 1 : 0 };
								
				if($index eq $input{'index'}){
					
					last;
					
				} else {
				
					$name = undef;
					$note = undef;
					$rule = undef;
					$index++;
					
				}
				
			}
			
		}
	
												
	}
	
	close WEB2BAN_LIST;
				
	if($index ne $input{'index'}){
		
		return modal_error("L__Beim Lesen der Regel ist ein Fehler aufgetreten.__L");
					 
	}	
		
	$template->param('index' => $index);
	$template->param('name' => $name);
	$template->param('note' => $note);
	$template->param('key' => $key);
	$template->param('rule' => $rule);
	$template->param('rule_rows' => $rule_rows < 3 ? 3 : $rule_rows);
	$template->param('testmode' => $list > 7 ? 1 : 0);
			
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_web2ban_edit_rule{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $result = $validation_result;
	my $error = '';
	
	logline("debug","exec_web2ban_edit_rule result:$result###");

	if($result){

	}
	else{
		
		$error = web2ban_add_edit_delete_rule('edit');
				
	}
		
	$result = 'L__Fehler__L: ' . $error if $error;
	
	return error($error) if $error;
	
	$result = 'L__Die Regel wurde geändert.__L';
	$success_text = $result;

	$template->param('result' => $result);
		
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=change_firewall&active_tab=2&success_text=' . encode_base64url($success_text);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub web2ban_add_rule{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'web2ban_add_edit_rule.html');
	$template->param('whitelist' => $input{'whitelist'});
	$template->param('blacklist' => $input{'blacklist'});
	$template->param('edit' => 0);
	$template->param('add' => 1);
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_web2ban_add_rule{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $result = $validation_result;
	my $error = '';

	logline("debug","exec_web2ban_add_rule result:$result###");

	if($result){

	}
	else{
		
		$error = web2ban_add_edit_delete_rule('add');
				
	}
		
	$result = 'L__Fehler__L: ' . $error if $error;
	
	return error($error) if $error;
	
	$result = 'L__Die Regel wurde hinzugefügt.__L';
	$success_text = $result;

	$template->param('result' => $result);
		
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=change_firewall&active_tab=2&success_text=' . encode_base64url($success_text);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub logrotate{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'change_logrotate.html');
	
	my $count=0;
	my $when='';
	
	if(-s '/usr/local/etc/newsyslog.conf.d/apache_mysql_mail.conf'){
	
		my $count_when	= `awk '/^\\// { print \$4"\\n"\$6; exit 0; }' /usr/local/etc/newsyslog.conf.d/apache_mysql_mail.conf`;
		chomp($count_when);
		($count,$when) = split(/[\r\n]+/,$count_when);
		
	}
		
	#logrotate_when_never
	
	if($when eq '$D'){
		
		$template->param('logrotate_when_daily' => 1);
		
	}
	elsif($when eq '$W1'){
		
		$template->param('logrotate_when_weekly' => 1);
		
	}
	elsif($when eq '$M1'){
		
		$template->param('logrotate_when_monthly' => 1);
		
	} else {
		
		$template->param('logrotate_when_never' => 1);
		
	}
	
	$template->param('logrotate_count' => $count);
	
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_logrotate{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $result = $validation_result;
	my $error = '';

	logline("debug","exec_logrotate result:$result###");

	if($result){

	}
	else{
		
		if($input{'logrotate_when'} eq 'never'){
			
			`rm -f /usr/local/etc/newsyslog.conf.d/apache_mysql_mail.conf`;
			
			if(-f '/usr/local/etc/newsyslog.conf.d/apache_mysql_mail.conf'){
				
				$error = "L__Fehler beim Löschen der newsyslog-Datei__L /usr/local/etc/newsyslog.conf.d/apache_mysql_mail.conf";
			
			}
			
		} else {
			
			if(! -f '/usr/local/etc/newsyslog.conf.d/apache_mysql_mail.conf'){
			
				if(! -f '/usr/local/etc/newsyslog.conf.d/'){
						
					`/usr/iports/bin/sudo /usr/sbin/webmkdir -p /usr/local/etc/newsyslog.conf.d 2>&1`;
					`/usr/iports/bin/sudo /usr/sbin/chown.pl admin:vuser /usr/local/etc/newsyslog.conf.d d 2>&1`;
		
				}
		
				`cat /usr/local/etc/easytecc/newsyslog_apache_mysql_mail.conf > /usr/local/etc/newsyslog.conf.d/apache_mysql_mail.conf`;
				
				if(! -f '/usr/local/etc/newsyslog.conf.d/apache_mysql_mail.conf'){
					
					return(error("L__Fehler beim Anlegen der newsyslog-Datei__L /usr/local/etc/newsyslog.conf.d/apache_mysql_mail.conf"));
				
				}
			
				#change awstats cron
				`sed -i '' 's/^[0-9]*[^0-9]*00*\\(.*awstats_updateall.pl.*\\)\$/55 23\\1/' /home/web/cronfile && /usr/iports/bin/sudo /usr/sbin/webcron`
				
			
			}
			
			# remove lars' logrotate
			if(-f '/etc/newsyslog.conf.d/default_logrotate.conf'){
				
				`cp /etc/newsyslog.conf.d/default_logrotate.conf /usr/local/etc/easytecc/backup_files/ 2>/dev/null`;
				`cat /dev/null > /etc/newsyslog.conf.d/default_logrotate.conf`;
				
			}
			
			my $when = '';
			
			if($input{'logrotate_when'} eq 'daily'){
				
				$when = '\$D';
			}
			elsif($input{'logrotate_when'} eq 'weekly'){
				
				$when = '\$W1';
		
			}
			elsif($input{'logrotate_when'} eq 'monthly'){
				
				$when = '\$M1';
				
			}
			
			my $count = $input{'logrotate_count'};
			
			$error = `sed -i '' "s/^\\(\\/[^:]*:[^0-9]*[0-9]*[^0-9]*\\)[0-9]*\\([^\\*]*\\*[^\\\$]*\\)\\\$[DWM]1*\\(.*\\)\$/\\1$count\\2$when\\3/" /usr/local/etc/newsyslog.conf.d/apache_mysql_mail.conf 2>&1`;
			
			if($error){
				
				$error = "L__Fehler beim Ändern der newsyslog-Datei__L /usr/local/etc/newsyslog.conf.d/apache_mysql_mail.conf: $error";
				
			}
			
		}				
	}
			
	$result = 'L__Fehler__L: ' . $error if $error;
	
	return error($error) if $error;
	
	$result = 'L__Die Einstellungen wurden gespeichert.__L';
	$success_text = $result;

	$template->param('result' => $result);
		
	$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_logfiles&success_text=' . encode_base64url($success_text);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub search_logs{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	
	my $ip = $input{'ip'};
	my $hostname = `/usr/bin/host -W 1 -t PTR $ip 2>/dev/null || echo 'NXDOMAIN' | /usr/bin/tail -n 1 2>/dev/null | /usr/bin/sed '/NXDOMAIN/d ; s/^.*LOCALHOST.*\$//i ; /^\$/d ; s/^.* // ; s/\.\$//' 2>/dev/null`;
	chomp($hostname);
	my $search_host_or_ip = length($hostname) ? "($ip|$hostname)" : $ip;  
	$search_host_or_ip =~ s/\./\\\./g;
#	my $result = `/usr/iports/bin/sudo /usr/bin/bzgrep -E '$search' /var/log/auth.log /var/log/auth.log.0.bz2 /var/log/auth.log.1.bz2 /var/log/messages /var/log/messages.0.bz2 /var/log/messages.1.bz2 /var/log/maillog /var/log/maillog.0.bz2 /var/log/maillog.1.bz2 /var/log/apache/httpd-error.log /var/log/apache/httpd-error.log.0.bz2 /var/log/apache/httpd-error.log.1.bz2 2>/dev/null`;
	
	my $servername = `sed 's/^.* // ; s/\$/.han-solo.net/' /etc/FQDN 2>/dev/null`;
	chomp $servername;
	
	my $result='';
	
	
		
	my %logfiles = ( 'TCPDUMP' => '/var/log/tcpdump.log', 'AUTHLOG' => '/var/log/auth.log', 'MESSAGES' => '/var/log/messages', 'MAILLOG' => '/var/log/maillog', 'HTTPDERRORLOG' => '/var/log/apache/httpd-error.log', 'MYSQLLOG' => '/var/db/mysql/' . $servername . '.err' );
	my $logname;
				
	my $prefix = $input{'whitelist'} ? 'WHITELIST' : 'BLACKLIST';	
		
	# sort explicit	
	#foreach $logname (keys %logfiles){
	foreach $logname ('TCPDUMP','AUTHLOG','MAILLOG','MESSAGES','HTTPDERRORLOG','MYSQLLOG'){
		
		my $regexfile = '/usr/local/etc/easytecc/shell2ban/' . $prefix . '_' . $logname . '.regex';
		my $base_logfile = $logfiles{$logname};
		my $groupresult='';
		
		my $index;
		foreach $index (-1 .. 6){
		
			my $logfile = $base_logfile . ($index >= 0 ? ".$index.bz2" : '');
			if(-e $logfile){
			
				#logline("debug","/usr/iports/bin/sudo /usr/bin/bzgrep -E '$search' $logfile 2>/dev/null | /usr/bin/sed -E -f $regexfile 2>/dev/null");
			
				my $search = $search_host_or_ip;
				my $logresult = '';
				
				if($logname eq 'HTTPDERRORLOG'){
					
					$search = "\\[[a-z]* $search";
						
				}
			
				if($logname eq 'HTTPDERRORLOG' && -e '/usr/local/etc/easytecc/shell2ban/WEB2BAN_HTTPDERRORLOG.regex'){
					
					$logresult = `/usr/iports/bin/sudo /usr/sbin/bzgrep -E '$search' $logfile 2>/dev/null | /usr/bin/sed -E -f $regexfile 2>/dev/null | /usr/bin/tail -r -n 100 2>/dev/null | /usr/bin/sed -f '/usr/local/etc/easytecc/shell2ban/WEB2BAN_HTTPDERRORLOG.regex' 2>/dev/null`;
				
				} else {
					
					$logresult = `/usr/iports/bin/sudo /usr/sbin/bzgrep -E '$search' $logfile 2>/dev/null | /usr/bin/sed -E -f $regexfile 2>/dev/null | /usr/bin/tail -r -n 100 2>/dev/null`;
					
				}
										
				logline("debug","/usr/iports/bin/sudo /usr/sbin/bzgrep -E '$search' $logfile 2>/dev/null");
				
				chomp($logresult);
				
				if(length($logresult)){
					
					$groupresult .= "$logresult\n";
					
				}
				
				logline("debug","##$search##$logfile##$logresult##$groupresult##");
				
			}
		}
		
		if(length($groupresult)){
				
			logline("debug","##$search##$base_logfile##$groupresult##$result##");
		
			if(length($result)){
				$result .= "\n";
			}
			
			$result .= "[$base_logfile*]\n$groupresult";
			
		}
		
	}
		
	if(!length($result)){

		$result = 'L__keine Logeinträge__L';
	
	}
	
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(modal_message('L__Logeinträge für__L ' . $ip . (length($hostname) ? " ($hostname)" : ''),'<pre>' . $result . '</pre>'));
}

sub whois{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	
	my $ip = $input{'ip'};
	my $hostname = `/usr/bin/host -W 1 -t PTR $ip 2>/dev/null | /usr/bin/tail -n 1 2>/dev/null | /usr/bin/sed '/NXDOMAIN/d ; s/^.*LOCALHOST.*\$//i ; /^\$/d ; s/^.* // ; s/\.\$//' 2>/dev/null`;
	chomp($hostname);

	my $result=`wget -q -O - http://info.api.2014.de/api/info/ip/$ip/whois 2>/dev/null | sed '/^#/d ; s/^\\(.*abuse.*\@.*\\)\$/<strong>\\1<\\/strong>/i ; s/^\\(.*[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*\\/[0-9][0-9]*.*\\)\$/<strong>\\1<\\/strong>/' 2>/dev/null | cat -s`;
	
#	my $result=`whois $ip 2>/dev/null | sed '/^#/d ; s/^\\(.*abuse.*\\)\$/<strong>\\1<\\/strong>/i' 2>/dev/null | cat -s`;
#	if($result !~ m/CIDR:/){
	
#		$result=`whois '= n + $ip' 2>/dev/null | sed '/^#/d ; s/^\\(.*abuse.*\\)\$/<strong>\\1<\\/strong>/i' 2>/dev/null | cat -s`;
	
#	}

		
	
	##my $result=`whois $ip 2>/dev/null`;
	#my $whois_server = `whois -I $ip 2>/dev/null | sed '/^whois:/!d ; s/^whois: *//' 2>/dev/null`;
	#chomp($whois_server);
	#
	#if(!length($whois_server)){
	#	
	#	$whois_server = 'whois.arin.net';
	#
	#}
	#
	#my $whois_param;
	#if($whois_server eq 'whois.arin.net'){
	#	
	#	$whois_param = " \"= n + $ip\"";
	#	
	#} else {
	#	
	#	$whois_param .= " $ip";
	#	
	#}	
	#	
	#my $result=`whois -h $whois_server $whois_param 2>/dev/null | sed '/^#/d ; s/^\\(.*abuse.*\\)\$/<strong>\\1<\\/strong>/i' 2>/dev/null | cat -s`;
	chomp($result);
		
	if(!length($result)){
	
		$result = 'L__keine Whois-Daten__L';
		
	}	
				
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(modal_message('L__Whois-Daten für__L ' . $ip . (length($hostname) ? " ($hostname)" : ''),'<pre>' . $result . '</pre>'));
}

sub show_create_dkim{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	
	my $domain = $input{'domain'};
	
	if(! -s "/etc/dkim/txt/$domain"){
			
		`/usr/sbin/opendkim-add-domain.sh $domain`;
		
	}
	
	if(! -s "/etc/dkim/txt/$domain"){
			
		$result = 'L__Es ist ein Fehler aufgetreten__L.';
		
	} else {
		
		$result = `cat "/etc/dkim/txt/$domain"`;
		chomp($result);
		
		my ($key,$type,$value) = split(/\s/,$result,3);
		$value =~ s/\"//g;
		
		$result = "L__Bitte setzen Sie in der__L <a href=\"https://www.hostnet.de/konto.html#dns:$domain\" target=\"blank\">L__DNS-Verwaltung für__L $domain</a> L__folgenden Eintrag__L:<br><br>
		L__Hostname__L<br><br>
		<pre><strong>$key</strong></pre><br>
		L__Typ__L<br><br>
		<pre><strong>$type</strong></pre><br>
		L__Ziel__L<br><br>
		<pre style=\"white-space: normal;\"><strong>$value</strong></pre><br>
		L__um DKIM für die Domain zu konfigurieren__L.";
	}	
					
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(modal_message('L__DKIM für__L ' . $domain,$result));
}

sub info_mailuser{
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'info_mailuser.html');
		
	my $mailuser = $input{'mailuser'};
	my $idn_mailuser = encode('utf-8', email_to_unicode($mailuser));
	my $domain = $input{'domain'};
	
	$template->param('mailuser' => $mailuser);
	$template->param('idn_mailuser' => $idn_mailuser);
	$template->param('domain' => $domain);
	
	#if($session && $session->param('is_mailuser')){
	#		
	#		$template->param('is_mailuser' => 1);
	#		
	#}
				
	my $mailstats=`$easytecc_prefix/mailstats.pl $mailuser 2>/dev/null`;
	chomp $mailstats;
	my @mailstats=split(/[\r\n]+/,$mailstats);
	if(!scalar @mailstats){
		return(error("L__Beim Abrufen der Details ist ein Fehler aufgetreten.__L"));
	}
	
	my $table_data = {};
	my $table_data_sum = {};
	foreach my $boxstats (@mailstats){
		
		my ($box,$guid,$messages,$unseen,$spam,$vsize) = $boxstats =~ m/^[^\/]*\/([^\(]+)\(?([a-f0-9]+)?\)?\smessages=([0-9]+)\sunseen=([0-9]+)\sspam=([0-9]+)\svsize=([0-9]+)$/;
		
		if($box ne '*'){
		
			my $box_html = $box;
			$box_html =~ s/\./&nbsp;\/&nbsp;/g;
			$table_data->{$box}{'box'} = $box_html;
			$table_data->{$box}{'box_encoded'} = encode_base64url($box_html);
			$table_data->{$box}{'guid'} = $guid;
			$table_data->{$box}{'messages'} = $messages;
			$table_data->{$box}{'unseen'} = $unseen;
			$table_data->{$box}{'spam'} = $spam;
			$table_data->{$box}{'size'} = easytecc3::getsize($vsize / 1024);
			$table_data->{$box}{'mailuser'} = $mailuser;
			$table_data->{$box}{'domain'} = $domain;
							
		} else {
			
			$table_data_sum->{$box}{'box'} = "L__Summe__L";
			$table_data_sum->{$box}{'messages'} = $messages;
			$table_data_sum->{$box}{'unseen'} = $unseen;
			$table_data_sum->{$box}{'spam'} = $spam;
			$table_data_sum->{$box}{'size'} = easytecc3::getsize($vsize / 1024);
			$table_data_sum->{$box}{'mailuser'} = $mailuser;
			$table_data_sum->{$box}{'domain'} = $domain;
							
		}
			
		
	}
	
	
	#$template->param('table_tr_info_mailuser_template' => $mailstats);
	easytecc3::table_e4($template, $table_data, 'table_tr_info_mailuser_template.html');
	easytecc3::table_e4($template, $table_data_sum, 'table_tr_info_mailuser_template_sum.html');
								
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);

}

sub import_mailuser{
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'import_mailuser.html');
		
	my $mailuser = $input{'mailuser'};
	my $idn_mailuser = encode('utf-8', email_to_unicode($mailuser));
	my $domain = $input{'domain'};
			
	$template->param('mailuser' => $mailuser);
	$template->param('idn_mailuser' => $idn_mailuser);
	$template->param('domain' => $domain);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);

}

sub exec_import_mailuser{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	my $error = '';
	my $result = $validation_result;

	logline("debug","exec_import_mailuser result:$result###");

	if($result){

	}
	else{
				
		my $host2 = `sed 's/^.* // ; s/\$/.han-solo.net/' /etc/FQDN 2>/dev/null`;
		chomp $host2;
		my $user2 = $input{'mailuser'};
		my $password2 = easytecc3::decrypt("/usr/local/etc/easytecc/$user2.pass");
		
		my $host1 = $input{'host'};
		my $user1 = $input{'user'};
		my $password1 = $input{'pass'};
				
		my $pidfile = "/tmp/imapsync-$user2.pid";		
						
		if(-f $pidfile){
			
			$error .= 'L__Es wird bereits ein Import für dieses Postfach ausgeführt__L';
		
		} else {
						
			my $imapsync = "/usr/iports/bin/imapsync";
			if(! -x $imapsync){
				
				$imapsync = "/usr/local/bin/imapsync";
				
			}
			if(! -x $imapsync){
			
				$error .= 'L__Imapsync ist auf diesem Server nicht installiert__L';	
			
			} else {
		
		
				$imapsync .= ' --maxbytespersecond 256';
		
				my $logfile = "/tmp/imapsync-$user2.log";
				my $successfile = "/tmp/imapsync-$user2.ok";
				if (-f $successfile){
					unlink $successfile;
				}
											
				$| = 1;
				#child
				unless(my $pid = fork){
					close (STDIN);
					close (STDOUT);
					close (STDERR);
					open STDIN, '>/dev/null';
					open STDOUT, '>/dev/null';
					open STDERR, '>/dev/null';
					
					#`. /etc/apache24/envvars.d/perl.env; $imapsync --host1 $host1 --user1 $user1 --password1 '$password1' --host2 $host2 --user2 $user2 --password2 '$password2' --pidfile $pidfile > $logfile 2>&1 &`;
					
					my $cmd = '';
					# suexec clears env
					$cmd .= '. /etc/apache24/envvars.d/perl.env;';
					# imapsync detects cgo otherwise
					$cmd .= 'SERVER_SOFTWARE=;';
					$cmd .= "$imapsync --host1 $host1 --user1 $user1 --password1 '$password1' --host2 $host2 --user2 $user2 --password2 '$password2' --pidfile $pidfile --logfile $logfile";
					$cmd .= ">$logfile 2>&1 ";
					$cmd .= "&& touch $successfile";
					system "$cmd &";
					
					# some time to write a pidfile
					#sleep(1);
					logline("debug","exec_import_mailuser cmd:$cmd###");
					
					#`echo ". /etc/apache24/envvars.d/perl.env" > $cmdfile`;
					#`echo SERVER_SOFTWARE= >> $cmdfile`;
					#`echo "$imapsync --host1 $host1 --user1 $user1 --password1 '$password1' --host2 $host2 --user2 $user2 --password2 '$password2' --pidfile $pidfile --logfile $logfile > $logfile 2>&1" >> $cmdfile`;
					#`. $cmdfile &`;
					
					#system "/bin/sh -c"," . /etc/apache24/envvars.d/perl.env; $imapsync","--host1",$host1," --user1 $user1 --password1 $password1 --host2 $host2 --user2 $user2 --password2 $password2 --pidfile $pidfile > $logfile 2>&1' &";
					
					
					#system ". /etc/apache24/envvars.d/perl.env; $imapsync","--host1",$host1,"--user1",$user1,"--password1","\'$password1\'","--host2",$host2,"--user2",$user2,"--password2","\'$password2\'","--pidfile",$pidfile,"> $alogfile 2>&1 &";
				
					#`/bin/sh -c '. /etc/apache24/envvars.d/perl.env; echo "\$PERL5LIB" > $logfile 2>&1' &`;
					exit(0);
				}
			
			}
					
		}
		
	}

	$result = 'L__Fehler__L: ' . $error if $error;
	
	return(html_error({'non_specific' => "$error"})) if $error;
	
	$result = 'L__Der Import wurde gestartet__L';
	$success_text = 'L__Der Import wurde gestartet__L';

	$template->param('result' => $result);
	logline("debug","result = " . $result);

	sleep(1);
	return change_popuser();
	
	$json_output{'success_message'} = '1';
	
	#$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?action=show_email&success_text=' . encode_base64url($success_text);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub stop_import_mailuser{
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
			
	my $user = $input{'mailuser'};
	my $pidfile = "/tmp/imapsync-$user.pid";		
	my $pid = `cat $pidfile`;
	chomp $pid;
	
	`kill $pid`;
	`rm -f $pidfile`; 
		
	$result = 'L__Fehler__L: ' . $error if $error;
	
	return(html_error({'non_specific' => "$error"})) if $error;
	
	$result = 'L__Der Import wurde abgebrochen__L';
	$success_text = 'L__Der Import wurde abgebrochen__L';

	$template->param('result' => $result);
	logline("debug","result = " . $result);

	#$json_output{'modal_action'} = 'change_popuser';
	#$json_output{'modal_action_args'} = '&amp;domain=' . $input{'domain'};
	
	#return show_email();
	
	#return(\$template);
	
	return change_popuser();
	
	
}

sub showlog_import_mailuser{
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
				
	my $user = $input{'mailuser'};
	my $logfile = "/tmp/imapsync-$user.log";		
	
	my $result=`cat $logfile`;
		
	if(!length($result)){

		$result = 'L__keine Logeinträge__L';
	
	} else {
		
		unlink $logfile;
		
	}
		
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(modal_message('L__Logeinträge für E-Mail-Import__L ' . $user,'<pre>' . $result . '</pre>'));
}

sub confirm_expunge_mailbox{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $guid = $input{'guid'};
	my $box = decode_base64url($input{box});
	my $mailuser = $input{'mailuser'};
	my $idn_mailuser = encode('utf-8', email_to_unicode($mailuser));
	
	my $template = HTML::Template->new(filename => 'confirm_expunge_mailbox.html');
		
	$template->param('guid' => $guid);
	$template->param('box' => $box);
	$template->param('mailuser' => $mailuser);
	$template->param('idn_mailuser' => $idn_mailuser);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
}

sub exec_expunge_mailbox{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'result.html');
	
	my $guid = $input{'guid'};
	my $mailuser = $input{'mailuser'};
	
	my $doveadm='/usr/sbin/doveadm';
	if(!defined($doveadm) || ! -f $doveadm){
		return(error("L__Fehler beim Leeren des Postfachs.__L"));
	}
	$doveadm = "/usr/iports/bin/sudo $doveadm -Dv expunge -u $mailuser";
	
	if(defined($guid)){
		$doveadm .= " mailbox-guid $guid all";
	} else {
		$doveadm .= " mailbox '*' all";
	}
		
	my $expunged = `$doveadm 2>&1 | grep -c 'expunge:' 2>/dev/null`;
	chomp $expunged;		
	my $success_text = $expunged . ' L__E-Mails gelöscht.__L';
	$template->param('result' => $success_text);
			
	# mailuser hack	
	if($session && $session->param('is_mailuser')){
		
		$json_output{'redirect_to'} = '/cgi-bin/easytecc4/index.pl?active_tab=_mailbox&success_text=' . encode_base64url($success_text);
		
	} else {
	
		$json_output{'success_message'} = '1';
		
	}
		
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
		
}

sub exec_change_autoresponder_sieve{
	
	return change_autoresponder_sieve();
	
}

sub change_autoresponder_sieve{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	
	my $template = HTML::Template->new(filename => 'change_autoresponder_sieve.html');
	$template->param('disabled' => $input{'disabled'});
		
	my $mailuser = $input{'mailuser'};
	$template->param('mailuser' => $mailuser);
		
	# copy from change_special_spamfilter / new_special_spamfilter output
	$input{'special_spam_user_domain'} = $mailuser;
	
	# keep parent modal stuff
	if($input{'parent'}){
		$template->param('parent' => $input{'parent'});
	}
	
	my $spamfilter_template;
	if(-f "/home/$mailuser/.spamproc"){
		
		$spamfilter_template = ${change_special_spamfilter()};
		
	} else {
		
		$spamfilter_template = ${new_special_spamfilter()};
		
	}
		
	foreach my $param ('special_subj_virus','special_subj_pspam','special_subj_cspam'){
		
		$template->param($param => $spamfilter_template->param($param));
		
	}
	
	# read sieve
	my ($forward_filter, $forward_to, $autoresponder_filter, $autoresponder_subject, $autoresponder_message) = read_sieve($mailuser);
		
	# easytecc autoresponder
	my $autoresponder_file = $mailuser;
	$autoresponder_file =~ s/\@/_/;
	$autoresponder_file .= '.aut';
	
	my $autoresponder_subject_easytecc = `sed '/^Subject: /!d ; s/^Subject: //' /usr/local/etc/$autoresponder_file /usr/local/etc/easytecc/$autoresponder_file 2>/dev/null`;
	chomp($autoresponder_subject_easytecc);
	
	my $autoresponder_message_easytecc = `sed -r '/^(Subject|From): /d' /usr/local/etc/$autoresponder_file /usr/local/etc/easytecc/$autoresponder_file 2>/dev/null`;
	chomp($autoresponder_message_easytecc);
	
	if(!length($autoresponder_subject_easytecc) && !length($autoresponder_message_easytecc)){
		
		$autoresponder_filter = 1;
		
	} elsif(!length($autoresponder_message)){
		
		$autoresponder_subject = encode('utf-8',$autoresponder_subject_easytecc);
		$autoresponder_message = encode('utf-8',$autoresponder_message_easytecc);
		$autoresponder_filter = 0;
	
	} else {
		
		$autoresponder_filter = 1;
		
	}
	
	# mailuser
	if(-d "/home/$mailuser/mail"){
		
		$template->param('can_filter' => 1);
				
	}
		
	if($input{'write_sieve'}){
		
		$autoresponder_filter = $input{'autoresponder_filter'};
		$autoresponder_subject = $input{'autoresponder_subject'};			
		$autoresponder_message = $input{'autoresponder_message'};
		
		if(length($autoresponder_message)){
							
			$success_text = "L__Die Abwesenheitsbenachrichtigung wurde erfolgreich angelegt.__L";
		
			if($autoresponder_filter){
				
				remove_sendmail_autoresponder($mailuser);
				write_sieve($mailuser, $forward_sieve, $autoresponder_subject, $autoresponder_message, $input{'subj_virus'}, $input{'subj_pspam'}, $input{'subj_cspam'});
			
			} else {
				
				add_sendmail_autoresponder($mailuser, $autoresponder_subject, $autoresponder_message);
				write_sieve($mailuser, $forward_sieve, '', '', $input{'subj_virus'}, $input{'subj_pspam'}, $input{'subj_cspam'});
				
			}
					
		} else {
			
			$success_text = "L__Die Abwesenheitsbenachrichtigung wurde gelöscht.__L";
			
			remove_sendmail_autoresponder($mailuser);
			write_sieve($mailuser, $forward_sieve, '', '', $input{'subj_virus'}, $input{'subj_pspam'}, $input{'subj_cspam'});
			$autoresponder_filter = 1;
			$autoresponder_subject = '';
						
		}
			
	}
		
	if($autoresponder_filter){
		
		$template->param('autoresponder_filter_on' => 'checked');
		
	} else {
		
		$template->param('autoresponder_filter_off' => 'checked');
		
	}
	
	$template->param('autoresponder_subject' => $autoresponder_subject);
	$template->param('autoresponder_message' => $autoresponder_message);
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	
	if(!$input{'parent'}){
	
		$json_output{'redirect_to'} = '&success_text=' . encode_base64url($success_text);
	
	} else {
		
		$success_text = '';
		
	}
	
	return(\$template);
	
}

sub exec_change_forward_sieve{
	
	return change_forward_sieve();
	
}

sub change_forward_sieve{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	
	my $template = HTML::Template->new(filename => 'change_forward_sieve.html');
	$template->param('disabled' => $input{'disabled'});
		
	my $mailuser = $input{'mailuser'};
	$template->param('mailuser' => $mailuser);
			
	# copy from change_special_spamfilter / new_special_spamfilter output
	$input{'special_spam_user_domain'} = $mailuser;
	
	# keep parent modal stuff
	if($input{'parent'}){
		$template->param('parent' => $input{'parent'});
	}
	
	my $spamfilter_template;
	if(-f "/home/$mailuser/.spamproc"){
		
		$spamfilter_template = ${change_special_spamfilter()};
		
	} else {
		
		$spamfilter_template = ${new_special_spamfilter()};
		
	}
		
	foreach my $param ('special_subj_virus','special_subj_pspam','special_subj_cspam'){
			
		$template->param($param => $spamfilter_template->param($param));
		
	}
	
	# read sieve
	my ($forward_filter, $forward_to, $autoresponder_filter, $autoresponder_subject, $autoresponder_message) = read_sieve($mailuser);
	if(scalar @{$forward_to}){
		
		$forward_filter = 'sieve';
					
	}
	
	# external
	my $sendmail_target = $mailuser;
	
	# add random local part to catch all
	if($mailuser =~ m/^@/){
		
		$sendmail_target = 'catchall' . $$ . $sendmail_target;
		
	}
		
	my $sendmail_forward = `/usr/sbin/sendmail -d27 -bv $sendmail_target 2>/dev/null | grep -m 1 'aliased to' 2>/dev/null  | sed 's/^.*aliased to // ; s/"//g' 2>/dev/null`;
	chomp($sendmail_forward);
	
	# single virtmaps line
	if(!length($sendmail_forward)){
		
		$sendmail_forward = `/usr/sbin/sendmail -d60 -bv $sendmail_target 2>/dev/null | grep -m 1 'map_lookup(virtuser' 2>/dev/null | sed 's/.*> // ; s/ .*//' 2>/dev/null`;
		
	}
	
	$sendmail_forward = get_sendmail_forward($mailuser);
	my %mailpasswd = %{easytecc3::get_mailpasswd()->file_parsed_hash()};
	
	my $forward_target;
	foreach $forward_target (split(/,\s*/,$sendmail_forward)){
				
		# fwd_as_att
		if($forward_target =~ m/fwd_as_att\s([^"]*)"/){
			
			$forward_target = $1;
			foreach $forward_target (split(/\s+/,$forward_target)){
				
				if($forward_target !~ /^\//){
			
					push(@{$forward_to}, $forward_target);
												
				}		
												
			}
			$forward_filter = 'att';
			
		}
		
		# email / user 
		elsif($forward_target =~ m/^([^\|\/\s\"]+)$/ && !exists($mailpasswd{$1})){
			
			push(@{$forward_to}, $1);
			
			if($forward_filter ne 'att'){
				
				$forward_filter = 'off';
				
			}
			
		}
							
	}
		
	my $forward_as_att_file = "/usr/local/etc/easytecc/$mailuser.fwdmsg";
	my $fh;
	my $fwd_as_att_message;
	my $fwd_as_att_from;
	my $fwd_as_att_subject;
	
	if(-f $forward_as_att_file && open($fh, '<', $forward_as_att_file)){

		$fwd_as_att_text = '';
	
        while($line = <$fh>){

			chomp($line);

			# from
			if($line =~ m/^From:\s*(.+)$/ && !length($fwd_as_att_from)){

				$fwd_as_att_from = $1;

			}
			# subject
			elsif($line =~ m/^Subject:\s*(.+)$/ && !length($fwd_as_att_subject)){

				$fwd_as_att_subject = $1;

			}
			# ignore leading blank lines
			elsif(length($fwd_as_att_text) || length($line)){

				$fwd_as_att_text .= $line . "\n";

			}

        }

        close $fh;

        if($fwd_as_att_text =~ m/^\s*$/s){

               $fwd_as_att_text = undef;

        }
		
		$template->param('forward_from' => $fwd_as_att_from);
		$template->param('forward_subject' => $fwd_as_att_subject);
		$template->param('forward_text' => $fwd_as_att_text);
		
	}
	
	my $forward_text_count = scalar split(/\n/,$fwd_as_att_text) + 1;
	if($forward_text_count < 6){
		
		$forward_text_count = 6;
		
	}
	$template->param('forward_text_count' => $forward_text_count);
			
	# unique
	@{$forward_to} = keys %{{ map { $_ => 1 } @{$forward_to} }};
	my $forward_sieve = $forward_to;
	
	my $forward_to_count = scalar @{$forward_to} + 1;
	if($forward_to_count < 3){
		
		if($forward_to_count == 1){
		
			$forward_filter = 'att';
				
		}
		
		$forward_to_count = 3;
		
	}
	$template->param('forward_to_count' => $forward_to_count);
	
	# mailuser
	if(-d "/home/$mailuser/mail"){
		
		$template->param('can_filter' => 1);
				
	}
			
	if($input{'write_sieve'}){
				
		$forward_filter = $input{'forward_filter'};
		$forward_from = $input{'forward_from'};
		$forward_subject = $input{'forward_subject'};
		$forward_text = $input{'forward_text'};
		
		$template->param('forward_from' => encode('utf-8',$forward_from));	
		$template->param('forward_subject' => encode('utf-8',$forward_subject));
		$template->param('forward_text' => encode('utf-8',$forward_text));
		
		# no mailuser
		if(! -d "/home/$mailuser/mail" && $forward_filter eq 'sieve'){
			
			$forward_filter = 'att';
			
		}
									
		my @forward_to;
		if(length($input{'forward_to'})){
			
			chomp($input{'forward_to'});
			@forward_to = split(/[\r\n,; ]+/,$input{'forward_to'});
											
		}
		$forward_to = \@forward_to;
		
		$forward_sieve = [];
		my $forward_sendmail = [];
								
		if(@forward_to){

			if($forward_filter eq 'sieve'){
				
				$forward_sieve = $forward_to;
															
			} else {
				
				$forward_sendmail = $forward_to;
												
			}
			
			$success_text = "L__Die Weiterletungen wurden erfolgreich angelegt.__L";
					
		} else {
			
			$success_text = "L__Die Weiterletungen wurden gelöscht.__L";

			$forward_filter = 'att'; 
			
		}
		
		if(@{$forward_sendmail}){
				
			if($forward_filter eq 'att'){
				
				add_sendmail_forward_as_att($mailuser,$forward_from,$forward_subject,$forward_text,$forward_sendmail);
				
			} else {
				
				add_sendmail_forward($mailuser,$forward_sendmail);
				
			}
							
		} else {
			
			remove_sendmail_forward($mailuser);
							
		}
		
		write_sieve($mailuser, $forward_sieve, $autoresponder_subject, $autoresponder_message, $input{'subj_virus'}, $input{'subj_pspam'}, $input{'subj_cspam'});
				
	}
				
	
	if($forward_filter eq 'att'){
		
		$template->param('forward_filter_att' => 'checked');
		
	} elsif($forward_filter eq 'sieve'){
		
		$template->param('forward_filter_sieve' => 'checked');
		
	} else {
		
		$template->param('forward_filter_off' => 'checked');
		
	}
	
	$template->param('forward_to' => join("\n",@{$forward_to}));
	
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	
	if(!$input{'parent'}){
	
		$json_output{'redirect_to'} = '&success_text=' . encode_base64url($success_text);
	
	} else {
		
		$success_text = '';
		
	}
	
	return(\$template);
	
}

sub mailuser_interface{
	
	if(!$session || !$session->param('is_mailuser')){
		return start();
	}
	
	my $mailuser = $session->param('user');
	my $mailaddress = $session->param('mailaddress');
	
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $template = HTML::Template->new(filename => 'mailuser_interface.html');
	
	# user + address
	$template->param('mailuser' => $mailuser);
	$template->param('mailaddress' => $mailaddress);
	
	# password
	$template->param('show_password' => 1);
	$template->param('active_tab_password' => 1);

	# 2fa
	if($fb){
		
		$template->param('show_2fa' => 1);
		
	} else {
		
		$template->param('show_2fa' => 0);
		
	}
		
	if(defined($input{'2fa'}) && $input{'2fa'} ne 'noop'){
	
		if($input{'2fa'} eq 'new'){
			
			my $qrcode_url = `/usr/local/bin/google-authenticator -C -t -d -f -l $mailuser -i easyTECC -Q UTF8 -r 3 -R 30 -s /usr/local/etc/easytecc/2fa/$mailuser.setup -S 30 -w 3`;
			($qrcode_url) = $qrcode_url =~ m/(https:\/\/www\.google\.com\/chart[^\s]+)/;
			#$qrcode_url =~ s/https:\/\/www\.google\.com/https:\/\/chart.googleapis.com/;
			`wget -q -O - '$qrcode_url' | openssl base64 | tr -d '\n' > /usr/local/etc/easytecc/2fa/$mailuser.qr`;
						
		}
		elsif($input{'2fa'} eq 'ok'){
			
			`mv /usr/local/etc/easytecc/2fa/$mailuser.setup /usr/local/etc/easytecc/2fa/$mailuser`;
			`rm /usr/local/etc/easytecc/2fa/$mailuser.qr`;
			
		}
		elsif($input{'2fa'} eq 'del'){
			
			`rm -f /usr/local/etc/easytecc/2fa/$mailuser*`;
			
		}
		
	}	
			
	# 2fa setup
	if(-f "/usr/local/etc/easytecc/2fa/$mailuser.setup"){
		
		$template->param('2fa_setup' => 1);
		$qrcode_url = 'data:image/png;base64,' . `cat /usr/local/etc/easytecc/2fa/$mailuser.qr`;
		$template->param('qrcode_url' => $qrcode_url);
		
	}
		
	# 2fa present
	if( -f "/usr/local/etc/easytecc/2fa/$mailuser"){
		
		$template->param('2fa_active' => 1);
		
	}
		
	# mailbox
	$template->param('show_mailbox' => 1);
		
	# quota
	my $mailquota = {};
	
	if (easytecc3::extern_mx() || $fb) {
		$mailpasswd = easytecc3::get_mailpasswd();
		my %passwd = %{$mailpasswd->file_parsed_hash()};
		($mailquota, undef, undef, undef) = easytecc3::getquota_mail(\%passwd);
	}
	else{
		($mailquota, undef, undef, undef) = easytecc3::getquota_ftp();
	}

	$template->param('quota_max' => easytecc3::getsize($mailquota->{$mailuser}{'quota'}));
	$template->param('quota_use' => easytecc3::getsize($mailquota->{$mailuser}{'use'}));
	if($mailquota->{$mailuser}{'quota'} > 0){
		$template->param('quota_percent' => sprintf("%.0f", ($mailquota->{$mailuser}{'use'}/$mailquota->{$mailuser}{'quota'})*100));
	} elsif($mailquota->{$mailuser}{'use'} > 0) {
		$template->param('quota_percent' => 100);
	} else {
		$template->param('quota_percent' => 0);
	}
	
	# mailboxes
	if($fb){
		
		$template->param('show_mailboxes' => 1);
	
		my $mailstats=`$easytecc_prefix/mailstats.pl $mailuser 2>/dev/null`;
		chomp $mailstats;
		my @mailstats=split(/[\r\n]+/,$mailstats);
		if(!scalar @mailstats){
			my $error_tab_mailbox = error("L__Beim Abrufen der Ordner ist ein Fehler aufgetreten.__L");
			$template->param('error_tab_mailbox' => $$error_tab_mailbox->output());
		}
		
		my @mailboxes = {};
		foreach my $boxstats (@mailstats){
			
			my ($box,$guid,$messages,$unseen,$spam,$vsize) = $boxstats =~ m/^[^\/]*\/([^\(]+)\(?([a-f0-9]+)?\)?\smessages=([0-9]+)\sunseen=([0-9]+)\sspam=([0-9]+)\svsize=([0-9]+)$/;
			
			if($box ne '*'){
			
				my $box_html = $box;
				$box_html =~ s/\./&nbsp;\/&nbsp;/g;
				
				push @mailboxes, {
					box => $box_html,
					ttl => $ttl,
					box_encoded => encode_base64url($box_html),
					guid => $guid,
					messages => $messages,
					unseeen => $unseen,
					spam => $spam,
					size =>  easytecc3::getsize($vsize / 1024),
				};
				
								
			} else {
				
				$template->param('sum_messages' => $messages);
				$template->param('sum_unseen' => $unseen);
				$template->param('sum_spam' => $spam);
				$template->param('sum_size' => easytecc3::getsize($vsize / 1024));
								
			}
				
			
		}
	
		$template->param('mailboxes' => \@mailboxes);	
				
	} else {
		
		$template->param('show_mailboxes' => 0);
		
	}
		
	# spamfilter
	$template->param('show_spamfilter' => 1);
	
	# copy from change_special_spamfilter / new_special_spamfilter output
	$input{'special_spam_user_domain'} = $mailuser;
	
	my $spamfilter_template;
	if(-f "/home/$mailuser/.spamproc"){
		
		$spamfilter_template = ${change_special_spamfilter()};
		
	} else {
		
		$spamfilter_template = ${new_special_spamfilter()};
		
	}
		
	foreach my $param ($spamfilter_template->param()){
			
		$template->param($param => $spamfilter_template->param($param));
		
	}
		
	# forward + autoresponder
	if($mailaddress){
	
		$template->param('show_forward' => 1);
		$template->param('show_autoresponder' => 1);

	} else {
		
		$template->param('show_forward' => 0);
		$template->param('show_autoresponder' => 0);
		
	}
	
	if($fb && $mailuser eq $mailaddress){
		
		$template->param('can_filter' => 1);
		
	} else {
		
		$template->param('can_filter' => 0);
		
	}
		
	# read sieve
	my ($forward_filter, $forward_to, $autoresponder_filter, $autoresponder_subject, $autoresponder_message) = read_sieve($mailuser);
	if($fb && scalar @{$forward_to}){
		
		$forward_filter = 'sieve';
					
	}
	
	my $sendmail_target = $mailaddress;
	
	# add random local part to catch all
	if($sendmail_target =~ m/^@/){
		
		$sendmail_target = 'catchall' . $$ . $sendmail_target;
		
	}
	
	my $sendmail_forward = `/usr/sbin/sendmail -d27 -bv $sendmail_target 2>/dev/null | grep -m 1 'aliased to' 2>/dev/null  | sed 's/^.*aliased to // ; s/"//g' 2>/dev/null`;
	chomp($sendmail_forward);
	
	# single virtmaps line
	if(!length($sendmail_forward)){
		
		$sendmail_forward = `/usr/sbin/sendmail -d60 -bv $sendmail_target 2>/dev/null | grep -m 1 'map_lookup(virtuser' 2>/dev/null | sed 's/.*> // ; s/ .*//' 2>/dev/null`;
		
	}
	
	$sendmail_forward = get_sendmail_forward($mailaddress);
	
	my $forward_internal = '';
	my $forward_internal_count = 0;
	
	my $forward_target;
	foreach $forward_target (split(/,\s*/,$sendmail_forward)){
		
		# local
		if(
		   $fb && $forward_target =~ m/^.*procmail\s-a\s([^\@\s]+\@[^\@]+)/ ||
		   !$fb && $forward_target =~ m/^([^\@\|]+)$/
		){
		  
		   $forward_internal .= "$1\n";
		   $forward_internal_count++;
		}
		# email
		elsif($forward_target =~ m/^([^\@\s]+\@[^\@]+)$/){
			
			push(@{$forward_to}, $1);
			
			if($forward_filter ne 'att'){
				
				$forward_filter = 'off';
				
			}
			
		}
		# fwd_as_att
		elsif($forward_target =~ m/^\|\/usr\/sbin\/fwd_as_att\s(.*\.fwdmsg\s)*(.*)$/){
			
			push(@{$forward_to}, split(/\s/, $2));
			$forward_filter = 'att';
			
		}
			
		
	}
	
	$template->param('forward_internal' => $forward_internal);
	$template->param('forward_internal_count' => $forward_internal_count);
		
	my $forward_as_att_file = "/usr/local/etc/easytecc/$mailaddress.fwdmsg";
	my $fh;
	my $fwd_as_att_message;
	my $fwd_as_att_subject;
	
	my $fwd_as_att_from;
	my $fwd_as_att_subject;
	
	if(-f $forward_as_att_file && open($fh, '<', $forward_as_att_file)){

		$fwd_as_att_text = '';
	
        while($line = <$fh>){

			chomp($line);

			# from
			if($line =~ m/^From:\s*(.+)$/ && !length($fwd_as_att_from)){

				$fwd_as_att_from = $1;

			}
			# subject
			elsif($line =~ m/^Subject:\s*(.+)$/ && !length($fwd_as_att_subject)){

				$fwd_as_att_subject = $1;

			}
			# ignore leading blank lines
			elsif(length($fwd_as_att_text) || length($line)){

				$fwd_as_att_text .= $line . "\n";

			}

        }

        close $fh;

        if($fwd_as_att_text =~ m/^\s*$/s){

               $fwd_as_att_text = undef;

        }
		
		$template->param('forward_from' => $fwd_as_att_from);
		$template->param('forward_subject' => $fwd_as_att_subject);
		$template->param('forward_text' => $fwd_as_att_text);
		
	}
	
	my $forward_text_count = scalar split(/\n/,$fwd_as_att_text) + 1;
	if($forward_text_count < 6){
		
		$forward_text_count = 6;
		
	}
	$template->param('forward_text_count' => $forward_text_count);
			
	# unique
	@{$forward_to} = keys %{{ map { $_ => 1 } @{$forward_to} }};
	my $forward_sieve = $forward_to;
	
	my $forward_to_count = scalar @{$forward_to} + 1;
	if($forward_to_count < 3){
		
		if($forward_to_count == 1){
		
			$forward_filter = 'att';
			
		}
				
		$forward_to_count = 3;
		
	}
	$template->param('forward_to_count' => $forward_to_count);
	
	# easytecc autoresponder
	my $autoresponder_file = $mailaddress;
	$autoresponder_file =~ s/\@/_/;
	$autoresponder_file .= '.aut';
	
	my $autoresponder_subject_easytecc = `sed '/^Subject: /!d ; s/^Subject: //' /usr/local/etc/$autoresponder_file /usr/local/etc/easytecc/$autoresponder_file 2>/dev/null`;
	chomp($autoresponder_subject_easytecc);
	
	my $autoresponder_message_easytecc = `sed -r '/^(Subject|From): /d' /usr/local/etc/$autoresponder_file /usr/local/etc/easytecc/$autoresponder_file 2>/dev/null`;
	chomp($autoresponder_message_easytecc);
	
	if(!length($autoresponder_subject_easytecc) && !length($autoresponder_message_easytecc)){
		
		if($fb){
			
			$autoresponder_filter = 1;
			
		}
		
	} elsif(!length($autoresponder_message)){
		
		$autoresponder_subject = encode('utf-8',$autoresponder_subject_easytecc);
		$autoresponder_message = encode('utf-8',$autoresponder_message_easytecc);
		$autoresponder_filter = 0;
	
	} else {
		
		if($fb){
			
			$autoresponder_filter = 1;
			
		}
		
	}
			
	if($input{'write_sieve'}){
		
		if($input{'active_tab'} eq '_forward'){
				
			$forward_filter = $input{'forward_filter'};
			$forward_from = $input{'forward_from'};
			$forward_subject = $input{'forward_subject'};
			$forward_text = $input{'forward_text'};
			
			$template->param('forward_from' => encode('utf-8',$forward_from));
			$template->param('forward_subject' => encode('utf-8',$forward_subject));
			$template->param('forward_text' => encode('utf-8',$forward_text));
										
			my @forward_to;
			if(length($input{'forward_to'})){
				
				chomp($input{'forward_to'});
				@forward_to = split(/[\r\n,; ]+/,$input{'forward_to'});
												
			}
			$forward_to = \@forward_to;
			
			$forward_sieve = [];
			my $forward_sendmail = [];
									
			if(@forward_to){
	
				if($forward_filter eq 'sieve'){
					
					$forward_sieve = $forward_to;
																
				} else {
					
					$forward_sendmail = $forward_to;
													
				}
				
				$success_text = "L__Die Weiterletungen wurden erfolgreich angelegt.__L";
						
			} else {
				
				$success_text = "L__Die Weiterletungen wurden gelöscht.__L";
	
				$forward_filter = 'att'; 
				
			}
			
			if(@{$forward_sendmail}){
				
				if($forward_filter eq 'att'){
					
					add_sendmail_forward_as_att($mailaddress,$forward_from,$forward_subject,$forward_text,$forward_sendmail);
					
				} else {
					
					add_sendmail_forward($mailaddress,$forward_sendmail);
					
				}
								
			} else {
				
				remove_sendmail_forward($mailaddress);
								
			}
			
			write_sieve($mailuser, $forward_sieve, $autoresponder_subject, $autoresponder_message, $input{'subj_virus'}, $input{'subj_pspam'}, $input{'subj_cspam'});
																	
		}
		elsif($input{'active_tab'} eq '_autoresponder'){
			
			$autoresponder_filter = $input{'autoresponder_filter'};
			$autoresponder_subject = $input{'autoresponder_subject'};			
			$autoresponder_message = $input{'autoresponder_message'};
			
			if(length($autoresponder_message)){
							
				$success_text = "L__Die Abwesenheitsbenachrichtigung wurde erfolgreich angelegt.__L";
			
				if($autoresponder_filter){
					
					remove_sendmail_autoresponder($mailaddress);
					write_sieve($mailuser, $forward_sieve, $autoresponder_subject, $autoresponder_message, $input{'subj_virus'}, $input{'subj_pspam'}, $input{'subj_cspam'});
				
				} else {
					
					add_sendmail_autoresponder($mailaddress, $autoresponder_subject, $autoresponder_message);
					write_sieve($mailuser, $forward_sieve, '', '', $input{'subj_virus'}, $input{'subj_pspam'}, $input{'subj_cspam'});
					
				}
				
				$autoresponder_subject = encode('utf-8',$autoresponder_subject);
				$autoresponder_message = encode('utf-8',$autoresponder_message);
						
			} else {
				
				$success_text = "L__Die Abwesenheitsbenachrichtigung wurde gelöscht.__L";
				
				remove_sendmail_autoresponder($mailaddress);
				write_sieve($mailuser, $forward_sieve, '', '', $input{'subj_virus'}, $input{'subj_pspam'}, $input{'subj_cspam'});
				$autoresponder_filter = 1;
				$autoresponder_subject = '';
							
			}
						
		}
				
	}
	
				
	if($forward_filter eq 'att'){
		
		$template->param('forward_filter_att' => 'checked');
		
	} elsif($forward_filter eq 'sieve'){
		
		$template->param('forward_filter_sieve' => 'checked');
		
	} else {
		
		$template->param('forward_filter_off' => 'checked');
		
	}
	
	$template->param('forward_to' => join("\n",@{$forward_to}));
	
	if($autoresponder_filter){
		
		$template->param('autoresponder_filter_on' => 'checked');
		
	} else {
		
		$template->param('autoresponder_filter_off' => 'checked');
		
	}
	
	$template->param('autoresponder_subject' => $autoresponder_subject);
	$template->param('autoresponder_message' => $autoresponder_message);
		
	if($input{'active_tab'}){
		
		$template->param('active_tab_password' => 0);
		$template->param('active_tab_mailbox' => 0);
		$template->param('active_tab_spamfilter' => 0);
		$template->param('active_tab_forward' => 0);
		$template->param('active_tab_autoresponder' => 0);
		$template->param('active_tab' . $input{'active_tab'} => 1);
		
	}
	
	$template->param('show_webmail' => 1);
			
	logline("debug","<<< Leaving ".(caller(0))[3]."().");
	return(\$template);
		
}

sub read_sieve{
	
	my $mailuser = shift;
	
	# forward
	my $forward_filter = 1;
	my @forward_to;

	# autoresponder	
	my $autoresponder_filter = 1;
	my $autoresponder_subject;
	my $autoresponder_message;
	my $autoresponder_message_multiline = 0;
		
	# maybe dos	
	my @sieverules = split(/\r?\n/,`cat /home/$mailuser/.dovecot.sieve 2>/dev/null`);

	my $forward = 0;
	my $autoresponder = 0;
	
	foreach my $line (@sieverules){
	
		chomp($line);
	
		if($line eq '# rule:[Weiterleitung [easyTECC]]'){
			$forward = 1;
		}
		elsif($line eq '# rule:[Abwesenheit [easyTECC]]'){
			$autoresponder = 1;
		}
		elsif($line eq '}'){
			$forward = $autoresponder = $autoresponder_message_multiline = 0;
		}
		elsif($forward){
			
			if($line eq 'if anyof (true)'){
				
				$forward_filter = 0;
				
			}
			elsif($line =~ m/^\s*redirect\s+\"([^\"]+)\";?$/){
				
				push(@forward_to,$1);
				
			}
						
		}
		elsif($autoresponder){
			
			if($line eq 'if anyof (true)'){
				
				$autoresponder_filter = 0;
				
			}
			elsif($line =~ m/^\s*:subject\s+\"(.*)\";?$/){
				
				$autoresponder_subject = $1;
								
			}
			elsif($line =~ m/^\s*(:mime )?text:\s*$/ && !$autoresponder_message_multiline){
				
				$autoresponder_message_multiline = 1;
				
			}
			elsif($autoresponder_message_multiline){
				
				$autoresponder_message .= $line . "\n";
				
			}
			elsif($line =~/^\s*\"(.*)\";?$/){
		
				$autoresponder_message = $1;
				
			}
						
		}
		
	}
	
	$autoresponder_message =~ s/\n\.\n;$//s;
	chomp($autoresponder_message);
		
	if(!$forward){
		
		$forward_filter = 0;
		
	}
	
	if(!$autoresponder){
	
		$autoresponder_filter = 0;
		
	}
			
	return ($forward_filter, \@forward_to, $autoresponder_filter, $autoresponder_subject, $autoresponder_message);
		
}

sub write_sieve{
	
	my ($mailuser, $forward_to, $autoresponder_subject, $autoresponder_message, $subj_virus, $subj_pspam, $subj_cspam)  = @_;
	
	$autoresponder_subject = encode('utf-8',$autoresponder_subject);
	$autoresponder_message = encode('utf-8',$autoresponder_message);
	
	my $forward_filter = 1;
	my $autoresponder_filter = 1;
	
	my $autoresponder_message_multiline = 0;
	my $foreign_sieverules = '';
	
	my $sieve_file = `/usr/bin/grep managesieve /usr/local/www/roundcube/config/config.inc.php && echo managesieve.sieve || echo roundcube.sieve`;
	chomp($sieve_file);
		
	# fix perms and links
	if(! -d "/home/$mailuser/sieve"){
		
		`mkdir -p /home/$mailuser/sieve`;
		`/usr/iports/bin/sudo /usr/sbin/chown.pl virtmail:vuser /home/$mailuser/sieve`;
		`/usr/iports/bin/sudo /usr/sbin/chmod.pl 770 /home/$mailuser/sieve 2>/dev/null`;

		`touch /home/$mailuser/sieve/$sieve_file 2>/dev/null`;
		`/usr/iports/bin/sudo /usr/sbin/chown.pl virtmail:vuser /home/$mailuser/sieve/$sieve_file`;
		`/usr/iports/bin/sudo /usr/sbin/chmod.pl 660 /home/$mailuser/sieve/$sieve_file 2>/dev/null`;
					
	}

	if(! -e "/home/$mailuser/.dovecot.sieve"){
		
		`ln -s /home/$mailuser/sieve/$sieve_file /home/$mailuser/.dovecot.sieve 2>/dev/null`;
		`/usr/iports/bin/sudo /usr/sbin/chown.pl virtmail:vuser /home/$mailuser/.dovecot.sieve`;
					
	}
	
	# maybe dos	
	my @sieverules = split(/\r?\n/,`cat /home/$mailuser/.dovecot.sieve 2>/dev/null`);

	my $easytecc_rule = 0;
	foreach my $line (@sieverules){

		chomp($line);
	
		if($line =~ m/^# rule:\[(Weiterleitung|Abwesenheit) \[easyTECC\]\]/){
			$easytecc_rule = 1;
		}
		elsif($easytecc_rule){

			if($line eq '}'){

				$easytecc_rule = 0;
	
			}

		}
		else {
			
			$foreign_sieverules .= $line . "\n";
			
		}
		
	}
	
	$foreign_sieverules =~ s/\n+$//s;
	
	my $filter = '';
	if(length($subj_virus)){
		
		$filter .= "not header :contains \"Subject\" \"$subj_virus\",\n";
		
	}
	if(length($subj_pspam)){
		
		$filter .= "not header :contains \"Subject\" \"$subj_pspam\",\n";
		$filter .= "not header :contains \"X-Spam-Info\" \"$subj_pspam\",\n";
		
	}
	if(length($subj_cspam)){
		
		$filter .= "not header :contains \"Subject\" \"$subj_cspam\",\n";
		$filter .= "not header :contains \"X-Spam-Info\" \"$subj_cspam\",\n";
		
	}
	
	$filter =~ s/,\n$//s;
	
	if(!length($filter)){
		
		$forward_filter = $autoresponder_filter = 0;
		
	}
				
	my $easytecc_sieverules = '';
	if(@{$forward_to}){
		
		$easytecc_sieverules .= "# rule:[Weiterleitung [easyTECC]]\n";
		
		if($forward_filter){
						
			$easytecc_sieverules .= "if allof ($filter)\n";
			
		} else {
			
			$easytecc_sieverules .= "if anyof (true)\n";
			
		}

		$easytecc_sieverules .= "{\n";
		
		my $to_address;
		foreach $to_address (@{$forward_to}){
			
			$easytecc_sieverules .= "\tredirect \"$to_address\";\n";
						
		}
		
		$easytecc_sieverules .= "}\n";

	}
		
	if(length($autoresponder_subject) && length($autoresponder_message)){
		
		$easytecc_sieverules .= "# rule:[Abwesenheit [easyTECC]]\n";
		
		if($foreign_sieverules !~ m/^\s*require \["vacation"\];/sm){
			
			$foreign_sieverules = "require [\"vacation\"];\n$foreign_sieverules"
			
		}
		
		if($forward_filter){
						
			$easytecc_sieverules .= "if allof ($filter)\n";
			
		} else {
			
			$easytecc_sieverules .= "if anyof (true)\n";
			
		}

		$easytecc_sieverules .= "{\n";
		$easytecc_sieverules .= "\tvacation\n";
		$easytecc_sieverules .= "\t\t:subject \"$autoresponder_subject\"\n";
		$easytecc_sieverules .= "\t\t";
		
		if($autoresponder_message =~ m/^MIME-Version:/){
			
			$easytecc_sieverules .= ":mime ";
			
		}
		
		$easytecc_sieverules .= "text:\n$autoresponder_message\n";
		$easytecc_sieverules .= ".\n;\n}\n";
				
	}
	
	open(SIEVE, '>', "/home/$mailuser/.dovecot.sieve");
	binmode(SIEVE);
	print SIEVE $foreign_sieverules . "\n" . $easytecc_sieverules;
	close(SIEVE);						
	
	#/usr/iports/bin/sievec -D /home/$mailuser/sieve/roundcube.sieve
	
#	`echo '$foreign_sieverules' > /home/$mailuser/sieve/roundcube.sieve`;
#	`echo '$easytecc_sieverules' >> /home/$mailuser/sieve/roundcube.sieve`;
	
	logline("debug","sieve $foreign_sieverules");
	logline("debug","sieve $easytecc_sieverules");
				
}


sub remove_sendmail_autoresponder{
	
	my $mailuser = shift;
	
	my $autoresponder_file = $mailuser;
	$autoresponder_file =~ s/\@/_/;
	$autoresponder_file .= '.aut';
	
	if(-f "/usr/local/etc/easytecc/$autoresponder_file"){
		
		`rm -f /usr/local/etc/easytecc/$autoresponder_file`;
		
	} else {
		
		return;
	}
		
	my $virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
	$virtmaps->read_file;
	my %virtmaps = %{$virtmaps->file_parsed_hash()};

	my $aliases = file->new({file_name => '/etc/mail/aliases'});
	$aliases->read_file;
	my %aliases = %{$aliases->file_parsed_hash()};

	my @new_virtmaps = ();
	my @new_aliases = ();
		
	my $virtmaps_rhs = '';
	foreach($virtmaps->file_content){
		
		if(/^$mailuser\s+(.*)$/){
			
			$virtmaps_rhs = $1;
			
		} 
			
		push(@new_virtmaps, $_);
		
	}

	foreach($aliases->file_content){
		
		if(/^$virtmaps_rhs\s*:\s*(.*)$/){
			
			my $aliases = '';
			my @aliases = split(/,\s*/,$1);
						
			foreach(@aliases){
				
				if(! /\/autoresponder/){
					
					if(length($aliases)){
						
						$aliases .= ',';
						
					}
					$aliases .= $_;
					
				}
				
			}	
			
			push @new_aliases, "$virtmaps_rhs: $aliases";
			
		} else {
			
			push @new_aliases, $_;
			
		}
		
	}

	$aliases->file_content(\@new_aliases);
	$aliases->write_file;
	
	@new_virtmaps = map(lc, @new_virtmaps);
	$virtmaps->file_content(\@new_virtmaps);
	$virtmaps->write_file;
		
}

sub add_sendmail_autoresponder{
	
	my $mailuser = shift;
	my $subject = shift;
	my $text = shift;
	
	my ($user,$domain) = split(/@/,$mailuser);
	my $autoreply = file->new({	file_name => '/usr/local/etc/easytecc/' . $user . '_' . $domain . '.aut', user => $user, domain => $domain});
	my @autoreply_content = ("From: $mailuser", "Subject: $subject\n", "$text");
	$autoreply->file_content(\@autoreply_content);
	$autoreply->write_file;
		
	my $virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
	$virtmaps->read_file;
	my %virtmaps = %{$virtmaps->file_parsed_hash()};

	my $aliases = file->new({file_name => '/etc/mail/aliases'});
	$aliases->read_file;
	my %aliases = %{$aliases->file_parsed_hash()};

	my @new_virtmaps = ();
	my @new_aliases = ();
		
	my $virtmaps_rhs = $mailuser;
	$virtmaps_rhs =~ s/@/_/;
	$virtmaps_rhs .= '_spl';
		
	my $found = 0;
	foreach($virtmaps->file_content){
		
		if(/^$mailuser\s+(.*)$/){
			
			push(@new_virtmaps, "$mailuser\t$virtmaps_rhs");
			$found = 1;
			
		} else {
			
			push(@new_virtmaps, $_);
			
		}	
		
	}
	
	if(!$found){
		
		push(@new_virtmaps, "$mailuser\t$virtmaps_rhs");
		
	}
	
	$found = 0;
	foreach($aliases->file_content){
		
		if(/^$virtmaps_rhs\s*:\s*(.*)$/){
						
			foreach my $alias (split(/,\s*/,$1)){
				
				if($alias !~ /\/autoresponder/){
					
					push @aliases, $alias; 
					
				}
				
			}
	
			push @aliases, "\"|$autoresponder /usr/local/etc/easytecc/" . $user . '_' . $domain . '.aut' . "\"";
			# unique
			@aliases = keys %{{ map { $_ => 1 } @aliases }};
			my $aliases = join(',',@aliases);
								
			push @new_aliases, "$virtmaps_rhs: $aliases";
			$found = 1;
			
		} else {
			
			push @new_aliases, $_;
			
		}
		
	}
	
	if(!$found){
		
		push @new_aliases, "$virtmaps_rhs: \"|$autoresponder /usr/local/etc/easytecc/" . $user . '_' . $domain . '.aut' . "\"";
		
	}
	
	$aliases->file_content(\@new_aliases);
	$aliases->write_file;
	
	@new_virtmaps = map(lc, @new_virtmaps);
	$virtmaps->file_content(\@new_virtmaps);
	$virtmaps->write_file;
	
}

sub remove_sendmail_forward{
	
	my $mailuser = shift;
	
	my $virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
	$virtmaps->read_file;
	my %virtmaps = %{$virtmaps->file_parsed_hash()};

	my $aliases = file->new({file_name => '/etc/mail/aliases'});
	$aliases->read_file;
	my %aliases = %{$aliases->file_parsed_hash()};

	my @new_virtmaps = ();
	my @new_aliases = ();
		
	my $virtmaps_rhs = '';
	foreach($virtmaps->file_content){
		
		if(/^$mailuser\s+(.*)$/){
			
			$virtmaps_rhs = $1;
			
		} 
			
		push(@new_virtmaps, $_);
		
	}

	foreach($aliases->file_content){
		
		if(/^$virtmaps_rhs\s*:\s*(.*)$/){
			
			my $aliases = '';
			my @aliases = split(/,\s*/,$1);
						
			foreach(@aliases){
				
				if(! /^[^"@]+@.*/ && ! /fwd_as_att/){
					
					if(length($aliases)){
						
						$aliases .= ',';
						
					}
					$aliases .= $_;
					
				}
				
			}	
			
			push @new_aliases, "$virtmaps_rhs: $aliases";
			
		} else {
			
			push @new_aliases, $_;
			
		}
		
	}

	`rm -f /usr/local/etc/easytecc/$mailuser.fwdmsg`;
	
	$aliases->file_content(\@new_aliases);
	$aliases->write_file;
	
	@new_virtmaps = map(lc, @new_virtmaps);
	$virtmaps->file_content(\@new_virtmaps);
	$virtmaps->write_file;
	
}

sub add_sendmail_forward{
	
	my $mailuser = shift;
	my $forward_external = shift;
	
	my $virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
	$virtmaps->read_file;
	my %virtmaps = %{$virtmaps->file_parsed_hash()};

	my $aliases = file->new({file_name => '/etc/mail/aliases'});
	$aliases->read_file;
	my %aliases = %{$aliases->file_parsed_hash()};

	my @new_virtmaps = ();
	my @new_aliases = ();
		
	my $virtmaps_rhs = $mailuser;
	$virtmaps_rhs =~ s/@/_/;
	$virtmaps_rhs .= '_spl';
	
	my $found = 0;		
	foreach($virtmaps->file_content){
		
		if(/^$mailuser\s+(.*)$/){
			
			push(@new_virtmaps, "$mailuser\t$virtmaps_rhs");
			$found = 1;
			
		} else {
			
			push(@new_virtmaps, $_);
			
		}	
		
	}
	
	if(!$found){
		
		push(@new_virtmaps, "$mailuser\t$virtmaps_rhs");
		
	}
	
	my %mailpasswd = %{easytecc3::get_mailpasswd()->file_parsed_hash()};
	
	$found = 0;
	foreach($aliases->file_content){
		
		if(/^$virtmaps_rhs\s*:\s*(.*)$/){
						
			my @aliases = split(/,\s*/,$1);
			my @all_aliases = ();
			my $alias;
			foreach $alias (@aliases){
				
				if($alias =~ /(procmail|autoresponder)/ || exists($mailpasswd{$alias})){
					
					push @all_aliases, $alias;
					
				}
								
			}
			
			push @all_aliases, @{$forward_external};
			
			# unique
			@all_aliases = keys %{{ map { $_ => 1 } @all_aliases }};
			my $aliases = join(',',@all_aliases);
			push @new_aliases, "$virtmaps_rhs: $aliases";
			$found = 1;
						
		} else {
			
			push @new_aliases, $_;
			
		}
		
	}
	
	if(!$found){
		
		# unique
		@{$forward_external} = keys %{{ map { $_ => 1 } @{$forward_external} }};
		push @new_aliases, "$virtmaps_rhs: " . join(',',@{$forward_external});
		
	}
	

	$aliases->file_content(\@new_aliases);
	$aliases->write_file;
	
	@new_virtmaps = map(lc, @new_virtmaps);
	$virtmaps->file_content(\@new_virtmaps);
	$virtmaps->write_file;
	
}

sub get_sendmail_forward{
	
	my $mailaddress = shift;
	
	logline("debug","#######################mailaddress is $mailaddress ");
		
	my $virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
	$virtmaps->read_file;
	my %virtmaps = %{$virtmaps->file_parsed_hash()};

	my $aliases = file->new({file_name => '/etc/mail/aliases'});
	$aliases->read_file;
	my %aliases = %{$aliases->file_parsed_hash()};
		
	my $virtmaps_rhs;
	my @forward_to;
		
	foreach($virtmaps->file_content){
		
		if(/^$mailaddress\s+(.*)$/){
			
			my $match = $1;			
			if($match =~ /_spl$/){
				
				$virtmaps_rhs = $match;
				
			} else {
				
				push(@forward_to, $match);
				
			}
			
		}	
		
	}
	
	foreach($aliases->file_content){
		
		if(/^$virtmaps_rhs\s*:\s*(.*)$/){
						
			my @aliases = split(/,\s*/,$1);
			my $alias;
			foreach $alias (@aliases){
								
				push(@forward_to, $alias);
												
			}
			
		}
		
	}
	
	@forward_to = keys %{{ map { $_ => 1 } @forward_to }};
	return join(',',@forward_to);
	
}

sub add_sendmail_forward_as_att{
	
	my $mailuser = shift;
	my $forward_from = shift;
	my $forward_subject = shift;
	my $forward_text = shift;
	my $forward_to = shift;
		
	my $forward_as_att_file = "/usr/local/etc/easytecc/$mailuser.fwdmsg";
	my $forward_as_att_cmd = '|/usr/sbin/fwd_as_att';
	
	my $forward_header = '';
	if(length($forward_from)){
		
		$forward_header .= "From: $forward_from\n";
		
	}
	if(length($forward_subject)){
		
		$forward_header .= "Subject: $forward_subject\n";
		
	}
		
	if(length($forward_subject) || length($forward_text)){
	
		my $fh;
		open($fh, '>', $forward_as_att_file);
		binmode($fh);
		
		if(length($forward_header)){
				
			print $fh encode('utf-8',"$forward_header\n");
		
		}
		if(length($forward_text)){
		
			print $fh encode('utf-8',$forward_text);
		
		}
		
		close($fh);
		
		$forward_as_att_cmd .= " $forward_as_att_file";
		
	} else {
		
		`rm -f $forward_as_att_file 2>/dev/null`;
		
	}
	
	if(easytecc3::extern_mx()){
			
		my $socket = easytecc3::make_socket();
		
		if(-f $forward_as_att_file){
		
			print $socket "autoreply=$forward_as_att_file\n";
			
			
		} else {
			
			print $socket "del_autoreply_file=$forward_as_att_file\n";
			
		}
			
		easytecc3::close_socket($socket);	
			
	}
		
	my $virtmaps = file->new({file_name => '/etc/mail/virtmaps'});
	$virtmaps->read_file;
	my %virtmaps = %{$virtmaps->file_parsed_hash()};

	my $aliases = file->new({file_name => '/etc/mail/aliases'});
	$aliases->read_file;
	my %aliases = %{$aliases->file_parsed_hash()};

	my @new_virtmaps = ();
	my @new_aliases = ();
		
	my $virtmaps_rhs = $mailuser;
	$virtmaps_rhs =~ s/@/_/;
	$virtmaps_rhs .= '_spl';
	
	my $found = 0;	
	foreach($virtmaps->file_content){
		
		if(/^$mailuser\s+(.*)$/){
			
			push(@new_virtmaps, "$mailuser\t$virtmaps_rhs");
			$found = 1;
			
		} else {
			
			push(@new_virtmaps, $_);
			
		}	
		
	}
	
	if(!$found){
		
		push(@new_virtmaps, "$mailuser\t$virtmaps_rhs");
		
	}
	
	my %mailpasswd = %{easytecc3::get_mailpasswd()->file_parsed_hash()};
	
	$found = 0;
	foreach($aliases->file_content){
		
		if(/^$virtmaps_rhs\s*:\s*(.*)$/){
			
			my @aliases = split(/,\s*/,$1);
			my @all_aliases = ();
			my $alias;
			foreach $alias (@aliases){
				
				if($alias =~ /(procmail|autoresponder)/ || exists($mailpasswd{$alias})){
					
					push @all_aliases, $alias;
					
				}
								
			}
			
			push @all_aliases, "\"$forward_as_att_cmd " . join(' ',@{$forward_to}) . "\"";
			my $aliases = join(',',@all_aliases);
									
			push @new_aliases, "$virtmaps_rhs: $aliases";
			$found = 1;
						
		} else {
			
			push @new_aliases, $_;
			
		}
		
	}
	
	if(!$found){
		
		push @new_aliases, "$virtmaps_rhs: " . "\"$forward_as_att_cmd " . join(' ',@{$forward_to}) . "\"";
		
	}
	
	$aliases->file_content(\@new_aliases);
	$aliases->write_file;
	
	@new_virtmaps = map(lc, @new_virtmaps);
	$virtmaps->file_content(\@new_virtmaps);
	$virtmaps->write_file;
	
}

sub value{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $value = shift;
	my $form_input = shift;

	logline("debug",qq~#############value action=$input{'action'} input = $form_input~);

	if(exists $error_fields{$form_input}){
		logline("debug","$form_input value=error_fields");
		return(qq~"$input{$form_input}" class="has-error" ~);
		logline("debug","<<< Leaving ".(caller(0))[3]."().");
	}
	elsif(exists $input{$form_input} && $input{'action'} =~ /^exec_/){
		logline("debug","elsif input=" . $input{$form_input} . " value=$value und exec_");
		return(qq~"$input{$form_input}" <TMPL_VAR NAME=error_class_$form_input> ~);
		logline("debug","<<< Leaving ".(caller(0))[3]."().");
	}
	else{
		logline("debug","else input=$form_input value=$value");
		logline("debug","<<< Leaving ".(caller(0))[3]."().");
		return(qq~"$value"~);
	}
}

sub error_class{
	logline("debug",">>> Entering ".(caller(0))[3]."() from ".(caller(1))[3]."() Line: ".(caller(0))[2]);
	my $form_input = shift;

	logline("debug",qq~error_class input = $form_input~);

	if(exists $error_fields{$form_input}){
		logline("debug","error_class $form_input ".$error_fields{$form_input});
		return("has-error");
		logline("debug","<<< Leaving ".(caller(0))[3]."().");
	}
}

sub https_cert_expire{
	
	my $cert_file=shift;
	
	### Mario: Hash-Variable, um die SSL-Ablaufdaten nicht andauernd neu zu überprüfen ###
	my %ssl_expiry_dates;
	if(defined($session) && defined($session->param('ssl_expiry_dates'))){
		%ssl_expiry_dates = %{$session->param('ssl_expiry_dates')};
		
		if (exists($ssl_expiry_dates{$cert_file})){
			
			### Mario: Falls der %hash-Wert für die Domain bereits existiert, soll dieser gelesen werden ###
			return ($ssl_expiry_dates{$cert_file}{'cert_expire_date'}, $ssl_expiry_dates{$cert_file}{'cert_expire_days'});
			logline("debug"," -M A R I O- Rueckgabe der Hashwerte von \$ssl_expiry_dates  " . $cert_file );
		
		}
	
	}
		
	my $openssl = 'openssl';
	if(-e '/usr/local/bin/openssl'){
		$openssl = '/usr/local/bin/openssl';
	}
	
	my $cert_expire_date;
	if($fb){
		
		$cert_expire_date = `/bin/sh -c "/usr/iports/bin/sudo /usr/sbin/bzgrep . $cert_file | $openssl x509 -noout -enddate 2>/dev/null"`;
		
	} else {
		
		$cert_expire_date = `/bin/sh -c "cat $cert_file | $openssl x509 -noout -enddate 2>/dev/null"`;
		
	}
		
	logline("debug","cert_expire_date:$cert_expire_date\n");
	logline("debug","/bin/sh -c \"/usr/iports/bin/sudo /usr/sbin/bzgrep . $cert_file | $openssl x509 -noout -enddate 2>/dev/null\"\n");   
		
	if(length($cert_expire_date)){
	
		chomp($cert_expire_date);	
		$cert_expire_date = `/bin/sh -c "echo $cert_expire_date | sed 's#^.*=##;s#  *# #'"`;
		chomp($cert_expire_date);
		my $cert_expire_secs;
		my $now_secs;
		my $cert_expire_days;
		if ($fb){
			$cert_expire_secs = `/bin/sh -c "LC_ALL=C; date -j -f '%b %d %H:%M:%S %Y %Z' '$cert_expire_date' '+%s'"`;
			chomp($cert_expire_secs);
			$now_secs = `/bin/sh -c "date -j '+%s'"`;
			chomp($now_secs);
			$cert_expire_days = int(($cert_expire_secs - $now_secs) / 86400);
			$cert_expire_date = `/bin/sh -c "date -j -f '%s' '$cert_expire_secs' '+%d.%m.%Y'"`;
			chomp($cert_expire_date);
		} else {
			$cert_expire_secs = `/bin/sh -c "LC_ALL=C; date -d '$cert_expire_date' '+%s'"`;
			chomp($cert_expire_secs);
			$now_secs = `/bin/sh -c "date '+%s'"`;
			chomp($now_secs);
			$cert_expire_days = int(($cert_expire_secs - $now_secs) / 86400);
			$cert_expire_date = `/bin/sh -c "date -d '1970-01-01 $cert_expire_secs sec GMT' '+%d.%m.%Y'"`;
			chomp($cert_expire_date);
		}
		
		$ssl_expiry_dates{$cert_file}{'cert_expire_date'} = $cert_expire_date;
		$ssl_expiry_dates{$cert_file}{'cert_expire_days'} = $cert_expire_days;
		$session->param('ssl_expiry_dates', \%ssl_expiry_dates);
		$session->flush();
		
		return ($cert_expire_date, $cert_expire_days);
	}
	
}

sub logline($$) {
	my $level = shift;
	my $message = shift;
	if($debug){
		chomp $message;
		my ($package, $filename, $line) = caller;
		my $logline = sprintf '(%5.5d)', $line;
		$log->log( level => $level, message => $logline." ".$message);
	}
}

sub dienice ($) {
	# write die messages to the log before die'ing
	my ($package, $filename, $line) = caller;
	logline("alert","$_[0] at line $line in $filename");
	die $_[0];
}

# from http://cpansearch.perl.org/src/KAZUHO/MIME-Base64-URLSafe-0.01/lib/MIME/Base64/URLSafe.pm to avoid dependencies
sub encode_base64url ($) {
    my $data = encode_base64($_[0], '');
    $data =~ tr|+/=|\-_|d;
    $data;
}

# from https://github.com/ptarjan/base64url/blob/master/perl.pl
sub decode_base64url {
  (my $s = shift) =~ tr{-_}{+/};
  $s .= '=' x (4 - length($s));
  return decode_base64($s);
}