|
1 #! /usr/bin/env python |
|
2 |
|
3 # Convert MH directories (1 message per file) or MMDF mailboxes (4x^A |
|
4 # delimited) to unix mailbox (From ... delimited) on stdout. |
|
5 # If -f is given, files contain one message per file (e.g. MH messages) |
|
6 |
|
7 import rfc822 |
|
8 import sys |
|
9 import time |
|
10 import os |
|
11 import stat |
|
12 import getopt |
|
13 import re |
|
14 |
|
15 def main(): |
|
16 dofile = mmdf |
|
17 try: |
|
18 opts, args = getopt.getopt(sys.argv[1:], 'f') |
|
19 except getopt.error, msg: |
|
20 sys.stderr.write('%s\n' % msg) |
|
21 sys.exit(2) |
|
22 for o, a in opts: |
|
23 if o == '-f': |
|
24 dofile = message |
|
25 if not args: |
|
26 args = ['-'] |
|
27 sts = 0 |
|
28 for arg in args: |
|
29 if arg == '-' or arg == '': |
|
30 sts = dofile(sys.stdin) or sts |
|
31 elif os.path.isdir(arg): |
|
32 sts = mh(arg) or sts |
|
33 elif os.path.isfile(arg): |
|
34 try: |
|
35 f = open(arg) |
|
36 except IOError, msg: |
|
37 sys.stderr.write('%s: %s\n' % (arg, msg)) |
|
38 sts = 1 |
|
39 continue |
|
40 sts = dofile(f) or sts |
|
41 f.close() |
|
42 else: |
|
43 sys.stderr.write('%s: not found\n' % arg) |
|
44 sts = 1 |
|
45 if sts: |
|
46 sys.exit(sts) |
|
47 |
|
48 numeric = re.compile('[1-9][0-9]*') |
|
49 |
|
50 def mh(dir): |
|
51 sts = 0 |
|
52 msgs = os.listdir(dir) |
|
53 for msg in msgs: |
|
54 if numeric.match(msg) != len(msg): |
|
55 continue |
|
56 fn = os.path.join(dir, msg) |
|
57 try: |
|
58 f = open(fn) |
|
59 except IOError, msg: |
|
60 sys.stderr.write('%s: %s\n' % (fn, msg)) |
|
61 sts = 1 |
|
62 continue |
|
63 sts = message(f) or sts |
|
64 return sts |
|
65 |
|
66 def mmdf(f): |
|
67 sts = 0 |
|
68 while 1: |
|
69 line = f.readline() |
|
70 if not line: |
|
71 break |
|
72 if line == '\1\1\1\1\n': |
|
73 sts = message(f, line) or sts |
|
74 else: |
|
75 sys.stderr.write( |
|
76 'Bad line in MMFD mailbox: %r\n' % (line,)) |
|
77 return sts |
|
78 |
|
79 counter = 0 # for generating unique Message-ID headers |
|
80 |
|
81 def message(f, delimiter = ''): |
|
82 sts = 0 |
|
83 # Parse RFC822 header |
|
84 m = rfc822.Message(f) |
|
85 # Write unix header line |
|
86 fullname, email = m.getaddr('From') |
|
87 tt = m.getdate('Date') |
|
88 if tt: |
|
89 t = time.mktime(tt) |
|
90 else: |
|
91 sys.stderr.write( |
|
92 'Unparseable date: %r\n' % (m.getheader('Date'),)) |
|
93 t = os.fstat(f.fileno())[stat.ST_MTIME] |
|
94 print 'From', email, time.ctime(t) |
|
95 # Copy RFC822 header |
|
96 for line in m.headers: |
|
97 print line, |
|
98 # Invent Message-ID header if none is present |
|
99 if not m.has_key('message-id'): |
|
100 global counter |
|
101 counter = counter + 1 |
|
102 msgid = "<%s.%d>" % (hex(t), counter) |
|
103 sys.stderr.write("Adding Message-ID %s (From %s)\n" % |
|
104 (msgid, email)) |
|
105 print "Message-ID:", msgid |
|
106 print |
|
107 # Copy body |
|
108 while 1: |
|
109 line = f.readline() |
|
110 if line == delimiter: |
|
111 break |
|
112 if not line: |
|
113 sys.stderr.write('Unexpected EOF in message\n') |
|
114 sts = 1 |
|
115 break |
|
116 if line[:5] == 'From ': |
|
117 line = '>' + line |
|
118 print line, |
|
119 # Print trailing newline |
|
120 print |
|
121 return sts |
|
122 |
|
123 if __name__ == "__main__": |
|
124 main() |