blob: 88b0b89c87963315c70d37d822c5cd1786b2d425 [file] [log] [blame]
Guido van Rossumf06ee5f1996-11-27 19:52:01 +00001#! /usr/bin/env python
Guido van Rossum18468821994-06-20 07:49:28 +00002
3# Scan MH folder, display results in window
4
5import os
6import sys
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00007import re
Guido van Rossum18468821994-06-20 07:49:28 +00008import getopt
9import string
10import mhlib
11
12from Tkinter import *
13
14from dialog import dialog
15
16mailbox = os.environ['HOME'] + '/Mail'
17
18def main():
Tim Peters182b5ac2004-07-18 06:16:08 +000019 global root, tk, top, mid, bot
20 global folderbox, foldermenu, scanbox, scanmenu, viewer
21 global folder, seq
22 global mh, mhf
Guido van Rossum18468821994-06-20 07:49:28 +000023
Tim Peters182b5ac2004-07-18 06:16:08 +000024 # Parse command line options
Guido van Rossum18468821994-06-20 07:49:28 +000025
Tim Peters182b5ac2004-07-18 06:16:08 +000026 folder = 'inbox'
27 seq = 'all'
28 try:
29 opts, args = getopt.getopt(sys.argv[1:], '')
Guido van Rossumb940e112007-01-10 16:19:56 +000030 except getopt.error as msg:
Collin Winter6f2df4d2007-07-17 20:59:35 +000031 print(msg)
Tim Peters182b5ac2004-07-18 06:16:08 +000032 sys.exit(2)
33 for arg in args:
34 if arg[:1] == '+':
35 folder = arg[1:]
36 else:
37 seq = arg
Guido van Rossum18468821994-06-20 07:49:28 +000038
Tim Peters182b5ac2004-07-18 06:16:08 +000039 # Initialize MH
Guido van Rossum18468821994-06-20 07:49:28 +000040
Tim Peters182b5ac2004-07-18 06:16:08 +000041 mh = mhlib.MH()
42 mhf = mh.openfolder(folder)
Guido van Rossum18468821994-06-20 07:49:28 +000043
Tim Peters182b5ac2004-07-18 06:16:08 +000044 # Build widget hierarchy
Guido van Rossum18468821994-06-20 07:49:28 +000045
Tim Peters182b5ac2004-07-18 06:16:08 +000046 root = Tk()
47 tk = root.tk
Guido van Rossum18468821994-06-20 07:49:28 +000048
Tim Peters182b5ac2004-07-18 06:16:08 +000049 top = Frame(root)
50 top.pack({'expand': 1, 'fill': 'both'})
Guido van Rossum18468821994-06-20 07:49:28 +000051
Tim Peters182b5ac2004-07-18 06:16:08 +000052 # Build right part: folder list
Guido van Rossum18468821994-06-20 07:49:28 +000053
Tim Peters182b5ac2004-07-18 06:16:08 +000054 right = Frame(top)
55 right.pack({'fill': 'y', 'side': 'right'})
Guido van Rossum18468821994-06-20 07:49:28 +000056
Tim Peters182b5ac2004-07-18 06:16:08 +000057 folderbar = Scrollbar(right, {'relief': 'sunken', 'bd': 2})
58 folderbar.pack({'fill': 'y', 'side': 'right'})
Guido van Rossum18468821994-06-20 07:49:28 +000059
Tim Peters182b5ac2004-07-18 06:16:08 +000060 folderbox = Listbox(right, {'exportselection': 0})
61 folderbox.pack({'expand': 1, 'fill': 'both', 'side': 'left'})
Guido van Rossum18468821994-06-20 07:49:28 +000062
Tim Peters182b5ac2004-07-18 06:16:08 +000063 foldermenu = Menu(root)
64 foldermenu.add('command',
65 {'label': 'Open Folder',
66 'command': open_folder})
67 foldermenu.add('separator')
68 foldermenu.add('command',
69 {'label': 'Quit',
70 'command': 'exit'})
71 foldermenu.bind('<ButtonRelease-3>', folder_unpost)
Guido van Rossum18468821994-06-20 07:49:28 +000072
Tim Peters182b5ac2004-07-18 06:16:08 +000073 folderbox['yscrollcommand'] = (folderbar, 'set')
74 folderbar['command'] = (folderbox, 'yview')
75 folderbox.bind('<Double-1>', open_folder, 1)
76 folderbox.bind('<3>', folder_post)
Guido van Rossum18468821994-06-20 07:49:28 +000077
Tim Peters182b5ac2004-07-18 06:16:08 +000078 # Build left part: scan list
Guido van Rossum18468821994-06-20 07:49:28 +000079
Tim Peters182b5ac2004-07-18 06:16:08 +000080 left = Frame(top)
81 left.pack({'expand': 1, 'fill': 'both', 'side': 'left'})
Guido van Rossum18468821994-06-20 07:49:28 +000082
Tim Peters182b5ac2004-07-18 06:16:08 +000083 scanbar = Scrollbar(left, {'relief': 'sunken', 'bd': 2})
84 scanbar.pack({'fill': 'y', 'side': 'right'})
Guido van Rossum18468821994-06-20 07:49:28 +000085
Tim Peters182b5ac2004-07-18 06:16:08 +000086 scanbox = Listbox(left, {'font': 'fixed'})
87 scanbox.pack({'expand': 1, 'fill': 'both', 'side': 'left'})
Guido van Rossum18468821994-06-20 07:49:28 +000088
Tim Peters182b5ac2004-07-18 06:16:08 +000089 scanmenu = Menu(root)
90 scanmenu.add('command',
91 {'label': 'Open Message',
92 'command': open_message})
93 scanmenu.add('command',
94 {'label': 'Remove Message',
95 'command': remove_message})
96 scanmenu.add('command',
97 {'label': 'Refile Message',
98 'command': refile_message})
99 scanmenu.add('separator')
100 scanmenu.add('command',
101 {'label': 'Quit',
102 'command': 'exit'})
103 scanmenu.bind('<ButtonRelease-3>', scan_unpost)
Guido van Rossum18468821994-06-20 07:49:28 +0000104
Tim Peters182b5ac2004-07-18 06:16:08 +0000105 scanbox['yscrollcommand'] = (scanbar, 'set')
106 scanbar['command'] = (scanbox, 'yview')
107 scanbox.bind('<Double-1>', open_message)
108 scanbox.bind('<3>', scan_post)
Guido van Rossum18468821994-06-20 07:49:28 +0000109
Tim Peters182b5ac2004-07-18 06:16:08 +0000110 # Separator between middle and bottom part
Guido van Rossum18468821994-06-20 07:49:28 +0000111
Tim Peters182b5ac2004-07-18 06:16:08 +0000112 rule2 = Frame(root, {'bg': 'black'})
113 rule2.pack({'fill': 'x'})
Guido van Rossum18468821994-06-20 07:49:28 +0000114
Tim Peters182b5ac2004-07-18 06:16:08 +0000115 # Build bottom part: current message
Guido van Rossum18468821994-06-20 07:49:28 +0000116
Tim Peters182b5ac2004-07-18 06:16:08 +0000117 bot = Frame(root)
118 bot.pack({'expand': 1, 'fill': 'both'})
119 #
120 viewer = None
Guido van Rossum18468821994-06-20 07:49:28 +0000121
Tim Peters182b5ac2004-07-18 06:16:08 +0000122 # Window manager commands
Guido van Rossum18468821994-06-20 07:49:28 +0000123
Tim Peters182b5ac2004-07-18 06:16:08 +0000124 root.minsize(800, 1) # Make window resizable
Guido van Rossum18468821994-06-20 07:49:28 +0000125
Tim Peters182b5ac2004-07-18 06:16:08 +0000126 # Fill folderbox with text
Guido van Rossum18468821994-06-20 07:49:28 +0000127
Tim Peters182b5ac2004-07-18 06:16:08 +0000128 setfolders()
Guido van Rossum18468821994-06-20 07:49:28 +0000129
Tim Peters182b5ac2004-07-18 06:16:08 +0000130 # Fill scanbox with text
Guido van Rossum18468821994-06-20 07:49:28 +0000131
Tim Peters182b5ac2004-07-18 06:16:08 +0000132 rescan()
Guido van Rossum18468821994-06-20 07:49:28 +0000133
Tim Peters182b5ac2004-07-18 06:16:08 +0000134 # Enter mainloop
Guido van Rossum18468821994-06-20 07:49:28 +0000135
Tim Peters182b5ac2004-07-18 06:16:08 +0000136 root.mainloop()
Guido van Rossum18468821994-06-20 07:49:28 +0000137
138def folder_post(e):
Tim Peters182b5ac2004-07-18 06:16:08 +0000139 x, y = e.x_root, e.y_root
140 foldermenu.post(x - 10, y - 10)
141 foldermenu.grab_set()
Guido van Rossum18468821994-06-20 07:49:28 +0000142
143def folder_unpost(e):
Tim Peters182b5ac2004-07-18 06:16:08 +0000144 tk.call('update', 'idletasks')
145 foldermenu.grab_release()
146 foldermenu.unpost()
147 foldermenu.invoke('active')
Guido van Rossum18468821994-06-20 07:49:28 +0000148
149def scan_post(e):
Tim Peters182b5ac2004-07-18 06:16:08 +0000150 x, y = e.x_root, e.y_root
151 scanmenu.post(x - 10, y - 10)
152 scanmenu.grab_set()
Guido van Rossum18468821994-06-20 07:49:28 +0000153
154def scan_unpost(e):
Tim Peters182b5ac2004-07-18 06:16:08 +0000155 tk.call('update', 'idletasks')
156 scanmenu.grab_release()
157 scanmenu.unpost()
158 scanmenu.invoke('active')
Guido van Rossum18468821994-06-20 07:49:28 +0000159
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000160scanparser = re.compile('^ *([0-9]+)')
Guido van Rossum18468821994-06-20 07:49:28 +0000161
Guido van Rossum78b0c821994-07-13 16:53:32 +0000162def open_folder(e=None):
Tim Peters182b5ac2004-07-18 06:16:08 +0000163 global folder, mhf
164 sel = folderbox.curselection()
165 if len(sel) != 1:
166 if len(sel) > 1:
167 msg = "Please open one folder at a time"
168 else:
169 msg = "Please select a folder to open"
170 dialog(root, "Can't Open Folder", msg, "", 0, "OK")
171 return
172 i = sel[0]
173 folder = folderbox.get(i)
174 mhf = mh.openfolder(folder)
175 rescan()
Guido van Rossum18468821994-06-20 07:49:28 +0000176
Guido van Rossum78b0c821994-07-13 16:53:32 +0000177def open_message(e=None):
Tim Peters182b5ac2004-07-18 06:16:08 +0000178 global viewer
179 sel = scanbox.curselection()
180 if len(sel) != 1:
181 if len(sel) > 1:
182 msg = "Please open one message at a time"
183 else:
184 msg = "Please select a message to open"
185 dialog(root, "Can't Open Message", msg, "", 0, "OK")
186 return
187 cursor = scanbox['cursor']
188 scanbox['cursor'] = 'watch'
189 tk.call('update', 'idletasks')
190 i = sel[0]
191 line = scanbox.get(i)
192 if scanparser.match(line) >= 0:
193 num = string.atoi(scanparser.group(1))
194 m = mhf.openmessage(num)
195 if viewer: viewer.destroy()
196 from MimeViewer import MimeViewer
197 viewer = MimeViewer(bot, '+%s/%d' % (folder, num), m)
198 viewer.pack()
199 viewer.show()
200 scanbox['cursor'] = cursor
Guido van Rossum18468821994-06-20 07:49:28 +0000201
202def interestingheader(header):
Tim Peters182b5ac2004-07-18 06:16:08 +0000203 return header != 'received'
Guido van Rossum18468821994-06-20 07:49:28 +0000204
Guido van Rossum78b0c821994-07-13 16:53:32 +0000205def remove_message(e=None):
Tim Peters182b5ac2004-07-18 06:16:08 +0000206 itop = scanbox.nearest(0)
207 sel = scanbox.curselection()
208 if not sel:
209 dialog(root, "No Message To Remove",
210 "Please select a message to remove", "", 0, "OK")
211 return
212 todo = []
213 for i in sel:
214 line = scanbox.get(i)
215 if scanparser.match(line) >= 0:
216 todo.append(string.atoi(scanparser.group(1)))
217 mhf.removemessages(todo)
218 rescan()
219 fixfocus(min(todo), itop)
Guido van Rossum18468821994-06-20 07:49:28 +0000220
221lastrefile = ''
222tofolder = None
Guido van Rossum78b0c821994-07-13 16:53:32 +0000223def refile_message(e=None):
Tim Peters182b5ac2004-07-18 06:16:08 +0000224 global lastrefile, tofolder
225 itop = scanbox.nearest(0)
226 sel = scanbox.curselection()
227 if not sel:
228 dialog(root, "No Message To Refile",
229 "Please select a message to refile", "", 0, "OK")
230 return
231 foldersel = folderbox.curselection()
232 if len(foldersel) != 1:
233 if not foldersel:
234 msg = "Please select a folder to refile to"
235 else:
236 msg = "Please select exactly one folder to refile to"
237 dialog(root, "No Folder To Refile", msg, "", 0, "OK")
238 return
239 refileto = folderbox.get(foldersel[0])
240 todo = []
241 for i in sel:
242 line = scanbox.get(i)
243 if scanparser.match(line) >= 0:
244 todo.append(string.atoi(scanparser.group(1)))
245 if lastrefile != refileto or not tofolder:
246 lastrefile = refileto
247 tofolder = None
248 tofolder = mh.openfolder(lastrefile)
249 mhf.refilemessages(todo, tofolder)
250 rescan()
251 fixfocus(min(todo), itop)
Guido van Rossum18468821994-06-20 07:49:28 +0000252
253def fixfocus(near, itop):
Tim Peters182b5ac2004-07-18 06:16:08 +0000254 n = scanbox.size()
255 for i in range(n):
256 line = scanbox.get(repr(i))
257 if scanparser.match(line) >= 0:
258 num = string.atoi(scanparser.group(1))
259 if num >= near:
260 break
261 else:
262 i = 'end'
263 scanbox.select_from(i)
264 scanbox.yview(itop)
Guido van Rossum18468821994-06-20 07:49:28 +0000265
266def setfolders():
Tim Peters182b5ac2004-07-18 06:16:08 +0000267 folderbox.delete(0, 'end')
268 for fn in mh.listallfolders():
269 folderbox.insert('end', fn)
Guido van Rossum18468821994-06-20 07:49:28 +0000270
271def rescan():
Tim Peters182b5ac2004-07-18 06:16:08 +0000272 global viewer
273 if viewer:
274 viewer.destroy()
275 viewer = None
276 scanbox.delete(0, 'end')
277 for line in scanfolder(folder, seq):
278 scanbox.insert('end', line)
Guido van Rossum18468821994-06-20 07:49:28 +0000279
280def scanfolder(folder = 'inbox', sequence = 'all'):
Collin Winter6f2df4d2007-07-17 20:59:35 +0000281 return [line[:-1] for line in os.popen('scan +%s %s' % (folder, sequence), 'r').readlines()]
Guido van Rossum18468821994-06-20 07:49:28 +0000282
283main()