# mailboxes-lib.pl
# Common functions for reading user mailboxes

do '../web-lib.pl';
do '../ui-lib.pl';
do 'boxes-lib.pl';
do 'folders-lib.pl';
&init_config();
%access = &get_module_acl();
$config{'perpage'} ||= 20;
$gconfig{'logfiles'} = 0;	# file change logged never needs to be done

# Always detect the mail system if not set
if ($config{'mail_system'} == 3) {
	$config{'mail_system'} = &detect_mail_system();
	&save_module_config() if ($config{'mail_system'} != 3);
	}

# send_mail_program(from, to)
# Returns the command for injecting email, based on the mail system in use
sub send_mail_program
{
if ($config{'mail_system'} == 1 || $config{'mail_system'} == 0) {
	# Use sendmail executable, or postfix wrapper
	local %sconfig = &foreign_check("sendmail") &&
			 $config{'mail_system'} == 1 ?
				&foreign_config("sendmail") : ( );
	local $cmd = &has_command($sconfig{'sendmail_path'} || "sendmail");
	return "$cmd -t -f".quotemeta($_[0]) if ($cmd);
	}
elsif ($config{'mail_system'} == 2) {
	# Use qmail injector
	local %qconfig = &foreign_check("qmailadmin") ?
				&foreign_config("qmailadmin") : ( );
	local $cmd = ($qconfig{'qmail_dir'} || "/var/qmail").
		     "/bin/qmail-inject";
	return $cmd if (-x $cmd);
	}
else {
	# Fallback - use sendmail command
	local $cmd = &has_command("sendmail");
	return "$cmd -t -f".quotemeta($_[0]) if ($cmd);
	}
return undef;
}

# list_folders()
# Returns a list of all user mailboxes
sub list_folders
{
setpwent();
local @uinfo;
local @rv;
while(@uinfo = getpwent()) {
	push(@rv, &list_user_folders(@uinfo));
	}
endpwent();
}

# list_user_folders(user, [other info])
# Returns a list of folders for mailboxes belonging to some user
sub list_user_folders
{
local @uinfo = @_ > 1 ? @_ : getpwnam($_[0]);
return ( ) if (!@uinfo);
local ($dir, $style, $mailbox, $maildir) = &get_mail_style();
local @rv;

# Check for /var/mail/USERNAME file
if ($dir) {
	local $mf = &mail_file_style($uinfo[0], $dir, $style);
	push(@rv, { 'type' => 0,
		    'name' => $mf,
		    'file' => $mf,
		    'user' => $uinfo[0],
		    'index' => scalar(@rv) });
	}

# Check for file in home dir
if ($mailbox) {
	local $mf = "$uinfo[7]/$mailbox";
	if (-r $mf || !@rv) {
		push(@rv, { 'type' => 0,
			    'name' => $mf,
			    'file' => $mf,
			    'user' => $uinfo[0],
			    'index' => scalar(@rv) });
		}
	}

# Check for directory in home dir
if ($maildir) {
	local $mf = "$uinfo[7]/$maildir";
	if (-d $mf || !@rv) {
		push(@rv, { 'type' => 1,
			    'name' => $mf."/",
			    'file' => $mf,
			    'user' => $uinfo[0],
			    'index' => scalar(@rv) });
		}
	}

# Add any ~/mail files
if ($config{'mail_usermin'}) {
	local $folders_dir = "$uinfo[7]/$config{'mail_usermin'}";
        foreach $p (&recursive_files($folders_dir, 1)) {
                local $f = $p;
                $f =~ s/^\Q$folders_dir\E\///;
                push(@rv, { 'name' => $p,
                            'file' => $p,
                            'type' => &folder_type($p),
                            'mode' => 0,
                            'index' => scalar(@rv) } );
                }
	}

return @rv;
}

sub list_user_folders_sorted
{
return &list_user_folders(@_);
}

# get_mail_style()
# Returns a list containing the mail base directory, directory style,
# mail file in home dir, and maildir in home dir
sub get_mail_style
{
if (!defined(@mail_style_cache)) {
	if ($config{'auto'}) {
		# Based on mail server
		if ($config{'mail_system'} == 1) {
			# Can get paths from Sendmail module config
			local %sconfig = &foreign_config("sendmail");
			if ($sconfig{'mail_dir'}) {
				return ($sconfig{'mail_dir'}, $sconfig{'mail_style'}, undef, undef);
				}
			else {
				return (undef, $sconfig{'mail_style'}, $sconfig{'mail_file'}, undef);
				}
			}
		elsif ($config{'mail_system'} == 0) {
			# Need to query Postfix module for paths
			&foreign_require("postfix", "postfix-lib.pl");
			local @s = &postfix::postfix_mail_system();
			if ($s[0] == 0) {
				return ($s[1], 0, undef, undef);
				}
			elsif ($s[0] == 1) {
				return (undef, 0, $s[1], undef);
				}
			elsif ($s[0] == 2) {
				return (undef, 0, undef, $s[1]);
				}
			}
		elsif ($config{'mail_system'} == 2) {
			# Need to check qmail module config for paths
			local %qconfig = &foreign_config("qmailadmin");
			if ($qconfig{'mail_system'} == 1) {
				return (undef, 0, undef,
					$qconfig{'mail_dir_qmail'});
				}
			elsif ($qconfig{'mail_dir'}) {
				return ($qconfig{'mail_dir'}, $qconfig{'mail_style'}, undef, undef);
				}
			else {
				return (undef, $qconfig{'mail_style'}, $qconfig{'mail_file'}, undef);
				}
			}
		else {
			# No mail server set yet!
			return (undef, undef, undef, undef);
			}
		}
	else {
		# Use config settings
		@mail_style_cache = ($config{'mail_dir'}, $config{'mail_style'},
				     $config{'mail_file'}, $config{'mail_sub'});
		}
	}
return @mail_style_cache;
}

# can_user(username, [other details])
sub can_user
{
local @u = @_ > 1 ? @_ : getpwnam($_[0]);
return 1 if ($_[0] && $access{'sent'} eq $_[0]);
return 1 if ($access{'mmode'} == 1);
return 0 if (!@u);
return 0 if ($_[0] =~ /\.\./);
return 0 if ($access{'mmode'} == 0);
local $u;
if ($access{'mmode'} == 2) {
	foreach $u (split(/\s+/, $access{'musers'})) {
		return 1 if ($u eq $_[0]);
		}
	return 0;
	}
elsif ($access{'mmode'} == 4) {
	return 1 if ($_[0] eq $remote_user);
	}
elsif ($access{'mmode'} == 5) {
	return $u[3] eq $access{'musers'};
	}
elsif ($access{'mmode'} == 3) {
	foreach $u (split(/\s+/, $access{'musers'})) {
		return 0 if ($u eq $_[0]);
		}
	return 1;
	}
elsif ($access{'mmode'} == 6) {
	return ($_[0] =~ /^$access{'musers'}$/);
	}
elsif ($access{'mmode'} == 7) {
	return (!$access{'musers'} || $u[2] >= $access{'musers'}) &&
	       (!$access{'musers2'} || $u[2] <= $access{'musers2'});
	}
return 0;	# can't happen!
}

# movecopy_user_select(number)
# Returns HTML for entering a username to copy mail to
sub movecopy_user_select
{
local $rv;
$rv .= "<input type=submit name=move$_[0] value=\"$text{'mail_move'}\" ".
       "onClick='return check_clicks(form)'>\n";
$rv .= "<input type=submit name=copy$_[0] value=\"$text{'mail_copy'}\" ".
       "onClick='return check_clicks(form)'>\n";
$rv .= &ui_user_textbox("mfolder$_[0]");
return $rv;
}

# need_delete_warn(&folder)
sub need_delete_warn
{
return 1 if ($config{'delete_warn'} eq 'y');
return 0 if ($config{'delete_warn'} eq 'n');
local $mf;
return $_[0]->{'type'} == 0 &&
       ($mf = &folder_file($_[0])) &&
       &disk_usage_kb($mf)*1024 > $config{'delete_warn'};
}

@mail_system_modules = ( [ "qmailadmin", 2 ], [ "postfix", 0 ], [ "sendmail", 1 ] );

# detect_mail_system()
# Works out which mail server is installed
sub detect_mail_system
{
foreach $m (@mail_system_modules) {
	return $m->[1] if (&foreign_installed($m->[0]));
	}
return 3;
}

# show_users_table(&users-list, [only-with-mail])
# Outputs HTML for a table of users, with the appropriate sorting and mode
sub show_users_table
{
local @users = @{$_[0]};
local ($u, %size);
if ($config{'sort_mode'} == 2 || $config{'show_size'} > 0 || $_[1]) {
	# Need to get sizes
	foreach $u (@users) {
		local @folders = &list_user_folders(@$u);
		$size{$u->[0]} = $config{'size_mode'} ?
					&folder_size(@folders) :
					&folder_size($folders[0]);
		}
	}

# Sort by chosen mode
if ($config{'sort_mode'} == 2) {
	@users = sort { $size{$b->[0]} <=> $size{$a->[0]} } @users;
	}
elsif ($config{'sort_mode'} == 1) {
	@users = sort { lc($a->[0]) cmp lc($b->[0]) } @users;
	}

if ($_[1]) {
	# Limit to those with mail
	local @mailonlyusers = grep { $size{$_->[0]} } @users;
	@users = @mailonlyusers if (@mailonlyusers);
	}

# Show table of users
if ($config{'show_size'} == 2) {
	# Show full user details
	local %uconfig = &foreign_config("useradmin");
	print &ui_columns_start( [ $text{'find_user'}, $text{'find_real'},
				   $text{'find_group'}, $text{'find_home'},
				   $text{'find_size'} ], 100);
	foreach $u (@users) {
		local $g = getgrgid($u->[3]);
		$u->[6] =~ s/,.*$// if ($uconfig{'extra_real'});
		local $home = $u->[7];
		if (length($home) > 30) {
			$home = "...".substr($home, -30);
			}
		print &ui_columns_row(
			[ "<a href='list_mail.cgi?user=$u->[0]'>$u->[0]</a>",
			  $u->[6], $g, $home,
			  $size{$u->[0]} == 0 ? $text{'index_empty'} :
				&nice_size($size{$u->[0]}) ],
			[ undef, undef, undef, undef, "nowrap" ]);
		}
	print &ui_columns_end();
	}
else {
	# Just showing username (and maybe size)
	print &ui_table_start($text{'index_header'}, "width=100%", 4);
	local $i = 0;
	foreach $u (@users) {
		print "<tr>\n" if ($i%4 == 0);
		print "<td width=25%><a href='list_mail.cgi?user=$u->[0]'>";
		print $u->[0];
		if ($config{'show_size'} == 1) {
			local @folders = &list_user_folders(@$u);
			local $total = &folder_size(@folders);
			if ($size{$u->[0]} > 0) {
				print " (",&nice_size($size{$u->[0]}),")";
				}
			}
		print "</a></td>\n";
		print "</tr>\n" if ($i%4 == 3);
		$i++;
		}
	if ($i%4) {
		while($i++%4) { print "<td width=25%></td>\n"; }
		print "</tr>\n";
		}
	print &ui_table_end();
	}
}

# switch_to_user(user)
# Switch to the Unix user that files are accessed as.
sub switch_to_user
{
if (!defined($old_uid)) {
        local @uinfo = getpwnam($_[0]);
        $old_uid = $>;
        $old_gid = $);
        $) = "$uinfo[3] $uinfo[3]";
        $> = $uinfo[2];
        }
}

sub switch_user_back
{
if (defined($old_uid)) {
        $> = $old_uid;
        $) = $old_gid;
        $old_uid = $old_gid = undef;
        }
}

sub folder_link
{
return "<a href='list_mail.cgi?user=$_[0]&folder=$_[1]->{'index'}'>$text{'mail_return2'}</a>";
}

# get_from_address()
# Returns the address to use when sending email
sub get_from_address
{
local $host = &get_system_hostname();
if ($config{'webmin_from'} =~ /\@/) {
	return $config{'webmin_from'};
	}
elsif (!$config{'webmin_from'}) {
	return "webmin\@$host";
	}
else {
	return "$config{'webmin_from'}\@$host";
	}
}

# check_modification(&folder)
# Display an error message if a folder has been modified since the time
# in $in{'mod'}
sub check_modification
{
local $newmod = &modification_time($_[0]);
if ($in{'mod'} && $in{'mod'} != $newmod) {
	# Changed!
	&error(&text('emodified', "list_mail.cgi?user=$in{'user'}&folder=$_[0]->{'index'}"));
	}
}

1;

