source: trunk/athena/bin/mitmailutils/mailquota.pl @ 24907

Revision 24907, 7.5 KB checked in by geofft, 14 years ago (diff)
In mitmailutils: * Have mailquota tell you what quota it's displaying, so that the mailquota output from dotfiles makes more sense.
RevLine 
[22834]1#!/usr/bin/perl -w
[19880]2
[20593]3# $Id: mailquota.pl,v 1.4 2004-07-29 19:11:52 rbasch Exp $
[19880]4
5# Display the IMAP resource usage on the user's post office server.
6
7use strict;
8use warnings FATAL => 'all';
9use Cyrus::IMAP;
10use Getopt::Std;
11
12sub usage(;$);
13sub print_quota($$$$$);
14sub send_command($);
15sub quota_callback(@);
16sub quotaroot_callback(@);
17sub capability_callback(@);
18sub close_and_errorout($);
19sub close_connection();
20sub errorout($);
21
22sub usage(;$) {
23    print STDERR "mailquota: $_[0]\n" if $_[0];
24    print STDERR <<EOF;
25Usage: mailquota [<options>] [<user>]
26  Options:
27    -h <host>     query <host> instead of default post office server
28    -m <mailbox>  query for <mailbox> (default is INBOX)
29    -n            be silent unless usage % is above the threshold
30    -u <percent>  usage % threshold (default is 90); implies -n
31    -d            turn on debugging
32EOF
33    exit 1;
34}
35
36my $need_header = 1;
37my $root_width = 16;
38my $num_width = 10;
39my $percent_width = 5;
40my $format = "%-${root_width}.${root_width}s" .
41    " %${num_width}s %${num_width}s %${percent_width}s" .
42    " %${num_width}s %${num_width}s %${percent_width}s\n";
43
44# Parse the command line arguments.
45my %opts;
46getopts('dh:m:nu:', \%opts) || usage;
[23693]47my $username = shift @ARGV || $ENV{'ATHENA_USER'} || $ENV{'USER'} || getlogin || (getpwuid($<))[0] ||
[19880]48        errorout "Cannot determine user name";
49
50usage "Too many arguments" if @ARGV > 0;
51my $debug = $opts{'d'};
52my $warn_only = $opts{'n'};
53my $usage_threshold = $opts{'u'};
[24300]54my $host = $opts{'h'} || (gethostbyname("$username.mail.mit.edu"))[0];
55errorout "Cannot find Post Office server for $username" unless $host;
[23913]56errorout "Exchange accounts are not supported yet. Try http://owa.mit.edu/." if $host =~ /EXCHANGE/;
[19880]57my $mbox = $opts{'m'} || "INBOX";
58
59# Validate the usage percentage threshold, allowing a trailing %.
60# Setting the threshold implies we should only display quotas
61# for which any resource usage is above the threshold.
62if (defined $usage_threshold) {
63    chop $usage_threshold if $usage_threshold =~ /^\d+%$/;
64    usage "-u argument must be numeric" if $usage_threshold !~ /^\d+$/;
65    $warn_only = 1;
66} else {
67    $usage_threshold = 90;
68}
69
70# Connect to the IMAP server, check for the QUOTA extension, and
71# authenticate.
72my $client = Cyrus::IMAP->new($host) ||
73    errorout "Cannot connect to IMAP server on $host";
74my $caps = '';
75$client->addcallback({-trigger => 'CAPABILITY',
76                      -callback => \&capability_callback,
77                      -rock => \$caps});
78send_command "CAPABILITY";
79$caps =~ '\bQUOTA\b' ||
80    close_and_errorout "$host does not support the IMAP QUOTA extension";
[24300]81$client->authenticate(-authz => $username, -maxssf => 0) ||
[19880]82    close_and_errorout "Cannot authenticate to $host";
83
84# Send the GETQUOTAROOT command, which returns both the QUOTA and
85# QUOTAROOT responses.  Quota information will be displayed via
86# the QUOTA callback.
87$client->addcallback({-trigger => 'QUOTA',
88                      -callback => \&quota_callback});
89$client->addcallback({-trigger => 'QUOTAROOT',
90                      -callback => \&quotaroot_callback});
[20505]91send_command "GETQUOTAROOT \"$mbox\"";
[19880]92
93# We are done talking to the IMAP server; close down the connection.
94close_connection();
95
96# Print the quota information for the given quota root and its
97# storage and message resource values.
98sub print_quota($$$$$) {
99    my ($root, $storage_used, $storage_max, $message_used, $message_max) = @_;
100    my $storage_percent;
101    my $storage_percent_out;
102    my $message_percent;
103    my $message_percent_out;
104
105    # Calculate the usage percentages, and format for output.
106    if ($storage_max) {
107        $storage_percent = ($storage_used / $storage_max) * 100;
108        $storage_percent_out = sprintf("%.0f%%", $storage_percent);
109    }
110    if ($message_max) {
111        $message_percent = ($message_used / $message_max) * 100;
112        $message_percent_out = sprintf("%.0f%%", $message_percent);
113    }
114
115    # Skip this quota if we are only displaying usages above the
116    # specified threshold.
117    return unless (!$warn_only ||
118                   (defined $storage_percent &&
119                    $storage_percent >= $usage_threshold) ||
120                   (defined $message_percent &&
121                    $message_percent >= $usage_threshold));
122
123    # Print a header if this is the first line of output.
124    if ($need_header) {
[24907]125        print "** IMAP e-mail usage for $mbox on $host:\n";
[19880]126        printf($format,
127               "Quota",
128               "KB Used", "KB Max", "KB %",
129               "# Msgs", "# Max", "# %");
130        $need_header = 0;
131    }
132    printf($format,
133           $root,
134           defined $storage_used ? $storage_used : '-',
135           defined $storage_max ? $storage_max : '-',
136           defined $storage_percent_out ? $storage_percent_out : '-',
137           defined $message_used ? $message_used : '-',
138           defined $message_max ? $message_max : '-',
139           defined $message_percent_out ? $message_percent_out : '-');
140}
141
142# Subroutine to send a command to the IMAP server, and wait for the
143# response; any defined callbacks for the response are invoked.
144# If the server response indicates failure, we error out.
145sub send_command($) {
146    print "Sending: $_[0]\n" if $debug;
147    my ($status, $text) = $client->send('', '', $_[0]);
148    print "Response: status $status, text $text\n" if $debug;
149    errorout "Premature end-of-file on IMAP connection to $host"
150        if $status eq 'EOF';
151    close_and_errorout "IMAP error for $mbox on $host: $text"
152        if $status ne 'OK';
153}
154
155# Callback subroutine to parse the QUOTA response.
156# The "-text" hash element contains the quota root name, and a list
157# of quota resource names, usages, and limits.  Recognized names are
158# STORAGE (sum of message sizes, in kilobytes) and MESSAGE (number of
159# messages).  See RFC 2087.
160sub quota_callback(@) {
161    my %cb = @_;
162    my ($root, $quotalist);
163    print "In QUOTA callback: text $cb{-text}\n" if $debug;
164    if (($root, $quotalist) = ($cb{-text} =~ /(\S*)\s+\((.*)\)/io)) {
165        my ($storage_used, $storage_max, $message_used, $message_max);
166        while ($quotalist) {
167            my ($resource, $used, $max);
168            ($resource, $used, $max, $quotalist) = split /\s/, $quotalist, 4;
169            last unless $max;
170            $resource = uc $resource;
171            if ($resource eq "STORAGE") {
172                $storage_used = $used;
173                $storage_max = $max;
174            }
175            elsif ($resource eq "MESSAGE") {
176                $message_used = $used;
177                $message_max = $max;
178            }
179        }
180        print_quota($root, $storage_used, $storage_max,
181                    $message_used, $message_max)
182            if (defined $storage_max || defined $message_max);
183    }
184}
185
186# Callback subroutine to parse the QUOTAROOT response.  The "-text"
187# hash element contains the mailbox name, and zero or more quota root
188# names.  This is currently used for debugging only.
189sub quotaroot_callback(@) {
190    my %cb = @_;
191    print "In QUOTAROOT callback: text $cb{-text}\n" if $debug;
192}
193
194# Callback subroutine to parse the CAPABILITY response.  The "-rock" hash
195# element is a reference to the string in which to store the space-separated
196# capability names.
197sub capability_callback(@) {
198    my %cb = @_;
199    print "In CAPABILITY callback: keyword $cb{-keyword}, text $cb{-text}\n"
200        if $debug;
201    ${$cb{-rock}} = $cb{-text};
202}
203
204# Close the connection to the IMAP server, and error out.
205sub close_and_errorout($) {
206    close_connection();
207    errorout $_[0];
208}
209
210# Logout from the IMAP server, and close the connection.
211sub close_connection() {
212    $client->send('', '', "LOGOUT");
[20593]213    # Set the client reference to undef, so that perl invokes the
214    # destructor, which closes the connection.  Note that if we invoke
215    # the destructor explicitly here, then perl will still invoke it
216    # again when the program exits, thus touching memory which has
217    # already been freed.
218    $client = undef;
[19880]219}
220
221sub errorout($) {
222    print STDERR "mailquota: $_[0]\n";
223    exit 1;
224}
Note: See TracBrowser for help on using the repository browser.