# webalizer-lib.pl
# Common functions for editing the webalizer config file

do '../web-lib.pl';
&init_config();

$cron_cmd = "$module_config_directory/webalizer.pl";
$custom_logs_file = "$module_config_directory/custom-logs";
%access = &get_module_acl();

# get_config([logfile])
# Parse the webalizer config file for a single logfile or global
sub get_config
{
local $file;
if ($_[0]) {
	$file = &config_file_name($_[0]);
	}
$file = $config{'webalizer_conf'} if (!$file || !-r $file);
local @rv;
local $lnum = 0;
open(FILE, $file);
while(<FILE>) {
	s/\r|\n//g;
	s/#.*$//;
	if (/^\s*(\S+)\s+(.*)/) {
		push(@rv, { 'name' => $1,
			    'value' => $2,
			    'line' => $lnum,
			    'file' => $file,
			    'index' => scalar(@rv) });
		}
	$lnum++;
	}
close(FILE);
return \@rv;
}

# save_directive(&config, name, [value]*)
sub save_directive
{
local ($conf, $name, @values) = @_;
local @old = &find($name, $conf);
local $lref = &read_file_lines($conf->[0]->{'file'});
local $i;
for($i=0; $i<@old || $i<@values; $i++) {
	if ($i < @old && $i < @values) {
		# Just replacing a line
		$lref->[$old[$i]->{'line'}] = "$name $values[$i]";
		}
	elsif ($i < @old) {
		# Deleting a line
		splice(@$lref, $old[$i]->{'line'}, 1);
		&renumber($conf, $old[$i]->{'line'}, -1);
		}
	elsif ($i < @values) {
		# Adding a line
		if (@old) {
			# after the last one of the same type
			splice(@$lref, $old[$#old]->{'line'}+1, 0,
			       "$name $values[$i]");
			&renumber($conf, $old[$#old]->{'line'}+1, 1);
			}
		else {
			# at end of file
			push(@$lref, "$name $values[$i]");
			}
		}
	}
}

# renumber(&config, line, offset)
sub renumber
{
foreach $c (@{$_[0]}) {
	$c->{'line'} += $_[2] if ($c->{'line'} >= $_[1]);
	}
}

# config_file_name(logfile)
sub config_file_name
{
local $p = $_[0];
$p =~ s/^\///;
$p =~ s/\//_/g;
return "$module_config_directory/$p.conf";
}

# find(name, &config)
sub find
{
local @rv;
foreach $c (@{$_[1]}) {
	push(@rv, $c) if (lc($c->{'name'}) eq lc($_[0]));
	}
return wantarray ? @rv : $rv[0];
}

# find_value(name, &config)
sub find_value
{
local @rv = map { $_->{'value'} } &find(@_);
return wantarray ? @rv : $rv[0];
}

# all_log_files(file)
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;
}

# get_log_config(path)
# Get the configuration for some log file
sub get_log_config
{
local %rv;
&read_file(&log_config_name($_[0]), \%rv) || return undef;
return \%rv;
}

# save_log_config(path, &config)
sub save_log_config
{
return &write_file(&log_config_name($_[0]), $_[1]);
}

# log_config_name(path)
sub log_config_name
{
local $p = $_[0];
$p =~ s/^\///;
$p =~ s/\//_/g;
return "$module_config_directory/$p.log";
}

# generate_report(file, handle, escape)
sub generate_report
{
local $h = $_[1];
local $lconf = &get_log_config($_[0]);
local @all = &all_log_files($_[0]);
if (!@all) {
	print $h "Log file $_[0] does not exist\n";
	return;
	}
local ($a, %mtime);
foreach $a (@all) {
	local @st = stat($a);
	$mtime{$a} = $st[9];
	}
local $type = $lconf->{'type'} == 1 ? "" :
	      $lconf->{'type'} == 2 ? "-F squid" :
	      $lconf->{'type'} == 3 ? "-F ftp" : "";
local $cfile = &config_file_name($_[0]);
local $conf = -r $cfile ? "-c $cfile" : "";
if ($lconf->{'over'}) {
	unlink("$lconf->{'dir'}/webalizer.current");
	unlink("$lconf->{'dir'}/webalizer.hist");
	}
local $user = $lconf->{'user'} || "root";
if ($user ne "root" && -r $cfile) {
	chmod(0644, $cfile);
	}
foreach $a (sort { $mtime{$a} <=> $mtime{$b} } @all) {
	local $cmd = "$config{'webalizer'} $conf -o '$lconf->{'dir'}' $type -p '$a'";
	if ($user ne "root") {
		local $shell;
		if ($config{'su_shell'}) {
			$shell = " -s /bin/sh";
			}
		$cmd = "su ".quotemeta($user)." $shell -c ".quotemeta($cmd);
		}
	open(OUT, "$cmd 2>&1 |");
	while(<OUT>) {
		print $h $_[2] ? &html_escape($_) : $_;
		}
	close(OUT);
	return 0 if ($?);
	&additional_log("exec", undef, $cmd);
	}
return 1;
}

# spaced_buttons(button, ...)
sub spaced_buttons
{
local $pc = int(100 / scalar(@_));
print "<table width=100%><tr>\n";
foreach $b (@_) {
	local $al = $b eq $_[0] ? "align=left" :
		    $b eq $_[@_-1] ? "align=right" : "align=center";
	print "<td width=$pc% $al>$b</td>\n";
	}
print "</table>\n";
}

# read_custom_logs()
sub read_custom_logs
{
open(LOGS, $custom_logs_file);
local @rv = map { /^(.*\S)\s+(\S+)/; { 'file' => $1, 'type' => $2 } } <LOGS>;
close(LOGS);
return @rv;
}

# write_custom_logs(log, ...)
sub write_custom_logs
{
open(LOGS, ">$custom_logs_file");
print LOGS map { "$_->{'file'} $_->{'type'}\n" } @_;
close(LOGS);
}

# can_edit_log(file)
sub can_edit_log
{
foreach $d (split(/\s+/, $access{'dir'})) {
	local $ok = &is_under_directory($d, $_[0]);
	return 1 if ($ok);
	}
return 0;
}

# get_webalizer_version(&out)
sub get_webalizer_version
{
local $out = `$config{'webalizer'} -v 2>&1`;
${$_[0]} = $out;
return $out =~ /\sV(\S+)/ ? $1 : undef;
}

1;

