|
1 #! /usr/bin/env python |
|
2 |
|
3 # View a single MIME multipart message. |
|
4 # Display each part as a box. |
|
5 |
|
6 import string |
|
7 from types import * |
|
8 from Tkinter import * |
|
9 from ScrolledText import ScrolledText |
|
10 |
|
11 class MimeViewer: |
|
12 def __init__(self, parent, title, msg): |
|
13 self.title = title |
|
14 self.msg = msg |
|
15 self.frame = Frame(parent, {'relief': 'raised', 'bd': 2}) |
|
16 self.frame.packing = {'expand': 0, 'fill': 'both'} |
|
17 self.button = Checkbutton(self.frame, |
|
18 {'text': title, |
|
19 'command': self.toggle}) |
|
20 self.button.pack({'anchor': 'w'}) |
|
21 headertext = msg.getheadertext( |
|
22 lambda x: x != 'received' and x[:5] != 'x400-') |
|
23 height = countlines(headertext, 4) |
|
24 if height: |
|
25 self.htext = ScrolledText(self.frame, |
|
26 {'height': height, |
|
27 'width': 80, |
|
28 'wrap': 'none', |
|
29 'relief': 'raised', |
|
30 'bd': 2}) |
|
31 self.htext.packing = {'expand': 1, 'fill': 'both', |
|
32 'after': self.button} |
|
33 self.htext.insert('end', headertext) |
|
34 else: |
|
35 self.htext = Frame(self.frame, |
|
36 {'relief': 'raised', 'bd': 2}) |
|
37 self.htext.packing = {'side': 'top', |
|
38 'ipady': 2, |
|
39 'fill': 'x', |
|
40 'after': self.button} |
|
41 body = msg.getbody() |
|
42 if type(body) == StringType: |
|
43 self.pad = None |
|
44 height = countlines(body, 10) |
|
45 if height: |
|
46 self.btext = ScrolledText(self.frame, |
|
47 {'height': height, |
|
48 'width': 80, |
|
49 'wrap': 'none', |
|
50 'relief': 'raised', |
|
51 'bd': 2}) |
|
52 self.btext.packing = {'expand': 1, |
|
53 'fill': 'both'} |
|
54 self.btext.insert('end', body) |
|
55 else: |
|
56 self.btext = None |
|
57 self.parts = None |
|
58 else: |
|
59 self.pad = Frame(self.frame, |
|
60 {'relief': 'flat', 'bd': 2}) |
|
61 self.pad.packing = {'side': 'left', 'ipadx': 10, |
|
62 'fill': 'y', 'after': self.htext} |
|
63 self.parts = [] |
|
64 for i in range(len(body)): |
|
65 p = MimeViewer(self.frame, |
|
66 '%s.%d' % (title, i+1), |
|
67 body[i]) |
|
68 self.parts.append(p) |
|
69 self.btext = None |
|
70 self.collapsed = 1 |
|
71 def pack(self): |
|
72 self.frame.pack(self.frame.packing) |
|
73 def destroy(self): |
|
74 self.frame.destroy() |
|
75 def show(self): |
|
76 if self.collapsed: |
|
77 self.button.invoke() |
|
78 def toggle(self): |
|
79 if self.collapsed: |
|
80 self.explode() |
|
81 else: |
|
82 self.collapse() |
|
83 def collapse(self): |
|
84 self.collapsed = 1 |
|
85 for comp in self.htext, self.btext, self.pad: |
|
86 if comp: |
|
87 comp.forget() |
|
88 if self.parts: |
|
89 for part in self.parts: |
|
90 part.frame.forget() |
|
91 self.frame.pack({'expand': 0}) |
|
92 def explode(self): |
|
93 self.collapsed = 0 |
|
94 for comp in self.htext, self.btext, self.pad: |
|
95 if comp: comp.pack(comp.packing) |
|
96 if self.parts: |
|
97 for part in self.parts: |
|
98 part.pack() |
|
99 self.frame.pack({'expand': 1}) |
|
100 |
|
101 def countlines(str, limit): |
|
102 i = 0 |
|
103 n = 0 |
|
104 while n < limit: |
|
105 i = string.find(str, '\n', i) |
|
106 if i < 0: break |
|
107 n = n+1 |
|
108 i = i+1 |
|
109 return n |
|
110 |
|
111 def main(): |
|
112 import sys |
|
113 import getopt |
|
114 import mhlib |
|
115 opts, args = getopt.getopt(sys.argv[1:], '') |
|
116 for o, a in opts: |
|
117 pass |
|
118 message = None |
|
119 folder = 'inbox' |
|
120 for arg in args: |
|
121 if arg[:1] == '+': |
|
122 folder = arg[1:] |
|
123 else: |
|
124 message = string.atoi(arg) |
|
125 |
|
126 mh = mhlib.MH() |
|
127 f = mh.openfolder(folder) |
|
128 if not message: |
|
129 message = f.getcurrent() |
|
130 m = f.openmessage(message) |
|
131 |
|
132 root = Tk() |
|
133 tk = root.tk |
|
134 |
|
135 top = MimeViewer(root, '+%s/%d' % (folder, message), m) |
|
136 top.pack() |
|
137 top.show() |
|
138 |
|
139 root.minsize(1, 1) |
|
140 |
|
141 tk.mainloop() |
|
142 |
|
143 if __name__ == '__main__': main() |