1#!/usr/local/bin/perl 2use strict; 3my $VERSION = '0.2'; 4my $COPYRIGHT = 'Copyright (C) 2005-2011 Jonathan Buhacoff <jonathan@buhacoff.net>'; 5my $LICENSE = 'http://www.gnu.org/licenses/gpl.txt'; 6my %status = ( 'OK' => 0, 'WARNING' => 1, 'CRITICAL' => 2, 'UNKNOWN' => 3 ); 7 8#### IDEA AND INITIAL IMPLEMENTATION BASED ON CHECK_IMAP_RECEIVE WAS CONTRIBUTED BY JOHAN ROMME from THE NETHERLANDS 14 Oct 2011 9 10# look for required modules 11exit $status{UNKNOWN} unless load_modules(qw/Getopt::Long Mail::IMAPClient/); 12 13BEGIN { 14 if( grep { /^--hires$/ } @ARGV ) { 15 eval "use Time::HiRes qw(time);"; 16 warn "Time::HiRes not installed\n" if $@; 17 } 18} 19 20# get options from command line 21Getopt::Long::Configure("bundling"); 22my $verbose = 0; 23my $help = ""; 24my $help_usage = ""; 25my $show_version = ""; 26my $imap_server = ""; 27my $default_imap_port = "143"; 28my $default_imap_ssl_port = "993"; 29my $imap_port = ""; 30my $username = ""; 31my $password = ""; 32my $mailbox = "INBOX"; 33my $warntime = 15; 34my $criticaltime = 30; 35my $timeout = 60; 36my $peek = ""; 37my $ssl = 0; 38my $tls = 0; 39my $time_hires = ""; 40my $ok; 41$ok = Getopt::Long::GetOptions( 42 "V|version"=>\$show_version, 43 "v|verbose+"=>\$verbose,"h|help"=>\$help,"usage"=>\$help_usage, 44 "w|warning=i"=>\$warntime,"c|critical=i"=>\$criticaltime,"t|timeout=i"=>\$timeout, 45 # imap settings 46 "H|hostname=s"=>\$imap_server,"p|port=i"=>\$imap_port, 47 "U|username=s"=>\$username,"P|password=s"=>\$password, "m|mailbox=s"=>\$mailbox, 48 "ssl!"=>\$ssl, "tls!"=>\$tls, 49 # search settings 50 "peek!"=>\$peek, 51 # Time 52 "hires"=>\$time_hires, 53 ); 54 55if( $show_version ) { 56 print "$VERSION\n"; 57 if( $verbose ) { 58 print "Default warning threshold: $warntime seconds\n"; 59 print "Default critical threshold: $criticaltime seconds\n"; 60 print "Default timeout: $timeout seconds\n"; 61 } 62 exit $status{UNKNOWN}; 63} 64 65if( $help ) { 66 exec "perldoc", $0 or print "Try `perldoc $0`\n"; 67 exit $status{UNKNOWN}; 68} 69 70my @required_module = (); 71push @required_module, 'IO::Socket::SSL' if $ssl || $tls; 72exit $status{UNKNOWN} unless load_modules(@required_module); 73 74if( $help_usage 75 || 76 ( $imap_server eq "" || $username eq "" || $password eq "" ) 77 ) { 78 print "Usage: $0 -H host [-p port] -U username -P password [--imap-retries <tries>]\n"; 79 exit $status{UNKNOWN}; 80} 81 82 83# initialize 84my $report = new PluginReport; 85my $time_start = time; 86 87# connect to IMAP server 88print "connecting to server $imap_server\n" if $verbose > 2; 89my $imap; 90eval { 91 local $SIG{ALRM} = sub { die "exceeded timeout $timeout seconds\n" }; # NB: \n required, see `perldoc -f alarm` 92 alarm $timeout; 93 94 if( $ssl || $tls ) { 95 $imap_port = $default_imap_ssl_port unless $imap_port; 96 my $socket = IO::Socket::SSL->new("$imap_server:$imap_port"); 97 die IO::Socket::SSL::errstr() unless $socket; 98 $socket->autoflush(1); 99 $imap = Mail::IMAPClient->new(Socket=>$socket, Debug => 0 ); 100 $imap->State(Mail::IMAPClient->Connected); 101 $imap->_read_line() if "$Mail::IMAPClient::VERSION" le "2.2.9"; # necessary to remove the server's "ready" line from the input buffer for old versions of Mail::IMAPClient. Using string comparison for the version check because the numeric didn't work on Darwin and for Mail::IMAPClient the next version is 2.3.0 and then 3.00 so string comparison works 102 $imap->User($username); 103 $imap->Password($password); 104 $imap->login() or die "$@"; 105 } 106 else { 107 $imap_port = $default_imap_port unless $imap_port; 108 $imap = Mail::IMAPClient->new(Debug => 0 ); 109 $imap->Server("$imap_server:$imap_port"); 110 $imap->User($username); 111 $imap->Password($password); 112 $imap->connect() or die "$@"; 113 } 114 115 $imap->Peek(1) if $peek; 116 $imap->Ignoresizeerrors(1); 117 118 alarm 0; 119}; 120if( $@ ) { 121 chomp $@; 122 print "IMAP QUOTA CRITICAL - Could not connect to $imap_server port $imap_port: $@\n"; 123 exit $status{CRITICAL}; 124} 125unless( $imap ) { 126 print "IMAP QUOTA CRITICAL - Could not connect to $imap_server port $imap_port: $@\n"; 127 exit $status{CRITICAL}; 128} 129my $time_connected = time; 130 131my $quotaUsed; 132my $quotaLimit; 133my $quotaPercentage; 134my $quotaPercentageWarning = 80; 135my $quotaPercentageCritical = 90; 136my $quotaMessage; 137 138# look for the quota limits 139my $tries = 0; 140my @msgs; 141 142eval { 143 my $k; 144 my @l = $imap->getquotaroot(); 145 foreach $k (@l) { 146 print "$k\n" if $verbose > 2; 147 if ($k =~ /STORAGE +(\d+) +(\d+)/) { 148 $quotaUsed = $1; 149 $quotaLimit = $2; 150 } 151 } 152 if (!length($quotaUsed) && !length($quotaLimit)) { 153 print "no answer from imap host\n" if $verbose > 2; 154 } elsif (!length($quotaUsed) || !length($quotaLimit)) { 155 print "incorrect answer from imap host\n"; 156 $imap->close(); 157 exit $status{UNKNOWN}; 158 } else { 159 $quotaPercentage = sprintf("%.1f", (100 * $quotaUsed) / $quotaLimit); 160 $quotaMessage = "$quotaUsed $quotaLimit - $quotaPercentage%"; 161 } 162}; 163if( $@ ) { 164 chomp $@; 165 print "IMAP QUOTA CRITICAL - Could not check quota at $imap_server port $imap_port: $@\n"; 166 exit $status{CRITICAL}; 167} 168 169 170# disconnect from IMAP server 171print "disconnecting from server\n" if $verbose > 2; 172$imap->logout(); 173 174# calculate elapsed time and issue warnings 175my $time_end = time; 176my $elapsedtime = $time_end - $time_start; 177$report->{seconds} = $elapsedtime; 178 179# print report and exit with known status 180 181if($quotaPercentage >= $quotaPercentageCritical) { 182 print "IMAP QUOTA CRITICAL - $quotaMessage\n"; 183 exit $status{CRITICAL}; 184} 185if($quotaPercentage >= $quotaPercentageWarning) { 186 print "IMAP QUOTA WARNING - $quotaMessage\n"; 187 exit $status{WARNING}; 188} 189print "IMAP QUOTA OK - $quotaMessage\n"; 190exit $status{OK}; 191 192 193# utility to load required modules. exits if unable to load one or more of the modules. 194sub load_modules { 195 my @missing_modules = (); 196 foreach( @_ ) { 197 eval "require $_"; 198 push @missing_modules, $_ if $@; 199 } 200 if( @missing_modules ) { 201 print "Missing perl modules: @missing_modules\n"; 202 return 0; 203 } 204 return 1; 205} 206 207 208# NAME 209# PluginReport 210# SYNOPSIS 211# $report = new PluginReport; 212# $report->{label1} = "value1"; 213# $report->{label2} = "value2"; 214# print $report->text(qw/label1 label2/); 215package PluginReport; 216 217sub new { 218 my ($proto,%p) = @_; 219 my $class = ref($proto) || $proto; 220 my $self = bless {}, $class; 221 $self->{$_} = $p{$_} foreach keys %p; 222 return $self; 223} 224 225sub text { 226 my ($self,@labels) = @_; 227 my @report = map { "$self->{$_} $_" } grep { defined $self->{$_} } @labels; 228 my $text = join(", ", @report); 229 return $text; 230} 231 232 233package main; 2341; 235 236__END__ 237 238 239=pod 240 241=head1 NAME 242 243check_imap_quota - connects to an IMAP account and checks the quota 244 245=head1 SYNOPSIS 246 247 check_imap_quota -vV 248 check_imap_quota -? 249 check_imap_quota --help 250 251=head1 OPTIONS 252 253=over 254 255=item --warning <seconds> 256 257Warn if it takes longer than <seconds> to connect to the IMAP server. Default is 15 seconds. 258Also known as: -w <seconds> 259 260=item --critical <seconds> 261 262Return a critical status if it takes longer than <seconds> to connect to the IMAP server. Default is 30 seconds. 263See also: --capture-critical <messages> 264Also known as: -c <seconds> 265 266=item --timeout <seconds> 267 268Abort with critical status if it takes longer than <seconds> to connect to the IMAP server. Default is 60 seconds. 269The difference between timeout and critical is that, with the default settings, if it takes 45 seconds to 270connect to the server then the connection will succeed but the plugin will return CRITICAL because it took longer 271than 30 seconds. 272Also known as: -t <seconds> 273 274=item --hostname <server> 275 276Address or name of the IMAP server. Examples: mail.server.com, localhost, 192.168.1.100 277Also known as: -H <server> 278 279=item --port <number> 280 281Service port on the IMAP server. Default is 143. If you use SSL, default is 993. 282Also known as: -p <number> 283 284=item --username <username> 285 286=item --password <password> 287 288Username and password to use when connecting to IMAP server. 289Also known as: -U <username> -P <password> 290 291=item --mailbox <mailbox> 292 293Use this option to specify the mailbox to search for messages. Default is INBOX. 294Also known as: -m <mailbox> 295 296=item --ssl 297 298=item --nossl 299 300Enable SSL protocol. Requires IO::Socket::SSL. 301 302Using this option automatically changes the default port from 143 to 993. You can still 303override this from the command line using the --port option. 304 305Use the nossl option to turn off the ssl option. 306 307=item --hires 308 309Use the Time::HiRes module to measure time, if available. 310 311=item --verbose 312 313Display additional information. Useful for troubleshooting. Use together with --version to see the default 314warning and critical timeout values. 315 316If the selected mailbox was not found, you can use verbosity level 3 (-vvv) to display a list of all 317available mailboxes on the server. 318 319Also known as: -v 320 321=item --version 322 323Display plugin version and exit. 324Also known as: -V 325 326=item --help 327 328Display this documentation and exit. Does not work in the ePN version. 329Also known as: -h 330 331=item --usage 332 333Display a short usage instruction and exit. 334 335=back 336 337=head1 EXAMPLES 338 339=head2 Report how many emails are in the mailbox 340 341 $ check_imap_receive -H mail.server.net --username mailuser --password mailpass 342 -s ALL --nodelete 343 344 IMAP RECEIVE OK - 1 seconds, 7 found 345 346=head2 Report the email with the highest value 347 348Suppose your mailbox has some emails from an automated script and that a message 349from this script typically looks like this (abbreviated): 350 351 To: mailuser@server.net 352 From: autoscript@server.net 353 Subject: Results of Autoscript 354 Date: Wed, 09 Nov 2005 08:30:40 -0800 355 Message-ID: <auto-000000992528@server.net> 356 357 Homeruns 5 358 359And further suppose that you are interested in reporting the message that has the 360highest number of home runs, and also to leave this message in the mailbox for future 361checks, but remove the other matching messages with lesser values: 362 363 $ check_imap_receive -H mail.server.net --username mailuser --password mailpass 364 -s SUBJECT -s "Results of Autoscript" --capture-max "Homeruns (\d+)" --nodelete-captured 365 366 IMAP RECEIVE OK - 1 seconds, 3 found, 1 captured, 5 max, 2 deleted 367 368=head2 Troubleshoot your search parameters 369 370Add the --nodelete and --imap-retries=1 parameters to your command line. 371 372=head1 EXIT CODES 373 374Complies with the Nagios plug-in specification: 375 0 OK The plugin was able to check the service and it appeared to be functioning properly 376 1 Warning The plugin was able to check the service, but it appeared to be above some "warning" threshold or did not appear to be working properly 377 2 Critical The plugin detected that either the service was not running or it was above some "critical" threshold 378 3 Unknown Invalid command line arguments were supplied to the plugin or the plugin was unable to check the status of the given hosts/service 379 380=head1 NAGIOS PLUGIN NOTES 381 382Nagios plugin reference: http://nagiosplug.sourceforge.net/developer-guidelines.html 383 384This plugin does NOT use Nagios DEFAULT_SOCKET_TIMEOUT (provided by utils.pm as $TIMEOUT) because 385the path to utils.pm must be specified completely in this program and forces users to edit the source 386code if their install location is different (if they realize this is the problem). You can view 387the default timeout for this module by using the --verbose and --version options together. The 388short form is -vV. 389 390Other than that, it attempts to follow published guidelines for Nagios plugins. 391 392=head1 SEE ALSO 393 394http://nagios.org/ 395http://search.cpan.org/~djkernen/Mail-IMAPClient-2.2.9/IMAPClient.pod 396http://search.cpan.org/~markov/Mail-IMAPClient-3.00/lib/Mail/IMAPClient.pod 397 398=head1 CHANGES 399 400 Fri Nov 11 04:53:09 AST 2011 401 + version 0.1 created with quota code contributed by Johan Romme 402 403 Tue Dec 20 17:38:04 PST 2011 404 + fixed bug where a quota of 0 was reported as an incorrect response from the server, thanks to Eike Arndt 405 + version 0.2 406 407=head1 AUTHOR 408 409Jonathan Buhacoff <jonathan@buhacoff.net> 410 411=head1 COPYRIGHT AND LICENSE 412 413 Copyright (C) 2011 Jonathan Buhacoff 414 415 This program is free software; you can redistribute it and/or modify 416 it under the terms of the GNU General Public License as published by 417 the Free Software Foundation; either version 3 of the License, or 418 (at your option) any later version. 419 420 This program is distributed in the hope that it will be useful, 421 but WITHOUT ANY WARRANTY; without even the implied warranty of 422 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 423 GNU General Public License for more details. 424 425 You should have received a copy of the GNU General Public License 426 along with this program. If not, see <http://www.gnu.org/licenses/>. 427 428 http://www.gnu.org/licenses/gpl.txt 429 430=cut 431 432