initial commit of file from CVS for e-smith-quota on Wed 12 Jul 09:07:49 BST 2023

This commit is contained in:
Brian Read
2023-07-12 09:07:49 +01:00
parent eb7764ae78
commit d4ad9b87d5
20 changed files with 2714 additions and 2 deletions

View File

@@ -0,0 +1,2 @@
# Send email reminders about being overquota. Do it daily (at 00:37)
37 0 * * * root /sbin/e-smith/warnquota

View File

@@ -0,0 +1,227 @@
#!/usr/bin/perl -w
#----------------------------------------------------------------------
# copyright (C) 2002 Mitel Networks Corporation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Technical support for this program is available from Mitel Networks
# Please visit our web site www.mitel.com/sme/ for details.
#----------------------------------------------------------------------
package esmith;
use strict;
use Errno;
use Quota;
use esmith::AccountsDB;
my $accounts = esmith::AccountsDB->open;
my @users = ();
my $event = $ARGV [0];
if ($event eq "bootstrap-console-save")
{
# For bootstrap-console-save, make sure that quota entries are
# set for each user
@users = $accounts->users;
}
else
{
# Otherwise just set quota for the named user.
my $userName = $ARGV [1];
#------------------------------------------------------------
# Check the Unix account
#------------------------------------------------------------
=begin testing
use esmith::TestUtils qw(simulate_perl_program);
my $exit = simulate_perl_program($Original_File, 'wibble-event',
'user_that_doesnt_exist');
is( $exit, 255 * 256, 'non-existent user - exit code' );
like( $@, qr{^Account "user_that_doesnt_exist" is not a user account},
' failure message');
$exit = simulate_perl_program($Original_File, 'wibble-event' );
is( $exit, 255 * 256, 'forgotten user - exit code' );
like( $@, qr{^Username argument missing},
' failure message');
=end testing
=cut
die "Username argument missing.\n" unless defined ($userName);
my $user = $accounts->get($userName);
if( !$user or $user->prop('type') ne 'user' )
{
die qq{Account "$userName" is not a user account; modify } .
"user quota failed.\n";
}
@users = ($user);
}
=begin testing
my $a_tmp = '50-e-smith-quota/accounts.conf';
$ENV{ESMITH_ACCOUNT_DB} = $a_tmp;
END { unlink $a_tmp };
open(TMP, ">$a_tmp") || die $!;
print TMP <<'OUT';
root=system|Gid|0|Uid|0
server-manager=url
server-manual=url
shared=system|Gid|500|Visible|internal
shutdown=system
slocate=system|Gid|21
user_quota=user|Gid|1000|Uid|1000|MaxBlocksSoftLim|10000|MaxBlocks|20000|MaxFilesSoftLim|1000|MaxFiles|2000
user_partial=user|Gid|1001|Uid|1001|MaxBlocksSoftLim|123456|MaxFiles|321
user_no_quota=user|Gid|1002|Uid|1002
OUT
close TMP;
# Quota properties in the order setqlim likes.
my @QProps = qw(MaxBlocksSoftLim MaxBlocks MaxFilesSoftLim MaxFiles);
my %curr_quota = (
1000 => { MaxFilesSoftLim => 100 },
1001 => { MaxBlocks => 30000, MaxBlocksSoftLim => 20000 },
1002 => { MaxFiles => 2 },
);
# What we expect the new quotas to be
my %expect_quotas = (
1000 => { MaxBlocksSoftLim => 10000, MaxBlocks => 20000,
MaxFilesSoftLim => 1000, MaxFiles => 2000 },
1001 => { MaxBlocksSoftLim => 123456, MaxBlocks => 30000,
MaxFilesSoftLim => 0, MaxFiles => 321 },
1002 => { MaxBlocksSoftLim => 0, MaxBlocks => 0,
MaxFilesSoftLim => 0, MaxFiles => 2 },
);
{
# Since these users don't really exist, we have to fool getpwnam
# into using the Uid from the dummy accounts DB.
no warnings 'once';
local *CORE::GLOBAL::getpwnam = sub {
esmith::AccountsDB->open->get($_[0])->prop('Uid');
};
# Override the Quota query and set functions since
# 1) these users probably don't exist
# 2) if they did, we don't want to screw with their quotas
# 3) we need to know how each Quota function is called
use Quota;
no warnings 'redefine';
my %query;
sub Quota::query {
my($dev, $uid, $isgrp) = @_;
$query{$uid} = { isgrp => $isgrp };
return (0,
$curr_quota{$uid}{MaxBlocksSoftLim} || 0,
$curr_quota{$uid}{MaxBlocks} || 0,
0,
0,
$curr_quota{$uid}{MaxFilesSoftLim} || 0,
$curr_quota{$uid}{MaxFiles} || 0,
0
);
}
my %set_quota = ();
sub Quota::setqlim {
my($dev, $uid) = (shift, shift);
my(@limits) = splice(@_, 0, 4);
my($tlo) = shift;
my %limits = ();
@limits{@QProps} = @limits;
$set_quota{$uid}{limits} = \%limits;
$set_quota{$uid}{tlo} = $tlo;
return 1;
}
$_STDOUT_ = '';
$_STDERR_ = '';
my $exit = simulate_perl_program($Original_File, 'bootstrap-console-save');
is( $exit, 0, 'bootstrap-console-save - exit code' );
is( $_STDOUT_, '' );
is( $_STDERR_, '' );
is( $@, '' );
is_deeply( [sort keys %set_quota], [sort qw(1000 1001 1002)] );
foreach my $uid (keys %set_quota)
{
is_deeply( $set_quota{$uid}{limits}, $expect_quotas{$uid},
"setqlim for $uid");
}
}
=end testing
=cut
# Quota properties in the order setqlim likes.
my @QProps = qw(MaxBlocksSoftLim MaxBlocks MaxFilesSoftLim MaxFiles);
foreach my $user (@users)
{
my $userName = $user->key;
my $uid = getpwnam($userName);
die qq{Could not get uid for user named "$userName"\n} unless $uid;
my(%uquota, %curr_quota);
foreach my $qprop (@QProps)
{
$uquota{$qprop} = $user->prop($qprop);
}
# Get a $dev value appropriate for use in Quota::query call.
my $dev = Quota::getqcarg("/home/e-smith/files");
# Get current quota settings.
@curr_quota{@QProps} = (Quota::query($dev, $uid, 0))[1,2,5,6];
if( !defined $curr_quota{MaxBlocks} ) # Quota::query failed
{
warn "Cannot query your quota for '$userName' on '$dev'\n";
warn "Quota error (are you using NFS?): ", Quota::strerr(), "\n";
next;
}
# Keep old values unless there are values defined in the account record
foreach my $qprop (@QProps)
{
$uquota{$qprop} = $curr_quota{$qprop}
unless defined $uquota{$qprop};
}
# Set the new quota
Quota::setqlim($dev, $uid, @uquota{@QProps}, 0);
}

View File

@@ -0,0 +1,130 @@
<lexicon lang="en-us">
<entry>
<base>FORM_TITLE</base>
<trans>Create, modify, or remove user account quotas</trans>
</entry>
<entry>
<base>UNABLE_TO_OPEN_ACCOUNTS</base>
<trans>Unable to open accounts db</trans>
</entry>
<entry>
<base>QUOTA_DESC</base>
<trans>
<![CDATA[
<p>You can set filesystem quotas for users on your system by clicking
the "Modify" button next to the user you wish to update.
<p>If the user exceeds the "Limit with grace period", warnings will be
generated. If this limit is exceeded for longer than a week or if the
"Absolute limit" is reached, the user will be unable to store any more
files or receive any more e-mail.
<p>A setting of '0' for either limit disables that limit for the
corresponding user.
<p>The disk space for each user includes the user's home directory,
e-mail, and any files owned by the user in information bays.
]]>
</trans>
</entry>
<entry>
<base>CURRENT_USAGE_AND_SETTINGS</base>
<trans>Current Quota Usage and Settings</trans>
</entry>
<entry>
<base>LIMIT_WITH_GRACE</base>
<trans>Limit with grace period</trans>
</entry>
<entry>
<base>LIMIT_WITH_GRACE_MB</base>
<trans>Limit with grace period (MB)</trans>
</entry>
<entry>
<base>ABS_LIMIT</base>
<trans>Absolute limit</trans>
</entry>
<entry>
<base>ABS_LIMIT_MB</base>
<trans>Absolute limit (MB)</trans>
</entry>
<entry>
<base>CURRENT_USAGE</base>
<trans>Current usage (MB)</trans>
</entry>
<entry>
<base>COULD_NOT_GET_UID</base>
<trans>Could not determine the uid for user: </trans>
</entry>
<entry>
<base>ERR_NO_SUCH_ACCT</base>
<trans>Error: there is no account named: </trans>
</entry>
<entry>
<base>ERR_NOT_A_USER_ACCT</base>
<trans>Error: the account is not a user account: </trans>
</entry>
<entry>
<base>ACCOUNT_IS_TYPE</base>
<trans>It is an account of type: </trans>
</entry>
<entry>
<base>MODIFY_USER_TITLE</base>
<trans>Modify user quota limits</trans>
</entry>
<entry>
<base>USER</base>
<trans>User: </trans>
</entry>
<entry>
<base>CURRENTLY_HAS</base>
<trans>currently has: </trans>
</entry>
<entry>
<base>FILES</base>
<trans>files</trans>
</entry>
<entry>
<base>OCCUPYING</base>
<trans>occupying: </trans>
</entry>
<entry>
<base>MEGABYTES</base>
<trans>megabytes</trans>
</entry>
<entry>
<base>INSTRUCTIONS</base>
<trans>
Enter the quota with optional unit suffix of 'K' for kilobytes, 'M' for megabytes,
'G' for gigabytes or 'T' for terabytes.
Entries with no suffix are assumed to be in megabytes. A setting of '0'
for either limit disables that limit for the corresponding user.
</trans>
</entry>
<entry>
<base>SOFT_VAL_MUST_BE_NUMBER</base>
<trans>Error: limit with grace period must be a number, optionally followed by one of the unit suffixes K, M, G, or T.</trans>
</entry>
<entry>
<base>HARD_VAL_MUST_BE_NUMBER</base>
<trans>Error: absolute limit must be a number, optionally followed by one of the unit suffixes K, M, G, or T.</trans>
</entry>
<entry>
<base>ERR_HARD_LT_SOFT</base>
<trans>
Error: absolute limit must be greater than limit with grace time.
</trans>
</entry>
<entry>
<base>ERR_MODIFYING</base>
<trans>Error occurred while modifying user.</trans>
</entry>
<entry>
<base>SUCCESSFULLY_MODIFIED</base>
<trans>Successfully modified quota for user account: </trans>
</entry>
<entry>
<base>Quotas</base>
<trans>Quotas</trans>
</entry>
</lexicon>

View File

@@ -0,0 +1,11 @@
{
# Change defaults => usrquota,grpquota for / file system
@lines = map {
/\s\/\s+ext[234]\s+defaults\s/ && s/defaults/usrquota,grpquota/;
/^\/dev\/main\/.*\s+ext[234]\s+defaults\s/ && s/defaults/usrquota,grpquota/;
/\s\/\s+xfs\s+defaults\s/ && s/defaults/uquota,gquota/;
/^\/dev\/main\/.*\s+xfs\s+defaults\s/ && s/defaults/uquota,gquota/;
$_
} @lines;
"";
}

View File

@@ -0,0 +1,44 @@
{
use esmith::I18N;
use Locale::gettext;
my $i18n = new esmith::I18N;
$i18n->setLocale('adminQuotaSummary.tmpl');
my $domain = $conf->get_value("DomainName") || "localhost";
my $systemName = $conf->get_value("SystemName") || "SME Server";
$OUT .= "To: ".gettext("System Administrator")." <admin\@${domain}>\n";
$OUT .= "From: \"".
gettext("Automated quota report").
"\" <do-not-reply\@${domain}>\n";
$OUT .= "Subject: ".
gettext("One or more users have exceeded their disk quota").
"\n";
#----------------------------------------------------------------------
# Over quota users:
#----------------------------------------------------------------------
$OUT .= gettext("The following users have exceeded their disk quota on the server called").
" \"$systemName\" ".gettext("All values are in megabytes.");
$OUT .= "\n";
$OUT .= sprintf("%-20s%+8s%+28s%+19s",
gettext("Account"),
gettext("Usage"),
gettext("Limit with grace period"),
gettext("Absolute limit")
) . "\n";
$OUT .= "-"x75 . "\n";;
foreach my $user (sort keys %usersOverQuota)
{
$OUT .= sprintf("%-20s%8.2f%28.2f%19.2f",
$user,
$usersOverQuota{$user}{usage},
$usersOverQuota{$user}{softQuota},
$usersOverQuota{$user}{hardQuota}
) . "\n";
}
}

View File

@@ -0,0 +1,31 @@
{
use esmith::I18N;
use Locale::gettext;
my $i18n = new esmith::I18N;
$i18n->setLocale('userOverQuota.tmpl');
my $domain = $conf->get_value("DomainName") || "localhost";
my $systemName = $conf->get_value("SystemName") || "SME Server";
my $gracePeriodEnds = localtime($data{gracePeriod});
$OUT .= "To: $data{fullname} <$data{username}\@${domain}>\n";
$OUT .= "From: \"".
gettext("Automated quota report").
"\" <do-not-reply\@${domain}>\n";
$OUT .= "Subject: ".gettext("You have exceeded your disk quota")."\n";
$OUT .= gettext("Your current disk usage:").
" $data{usage} ".gettext("Mb")."\n";
$OUT .= gettext("Your maximum usage:").
($data{hardQuota} == 0 ? gettext(" no limit set") :
" $data{hardQuota} ".gettext("Mb"))."\n";
$OUT .= gettext("Warnings start at:").
" $data{softQuota} ".gettext("Mb")."\n";
$OUT .= gettext("Grace period ends:")." $gracePeriodEnds\n";
$OUT .= gettext("System name:")." $systemName\n\n";
$OUT .= gettext("You are currently using more disk space than you have been allotted. You have until the Grace Period above to remove files so that you no longer exceed the warning level. At no time will you be permitted to store more than the maximum usage indicated above. This disk allocation includes all your e-mail, including unread e-mail.");
}

View File

@@ -0,0 +1,49 @@
#!/usr/bin/perl -wT
#----------------------------------------------------------------------
# heading : Collaboration
# description : Quotas
# navigation : 2000 2300
#----------------------------------------------------------------------
#----------------------------------------------------------------------
# copyright (C) 2002 Mitel Networks Corporation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Technical support for this program is available from Mitel Networks
# Please visit our web site www.e-smith.com for details.
#----------------------------------------------------------------------
use strict;
use esmith::FormMagick::Panel::quota;
my $panel = esmith::FormMagick::Panel::quota->new();
$panel->display();
__DATA__
<form title="FORM_TITLE" header="/etc/e-smith/web/common/head.tmpl"
footer="/etc/e-smith/web/common/foot.tmpl">
<page name="Initial" pre-event="print_status_message">
<subroutine src="showInitial()"/>
</page>
<page name="Modify" pre-event="turn_off_buttons"
post-event="performModifyUser">
<title>MODIFY_USER_TITLE</title>
<subroutine src="modifyUser()"/>
<subroutine src="print_button('SAVE')"/>
</page>
</form>

294
root/sbin/e-smith/warnquota Normal file
View File

@@ -0,0 +1,294 @@
#!/usr/bin/perl -w
package esmith;
use strict;
use esmith::ConfigDB;
use esmith::util;
use esmith::db;
use Text::Template;
sub getUserQuotas();
sub alertUsersOverQuota($$);
sub sendAdminSummary($$$$);
sub toMB ($);
sub toMBNoDecimalPlaces ($);
sub toKB ($);
my $conf = esmith::ConfigDB->open_ro;
=for testing
is( system("$^X -cw $Original_File 2>&1"), 0, 'it compiles' );
=head1 Automated quota reporting
This script iterates through each user account on the system and sends
an email report to each user when they are over quota.
It sends a combined summary report to the administrator.
=cut
#----------------------------------------------------------------------
# Set qmail environment variables so that we get decent looking mail
# headers (From, Return-Path)
#----------------------------------------------------------------------
my $domain = $conf->get_value("DomainName") || 'localhost';
my ($quotaOffenders, $quotaUsers, $quotalessUsers)
= getUserQuotas();
alertUsersOverQuota($conf, $quotaOffenders);
sendAdminSummary($conf, $quotaOffenders, $quotaUsers, $quotalessUsers);
=head2 getUserQuotas()
For each user on the system, determines their current disk usage, soft
and hard quota, and grace period remaining.
It returns three data structures containing users whom are over quota,
users whom are under quota, and those with no quotas:
%hash = {
'user1' => {
'hardQuota',
'softQuota',
'username',
'usage',
'fullname',
'gracePeriod'
},
.
.
.
.
'userX' => {
'hardQuota',
'softQuota',
'username',
'usage',
'fullname',
'gracePeriod'
}
};
=cut
sub getUserQuotas()
{
use Quota;
use esmith::AccountsDB;
my $adb = esmith::AccountsDB->open_ro();
my %usersOverQuota;
my %usersUnderQuota;
my %usersWithNoQuota;
# Make $dev arg for quota query calls
my $dev = Quota::getqcarg('/home/e-smith/files');
#------------------------------------------------------------
# Loop through all user accounts and collect stats.
#------------------------------------------------------------
foreach my $user ($adb->users)
{
my $uid = getpwnam($user->key);
unless ($uid)
{
warn("Could not get uid for user \"" . $user->key ."\"");
next;
}
my ($bc, $bs, $bh, $bt, $ic, $is, $ih, $it) =
Quota::query($dev, $uid);
if( !defined $bc ) # Quota::query failed
{
warn "Cannot query quota for '" . $user->key . "' on '$dev': ", Quota::strerr(), "\n";
next;
}
my $name = $user->prop('FirstName') . " " . $user->prop('LastName');
#------------------------------------------------------------
# Collect user stats if over quota.
# Everyone over quota goes into %usersOverQuota
# Everyone under quota goes into %usersUnderQuota
# Everyone else, goes into %usersWithNoQuota.
#------------------------------------------------------------
if ( ($bs == 0) && ($bh == 0) )
{
# User has no quota
# Add user to data structure.
${usersWithNoQuota{$user->key}} = {
username => $user->key,
fullname => $name,
usage => toMB($bc),
softQuota => toMB($bs),
hardQuota => toMB($bh),
gracePeriod => $bt
};
}
elsif ( (($bc > $bh) && ($bh > 0)) || (($bc > $bs) && ($bs > 0)) )
{
# User is over quota
# gracePeriod is 0 if over hard limit
# Add user to data structure.
${usersOverQuota{$user->key}} = {
username => $user->key,
fullname => $name,
usage => toMB($bc),
softQuota => toMB($bs),
hardQuota => toMB($bh),
gracePeriod => $bt
};
}
else
{
# User is within quota
# Add user to data structure.
${usersUnderQuota{$user->key}} = {
username => $user->key,
fullname => $name,
usage => toMB($bc),
softQuota => toMB($bs),
hardQuota => toMB($bh),
gracePeriod => $bt
};
}
}
return \%usersOverQuota, \%usersUnderQuota, \%usersWithNoQuota;
}
=head2 alertUsersOverQuota($)
This function iterates through all users who are over quota (contained
in data structure above), and sends email to each one.
It doesn't bother sending mail to those users who have exceeded their
hard quota, since they probably won't be able to receive e-mail, unless
there's either a delegate mail server defined, or their mail spool is
elsewhere.
=cut
sub alertUsersOverQuota($$)
{
my ($conf, $usersOverQuota) = @_;
return unless keys %$usersOverQuota;
foreach my $user (keys %$usersOverQuota)
{
#------------------------------------------------------------------
# Don't send email to users who are over their hard quota
# They likely won't be able to receive it.
# Plus, they've already had 7 days of warnings.
#------------------------------------------------------------------
next if ( ($usersOverQuota->{$user}{usage}
> $usersOverQuota->{$user}{hardQuota}) and
($usersOverQuota->{$user}{hardQuota} != 0) );
my $templates = '/etc/e-smith/templates';
my $source = '/usr/lib/e-smith-quota/userOverQuota.tmpl';
# Use templates-custom version by preference if it exists
-f "${templates}-custom${source}" and $templates .= "-custom";
my $t = new Text::Template(TYPE => 'FILE',
SOURCE => "${templates}${source}");
open(QMAIL, "|/var/qmail/bin/qmail-inject -fdo-not-reply\@$domain $user")
|| die "Could not send mail via qmail-inject!\n";
print QMAIL $t->fill_in( HASH => {
conf => \$conf,
data => $usersOverQuota->{$user}
});
close QMAIL;
}
}
=head2
sendAdminSummary($$$$)
Generates an email summary of users and their quota statuses. It takes
as arguments a reference to a tied configuration database hash, and
three data structures (format above) containing:
- users over quota
- users under quota
- users without quotas.
At the moment, it only emails those users who are over quota to the
administrator.
=cut
sub sendAdminSummary($$$$)
{
my ($conf, $usersOverQuota, $usersUnderQuota, $usersWithNoQuota) = @_;
return unless keys %$usersOverQuota;
my $templates = '/etc/e-smith/templates';
my $source = '/usr/lib/e-smith-quota/adminQuotaSummary.tmpl';
# Use templates-custom version by preference if it exists
-f "${templates}-custom${source}" and $templates .= "-custom";
my $t = new Text::Template(TYPE => 'FILE',
SOURCE => "${templates}${source}");
open(QMAIL, "|/var/qmail/bin/qmail-inject -fdo-not-reply\@$domain admin")
|| die "Could not send mail via qmail-inject!\n";
print QMAIL $t->fill_in( HASH => {
conf => \$conf,
usersOverQuota => $usersOverQuota,
usersUnderQuota => $usersUnderQuota
});
close QMAIL;
}
=head2
toMB($)
Takes a number as input, and output the number divided by 1024, but also
formatted to two decimal places.
A helper function to convert kilobytes to megabytes.
=cut
#----------------------------------------------------------------------
# Helper function to convert kilobytes to megabytes.
#----------------------------------------------------------------------
sub toMB ($)
{
my ($kb) = @_;
return sprintf("%.2f", $kb / 1024);
}

View File

@@ -0,0 +1,51 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Free Software Foundation, Inc.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2002-05-08 13:01-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/adminQuotaSummary.tmpl:16
msgid "System Administrator"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/adminQuotaSummary.tmpl:17
msgid "SME Server automated quota report"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/adminQuotaSummary.tmpl:18
msgid "One or more users have exceeded their disk quota"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/adminQuotaSummary.tmpl:24
msgid "The following users have exceeded their disk quota on the server called"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/adminQuotaSummary.tmpl:24
msgid "All values are in megabytes."
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/adminQuotaSummary.tmpl:27
msgid "Account"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/adminQuotaSummary.tmpl:28
msgid "Usage"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/adminQuotaSummary.tmpl:29
msgid "Limit with grace period"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/adminQuotaSummary.tmpl:30
msgid "Absolute limit"
msgstr ""

View File

@@ -0,0 +1,58 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Free Software Foundation, Inc.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2002-05-08 13:01-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/userOverQuota.tmpl:19
msgid "SME Server automated quota report"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/userOverQuota.tmpl:20
msgid "You have exceeded your disk quota"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/userOverQuota.tmpl:22
msgid "Your current disk usage:"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/userOverQuota.tmpl:22
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/userOverQuota.tmpl:23
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/userOverQuota.tmpl:24
msgid "Mb"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/userOverQuota.tmpl:23
msgid "Your maximum usage:"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/userOverQuota.tmpl:24
msgid "Warnings start at:"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/userOverQuota.tmpl:25
msgid "Grace period ends:"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/userOverQuota.tmpl:26
msgid "System name:"
msgstr ""
#: root/etc/e-smith/templates/usr/lib/e-smith-quota/userOverQuota.tmpl:28
msgid ""
"You are currently using more disk space than you have been allotted. You "
"have until the Grace Period above to remove files so that you no longer "
"exceed the warning level. At no time will you be permitted to store more "
"than the maximum usage indicated above. This disk allocation includes all "
"your e-mail, including unread e-mail."
msgstr ""

View File

@@ -0,0 +1,412 @@
#!/usr/bin/perl -w
#
# Copyright (C) 2002 Mitel Networks Corporation
#
# Technical support for this program is available from e-smith, inc.
# Please call us at (613) 236-0743 or visit our web site www.e-smith.net
# for details.
#
# $Id: quota.pm,v 1.14 2004/11/10 15:50:05 charlieb Exp $
#
#----------------------------------------------------------------------
package esmith::FormMagick::Panel::quota;
use strict;
use Exporter;
use Quota;
use esmith::AccountsDB;
use esmith::FormMagick;
use esmith::cgi;
use esmith::TestUtils;
use Scalar::Util qw(looks_like_number);
our @ISA = qw(esmith::FormMagick Exporter);
our @EXPORT = qw(
showInitial modifyUser performModifyUser
);
our $VERSION = sprintf '%d.%03d', q$Revision: 1.14 $ =~ /: (\d+).(\d+)/;
=pod
=head1 NAME
esmith::FormMagick::Panel::quota - useful panel functions
=head1 SYNOPSIS
use esmith::FormMagick::Panel::quota;
my $panel = esmith::FormMagick::Panel::quota->new();
$panel->display();
=head1 DESCRIPTION
=head2 new
Exactly as for esmith::FormMagick
=begin testing
use_ok('esmith::FormMagick::Panel::quota');
$FM = esmith::FormMagick::Panel::quota->new();
isa_ok($FM, 'esmith::FormMagick::Panel::quota');
$FM->{cgi} = CGI->new;
=end testing
=cut
sub new
{
shift;
my $self = esmith::FormMagick->new();
$self->{calling_package} = (caller)[0];
bless $self;
return $self;
}
=pod
=head2 showInitial
Display the contents of the initial page
=for testing
is($FM->showInitial(), '', 'showInitial');
=cut
sub showInitial
{
my $self = shift;
my $q = $self->{cgi};
#------------------------------------------------------------
# Look up accounts and user names
#------------------------------------------------------------
print '<tr><td>';
my $adb = esmith::AccountsDB->open()
|| die $self->localise("UNABLE_TO_OPEN_ACCOUNTS");
my @userAccounts = $adb->users;
unless (scalar @userAccounts)
{
print $q->h3 ($self->localise('ACCOUNT_USER_NONE'));
}
else
{
print $q->p ($self->localise('QUOTA_DESC')),"\n";
print $q->h3 ($self->localise('CURRENT_USAGE_AND_SETTINGS')),"\n";
#print $q->p ($q->b ($self->localise('CURRENT_USAGE_AND_SETTINGS')));
print $q->Tr ($q->start_table({class => "sme-border"})),"\n";
my $limit = $self->localise('LIMIT_WITH_GRACE_MB'); $limit =~ s#(grace)#<br>$1#;
my $absolute = $self->localise('ABS_LIMIT_MB'); $absolute =~ s#(limit)#<br>$1#;
my $current = $self->localise('CURRENT_USAGE'); $current =~ s#(usage)#<br>$1#;
print $q->Tr (esmith::cgi::genSmallCell ($q, ($self->localise('ACCOUNT')),"header"),
esmith::cgi::genSmallCell ($q, ($self->localise('USER_NAME')),"header"),
esmith::cgi::genSmallCell ($q, $limit,"header"),
esmith::cgi::genSmallCell ($q, $absolute,"header"),
esmith::cgi::genSmallCell ($q, $current,"header"),
esmith::cgi::genSmallCell ($q, ($self->localise('ACTION')),"header"));
foreach my $user (@userAccounts)
{
my $uid = getpwnam($user->key);
unless ($uid)
{
warn($self->localise('COULD_NOT_GET_UID'),$user->key);
next;
}
my $dev = Quota::getqcarg('/home/e-smith/files');
my ($bc, $bs, $bh, $bt, $ic, $is, $ih, $it) =
Quota::query($dev, $uid);
my $name = $user->prop("FirstName")." ".$user->prop("LastName");
print $q->Tr (esmith::cgi::genSmallCell ($q, $user->key,"normal"),
esmith::cgi::genSmallCell ($q, $name,"normal"),
esmith::cgi::genSmallCellRightJustified ($q,
$self->toMB($bs)),
esmith::cgi::genSmallCellRightJustified ($q,
$self->toMB($bh)),
esmith::cgi::genSmallCellRightJustified ($q, $self->toMB($bc)),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?page=0&Next=Next&acct="
. $user->key},
$self->localise("MODIFY")),"normal"));
}
print '</table></table>';
}
print '</td></tr>';
return '';
}
=pod
=head2 modifyUser
Display the modify user form for the specified user
=begin testing
$FM->{cgi}->param(-name=>'acct', -value=>'foononex');
is($FM->modifyUser(),'','modifyUser');
=end testing
=cut
sub modifyUser
{
my $self = shift;
my $q = $self->{cgi};
my $msg;
my $adb = esmith::AccountsDB->open();
my $acct = $q->param ('acct');
my $rec = $adb->get($acct);
unless (defined $rec)
{
$msg = $self->localise('ERR_NO_SUCH_ACCT').$acct;
return $self->error($msg, 'Initial');
}
my $type = $rec->prop('type');
unless ($type eq "user")
{
$msg = $self->localise('ERR_NOT_A_USER_ACCT').$acct.$self->localise('ACCOUNT_IS_TYPE').$type;
return $self->error($msg, 'Initial');
}
my $uid = getpwnam($acct);
unless ($uid)
{
$msg = $self->localise('COULD_NOT_GET_UID').$acct;
return $self->error($msg, 'Initial');
}
my $name = $rec->prop("FirstName")." ".$rec->prop("LastName");
my $dev = Quota::getqcarg('/home/e-smith/files');
my ($bc, $bs, $bh, $bt, $ic, $is, $ih, $it) =
Quota::query($dev, $uid);
print '<tr><td>';
print
$q->p($self->localise('USER')." $name (\"$acct\") ".
$self->localise('CURRENTLY_HAS')." $ic ".
$self->localise('FILES')." ".
$self->localise('OCCUPYING')." ". $self->toMB($bc) ." ".
$self->localise('MEGABYTES'));
print
$q->p($self->localise('INSTRUCTIONS'));
print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},
$q->Tr (esmith::cgi::genCell ($q, $self->localise("USER_NAME")),
esmith::cgi::genCell ($q, $name)),
$q->Tr (esmith::cgi::genCell ($q, $self->localise('LIMIT_WITH_GRACE')),
esmith::cgi::genCell ($q,
$q->textfield (-name => 'soft',
-override => 1,
-default => $self->toBestUnit($bs),
-size => 12))),
$q->Tr (esmith::cgi::genCell ($q, $self->localise('ABS_LIMIT')),
esmith::cgi::genCell ($q,
$q->textfield (-name => 'hard',
-override => 1,
-default => $self->toBestUnit($bh),
-size => 12))));
print '</td></tr>';
return '';
}
=pod
=head2 performModifyUser
Perform the modifications requested by the Modify page
=begin testing
$FM->{cgi}->param(-name=>'acct', -value=>'fooquuxb');
is($FM->performModifyUser(),'','performModifyUser');
=end testing
=cut
sub performModifyUser
{
my $self = shift;
my $q = $self->{cgi};
my $msg;
my $adb = esmith::AccountsDB->open();
my $acct = $q->param ('acct');
my $rec = $adb->get($acct);
unless (defined $rec)
{
$msg = $self->localise('ERR_NO_SUCH_ACCT').$acct;
return $self->error($msg, 'Initial');
}
my $type = $rec->prop('type');
unless ($type eq "user")
{
$msg = $self->localise('ERR_NOT_A_USER_ACCT').$acct.$self->localise('ACCOUNT_IS_TYPE').$type;
return $self->error($msg, 'Initial');
}
my $uid = getpwnam($acct);
unless ($uid)
{
$msg = $self->localise('COULD_NOT_GET_UID').$acct;
return $self->error($msg, 'Initial');
}
my $softlim = $q->param ('soft');
if (($softlim !~ /^(.+?)\s*([KMGT])?$/ ) || (!looks_like_number ($1)))
{
return $self->error('SOFT_VAL_MUST_BE_NUMBER', 'Initial');
}
my $exponent = 1; # Entries with no suffix are assumed to be in megabytes.
if (defined ($2))
{
$exponent = index("KMGT",$2);
}
$softlim = ($1 * 1024 ** $exponent);
my $hardlim = $q->param ('hard');
if (($hardlim !~ /^(.+?)\s*([KMGT])?$/ ) || (!looks_like_number ($1)))
{
return $self->error('HARD_VAL_MUST_BE_NUMBER', 'Initial');
}
$exponent = 1; # Entries with no suffix are assumed to be in megabytes.
if (defined ($2))
{
$exponent = index("KMGT",$2);
}
$hardlim = ($1 * 1024 ** $exponent);
#------------------------------------------------------------
# Make sure that soft limit is less than hard limit.
#------------------------------------------------------------
unless ($hardlim == 0 or $hardlim > $softlim)
{
return $self->error('ERR_HARD_LT_SOFT', 'Initial');
}
#------------------------------------------------------------
# Update accounts database and signal the user-modify event.
#------------------------------------------------------------
$rec->set_prop('MaxBlocks', $hardlim);
$rec->set_prop('MaxBlocksSoftLim', $softlim);
# Untaint $acct before using in system().
$acct =~ /^(\w[\-\w_\.]*)$/; $acct = $1;
system ("/sbin/e-smith/signal-event", "user-modify", "$acct") == 0
or die ($self->localise('ERR_MODIFYING')."\n");
$msg = $self->localise('SUCCESSFULLY_MODIFIED').$acct;
return $self->success($msg, 'Initial');
}
=pod
=head2 toMB ($kb)
Utility function to convert KB to MB
=for testing
is($FM->toMB(1024),'1.00','toMB');
=cut
sub toMB
{
my ($self,$kb) = @_;
return sprintf("%.2f", $kb / 1024);
}
=pod
=head2 toMBNoDecimalPlaces ($kb)
Utility function to convert KB to MB with no decimal places
=for testing
is($FM->toMBNoDecimalPlaces(2050), '2', 'toMBNoDecimalPlaces');
=cut
sub toMBNoDecimalPlaces
{
my ($self,$kb) = @_;
return sprintf("%.0f", $kb / 1024);
}
sub toGBNoDecimalPlaces
{
my ($self,$kb) = @_;
return sprintf("%.0f", $kb / 1024 / 1024);
}
=pod
=head2 toKB ($mb)
Utility function to convert MB to KB.
=for testing
is($FM->toKB(4),'4096','toKB');
=cut
sub toKB
{
my ($self,$mb) = @_;
return sprintf("%.0f", $mb * 1024);
}
=pod
Utility to convert GB to KB
=for testing
is($FM->GBtoKB(1),1048576,'GBtoKB');
=cut
sub GBtoKB
{
my ($self,$gb) = @_;
return sprintf("%.0f", $gb * 1024 * 1024);
}
sub MBtoKB
{
my ($self,$mb) = @_;
return sprintf("%.0f", $mb * 1024);
}
sub toBestUnit
{
my ($self,$kb) = @_;
return 0 if($kb == 0);
return $kb."K" if($kb < 1024);
return $kb."K" if($kb > 1024 && $kb < 1048576 && $kb % 1024 != 0);
return $self->toMBNoDecimalPlaces($kb)."M" if($kb < 1048576);
return $self->toMBNoDecimalPlaces($kb)."M" if($kb > 1048576
&& ($kb % 1048576 != 0));
return $self->toGBNoDecimalPlaces($kb)."G";
}
1;