#!/usr/bin/env python

#
# check-imap.py - 2006.05.05 Yann Grossel
#
# python2.4 ./check-imap.py  -s 212.43.194.89 -l 'check-nagios@sri.fr.clara.net' -p 'aeh3tCj3zI' -c 'nn!/@UirKixO%,YXM?_zIT=%dZWb770f'
#
# Usage :
#
#	check-imap.py [--ssl] [--port port] -s ip -l login -p password -c pattern
#
#	There must be at least one message in the mailbox, and it must contain "pattern" on a single line.
#
#	Errors are sent to syslog.
#

# Nagios states

STATE_OK				= 0
STATE_WARNING		= 1
STATE_CRITICAL		= 2
STATE_UNKNOWN		= 3
STATE_DEPENDENT	= 4

#

import os, sys, imaplib, signal, syslog, time

use_ssl		= False
port			= None
server_ip	= None
login			= None
password		= None
pattern		= None
error_msg	= ''

def get_arg(s):

	if not len(sys.argv):
		print "Missing argument after %s" % (s)
		sys.exit(STATE_UNKNOWN)

	arg, sys.argv = sys.argv[0], sys.argv[1:]

	return arg

def parse_args():

	global use_ssl, port, server_ip, login, password, pattern

	if not len(sys.argv): sys.exit(STATE_UNKNOWN)

	sys.argv = sys.argv[1:]

	while len(sys.argv) > 0:

		arg, sys.argv = sys.argv[0], sys.argv[1:]

		if arg == '--port':

			arg = get_arg(('--port'))

			try: port = int(arg)
			except:
				print "Bad port:", arg
				sys.exit(STATE_UNKNOWN)

			if port < 1 or port > 65535:
				print "Bad port:", arg
				sys.exit(STATE_UNKNOWN)

		elif arg == '--ssl':		use_ssl = True
		elif arg == '-l':			login = get_arg('-l')
		elif arg == '-p':			password = get_arg('-p')
		elif arg == '-s':			server_ip = get_arg('-s')
		elif arg == '-c':			pattern = get_arg('-c')
		else:
			print "Unknown argument '%s'" % (arg)
			sys.exit(STATE_UNKNOWN)

	if not server_ip:
		print "server_ip not specified"
		sys.exit(STATE_UNKNOWN)

	if not login:
		print "login not specified"
		sys.exit(STATE_UNKNOWN)

	if not password:
		print "password not specified"
		sys.exit(STATE_UNKNOWN)

	if not pattern:
		print "pattern not specified"
		sys.exit(STATE_UNKNOWN)

def timeout_callback(signum, frame):
	global error_msg
	error_msg = ' (timeout)'

def log_error(command, error):
	if error_msg != '': return
	msg = "imap4 server %s: %s: %s\n" % (server_ip, command, str(error))
	syslog.syslog(syslog.LOG_WARNING, msg)
	if sys.stderr.isatty(): sys.stderr.write("%s\n" % (msg))

# Main program.

parse_args()

if use_ssl and getattr(imaplib, 'IMAP4_SSL', None) == None:
	print "Your python has no support for IMAP4 over SSL !"
	sys.exit(STATE_UNKNOWN)

if port == None:
	if use_ssl:	port = 993
	else:			port = 143

if use_ssl:	imapclass = imaplib.IMAP4_SSL
else:			imapclass = imaplib.IMAP4

syslog.openlog("check-imap.py", 0, syslog.LOG_USER)

signal.signal(signal.SIGALRM, timeout_callback)

start = time.time()

# Connect to the server.

signal.alarm(3)

try: server = imapclass(server_ip, port)
except Exception, e:
	signal.alarm(0)
	print "Unable to connect to imap4 server%s !" % (error_msg)
	log_error("connect", e)
	sys.exit(STATE_CRITICAL)

# Send LOGIN to the server.

signal.alarm(5)

try: server.login(login, password)
except Exception, e:
	signal.alarm(0)
	print "Unable to login to imap4 server%s !" % (error_msg)
	log_error("LOGIN", e)
	sys.exit(STATE_CRITICAL)

# SELECT the INBOX.

signal.alarm(5)

try:	messages = server.select('INBOX', True)
except Exception, e:
	signal.alarm(0)
	print "SELECT INBOX failed%s !" % (error_msg)
	log_error("SELECT INBOX", e)
	sys.exit(STATE_CRITICAL)

signal.alarm(0)

if messages[0] != 'OK':
	# Status != OK
	print "SELECT INBOX: %s !" % (message[0])
	sys.exit(STATE_CRITICAL)

if int(messages[1][0]) < 1:
	# No message in mailbox !
	print "Mailbox is empty !"
	sys.exit(STATE_WARNING)

# At least a message. Fetch it.

signal.alarm(5)

try: lines = server.fetch('1', '(BODY[TEXT])')
except Exception, e:
	signal.alarm(0)
	print "RETR failed%s !" % (error_msg)
	log_error("RETR", e)
	sys.exit(STATE_CRITICAL)

if lines[0] != 'OK':
	# Status != OK
	print "FETCH: %s !" % (lines[0])
	sys.exit(STATE_CRITICAL)

try:
	lines = lines[1][0][1].split('\r\n')
except:
	print "FETCH: unexpected response format !"
	sys.exit(STATE_UNKNOWN)

# Try to LOGOUT nicely.

signal.alarm(5)

try: server.logout()
except Exception, e:
	signal.alarm(0)
	print "LOGOUT failed%s !" % (error_msg)
	log_error("LOGOUT", e)
	sys.exit(STATE_CRITICAL)

signal.alarm(0)

# Check wether the message contains the requested pattern.

found = False

for line in lines:
	if line.count(pattern) != 0:
		found = True
		break

if not found:
	print "Pattern not found in message !"
	sys.exit(STATE_WARNING)

# No problem detected.

end = time.time()

if use_ssl: print "SSL IMAP4 transaction OK (%.3f seconds)" % (end - start)
else:			print "IMAP4 transaction OK (%.3f seconds)" % (end - start)

sys.exit(STATE_OK)

# vim: set ts=3 sw=3:
