#!/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 # # 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))