i3status/contrib/check_mail.py
Dmitrij D. Czarkoff cc77338ff4 check_mail.py: more detailed report on IOError
When user doesn't have permissions to access some file, he is better served by
exact error message python recieved then by statement "not a mailbox".
2016-01-21 10:36:30 +01:00

166 lines
5.8 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This script wraps i3status output and inject mail status, or just reports
# status on command line. It is based on 'wrapper.py' script by Valentin
# Haenel, which could be found at:
# http://code.stapelberg.de/git/i3status/tree/contrib/wrapper.py
#
# To use it, ensure your ~/.i3status.conf contains this line:
# output_format = "i3bar"
# in the 'general' section.
# Then, in your ~/.i3/config, use:
# status_command i3status | path/to/check_mail.py ...
# In the 'bar' section.
#
# Or just run:
# ./check_mail.py -1 ...
#
# Information on command line arguments (flags) may be obtained by running
# ./check_mail.py -h
#
# © 2015 Dmitrij D. Czarkoff <czarkoff@gmail.com>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
import argparse
import json
import os
import os.path
import sys
def print_line(message):
""" Non-buffered printing to stdout. """
sys.stdout.write(message + '\n')
sys.stdout.flush()
def read_line():
""" Interrupted respecting reader for stdin. """
# try reading a line, removing any extra whitespace
try:
line = sys.stdin.readline().strip()
# i3status sends EOF, or an empty line
if not line:
sys.exit(3)
return line
# exit on ctrl-c
except KeyboardInterrupt:
sys.exit()
def check_mail(label, nomail, ignore, colors):
""" Check mail in mailbox "label" and return report and color """
name = label
if not os.path.isabs(name):
name = os.path.join(os.environ['HOME'], name)
if not os.path.exists(name) or os.path.getsize(name) == 0:
return nomail, colors[0]
if os.path.isfile(name):
import mailbox
try:
mbox = mailbox.mbox(name, create = False)
messages = 0
for msg in mbox:
if msg.get_flags() == '':
messages += 1
if messages > 0:
return '{0}:{1}'.format(os.path.basename(name),
messages), colors[1]
else:
return nomail, colors[0]
except IOError, exception:
return '{0}: {1}'.format(name, exception.strerror), colors[2]
except:
pass
elif os.path.isdir(name):
report = ''
maildirs = 0
for subdir in os.listdir(name):
subdirpath = os.path.join(name, subdir)
if 'new' in os.listdir(subdirpath):
maildirs += 1
if subdir not in ignore:
messages = len(os.listdir(os.path.join(subdirpath, 'new')))
if messages > 0:
report += ' {0}:{1}'.format(subdir, messages)
if maildirs > 0:
if len(report) > 0:
return report[1:], colors[1]
else:
return nomail, colors[0]
return '{0}: not a mailbox'.format(name), colors[2]
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Check mailboxes.')
parser.add_argument('mailbox', help='path to mailbox', type=str, nargs='*',
default=['/var/mail/{0}'.format(os.getlogin())])
parser.add_argument('-i', '--ignore', action='append', help='ignore named '
'mailboxes', type=str, dest='ignore', metavar='mailbox')
parser.add_argument('-1', '--once', help='check mailboxes, write results '
'to stdout and exit', action='store_true')
parser.add_argument('-0', '--nomail', help='text to print if no new mail '
'found', type=str, default='')
parser.add_argument('-g', '--good', help='color to use when there is no '
'new mail', type=str, default='#00FF00')
parser.add_argument('-d', '--degraded', help='color to use when there is '
'new mail', type=str, default='#FFFF00')
parser.add_argument('-b', '--bad', help='color to use when error was '
'detected', type=str, default='#FF0000')
parser.add_argument('-p', '--position', help='position of mail reports in '
'i3bar status', type=int, default=0)
args = parser.parse_args()
colors = [args.good, args.degraded, args.bad]
if args.once:
for name in args.mailbox:
report, color = check_mail(name, args.nomail, args.ignore, colors)
sys.stderr.write(report + '\n')
exit(0)
# Skip the first line which contains the version header.
print_line(read_line())
# The second line contains the start of the infinite array.
print_line(read_line())
while True:
line, prefix = read_line(), ''
# ignore comma at start of lines
if line.startswith(','):
line, prefix = line[1:], ','
j = json.loads(line)
# insert information into the start of the json
i = args.position
for name in args.mailbox:
report, color = check_mail(name, args.nomail, args.ignore, colors)
j.insert(i, {
'name' : 'mail',
'instance' : name,
'full_text' : report,
'color' : color
})
i += 1
# and echo back new encoded json
print_line(prefix+json.dumps(j))