22
33import string
44import rfc822
5+ import calendar
56import regex
67import os
78import sys
@@ -17,21 +18,22 @@ def is_warning(self):
1718 if not sub :
1819 return 0
1920 sub = string .lower (sub )
20- if sub == 'waiting mail' : return 1
21+ if sub [: 12 ] == 'waiting mail' : return 1
2122 if string .find (sub , 'warning' ) >= 0 : return 1
23+ self .sub = sub
2224 return 0
2325
2426 def get_errors (self ):
2527 for p in EMPARSERS :
2628 self .rewindbody ()
2729 try :
28- return p (self .fp )
30+ return p (self .fp , self . sub )
2931 except Unparseable :
3032 pass
3133 raise Unparseable
3234
3335sendmail_pattern = regex .compile ('[0-9][0-9][0-9] ' )
34- def emparse_sendmail (fp ):
36+ def emparse_sendmail (fp , sub ):
3537 while 1 :
3638 line = fp .readline ()
3739 if not line :
@@ -60,7 +62,6 @@ def emparse_sendmail(fp):
6062 line = line [:- 1 ]
6163 if not line :
6264 continue
63- found_a_line = 1
6465 if sendmail_pattern .match (line ) == 4 :
6566 # Yes, an error/warning line. Ignore 4, remember 5, stop on rest
6667 if line [0 ] == '5' :
@@ -72,12 +73,23 @@ def emparse_sendmail(fp):
7273 line = string .split (line )
7374 if line and line [0 ][:3 ] == '---' :
7475 break
76+ found_a_line = 1
77+ # special case for CWI sendmail
78+ if len (line ) > 1 and line [1 ] == 'Undelivered' :
79+ while 1 :
80+ line = fp .readline ()
81+ if not line :
82+ break
83+ line = string .strip (line )
84+ if not line :
85+ break
86+ errors .append (line + ': ' + sub )
7587 # Empty transcripts are ok, others without an error are not.
7688 if found_a_line and not (errors or warnings ):
7789 raise Unparseable
7890 return errors
7991
80- def emparse_cts (fp ):
92+ def emparse_cts (fp , sub ):
8193 while 1 :
8294 line = fp .readline ()
8395 if not line :
@@ -106,7 +118,7 @@ def emparse_cts(fp):
106118 errors .append (line )
107119 return errors
108120
109- def emparse_aol (fp ):
121+ def emparse_aol (fp , sub ):
110122 while 1 :
111123 line = fp .readline ()
112124 if not line :
@@ -132,7 +144,7 @@ def emparse_aol(fp):
132144 raise Unparseable
133145 return errors
134146
135- def emparse_compuserve (fp ):
147+ def emparse_compuserve (fp , sub ):
136148 while 1 :
137149 line = fp .readline ()
138150 if not line :
@@ -157,8 +169,7 @@ def emparse_compuserve(fp):
157169 return errors
158170
159171prov_pattern = regex .compile ('.* | \(.*\)' )
160-
161- def emparse_providence (fp ):
172+ def emparse_providence (fp , sub ):
162173 while 1 :
163174 line = fp .readline ()
164175 if not line :
@@ -189,58 +200,141 @@ def emparse_providence(fp):
189200 raise Unparseable
190201 return errors
191202
203+ def emparse_x400 (fp , sub ):
204+ exp = 'This report relates to your message:'
205+ while 1 :
206+ line = fp .readline ()
207+ if not line :
208+ raise Unparseable
209+ line = line [:- 1 ]
210+
211+ # Check that we're not in the returned message yet
212+ if string .lower (line )[:5 ] == 'from:' :
213+ raise Unparseable
214+ if line [:len (exp )] == exp :
215+ break
216+
217+ errors = []
218+ exp = 'Your message was not delivered to'
219+ while 1 :
220+ line = fp .readline ()
221+ if not line :
222+ break
223+ line = line [:- 1 ]
224+ if not line :
225+ continue
226+ if line [:len (exp )] == exp :
227+ error = string .strip (line [len (exp ):])
228+ sep = ': '
229+ while 1 :
230+ line = fp .readline ()
231+ if not line :
232+ break
233+ line = line [:- 1 ]
234+ if not line :
235+ break
236+ if line [0 ] == ' ' and line [- 1 ] != ':' :
237+ error = error + sep + string .strip (line )
238+ sep = '; '
239+ errors .append (error )
240+ return errors
241+ raise Unparseable
242+
243+ def emparse_passau (fp , sub ):
244+ exp = 'Unable to deliver message because'
245+ while 1 :
246+ line = fp .readline ()
247+ if not line :
248+ raise Unparseable
249+ if string .lower (line )[:5 ] == 'from:' :
250+ raise Unparseable
251+ if line [:len (exp )] == exp :
252+ break
253+
254+ errors = []
255+ exp = 'Returned Text follows'
256+ while 1 :
257+ line = fp .readline ()
258+ if not line :
259+ raise Unparseable
260+ line = line [:- 1 ]
261+ # Check that we're not in the returned message yet
262+ if string .lower (line )[:5 ] == 'from:' :
263+ raise Unparseable
264+ if not line :
265+ continue
266+ if line [:len (exp )] == exp :
267+ return errors
268+ errors .append (string .strip (line ))
269+
192270EMPARSERS = [emparse_sendmail , emparse_aol , emparse_cts , emparse_compuserve ,
193- emparse_providence ]
271+ emparse_providence , emparse_x400 , emparse_passau ]
272+
273+ def sort_numeric (a , b ):
274+ a = string .atoi (a )
275+ b = string .atoi (b )
276+ if a < b : return - 1
277+ elif a > b : return 1
278+ else : return 0
194279
195280def parsedir (dir , modify ):
196281 os .chdir (dir )
197- files = os .listdir ('.' )
198282 pat = regex .compile ('^[0-9]*$' )
199283 errordict = {}
284+ errorfirst = {}
200285 errorlast = {}
201286 nok = nwarn = nbad = 0
287+
288+ # find all numeric file names and sort them
289+ files = filter (lambda fn , pat = pat : pat .match (fn ) > 0 , os .listdir ('.' ))
290+ files .sort (sort_numeric )
202291
203292 for fn in files :
204- if pat .match (fn ) > 0 :
205- # Ok, so it's a numeric filename. Lets try to parse it.
206- fp = open (fn )
207- m = ErrorMessage (fp )
208- sender = m .getaddr ('From' )
209- print '%s\t %-40s\t ' % (fn , sender [1 ]),
210-
211- if m .is_warning ():
212- print 'warning only'
213- nwarn = nwarn + 1
214- if modify :
215- os .unlink (fn )
216- continue
217-
218- try :
219- errors = m .get_errors ()
220- except Unparseable :
221- print '** Not parseable'
222- nbad = nbad + 1
223- continue
224- print len (errors ), 'errors'
225-
226- # Remember them
227- for e in errors :
228- if not errordict .has_key (e ):
229- errordict [e ] = 1
230- else :
231- errordict [e ] = errordict [e ] + 1
232- errorlast [e ] = fn
293+ # Lets try to parse the file.
294+ fp = open (fn )
295+ m = ErrorMessage (fp )
296+ sender = m .getaddr ('From' )
297+ print '%s\t %-40s\t ' % (fn , sender [1 ]),
233298
234- nok = nok + 1
299+ if m .is_warning ():
300+ print 'warning only'
301+ nwarn = nwarn + 1
235302 if modify :
236303 os .unlink (fn )
304+ continue
305+
306+ try :
307+ errors = m .get_errors ()
308+ except Unparseable :
309+ print '** Not parseable'
310+ nbad = nbad + 1
311+ continue
312+ print len (errors ), 'errors'
313+
314+ # Remember them
315+ for e in errors :
316+ try :
317+ mm , dd = m .getdate ('date' )[1 :1 + 2 ]
318+ date = '%s %02d' % (calendar .month_abbr [mm ], dd )
319+ except :
320+ date = '??????'
321+ if not errordict .has_key (e ):
322+ errordict [e ] = 1
323+ errorfirst [e ] = '%s (%s)' % (fn , date )
324+ else :
325+ errordict [e ] = errordict [e ] + 1
326+ errorlast [e ] = '%s (%s)' % (fn , date )
327+
328+ nok = nok + 1
329+ if modify :
330+ os .unlink (fn )
237331
238332 print '--------------'
239333 print nok , 'files parsed,' ,nwarn ,'files warning-only,' ,
240334 print nbad ,'files unparseable'
241335 print '--------------'
242336 for e in errordict .keys ():
243- print errordict [e ], ' \t ' , errorlast [e ], '\t ' , e
337+ print errordict [e ], errorfirst [ e ], '- ' , errorlast [e ], '\t ' , e
244338
245339def main ():
246340 modify = 0
0 commit comments