# --------------------------------------------------------------------------
###
#
# Copyright (c) Ensim Corporation 2000, 2001   All Rights Reserved.
#
# This software is furnished under a license and may be used and copied
# only  in  accordance  with  the  terms  of such  license and with the
# inclusion of the above copyright notice. This software or any other
# copies thereof may not be provided or otherwise made available to any
# other person. No title to and ownership of the software is hereby
# transferred.
#
# The information in this software is subject to change without notice
# and  should  not be  construed  as  a commitment by Ensim Corporation.
# Ensim assumes no responsibility for the use or  reliability  of its
# software on equipment which is not supplied by Ensim.
#
# Exit codes (on failure error message goes to stderr):
#  0 - success
#  1 - failure
# 
# Boolean arguments on the command line are given as 0 or 1. All the
# command line arguments are encoded to avoid problems with escapes.
#
# All functions defined here either return an error message if an
# error occured and "" if everything went well or allways return a
# valid value, but exit (with code 1) printing an error message if an
# error occurs. This second type of functions have _e appended to
# their name. Functions are allowed to print results onto stdout, but
# errors are printed only in the main program.
#
###


# --------------------------------------------------------------------------
# $Id: mymajordomo-lib.pl,v 1.1.1.1 2008-03-01 00:21:36 aarefyev Exp $
# $Name: not supported by cvs2svn $
# --------------------------------------------------------------------------

# majordomo-lib.pl
# Common majordomo functions

require '/usr/lib/opcenter/majordomo/majordomo.pm';
require '/usr/lib/opcenter/sendmail/sendmail.pm';
&myinit_config();

%MAJOR_ENV = ( 'HOME', $config{'program_dir'} );

sub getMyOS() 
{
  $out=$ENV{'OSTYPE'} || `uname`;
  if ($out =~ /linux/i) {
    $os = "Linux";
  } elsif ($out =~/SunOS/) {
    $os = "SunOS";
  }
  return $os;
}
# writing our own init_config method!
sub myinit_config()
{
  $os = &getMyOS();
  
  #set the config
  if ($os eq "SunOS") {
  %config = ('program_dir',  '/usr/local/majordomo', 
             'majordomo_cf', '/usr/local/majordomo.cf', 
	     'homedir',    , '/usr/local/majordomo',
             'aliases_file', '/etc/mail/aliases');
  }
  else {
  %config = ('program_dir',  '/usr/lib/majordomo', 
             'majordomo_cf', '/etc/majordomo.cf', 
	     'homedir',    ,  '/usr/lib/majordomo',
             'aliases_file', '/etc/aliases');
 }
}


# get_config()
# Parse and return the majordomo config file
sub get_config
{
local(@rv, $line);
open(CONF, $config{'majordomo_cf'});
while(<CONF>) {
	s/\r|\n//g;
	if (/^\s*\$(\S+)\s*=\s*"(.*)";\s*$/) {
		# static config option
		push(@rv, { 'name' => $1,
			    'value' => &perl_unescape($2),

			    'line' => $line,
			    'eline' => $line });
		}
	elsif (/^\s*\$(\S+)\s*=\s*<<\s*'(\S+)';\s*$/) {
		# multiline config option
		local $o = { 'name' => $1,
			     'line' => $2 };
		local $end = $3;
		while(<CONF>) {
			$line++;
			last if ($_ =~ /^$end[\r\n]+$/);
			$o->{'value'} .= $_;
			}
		$o->{'eline'} = $line;
		push(@rv, $o);
		}
#	elsif (/^\s*\$(\S+)\s*=\s*\$ENV\{['"]([^'"]+)['"]\};\s*$/) {
#		# from majordomo environment variable
#		push(@rv, { 'name' => $1,
#			    'value' => $MAJOR_ENV{$2},
#			    'line' => $line,
#			    'eline' => $line });
#		}
	elsif (/^\s*\$(\S+)\s*=\s*(.*);\s*$/) {
		# computed config option
		push(@rv, { 'name' => $1,
			    'value' => $2,
			    'computed' => 1,
			    'line' => $line,
			    'eline' => $line });
		}
	$line++;
	}
close(CONF);
return \@rv;
}

# save_directive(&config, name, value)
# Update some directive in the global config file
sub save_directive
{
local $old = &find($_[1], $_[0]);
local $lref = &read_file_lines($config{'majordomo_cf'});
local $olen = $old->{'eline'} - $old->{'line'} + 1;
local $v = $_[2];
$v =~ s/\n$//;
if ($v =~ /\n/) {
	splice(@$lref, $old->{'line'}, $olen,
	       ( "\$$_[1] = <<'END';", split(/\n/, $v, -1), "END" ));
	}
else {
	$v =~ s/\@/\\@/g;
	splice(@$lref, $old->{'line'}, $olen, "\$$_[1] = \"$v\";");
	}
}

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

# find_value(name, &array)
sub find_value
{
local(@v);
@v = &find($_[0], $_[1]);
@v = grep { !$_->{'computed'} } @v;
if (!@v) { return undef; }
elsif (wantarray) { return map { $_->{'value'} } @v; }
else { return $v[0]->{'value'}; }
}

	

# get_list_config(file)
sub get_list_config
{
local(@rv, $line);
$lnum = 0;
open(CONF, $_[0]);
while(<CONF>) {
	s/\r|\n//g;
	s/#.*$//g;
	if (/^\s*(\S+)\s*=\s*(.*)$/) {
		# single value
		push(@rv, { 'name' => $1,
			    'value' => $2,
			    'index' => scalar(@rv),
			    'line' => $lnum,
			    'eline' => $lnum });
		}
	elsif (/^\s*(\S+)\s*<<\s*(\S+)/) {
		# multi-line value
		local $c = { 'name' => $1,
			     'index' => scalar(@rv),
			     'line' => $lnum };
		local $end = $2;
		while(<CONF>) {
			$lnum++;
			last if (/^$end[\r\n]+$/);
			s/^--/-/;
			s/^-\n/\n/;
			$c->{'value'} .= $_;
			}
		$c->{'eline'} = $lnum;
		push(@rv, $c);
		}
	$lnum++;
	}
return \@rv;
}

# save_list_directive(&config, file, name, value, multiline)
sub save_list_directive
{
local $old = &find($_[2], $_[0]);
local $lref = &read_file_lines($_[1]);
local ($pos, $olen, $nlen);
if ($old) {
	$olen = $old->{'eline'} - $old->{'line'} + 1;
	$pos = $old->{'line'};
	}
else {
	$olen = 0;
	$pos = @$lref;
	}
if ($_[4]) {
	local $v = $_[3];
	$v =~ s/\n$//;
	local @lines = split(/\n/, $v, -1);
	@lines = map { s/^-/--/; s/^$/-/; $_ } @lines;
	splice(@$lref, $pos, $olen, ("$_[2]        <<   END", @lines, "END"));
	$nlen = @lines + 2;
	}
else {
	splice(@$lref, $pos, $olen, "$_[2] = $_[3]");
	$nlen = 1;
	}
if ($old && $nlen != $olen) {
	foreach $c (@{$_[0]}) {
		if ($c->{'line'} > $old->{'eline'}) {
			$c->{'line'} += ($nlen - $olen);
			$c->{'eline'} += ($nlen - $olen);
			}
		}
	}
}

# get_aliases_file()
# Returns the paths to the sendmail-style aliases files
sub get_aliases_file
{
return [ $config{'aliases_file'} ] if ($config{'aliases_file'});
local $sm_conf = &majordomo::sendmail_call("get_sendmailcf");
return &majordomo::sendmail_call("aliases_file", $sm_conf);
}

# perl_unescape(string)
# Converts a string like "hello\@there\\foo" to "hello@there\foo"
sub perl_unescape
{
local $v = $_[0];
$v =~ s/\\(.)/$1/g;
return $v;
}

# perl_var_replace(string, &config)
# Replaces variables like $foo in a string with their value from
# the config file
sub perl_var_replace
{
local $str = $_[0];
local %donevar;
while($str =~ /\$([A-z0-9\_]+)/ && !$donevar{$1}) {
	$donevar{$1}++;
	local $val = &find_value($1, $_[1]);
	$str =~ s/\$([A-z0-9\_]+)/$val/;
	}
return $str;
}

# set_permissions(file)
# Sets the ownership and permissions on some file or directory,
# based on the ownership of the lists directory
sub set_permissions
{
local $conf = &get_config();
#local $ldir = &perl_var_replace(&find_value("listdir", $conf), $conf);
$myos = &getMyOS();
if ($myos eq "SunOS") {
$ldir = '/usr/local/majordomo/lists';
}
else {
$ldir = '/var/lib/majordomo/lists';
}
local @ldir = stat($ldir);
chown($ldir[4], $ldir[5], $_[0]);
chmod(-d $_[0] ? 0775 : 0644, $_[0]);
}

# choice_input(name, text, &config, [opt, display]+)
sub choice_input
{
local $v = &find_value($_[0], $_[2]);
local $rv = "<td><b>$_[1]</b></td> <td nowrap>";
for($i=3; $i<@_; $i+=2) {
	local $ch = $v eq $_[$i] ? "checked" : "";
	$rv .= "<input name=$_[0] type=radio value='$_[$i]' $ch> ".$_[$i+1];
	}
$rv .= "</td>\n";
return $rv;
}

# save_choice(&config, file, name)
sub save_choice
{
&save_list_directive($_[0], $_[1], $_[2], $in{$_[2]});
}

# opt_input(name, text, &config, default, size, [units])
sub opt_input
{
local $v = &find_value($_[0], $_[2]);
local $rv = "<td><b>$_[1]</b></td> <td nowrap>";
$rv .= sprintf "<input type=radio name=$_[0]_def value=1 %s> $_[3]\n",
		$v eq "" ? "checked" : "";
$rv .= sprintf "<input type=radio name=$_[0]_def value=0 %s>\n",
		$v eq "" ? "" : "checked";
local $passwd = $_[0] =~ /passwd/ ? "type=password" : "";
$rv .= "<input $passwd name=$_[0] size=$_[4] value=\"$v\"> $_[5]</td>\n";
return $rv;
}

# save_opt(&config, file, name, [&func])
sub save_opt
{
if ($in{"$_[2]_def"}) { &save_list_directive($_[0], $_[1], $_[2], ""); }
elsif ($_[3] && ($err = &{$_[3]}($in{$_[2]}))) { &error($err); }
else { &save_list_directive($_[0], $_[1], $_[2], $in{$_[2]}); }
}

# select_input(name, text, &config, [opt, display]+)
sub select_input
{
local $v = &find_value($_[0], $_[2]);
local $rv = "<td><b>$_[1]</b></td> <td nowrap><select name=$_[0]>";
for($i=3; $i<@_; $i+=2) {
	local $ch = $v eq $_[$i] ? "selected" : "";
	$rv .= "<option value='$_[$i]' $ch> ".$_[$i+1];
	}
$rv .= "</select></td>\n";
return $rv;
}

# save_select(&config, file, name)
sub save_select
{
&save_list_directive($_[0], $_[1], $_[2], $in{$_[2]});
}

# multi_input(name, text, &config)
sub multi_input
{
local $v = &find_value($_[0], $_[2]);
local $rv = "<tr> <td valign=top><b>$_[1]</b></td> <td colspan=3>".
	    "<textarea rows=4 cols=80 name=$_[0]>\n$v</textarea></td> </tr>\n";
return $rv;
}

# save_multi(&config, file, name)
sub save_multi
{
$in{$_[2]} =~ s/\r//g;
&save_list_directive($_[0], $_[1], $_[2], $in{$_[2]}, 1);
}

# can_edit_list(&access, name)
sub can_edit_list
{
foreach (split(/\s+/, $_[0]->{'lists'})) {
	return 1 if ($_ eq "*" || $_ eq $_[1]);
	}
return 0;
}


# read_file_lines(file)
# Returns a reference to an array containing the lines from some file. This
# array can be modified, and will be written out when flush_file_lines()
# is called.
sub read_file_lines
{
if (!$file_cache{$_[0]}) {
        local(@lines, $_);
        open(READFILE, $_[0]);
        while(<READFILE>) {
                s/\r|\n//g;
                push(@lines, $_);
                }
        close(READFILE);
        $file_cache{$_[0]} = \@lines;
        }
return $file_cache{$_[0]};
}


# flush_file_lines()
sub flush_file_lines
{
foreach $f (keys %file_cache) {
        open(FLUSHFILE, "> $f");
        foreach $line (@{$file_cache{$f}}) {
                print FLUSHFILE $line,"\n";
                }
        close(FLUSHFILE);               
        }                               
}                                       


#foreign_call(module, function, [arg]*)
#Call a function in another module
sub foreign_call
{
 chdir("../$_[0]");
 local @args = @_[2 .. @_-1];
 $main::foreign_args = \@args;
 local @rv = eval <<EOF;
 package $_[0];
 &$_[1](\@{\$main::foreign_args});
EOF
 if ($@) { &error($@); }
 chdir("../$module_name");
 return wantarray ? @rv : $rv[0];
 }



# foreign_config(module)
# Get the configuration from another module
sub foreign_config
{
local %fconfig;
&read_file("$config_directory/$_[0]/config", \%fconfig);
return %fconfig;
}



sub wsplit
{
my ($s, $w, @rv); $s = $_[0];
$s =~ s/\\\"/\0/g;
while($s =~ /^"([^"]*)"\s*(.*)$/ || $s =~ /^(\S+)\s*(.*)$/) {
        $w = $1; $s = $2;
        $w =~ s/\0/"/g; push(@rv, $w);
        }
return @rv;
}

# takes one argument whihc is the alias name to get 
sub get_alias_name
{
#we need to look up the value of sender from /etc/aliases
$os = &getMyOS();
if ($os eq "SunOS") {
  $aliasfile = "/etc/mail/aliases";
 }
 else {
  $aliasfile = "/etc/aliases";
  } 
open(ALIASES, $aliasfile);
local (@alias_list)=<ALIASES>;
close(ALIASES);

my ($entry);

foreach $entry (@alias_list) {
  my (@fields);
  (@fields) = wsplit($entry);
  chomp(@fields);
  if($fields[0] eq "$_[0]:") {
    return "$fields[1]";
  }
}

}


1;

