mirror of
https://github.com/webmin/webmin.git
synced 2025-07-21 23:40:34 +00:00
1290 lines
34 KiB
Perl
Executable File
1290 lines
34 KiB
Perl
Executable File
# mailboxes-lib.pl
|
|
# Common functions for reading user mailboxes
|
|
|
|
BEGIN { push(@INC, ".."); };
|
|
use WebminCore;
|
|
&init_config();
|
|
do "$module_root_directory/boxes-lib.pl";
|
|
do "$module_root_directory/folders-lib.pl";
|
|
%access = &get_module_acl();
|
|
$config{'perpage'} ||= 20;
|
|
$config{'column_count'} ||= 4;
|
|
$no_log_file_changes = 1; # Turn off file change logging for this module
|
|
|
|
@mail_system_modules = (
|
|
[ undef, 4, \&check_qmail_ldap, \&test_qmail_ldap ],
|
|
[ undef, 5, \&check_vpopmail ],
|
|
[ "qmailadmin", 2 ],
|
|
[ "postfix", 0 ],
|
|
[ "sendmail", 1 ],
|
|
[undef, 6, \&check_exim ]
|
|
);
|
|
|
|
@ignore_users_list = &split_quoted_string($config{'ignore_users'});
|
|
|
|
# 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, &dests)
|
|
# Returns the command for injecting email, based on the mail system in use
|
|
sub send_mail_program
|
|
{
|
|
my ($from, $dests) = @_;
|
|
my $qdests = join(" ", map { quotemeta($_) } @$dests);
|
|
|
|
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 -f".quotemeta($_[0])." ".$qdests 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 -f".quotemeta($_[0])." ".$qdests if ($cmd);
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
# list_folders()
|
|
# Returns a list of all mailboxes for all users
|
|
sub list_folders
|
|
{
|
|
local (@rv, $uinfo);
|
|
foreach $uinfo (&list_mail_users()) {
|
|
push(@rv, &list_user_folders(@$uinfo));
|
|
}
|
|
return @rv;
|
|
}
|
|
|
|
# list_user_folders(user, [other info])
|
|
# Returns a list of folders for mailboxes belonging to some user
|
|
sub list_user_folders
|
|
{
|
|
if ($_[0] =~ /^\//) {
|
|
# A path .. return a folder just for it
|
|
return ( { 'name' => $_[0],
|
|
'file' => $_[0],
|
|
'type' => &folder_type($_[0]),
|
|
'mode' => 1,
|
|
'index' => 0 } );
|
|
}
|
|
else {
|
|
# Getting folders for a user
|
|
local @uinfo = @_ > 1 ? @_ : &get_mail_user($_[0]);
|
|
return ( ) if (!@uinfo);
|
|
local ($dir, $style, $mailbox, $maildir) = &get_mail_style();
|
|
local @rv;
|
|
|
|
# Check for user-specified mail store
|
|
if ($uinfo[10]) {
|
|
push(@rv, { 'name' => $uinfo[10],
|
|
'file' => $uinfo[10],
|
|
'type' => &folder_type($uinfo[10]),
|
|
'mode' => 0,
|
|
'index' => scalar(@rv) } );
|
|
}
|
|
|
|
# Check for /var/mail/USERNAME file or directory
|
|
if ($dir) {
|
|
$dir =~ s/\/$//; # Trailing / means maildir format.
|
|
# Postfix sometimes does this.
|
|
local $mf = &mail_file_style($uinfo[0], $dir, $style);
|
|
push(@rv, { 'type' => -d $mf ? 1 : 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' => "~$uinfo[0]/$mailbox",
|
|
'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' => "~$uinfo[0]/$maildir/",
|
|
'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, { 'file' => $p,
|
|
'name' => "~$uinfo[0]/$config{'mail_usermin'}/$f",
|
|
'type' => &folder_type($p),
|
|
'mode' => 0,
|
|
'sent' => $f eq "sentmail",
|
|
'index' => scalar(@rv) } );
|
|
|
|
# Work out if this is a spam folder
|
|
if (lc($f) eq "spam" || lc($f) eq ".spam") {
|
|
# Has spam in the name
|
|
$rv[$#rv]->{'spam'} = 1;
|
|
}
|
|
elsif (&foreign_check("virtual-server")) {
|
|
# Check if Virtualmin is defaulting to it
|
|
local %vconfig = &foreign_config(
|
|
"virtual-server");
|
|
local $sf = $vconfig{'spam_delivery'};
|
|
if ($sf) {
|
|
$sf =~ s/\$HOME/$uinfo[7]/g;
|
|
$sf =~ s/\~/$uinfo[7]/g;
|
|
if ($sf !~ /^\//) {
|
|
$sf = $uinfo[7]."/".$sf;
|
|
}
|
|
$sf =~ s/\/$//;
|
|
if ($p eq $sf) {
|
|
$rv[$#rv]->{'spam'} = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Add any Usermin external mail files
|
|
if ($config{'mailbox_user'}) {
|
|
local %userconfig;
|
|
&read_file_cached("$uinfo[7]/$config{'mailbox_user'}/config",
|
|
\%userconfig);
|
|
local $o;
|
|
foreach $o (split(/\t+/, $userconfig{'mailboxes'})) {
|
|
$o =~ /\/([^\/]+)$/ || next;
|
|
push(@rv, { 'name' => $o,
|
|
'file' => $o,
|
|
'type' => &folder_type($o),
|
|
'mode' => 1,
|
|
'index' => scalar(@rv) } );
|
|
}
|
|
}
|
|
|
|
foreach my $f (@rv) {
|
|
$f->{'user'} = $_[0];
|
|
}
|
|
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 (!scalar(@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'}) {
|
|
# File under /var/mail
|
|
return ($sconfig{'mail_dir'},
|
|
$sconfig{'mail_style'}, undef, undef);
|
|
}
|
|
elsif ($sconfig{'mail_type'}) {
|
|
# Maildir under home directory
|
|
return (undef, $sconfig{'mail_style'},
|
|
undef, $sconfig{'mail_file'});
|
|
}
|
|
else {
|
|
# mbox under home directory
|
|
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 ||
|
|
$config{'mail_system'} == 4) {
|
|
# 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);
|
|
}
|
|
}
|
|
elsif ($config{'mail_system'} == 5) {
|
|
# vpopmail always uses ~/Maildir
|
|
return ( undef, 0, undef, "Maildir" );
|
|
}
|
|
elsif ($config{'mail_system'} == 6) {
|
|
# localmail using smail or exim
|
|
return ( "/var/spool/mail", 0, undef, 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
|
|
{
|
|
if (!&is_user($_[0])) {
|
|
# For external files, check if the file is under an allowed
|
|
# directory, or owned by an allowed user.
|
|
local @st = stat($_[0]);
|
|
local @uinfo = &get_mail_uid($st[4]);
|
|
return 1 if (@uinfo && &can_user(@uinfo));
|
|
local $dir = &allowed_directory();
|
|
return defined($dir) && &is_under_directory($dir, $_[0]);
|
|
}
|
|
local @u = @_ > 1 ? @_ : &get_mail_user($_[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) {
|
|
# Is user in list of users?
|
|
foreach $u (split(/\s+/, $access{'musers'})) {
|
|
return 1 if ($u eq $_[0]);
|
|
}
|
|
return 0;
|
|
}
|
|
elsif ($access{'mmode'} == 4) {
|
|
# Is user the current Webmin user?
|
|
return 1 if ($_[0] eq $remote_user);
|
|
}
|
|
elsif ($access{'mmode'} == 5) {
|
|
# Is the user's gid in the list of groups?
|
|
local $gid;
|
|
foreach $gid (split(/\s+/, $access{'musers'})) {
|
|
return 1 if ($u[3] == $gid);
|
|
if ($access{'msec'}) {
|
|
# Check user's secondary groups too
|
|
local @ginfo = getgrgid($gid);
|
|
local @m = split(/\s+/, $ginfo[3]);
|
|
return 1 if (&indexof($_[0], @m) >= 0);
|
|
}
|
|
}
|
|
}
|
|
elsif ($access{'mmode'} == 3) {
|
|
# Is the user not in the list of denied users
|
|
foreach $u (split(/\s+/, $access{'musers'})) {
|
|
return 0 if ($u eq $_[0]);
|
|
}
|
|
return 1;
|
|
}
|
|
elsif ($access{'mmode'} == 6) {
|
|
# Does the user match a regexp?
|
|
return ($_[0] =~ /^$access{'musers'}$/);
|
|
}
|
|
elsif ($access{'mmode'} == 7) {
|
|
# Is the user's UID within the allowed range?
|
|
return (!$access{'musers'} || $u[2] >= $access{'musers'}) &&
|
|
(!$access{'musers2'} || $u[2] <= $access{'musers2'});
|
|
}
|
|
return 0; # can't happen!
|
|
}
|
|
|
|
# movecopy_user_select(number, folders, folder, form-no)
|
|
# 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'}\">";
|
|
$rv .= "<input type=submit name=copy$_[0] value=\"$text{'mail_copy'}\">";
|
|
$rv .= &ui_user_textbox("mfolder$_[0]", undef, $_[3]);
|
|
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'};
|
|
}
|
|
|
|
# detect_mail_system()
|
|
# Works out which mail server is installed
|
|
sub detect_mail_system
|
|
{
|
|
foreach my $m (@mail_system_modules) {
|
|
return $m->[1] if (&check_mail_system($m));
|
|
}
|
|
return 3;
|
|
}
|
|
|
|
# check_mail_system(&mailsystem)
|
|
sub check_mail_system
|
|
{
|
|
if ($_[0]->[0]) {
|
|
# Just check module
|
|
return &foreign_installed($_[0]->[0]);
|
|
}
|
|
else {
|
|
# Call function
|
|
local $func = $_[0]->[2];
|
|
return &$func($_[0]);
|
|
}
|
|
}
|
|
|
|
# test_mail_system([&mailsystem])
|
|
# Returns an error message if the mail system is invalid
|
|
sub test_mail_system
|
|
{
|
|
local $ms;
|
|
if (!$ms) {
|
|
($ms) = grep { $_->[1] == $config{'mail_system'} } @mail_system_modules;
|
|
}
|
|
if ($ms->[3]) {
|
|
local $func = $ms->[3];
|
|
return &$func();
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
# check_qmail_ldap()
|
|
# Make sure Qmail with LDAP extensions is installed
|
|
sub check_qmail_ldap
|
|
{
|
|
return 0 if (&foreign_installed("qmailadmin", 1) != 2);
|
|
local %qconfig = &foreign_config("qmailadmin");
|
|
return 0 if (!-r "$qconfig{'qmail_dir'}/control/ldapserver");
|
|
return 1;
|
|
}
|
|
|
|
# check_vpopmail()
|
|
# Make sure Qmail with VPopMail extensions is installed
|
|
sub check_vpopmail
|
|
{
|
|
return 0 if (&foreign_installed("qmailadmin", 1) != 2);
|
|
return -x "$config{'vpopmail_dir'}/bin/vadddomain";
|
|
}
|
|
|
|
# check_exim()
|
|
# Make sure Exim is installed
|
|
sub check_exim
|
|
{
|
|
return &has_command('exim');
|
|
}
|
|
|
|
|
|
# test_qmail_ldap()
|
|
# Returns undef the Qmail+LDAP database can be contacted OK, or an error message
|
|
sub test_qmail_ldap
|
|
{
|
|
$config{'ldap_host'} || return $text{'ldap_ehost'};
|
|
$config{'ldap_port'} =~ /^\d+$/ || return $text{'ldap_eport'};
|
|
$config{'ldap_login'} || return $text{'ldap_euser'};
|
|
$config{'ldap_base'} || return $text{'ldap_ebase'};
|
|
local $err = &connect_qmail_ldap(1);
|
|
return ref($err) ? undef : $err;
|
|
}
|
|
|
|
# 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
|
|
{
|
|
my @users = @{$_[0]};
|
|
my ($u, %size, %incount, %sentcount, %foldercount);
|
|
if ($config{'sort_mode'} == 2 || $config{'show_size'} > 0 || $_[1] ||
|
|
$config{'show_count'} || $config{'show_sent'}) {
|
|
# Need to check folders
|
|
foreach $u (@users) {
|
|
next if ($config{'ignore_users_enabled'} == 1 &&
|
|
&indexof($u->[0], @ignore_users_list) >= 0);
|
|
local @folders = &list_user_folders(@$u);
|
|
$foldercount{$u->[0]} = scalar(@folders);
|
|
if ($config{'sort_mode'} == 2 ||
|
|
$config{'show_size'} > 0 || $_[1]) {
|
|
# Compute size of folders
|
|
$size{$u->[0]} = $config{'size_mode'} ?
|
|
&folder_size(@folders) :
|
|
&folder_size($folders[0]);
|
|
}
|
|
if ($config{'show_count'}) {
|
|
# Get number of mails in inbox
|
|
$incount{$u->[0]} = &mailbox_folder_size($folders[0]);
|
|
}
|
|
if ($config{'show_sent'}) {
|
|
# Count number of messages in sent mail
|
|
local ($sent) = grep { $_->{'sent'} } @folders;
|
|
$sentcount{$u->[0]} = &mailbox_folder_size($sent)
|
|
if ($sent);
|
|
}
|
|
}
|
|
}
|
|
|
|
# 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;
|
|
}
|
|
|
|
local @allusers = @users;
|
|
if ($_[1]) {
|
|
# Limit to those with mail
|
|
@users = grep { $size{$_->[0]} } @users;
|
|
}
|
|
|
|
# Show table of users
|
|
if (!@allusers) {
|
|
print "<b>$text{'index_nousers'}</b><p>\n";
|
|
}
|
|
elsif (!@users) {
|
|
print "<b>$text{'index_nousersmail'}</b><p>\n";
|
|
}
|
|
elsif ($config{'show_size'} == 2) {
|
|
# Show full user details
|
|
local %uconfig = &foreign_config("useradmin");
|
|
local @ccols;
|
|
push(@ccols, $text{'find_incount'}) if ($config{'show_count'});
|
|
push(@ccols, $text{'find_sentcount'}) if ($config{'show_sent'});
|
|
push(@ccols, $text{'find_fcount'}) if (%foldercount);
|
|
print &ui_columns_start( [ $text{'find_user'}, $text{'find_real'},
|
|
$text{'find_group'},
|
|
$text{'find_size'}, @ccols ], 100);
|
|
foreach $u (@users) {
|
|
local $g = getgrgid($u->[3]);
|
|
next if ($config{'ignore_users_enabled'} == 1 &&
|
|
&indexof($u->[0], @ignore_users_list) >= 0);
|
|
$u->[6] =~ s/,.*$// if ($uconfig{'extra_real'} ||
|
|
$u->[6] =~ /,$/);
|
|
local $home = $u->[7];
|
|
if (length($home) > 30) {
|
|
$home = "...".substr($home, -30);
|
|
}
|
|
local @ccols;
|
|
if ($config{'show_count'}) {
|
|
push(@ccols, int($incount{$u->[0]}))
|
|
}
|
|
if ($config{'show_sent'}) {
|
|
push(@ccols, int($sentcount{$u->[0]}))
|
|
}
|
|
if (%foldercount) {
|
|
push(@ccols, int($foldercount{$u->[0]}))
|
|
}
|
|
print &ui_columns_row(
|
|
[ &ui_link("list_mail.cgi?user=$u->[0]","$u->[0]"),
|
|
$u->[6], $g,
|
|
$size{$u->[0]} == 0 ? $text{'index_empty'} :
|
|
&nice_size($size{$u->[0]}),
|
|
@ccols ],
|
|
[ undef, undef, undef, undef, "nowrap" ]);
|
|
}
|
|
print &ui_columns_end();
|
|
}
|
|
else {
|
|
# Just showing username (and maybe size)
|
|
my @grid;
|
|
foreach $u (@users) {
|
|
next if ($config{'ignore_users_enabled'} == 1 &&
|
|
&indexof($u->[0], @ignore_users_list) >= 0);
|
|
my $g = "<a href='list_mail.cgi?user=".&urlize($u->[0])."'>";
|
|
$g .= &html_escape($u->[0]);
|
|
if ($config{'show_size'} == 1) {
|
|
local @folders = &list_user_folders(@$u);
|
|
local $total = &folder_size(@folders);
|
|
if ($size{$u->[0]} > 0) {
|
|
$g .= $config{'show_size_below'} ? '<br>' : ' ';
|
|
$g .= "(";
|
|
if (%foldercount) {
|
|
$g .= &text('find_in',
|
|
&nice_size($size{$u->[0]}),
|
|
$foldercount{$u->[0]});
|
|
}
|
|
else {
|
|
$g .= &nice_size($size{$u->[0]});
|
|
}
|
|
$g .= ")";
|
|
}
|
|
}
|
|
$g .= "</a>";
|
|
push(@grid, $g);
|
|
}
|
|
my $w = int(100/$config{'column_count'});
|
|
my @tds = map { "width=".int($w)."%" } (1..$config{'column_count'});
|
|
print &ui_grid_table(\@grid, $config{'column_count'}, 100, \@tds, undef,
|
|
$text{'index_header'});
|
|
}
|
|
}
|
|
|
|
# switch_to_user(user)
|
|
# Switch to the Unix user that files are accessed as.
|
|
sub switch_to_user
|
|
{
|
|
if (!defined($old_uid)) {
|
|
local @uinfo = &get_mail_user($_[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 &ui_link("list_mail.cgi?user=$_[0]&folder=$_[1]->{'index'}",$text{'mail_return2'});
|
|
}
|
|
|
|
# get_from_address()
|
|
# Returns the address to use when sending email from a script
|
|
sub get_from_address
|
|
{
|
|
local $host = &get_from_domain();
|
|
if ($config{'webmin_from'} =~ /\@/) {
|
|
return $config{'webmin_from'};
|
|
}
|
|
elsif (!$config{'webmin_from'}) {
|
|
return "webmin-noreply\@$host";
|
|
}
|
|
else {
|
|
return "$config{'webmin_from'}\@$host";
|
|
}
|
|
}
|
|
|
|
# get_from_domain()
|
|
# Returns the default domain for From: addresses
|
|
sub get_from_domain
|
|
{
|
|
return $config{'from_dom'} || &get_display_hostname();
|
|
}
|
|
|
|
# get_user_from_address(&uinfo)
|
|
# Returns the default From: address for mail sent from some user's mailbox
|
|
sub get_user_from_address
|
|
{
|
|
local $uinfo = $_[0];
|
|
if ($config{'from_addr'}) {
|
|
return $config{'from_addr'};
|
|
}
|
|
elsif ($uinfo->[11]) {
|
|
return $uinfo->[11];
|
|
}
|
|
elsif ($config{'from_virtualmin'} && &foreign_check("virtual-server")) {
|
|
# Does Virtualmin manage this user?
|
|
&foreign_require("virtual-server", "virtual-server-lib.pl");
|
|
local $d;
|
|
foreach $d (&virtual_server::list_domains()) {
|
|
local @users = &virtual_server::list_domain_users($d, 0, 0, 1);
|
|
local $u;
|
|
foreach $u (@users) {
|
|
if ($u->{'user'} eq $uinfo->[0] && $u->{'email'}) {
|
|
# Found him!
|
|
return $u->{'email'};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ($uinfo->[0] =~ /\@/) {
|
|
return $uinfo->[0];
|
|
}
|
|
else {
|
|
return $uinfo->[0].'@'.&get_from_domain();
|
|
}
|
|
}
|
|
|
|
# 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 && $config{'check_mod'}) {
|
|
# Changed!
|
|
&error(&text('emodified', "list_mail.cgi?user=$in{'user'}&folder=$_[0]->{'index'}"));
|
|
}
|
|
}
|
|
|
|
# spam_report_cmd(user)
|
|
# Returns a command for reporting spam, or undef if none
|
|
sub spam_report_cmd
|
|
{
|
|
local ($user) = @_;
|
|
local %sconfig = &foreign_config("spam");
|
|
local $cmd;
|
|
if ($config{'spam_report'} eq 'sa_learn') {
|
|
$cmd = &has_command($sconfig{'sa_learn'}) ? "$sconfig{'sa_learn'} --spam --mbox" : undef;
|
|
}
|
|
elsif ($config{'spam_report'} eq 'spamassassin') {
|
|
$cmd = &has_command($sconfig{'spamassassin'}) ? "$sconfig{'spamassassin'} --r" : undef;
|
|
}
|
|
else {
|
|
$cmd = &has_command($sconfig{'sa_learn'}) ?
|
|
"$sconfig{'sa_learn'} --spam --mbox" :
|
|
&has_command($sconfig{'spamassassin'}) ?
|
|
"$sconfig{'spamassassin'} --r" : undef;
|
|
}
|
|
return $user eq "root" ? $cmd :
|
|
$cmd ? &command_as_user($user, 0, $cmd) : undef;
|
|
}
|
|
|
|
# ham_report_cmd()
|
|
# Returns a command for reporting ham, or undef if none
|
|
sub ham_report_cmd
|
|
{
|
|
local %sconfig = &foreign_config("spam");
|
|
return &has_command($sconfig{'sa_learn'}) ? "$sconfig{'sa_learn'} --ham --mbox" : undef;
|
|
}
|
|
|
|
# allowed_directory()
|
|
# Returns base directory for mail files, or undef if not allowed
|
|
sub allowed_directory
|
|
{
|
|
if ($access{'dir'}) {
|
|
return $access{'dir'};
|
|
}
|
|
else {
|
|
return $access{'mmode'} == 1 ? "/" : undef;
|
|
}
|
|
}
|
|
|
|
# is_user(user)
|
|
sub is_user
|
|
{
|
|
return $_[0] !~ /^\//;
|
|
}
|
|
|
|
# list_mail_users([max], [filterfunc])
|
|
# Returns getpw* style structures for all users who can receive mail. Those with
|
|
# duplicate info are skipped.
|
|
sub list_mail_users
|
|
{
|
|
local ($max, $filter) = @_;
|
|
local @rv;
|
|
|
|
if ($config{'mail_system'} < 3 or $config{'mail_system'} == 6 ) {
|
|
# Postfix, Sendmail, smail, exim and Qmail all use Unix users
|
|
local %found;
|
|
local %hfound;
|
|
local ($dir, $style, $mailbox, $maildir) = &get_mail_style();
|
|
setpwent();
|
|
while(my (@uinfo) = getpwent()) {
|
|
if ($found{$uinfo[0]}++) {
|
|
# done this username already
|
|
next;
|
|
}
|
|
if (!$dir && $hfound{$uinfo[7]}++) {
|
|
# done this home directory (and thus inbox) already
|
|
next;
|
|
}
|
|
if ($dir && $uinfo[0] =~ /\@/) {
|
|
# If this is a user@domain username, mark user-domain
|
|
# as done already, to avoid showing dupes
|
|
local $noat = $uinfo[0];
|
|
$noat =~ s/\@/-/g;
|
|
$found{$noat}++;
|
|
}
|
|
next if ($filter && !&$filter(@uinfo));
|
|
push(@rv, \@uinfo);
|
|
last if ($max && @rv > $max);
|
|
}
|
|
endpwent();
|
|
}
|
|
elsif ($config{'mail_system'} == 4) {
|
|
# Qmail+LDAP uses an LDAP db
|
|
local $ldap = &connect_qmail_ldap();
|
|
local $rv = $ldap->search(base => $config{'ldap_base'},
|
|
filter => "(objectClass=qmailUser)");
|
|
&error($rv->error) if ($rv->code);
|
|
local $u;
|
|
foreach $u ($rv->all_entries) {
|
|
local @uinfo = &qmail_dn_to_user($u);
|
|
next if (!$uinfo[10]); # alias only
|
|
next if ($filter && !&$filter(@uinfo));
|
|
push(@rv, \@uinfo);
|
|
last if ($max && @rv > $max);
|
|
}
|
|
$ldap->unbind();
|
|
}
|
|
elsif ($config{'mail_system'} == 5) {
|
|
# Get vpopmail user list for all domains
|
|
opendir(DOMS, "$config{'vpopmail_dir'}/domains");
|
|
foreach my $d (readdir(DOMS)) {
|
|
next if ($d =~ /^\./);
|
|
local @uinfos = &parse_vpopmail_users("-D $d", $d);
|
|
if ($filter) {
|
|
@uinfos = grep { &$filter(@$_) } @uinfos;
|
|
}
|
|
push(@rv, @uinfos);
|
|
last if ($max && @rv > $max);
|
|
}
|
|
closedir(DOMS);
|
|
}
|
|
return @rv;
|
|
}
|
|
|
|
# parse_vpopmail_users(command, domain)
|
|
sub parse_vpopmail_users
|
|
{
|
|
local %attr_map = ( "passwd" => 1,
|
|
"gecos" => 5,
|
|
"dir" => 7 );
|
|
local (@rv, $user);
|
|
open(UINFO, "$config{'vpopmail_dir'}/bin/vuserinfo $_[0] |");
|
|
while(<UINFO>) {
|
|
s/\r|\n//g;
|
|
if (/^([^:]+):\s+(.*)$/) {
|
|
local ($attr, $value) = ($1, $2);
|
|
if ($attr eq "name") {
|
|
# Start of a new user
|
|
$user = [ "$value\@$_[1]" ];
|
|
$user->[11] = $user->[0];
|
|
push(@rv, $user);
|
|
}
|
|
local $amapped = $attr_map{$attr};
|
|
$user->[$amapped] = $value if ($amapped);
|
|
}
|
|
}
|
|
close(UINFO);
|
|
return @rv;
|
|
}
|
|
|
|
# get_mail_user(name)
|
|
# Looks up a user by name
|
|
sub get_mail_user
|
|
{
|
|
if ($config{'mail_system'} < 3 || $config{'mail_system'} == 6) {
|
|
# Just find Unix user for Sendmail, Postfix, Qmail and Exim
|
|
return getpwnam($_[0]);
|
|
}
|
|
elsif ($config{'mail_system'} == 4) {
|
|
# Lookup in LDAP DB
|
|
local $ldap = &connect_qmail_ldap();
|
|
local $rv = $ldap->search(base => $config{'ldap_base'},
|
|
filter => "(&(objectClass=qmailUser)(uid=$_[0]))");
|
|
&error($rv->error) if ($rv->code);
|
|
local ($u) = $rv->all_entries;
|
|
if ($u) {
|
|
# Found in LDAP
|
|
local @uinfo = &qmail_dn_to_user($u);
|
|
$ldap->unbind();
|
|
return @uinfo;
|
|
}
|
|
else {
|
|
# Fall back to Unix user
|
|
return getpwnam($_[0]);
|
|
}
|
|
}
|
|
elsif ($config{'mail_system'} == 5) {
|
|
# Find in vpopmail
|
|
local ($box, $dom) = split(/\@/, $_[0]);
|
|
local @users = &parse_vpopmail_users($_[0], $dom);
|
|
return @{$users[0]};
|
|
}
|
|
}
|
|
|
|
# get_mail_uid(name)
|
|
# Looks up a user by UID
|
|
sub get_mail_uid
|
|
{
|
|
if ($config{'mail_system'} < 3) {
|
|
# Just find Unix user
|
|
return getpwuid($_[0]);
|
|
}
|
|
elsif ($config{'mail_system'} == 4) {
|
|
# Lookup in LDAP DB
|
|
local $ldap = &connect_qmail_ldap();
|
|
local $rv = $ldap->search(base => $config{'ldap_base'},
|
|
filter => "(&(objectClass=qmailUser)(uidNumber=$_[0]))");
|
|
&error($rv->error) if ($rv->code);
|
|
local ($u) = $rv->all_entries;
|
|
local @uinfo = &qmail_dn_to_user($u);
|
|
$ldap->unbind();
|
|
return @uinfo;
|
|
}
|
|
elsif ($config{'mail_system'} == 5) {
|
|
# Find in vpopmail
|
|
return ( ); # not possible, since UIDs aren't used!
|
|
}
|
|
}
|
|
|
|
# connect_qmail_ldap([return-error])
|
|
# Connect to the LDAP server used for Qmail. Returns an LDAP handle on success,
|
|
# or an error message on failure.
|
|
sub connect_qmail_ldap
|
|
{
|
|
eval "use Net::LDAP";
|
|
if ($@) {
|
|
local $err = &text('ldap_emod', "<tt>Net::LDAP</tt>");
|
|
if ($_[0]) { return $err; }
|
|
else { &error($err); }
|
|
}
|
|
|
|
# Connect to server
|
|
local $port = $config{'ldap_port'} || 389;
|
|
local $ldap = Net::LDAP->new($config{'ldap_host'}, port => $port);
|
|
if (!$ldap) {
|
|
local $err = &text('ldap_econn',
|
|
"<tt>$config{'ldap_host'}</tt>","<tt>$port</tt>");
|
|
if ($_[0]) { return $err; }
|
|
else { &error($err); }
|
|
}
|
|
|
|
# Start TLS if configured
|
|
if ($config{'ldap_tls'}) {
|
|
$ldap->start_tls();
|
|
}
|
|
|
|
# Login
|
|
local $mesg;
|
|
if ($config{'ldap_login'}) {
|
|
$mesg = $ldap->bind(dn => $config{'ldap_login'},
|
|
password => $config{'ldap_pass'});
|
|
}
|
|
else {
|
|
$mesg = $ldap->bind(anonymous => 1);
|
|
}
|
|
if (!$mesg || $mesg->code) {
|
|
local $err = &text('ldap_elogin', "<tt>$config{'ldap_host'}</tt>",
|
|
$dn, $mesg ? $mesg->error : "Unknown error");
|
|
if ($_[0]) { return $err; }
|
|
else { &error($err); }
|
|
}
|
|
return $ldap;
|
|
}
|
|
|
|
# qmail_dn_to_user(&dn)
|
|
sub qmail_dn_to_user
|
|
{
|
|
local $mms = &add_ldapmessagestore(
|
|
scalar($_[0]->get_value("mailMessageStore")));
|
|
if (-d "$mms/Maildir") {
|
|
$mms .= "/" if ($mms !~ /\/$/);
|
|
$mms .= "Maildir";
|
|
}
|
|
return ( scalar($_[0]->get_value("uid")),
|
|
scalar($_[0]->get_value("userPassword")),
|
|
scalar($_[0]->get_value("uidNumber")),
|
|
scalar($_[0]->get_value("gidNumber")),
|
|
scalar($_[0]->get_value("mailQuotaSize")),
|
|
scalar($_[0]->get_value("cn")),
|
|
scalar($_[0]->get_value("cn")),
|
|
scalar($_[0]->get_value("homeDirectory")),
|
|
scalar($_[0]->get_value("loginShell")),
|
|
undef,
|
|
$mms,
|
|
scalar($_[0]->get_value("mail")),
|
|
);
|
|
}
|
|
|
|
# add_ldapmessagestore(path)
|
|
sub add_ldapmessagestore
|
|
{
|
|
if (!$_[0]) {
|
|
return $_[0];
|
|
}
|
|
elsif ($_[0] =~ /^\//) {
|
|
return $_[0];
|
|
}
|
|
else {
|
|
&foreign_require("qmailadmin", "qmail-lib.pl");
|
|
local $pfx = &qmailadmin::get_control_file("ldapmessagestore");
|
|
return $pfx."/".$_[0];
|
|
}
|
|
}
|
|
|
|
# show_buttons(number, &folders, current-folder, &mail, user, search-mode)
|
|
sub show_buttons
|
|
{
|
|
local ($num, $folders, $folder, $mail, $user, $search) = @_;
|
|
local $uuser = &urlize($user);
|
|
local $spacer = " \n";
|
|
if (@$mail) {
|
|
# Delete
|
|
print "<input type=submit name=delete value=\"$text{'mail_delete'}\">";
|
|
if ($config{'show_delall'} && !$search) {
|
|
print "<input type=submit name=deleteall value=\"$text{'mail_deleteall'}\">";
|
|
}
|
|
print $spacer;
|
|
|
|
# Mark as
|
|
print "<input type=submit name=mark$_[0] value=\"$text{'mail_mark'}\">";
|
|
print "<select name=mode$_[0]>\n";
|
|
print "<option value=1 checked>$text{'mail_mark1'}</option>\n";
|
|
print "<option value=0>$text{'mail_mark0'}</option>\n";
|
|
print "<option value=2>$text{'mail_mark2'}</option>\n";
|
|
print "</select>";
|
|
print $spacer;
|
|
|
|
if (&is_user($user)) {
|
|
# Forward
|
|
if ($config{'open_mode'}) {
|
|
# Forward messages in a separate window
|
|
print "<input type=submit name=forward value=\"$text{'mail_forward'}\" onClick='args = \"user=$uuser&folder=$folder->{'index'}\"; for(i=0; i<form.d.length; i++) { if (form.d[i].checked) { args += \"&mailforward=\"+form.d[i].value; } } window.open(\"reply_mail.cgi?\"+args, \"compose\", \"toolbar=no,menubar=no,scrollbars=yes,width=1024,height=768\"); return false'>";
|
|
|
|
}
|
|
else {
|
|
print "<input type=submit name=forward value=\"$text{'mail_forward'}\">";
|
|
}
|
|
print $spacer;
|
|
}
|
|
|
|
# Move/copy
|
|
print &movecopy_user_select($_[0], $folders, $folder, 1);
|
|
print $spacer;
|
|
|
|
# Show spam report buttons
|
|
if (!$folder->{'spam'} &&
|
|
&foreign_installed("spam") &&
|
|
$config{'spam_buttons'} =~ /list/ &&
|
|
&spam_report_cmd($user)) {
|
|
if (&foreign_available("spam")) {
|
|
print "<input type=submit value=\"$text{'mail_black'}\" name=black>";
|
|
}
|
|
if ($config{'spam_del'}) {
|
|
print "<input type=submit value=\"$text{'view_razordel'}\" name=razor>\n";
|
|
}
|
|
else {
|
|
print "<input type=submit value=\"$text{'view_razor'}\" name=razor>";
|
|
}
|
|
print $spacer;
|
|
}
|
|
elsif ($folder->{'spam'} &&
|
|
&foreign_installed("spam") &&
|
|
$config{'spam_buttons'} =~ /list/ &&
|
|
&ham_report_cmd($user)) {
|
|
if (&foreign_available("spam")) {
|
|
print "<input type=submit value=\"$text{'mail_white'}\" name=white>";
|
|
}
|
|
print "<input type=submit value=\"$text{'view_ham'}\" name=ham>";
|
|
print $spacer;
|
|
}
|
|
}
|
|
|
|
if ($config{'open_mode'}) {
|
|
# Show mass open button
|
|
print "<input type=submit name=new value=\"$text{'mail_open'}\" onClick='for(i=0; i<form.d.length; i++) { if (form.d[i].checked) { window.open(\"view_mail.cgi?user=$uuser&folder=$folder->{'index'}&idx=\"+form.d[i].value, \"view\"+i, \"toolbar=no,menubar=no,scrollbars=yes,width=1024,height=768\"); } }
|
|
return false'>";
|
|
print $spacer;
|
|
}
|
|
|
|
# Compose
|
|
if (&is_user($user)) {
|
|
if ($config{'open_mode'}) {
|
|
# In a separate window
|
|
print "<input type=submit name=new value=\"$text{'mail_compose'}\" onClick='window.open(\"reply_mail.cgi?user=$user&new=1\", \"compose\", \"toolbar=no,menubar=no,scrollbars=yes,width=1024,height=768\"); return false'>";
|
|
}
|
|
else {
|
|
print "<input type=submit name=new value=\"$text{'mail_compose'}\">";
|
|
}
|
|
}
|
|
print "<br>\n";
|
|
}
|
|
|
|
# get_signature(user)
|
|
# Returns the users signature, if any
|
|
sub get_signature
|
|
{
|
|
local $sf = &get_signature_file($_[0]);
|
|
$sf || return undef;
|
|
local $sig;
|
|
open(SIG, "<".$sf) || return undef;
|
|
while(<SIG>) {
|
|
$sig .= $_;
|
|
}
|
|
close(SIG);
|
|
return $sig;
|
|
}
|
|
|
|
# get_signature_file(user)
|
|
# Returns the full path to the file that should contain the user's signature,
|
|
# or undef if none is defined
|
|
sub get_signature_file
|
|
{
|
|
return undef if ($config{'sig_file'} eq '*' || $config{'sig_file'} eq '');
|
|
local $sf = $config{'sig_file'};
|
|
if ($sf !~ /^\//) {
|
|
local @uinfo = getpwnam($_[0]);
|
|
$sf = "$uinfo[7]/$sf";
|
|
}
|
|
return $sf;
|
|
}
|
|
|
|
# view_mail_link(user, &folder, index, from-to-text, [dom])
|
|
sub view_mail_link
|
|
{
|
|
local ($user, $folder, $idx, $txt, $dom) = @_;
|
|
local $uuser = &urlize($user);
|
|
local $url = "view_mail.cgi?user=$uuser&idx=$idx&folder=$folder->{'index'}".
|
|
"&dom=$dom";
|
|
if ($config{'open_mode'}) {
|
|
return "<a href='' onClick='window.open(\"$url\", \"viewmail\", \"toolbar=no,menubar=no,scrollbars=yes,width=1024,height=768\"); return false'>".
|
|
&simplify_from($txt)."</a>";
|
|
}
|
|
else {
|
|
return "<a href='$url'>".&simplify_from($txt)."</a>";
|
|
}
|
|
}
|
|
|
|
# mail_page_header(title, headstuff, bodystuff, rightstuff)
|
|
sub mail_page_header
|
|
{
|
|
if ($config{'open_mode'}) {
|
|
&popup_header($_[0], $_[1], $_[2]);
|
|
}
|
|
else {
|
|
&ui_print_header(undef, $_[0], "", undef, 0, 0, 0, $_[3], $_[1], $_[2]);
|
|
}
|
|
}
|
|
|
|
# mail_page_footer(link, text, ...)
|
|
sub mail_page_footer
|
|
{
|
|
if ($config{'open_mode'}) {
|
|
&popup_footer();
|
|
}
|
|
else {
|
|
&ui_print_footer(@_);
|
|
}
|
|
}
|
|
|
|
# delete_user_index_files(name)
|
|
# Delete all files associated with some user's mail, such as index and maildir
|
|
# cache files
|
|
sub delete_user_index_files
|
|
{
|
|
local ($user) = @_;
|
|
foreach my $folder (&list_user_folders($user)) {
|
|
if ($folder->{'type'} == 0) {
|
|
# Remove mbox index
|
|
local $ifile = &user_index_file($folder->{'file'});
|
|
if (-r $ifile) {
|
|
&unlink_file($ifile);
|
|
}
|
|
else {
|
|
&unlink_file(glob("\Q$ifile\E.{dir,pag,db}"));
|
|
}
|
|
&unlink_file("$ifile.ids");
|
|
}
|
|
elsif ($folder->{'type'} == 1) {
|
|
# Remove Maildir files file
|
|
&unlink_file(&get_maildir_cachefile($folder->{'file'}));
|
|
}
|
|
# Remove sort index
|
|
local $ifile = &folder_new_sort_index_file($folder);
|
|
if (-r $ifile) {
|
|
&unlink_file($ifile);
|
|
}
|
|
else {
|
|
&unlink_file(glob("\Q$ifile\E.{dir,pag,db}"));
|
|
}
|
|
}
|
|
# Remove read file
|
|
local $read = &user_read_dbm_file($user);
|
|
if (-r $read) {
|
|
&unlink_file($read);
|
|
}
|
|
else {
|
|
&unlink_file(glob("\Q$read\E.{dir,pag,db}"));
|
|
}
|
|
}
|
|
|
|
# get_mail_read(&folder, &mail)
|
|
# Returns the read flag for some message, from the DBM
|
|
sub get_mail_read
|
|
{
|
|
local ($folder, $mail) = @_;
|
|
if (!$done_dbmopen_read++) {
|
|
&open_dbm_db(\%read, &user_read_dbm_file($folder->{'user'}), 0600);
|
|
}
|
|
return $read{$mail->{'header'}->{'message-id'}};
|
|
}
|
|
|
|
# set_mail_read(&folder, &mail, read)
|
|
# Sets the read flag for some message in the DBM
|
|
sub set_mail_read
|
|
{
|
|
local ($folder, $mail, $read) = @_;
|
|
if (!$done_dbmopen_read++) {
|
|
&open_dbm_db(\%read, &user_read_dbm_file($folder->{'user'}), 0600);
|
|
}
|
|
$read{$mail->{'header'}->{'message-id'}} = $read;
|
|
}
|
|
|
|
# show_mail_table(&mails, &folder, formno, [&read])
|
|
# Output a full table of messages
|
|
sub show_mail_table
|
|
{
|
|
local @mail = @{$_[0]};
|
|
local (undef, $folder, $formno) = @_;
|
|
|
|
my $showto = !$folder ? 0 :
|
|
$folder->{'sent'} || $folder->{'drafts'} ? 1 : 0;
|
|
my @tds = ( "nowrap", "nowrap", "nowrap", "nowrap" );
|
|
|
|
# Show mailbox headers
|
|
local @hcols;
|
|
if ($folder) {
|
|
push(@hcols, "");
|
|
splice(@tds, "width=5", 0, 0);
|
|
}
|
|
push(@hcols, $showto ? $text{'mail_to'} : $text{'mail_from'});
|
|
push(@hcols, $config{'show_to'} ? $showto ? ( $text{'mail_from'} ) :
|
|
( $text{'mail_to'} ) : ());
|
|
push(@hcols, $text{'mail_date'});
|
|
push(@hcols, $text{'mail_size'});
|
|
push(@hcols, $text{'mail_subject'});
|
|
my @links = ( &select_all_link("d", $formno),
|
|
&select_invert_link("d", $formno) );
|
|
if ($folder) {
|
|
print &ui_links_row(\@links);
|
|
}
|
|
print &ui_columns_start(\@hcols, 100, 0, \@tds);
|
|
|
|
# Show rows for actual mail messages
|
|
my $i = 0;
|
|
foreach my $mail (@mail) {
|
|
local $idx = $mail->{'idx'};
|
|
local $cols = 0;
|
|
local @cols;
|
|
local @rowtds = @tds;
|
|
|
|
# From and To columns, with links
|
|
local $from = $mail->{'header'}->{$showto ? 'to' : 'from'};
|
|
$from = $text{'mail_unknown'} if ($from !~ /\S/);
|
|
local $mfolder = $mail->{'folder'} || $folder;
|
|
push(@cols, &view_mail_link($in{'user'}, $mfolder, $idx, $from,
|
|
$in{'dom'}));
|
|
if ($config{'show_to'}) {
|
|
push(@cols, &simplify_from(
|
|
$mail->{'header'}->{$showto ? 'from' : 'to'}));
|
|
}
|
|
|
|
# Date and size columns
|
|
push(@cols, &eucconv_and_escape(&simplify_date($mail->{'header'}->{'date'})));
|
|
push(@cols, &nice_size($mail->{'size'}, 1024));
|
|
$rowtds[$#cols] .= " data-sort=".&parse_mail_date($mail->{'header'}->{'date'});
|
|
|
|
# Subject with icons
|
|
local @icons = &message_icons($mail, $mfolder->{'sent'}, $mfolder);
|
|
push(@cols, &simplify_subject($mail->{'header'}->{'subject'}).
|
|
join(" ", @icons));
|
|
|
|
# Flag unread mails
|
|
local $hid = $mail->{'header'}->{'message-id'};
|
|
if ($_[3] && !$_[3]->{$hid}) {
|
|
@cols = map { "<b>$_</b>" } @cols;
|
|
}
|
|
|
|
# Generate the row
|
|
if (!$folder) {
|
|
print &ui_columns_row(\@cols, \@rowtds);
|
|
}
|
|
elsif (&editable_mail($mail)) {
|
|
print &ui_checked_columns_row(\@cols, \@rowtds, "d", $idx);
|
|
}
|
|
else {
|
|
print &ui_columns_row([ "", @cols ], \@tds);
|
|
}
|
|
|
|
if ($config{'show_body'}) {
|
|
# Show part of the body too
|
|
&parse_mail($mail);
|
|
local $data = &mail_preview($mail);
|
|
if ($data) {
|
|
print "<tr $cb> <td colspan=",(scalar(@cols)+1),"><tt>",
|
|
&html_escape($data),"</tt></td> </tr>\n";
|
|
}
|
|
}
|
|
$i++;
|
|
}
|
|
print &ui_columns_end();
|
|
if ($folder) {
|
|
print &ui_links_row(\@links);
|
|
}
|
|
}
|
|
|
|
sub user_list_link
|
|
{
|
|
if ($in{'dom'}) {
|
|
return "../virtual-server/list_users.cgi?dom=$in{'dom'}";
|
|
}
|
|
else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
# user_read_dbm_file(user)
|
|
# Returns the DBM base filename to track read status for messages to some user
|
|
sub user_read_dbm_file
|
|
{
|
|
my ($user) = @_;
|
|
my $rv = "$module_config_directory/$user.read";
|
|
if (!glob("\Q$rv\E.*")) {
|
|
$rv = "$module_var_directory/$user.read";
|
|
}
|
|
return $rv;
|
|
}
|
|
|
|
1;
|