summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xTools/scripts/mailerdaemon.py201
1 files changed, 201 insertions, 0 deletions
diff --git a/Tools/scripts/mailerdaemon.py b/Tools/scripts/mailerdaemon.py
new file mode 100755
index 0000000..b39760e4
--- /dev/null
+++ b/Tools/scripts/mailerdaemon.py
@@ -0,0 +1,201 @@
+"""mailerdaemon - classes to parse mailer-daemon messages"""
+
+import string
+import rfc822
+import regex
+import os
+import sys
+
+Unparseable = 'mailerdaemon.Unparseable'
+
+class ErrorMessage(rfc822.Message):
+ def __init__(self, fp):
+ rfc822.Message.__init__(self, fp)
+
+ def is_warning(self):
+ sub = self.getheader('Subject')
+ if not sub:
+ return 0
+ sub = string.lower(sub)
+ if sub == 'waiting mail': return 1
+ if string.find(sub, 'warning') >= 0: return 1
+ return 0
+
+ def get_errors(self):
+ for p in EMPARSERS:
+ self.rewindbody()
+ try:
+ return p(self.fp)
+ except Unparseable:
+ pass
+ raise Unparseable
+
+sendmail_pattern = regex.compile('[0-9][0-9][0-9] ')
+def emparse_sendmail(fp):
+ while 1:
+ line = fp.readline()
+ if not line:
+ raise Unparseable
+ line = line[:-1]
+
+ # Check that we're not in the returned message yet
+ if string.lower(line)[:5] == 'from:':
+ raise Unparseable
+ line = string.split(line)
+ if len(line) > 3 and \
+ ((line[0] == '-----' and line[1] == 'Transcript') or
+ (line[0] == '---' and line[1] == 'The' and
+ line[2] == 'transcript') or
+ (line[0] == 'While' and line[1] == 'talking' and line[2] == 'to')):
+ # Yes, found it!
+ break
+
+ errors = []
+ found_a_line = 0
+ warnings = 0
+ while 1:
+ line = fp.readline()
+ if not line:
+ break
+ line = line[:-1]
+ if not line:
+ continue
+ found_a_line = 1
+ if sendmail_pattern.match(line) == 4:
+ # Yes, an error/warning line. Ignore 4, remember 5, stop on rest
+ if line[0] == '5':
+ errors.append(line)
+ elif line[0] == '4':
+ warnings = 1
+ else:
+ raise Unparseable
+ line = string.split(line)
+ if line and line[0][:3] == '---':
+ break
+ # Empty transcripts are ok, others without an error are not.
+ if found_a_line and not (errors or warnings):
+ raise Unparseable
+ return errors
+
+def emparse_cts(fp):
+ while 1:
+ line = fp.readline()
+ if not line:
+ raise Unparseable
+ line = line[:-1]
+
+ # Check that we're not in the returned message yet
+ if string.lower(line)[:5] == 'from:':
+ raise Unparseable
+ line = string.split(line)
+ if len(line) > 3 and line[0][:2] == '|-' and line[1] == 'Failed' \
+ and line[2] == 'addresses':
+ # Yes, found it!
+ break
+
+ errors = []
+ while 1:
+ line = fp.readline()
+ if not line:
+ break
+ line = line[:-1]
+ if not line:
+ continue
+ errors.append(line)
+ if line[:2] == '|-':
+ break
+ return errors
+
+def emparse_aol(fp):
+ while 1:
+ line = fp.readline()
+ if not line:
+ raise Unparseable
+ line = line[:-1]
+ if line:
+ break
+ exp = 'The mail you sent could not be delivered to:'
+ if line[:len(exp)] != exp:
+ raise Unparseable
+ errors = []
+ while 1:
+ line = fp.readline()
+ if sendmail_pattern.match(line) == 4:
+ # Yes, an error/warning line. Ignore 4, remember 5, stop on rest
+ if line[0] == '5':
+ errors.append(line)
+ elif line[0] != '4':
+ raise Unparseable
+ elif line == '\n':
+ break
+ else:
+ raise Unparseable
+ return errors
+
+
+
+EMPARSERS = [emparse_sendmail, emparse_aol, emparse_cts]
+
+def parsedir(dir, modify):
+ os.chdir(dir)
+ files = os.listdir('.')
+ pat = regex.compile('^[0-9]*$')
+ errordict = {}
+ errorlast = {}
+ nok = nwarn = nbad = 0
+
+ for fn in files:
+ if pat.match(fn) > 0:
+ # Ok, so it's a numeric filename. Lets try to parse it.
+ fp = open(fn)
+ m = ErrorMessage(fp)
+ sender = m.getaddr('From')
+ print '%s\t%-40s\t'%(fn, sender[1]),
+
+ if m.is_warning():
+ print 'warning only'
+ nwarn = nwarn + 1
+ if modify:
+ os.unlink(fn)
+ continue
+
+ try:
+ errors = m.get_errors()
+ except Unparseable:
+ print '** Not parseable'
+ nbad = nbad + 1
+ continue
+ print len(errors), 'errors'
+
+ # Remember them
+ for e in errors:
+ if not errordict.has_key(e):
+ errordict[e] = 1
+ else:
+ errordict[e] = errordict[e] + 1
+ errorlast[e] = fn
+
+ nok = nok + 1
+ if modify:
+ os.unlink(fn)
+
+ print '--------------'
+ print nok, 'files parsed,',nwarn,'files warning-only,',
+ print nbad,'files unparseable'
+ print '--------------'
+ for e in errordict.keys():
+ print errordict[e], '\t', errorlast[e], '\t', e
+
+def main():
+ modify = 0
+ if len(sys.argv) > 1 and sys.argv[1] == '-d':
+ modify = 1
+ del sys.argv[1]
+ if len(sys.argv) > 1:
+ for folder in sys.argv[1:]:
+ parsedir(folder, modify)
+ else:
+ parsedir('/ufs/jack/Mail/errorsinbox', modify)
+
+if __name__ == '__main__' or sys.argv[0] == __name__:
+ main()