#!/usr/bin/python2.1
#!/usr/bin/env python2.1
#!/usr/bin/env python
#!/usr/local/bin/python

'''
Emails the address specified if the command run has output,
othwise remains silent.
'''

version = "1.2"
versiondate = "2005-Mar-21"

helptext='''Usage: cron-wrapper [option]
  -email=address       send email to these address (comma separated)
                       default user who is running the script
  -goofey=nic          goof these people (comma separated)
  -subject=text        use this subject in the email
  -blurb=text          put this at the start of the email
  -countmatch=pattern  put a count of lines mating pattern in subject
                       can be used multiple times
  -run=program         run this program
  -diff[=dir]          only send mail if output differs from last run
                       save output in this directory
		       default dir is ~/cron-diff
  -timeout=seconds     kill command if it takes longer than this
'''

import sys, string, os, pwd, socket, re, select, time

# use username @ host
email = pwd.getpwuid(os.getuid())[0]+'@'+socket.gethostname()
goofey=None
subject=None
blurb=''
countmatch=[]
diff=0
diffdir = os.path.join(os.environ['HOME'], 'cron-diff')
#timeout = 300	# 5 minutes
timeout = None	# 5 minutes

def lefteq(a, b):
	return a == b[:len(a)]

# collect stderr as well.
# the 2> /dev/null is requied to stop telnet printing
# "Connection closed by foreigh host."
#progredirect = ' 2> /dev/null 2>&1'
progredirect = ' 2>&1'

def runprogram(program):
	global blurb
	progfd = os.popen(program + progredirect, 'r')
	if timeout:
		output = ''
		starttime = time.time()
		while 1:
			timeleft = time.time() - starttime + timeout
			print 'timeleft =', timeleft
			if timeleft <= 0:
				break
			ready = select.select([], [progfd], [progfd], timeleft)
			if ready[1]:
				data = progfd.read(1)
				print 'read output:', `data`
				if not data:
					print 'Finished command.'
					break
				output = output + data
			elif ready[2]:
				print 'Exceptional condition.'
			else:
				print 'Timeout!'
				break
	else:
		output = progfd.read()
	progfd.close()
	if output:
		if diff:
			if not os.path.exists(diffdir):
				os.mkdir(diffdir)
			filename = os.path.join(diffdir, re.sub('[^a-z]', '', program))
			try:
				fh = open(filename, 'r')
				oldoutput = fh.read()
				fh.close()
			except IOError:
				oldoutput = ''
			if oldoutput == output:
				return
			fh = open(filename, 'w')
			fh.write(output)
			fh.close()
			if not blurb:
				blurb = 'Output has changed since last run.\n'
		if countmatch:
			count = []
			for i in countmatch:
				count.append('%i %s' % (len(re.compile(i, re.I).findall(output)), i.strip()))
			failtext = '(%s)' % ('; '.join(count))
		else:
			failtext=''
		if os.path.isfile('/usr/sbin/sendmail'):
			sendmail = '/usr/sbin/sendmail'
		elif os.path.isfile('/usr/lib/sendmail'):
			sendmail = '/usr/lib/sendmail'
		else: # giveup
			sendmail = 'sendmail'
		mailfd = os.popen(sendmail + ' -oi -t', 'w')
		mailfd.write('To: '+email+'\n')
		if subject == None:
			mailfd.write('Subject: cron-wrapper '+program+failtext+'\n\n')
		else:
			mailfd.write('Subject: '+subject+failtext+'\n\n')
		if blurb:
			mailfd.write(blurb+'\n')
		mailfd.write(output)
		mailfd.write('\nThis message brought to you by '+pwd.getpwuid(os.getuid())[0]+'@'+socket.gethostname()+' running cron-wrapper.\n')
		mailfd.write('run command: '+program+'\n')
		mailfd.close()
		if goofey:
			gooffd = os.popen('/usr/bin/goofey -s '+goofey+' > /dev/null', 'w')
			gooffd.write('\nOutput from "'+program+'"\n')
			gooffd.write(output)
			gooffd.close()

if len(sys.argv) < 2:
	print helptext
	sys.exit(1)

for i in sys.argv[1:]:
	if i in ('-h', 'help', '--help', '-help'):
		print helptext
	elif lefteq('-email=', i):
		email = string.split(i, '=', 1)[1]
	elif lefteq('-goofey=', i):
		goofey = string.split(i, '=', 1)[1]
	elif lefteq('-subject=', i):
		subject = string.split(i, '=', 1)[1]
	elif lefteq('-blurb=', i):
		blurb = string.split(i, '=', 1)[1]
	elif lefteq('-run=', i):
		runprogram(string.split(i, '=', 1)[1])
	elif lefteq('-countmatch=', i):
		countmatch.append(string.split(i, '=', 1)[1])
	elif lefteq('-timeout=', i):
		timeout = int(string.split(i, '=', 1)[1])
	elif lefteq('-diff', i):
		diff = 1
		difftuple=string.split(i, '=', 1)
		if len(difftuple) > 1:
			diffdir = difftuple[1]
	else:
		print 'Unknown option:', i
		print helptext
