# custom-lib.pl
# Functions for storing custom commands

do '../web-lib.pl';
&init_config();
%access = &get_module_acl();
require '../ui-lib.pl';

# list_commands()
# Returns a list of all custom commands
sub list_commands
{
local (@rv, $f);
local $mcd = $module_info{'usermin'} ? $config{'webmin_config'}
				     : $module_config_directory;
opendir(DIR, $mcd);
while($f = readdir(DIR)) {
	if ($f =~ /^(\d+)\.cmd$/) {
		local %cmd;
		$cmd{'file'} = "$mcd/$f";
		$cmd{'id'} = $1;
		open(FILE, $cmd{'file'});
		chop($cmd{'cmd'} = <FILE>);
		chop($cmd{'desc'} = <FILE>);
		local @o = split(/\s+/, <FILE>);
		$cmd{'user'} = $o[0];
		$cmd{'raw'} = int($o[1]);
		$cmd{'su'} = int($o[2]);
		$cmd{'order'} = int($o[3]);
		$cmd{'noshow'} = int($o[4]);
		$cmd{'usermin'} = int($o[5]);
		$cmd{'timeout'} = int($o[6]);
		$cmd{'clear'} = int($o[7]);
		while(<FILE>) {
			s/\r|\n//g;
			local @a = split(/:/, $_, 5);
			push(@{$cmd{'args'}}, { 'name' => $a[0],
						'type' => $a[1],
						'opts' => $a[2],
						'quote' => $a[3],
						'desc' => $a[4] });
			}
		close(FILE);
		$cmd{'index'} = scalar(@rv);
		open(HTML, "$mcd/$cmd{'id'}.html");
		while(<HTML>) {
			$cmd{'html'} .= $_;
			}
		close(HTML);
		push(@rv, \%cmd);
		}
	elsif ($f =~ /^(\d+)\.edit$/) {
		local %edit;
		$edit{'file'} = "$mcd/$f";
		$edit{'id'} = $1;
		open(FILE, $edit{'file'});
		chop($edit{'edit'} = <FILE>);
		chop($edit{'desc'} = <FILE>);
		chop($edit{'user'} = <FILE>);
		chop($edit{'group'} = <FILE>);
		chop($edit{'perms'} = <FILE>);
		chop($edit{'before'} = <FILE>);
		chop($edit{'after'} = <FILE>);
		chop($edit{'order'} = <FILE>);
		$edit{'order'} = int($edit{'order'});
		chop($edit{'usermin'} = <FILE>);
		chop($edit{'envs'} = <FILE>);
		close(FILE);
		$edit{'index'} = scalar(@rv);
		open(HTML, "$mcd/$edit{'id'}.html");
		while(<HTML>) {
			$edit{'html'} .= $_;
			}
		close(HTML);
		push(@rv, \%edit);
		}
	}
closedir(DIR);
return @rv;
}

# save_command(&command)
sub save_command
{
local $c = $_[0];
if ($c->{'edit'}) {
	# Save a file editor
	&lock_file("$module_config_directory/$c->{'id'}.edit");
	open(FILE, ">$module_config_directory/$c->{'id'}.edit");
	print FILE $c->{'edit'},"\n";
	print FILE $c->{'desc'},"\n";
	print FILE $c->{'user'},"\n";
	print FILE $c->{'group'},"\n";
	print FILE $c->{'perms'},"\n";
	print FILE $c->{'before'},"\n";
	print FILE $c->{'after'},"\n";
	print FILE $c->{'order'},"\n";
	print FILE $c->{'usermin'},"\n";
	print FILE $c->{'envs'},"\n";
	close(FILE);
	&unlock_file("$module_config_directory/$c->{'id'}.edit");
	}
else {
	# Save a custom command
	&lock_file("$module_config_directory/$c->{'id'}.cmd");
	open(FILE, ">$module_config_directory/$c->{'id'}.cmd");
	print FILE $c->{'cmd'},"\n";
	print FILE $c->{'desc'},"\n";
	print FILE $c->{'user'}," ",int($c->{'raw'})," ",int($c->{'su'})," ",
		   int($c->{'order'})," ",int($c->{'noshow'})," ",
		   int($c->{'usermin'})," ",int($c->{'timeout'})," ",
		   int($c->{'clear'}),"\n";
	foreach $a (@{$c->{'args'}}) {
		print FILE $a->{'name'},":",$a->{'type'},":",
			   $a->{'opts'},":",$a->{'quote'},":",$a->{'desc'},"\n";
		}
	close(FILE);
	&unlock_file("$module_config_directory/$c->{'id'}.cmd");
	}
&lock_file("$module_config_directory/$c->{'id'}.html");
if ($cmd->{'html'}) {
	open(HTML, ">$module_config_directory/$c->{'id'}.html");
	print HTML $cmd->{'html'};
	close(HTML);
	}
else {
	unlink("$module_config_directory/$c->{'id'}.html");
	}
&unlock_file("$module_config_directory/$c->{'id'}.html");
}

# delete_command(&command)
sub delete_command
{
local $f = "$module_config_directory/$_[0]->{'id'}".
	   ($_[0]->{'edit'} ? ".edit" : ".cmd");
&lock_file($f);
unlink($f);
&unlock_file($f);
}

sub can_run_command
{
if ($module_info{'usermin'}) {
	# Only modules marked as for Usermin are considered
	return 0 if (!$_[0]->{'usermin'});

	# Check detailed access control list
	local @uinfo = @remote_user_info;
	@uinfo = getpwnam($remote_user) if (!@uinfo);
	foreach $l (split(/\t/, $config{'access'})) {
		if ($l =~ /^(\S+):\s*(.*)$/) {
			local ($user, $ids) = ($1, $2);
			local $applies;
			if ($user =~ /^\@(.*)$/) {
				# Check if user is in group
				local @ginfo = getgrnam($1);
				$applies++
				   if (@ginfo && ($ginfo[2] == $uinfo[3] ||
				       &indexof($remote_user,
						split(/\s+/, $ginfo[3])) >= 0));
				}
			elsif ($user eq $remote_user || $user eq "*") {
				$applies++;
				}
			if ($applies) {
				# Rule is for this user - check list
				local @ids = split(/\s+/, $ids);
				local $d;
				foreach $d (@ids) {
					return 1 if ($d eq '*' ||
						     $_[0]->{'id'} eq $d);
					}
				return 0;
				}
			}
		}
	return 0;

	}
else {
	# Just use Webmin user's list of databases
	local $c;
	local $found;
	return 1 if ($access{'cmds'} eq '*');
	local @cmds = split(/\s+/, $access{'cmds'});
	foreach $c (@cmds) {
		$found++ if ($c eq $_[0]->{'id'});
		}
	return $cmds[0] eq '!' ? !$found : $found;
	}
}

# read_opts_file(file)
sub read_opts_file
{
local @rv;
local $file = $_[0];
if ($file !~ /^\//) {
	local @uinfo = getpwnam($remote_user);
	if (@uinfo) {
		$file = "$uinfo[7]/$file";
		}
	}
open(FILE, $file);
while(<FILE>) {
	s/\r|\n//g;
	if (/^"([^"]*)"\s+"([^"]*)"$/) {
		push(@rv, [ $1, $2 ]);
		}
	elsif (/^"([^"]*)"$/) {
		push(@rv, [ $1, $1 ]);
		}
	elsif (/^(\S+)\s+(\S.*)/) {
		push(@rv, [ $1, $2 ]);
		}
	else {
		push(@rv, [ $_, $_ ]);
		}
	}
close(FILE);
return @rv;
}

1;
