Benjamin Peterson | 90f5ba5 | 2010-03-11 22:53:45 +0000 | [diff] [blame] | 1 | #! /usr/bin/env python3 |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 2 | |
| 3 | # Scan MH folder, display results in window |
| 4 | |
| 5 | import os |
Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 6 | import re |
Georg Brandl | 856023a | 2010-10-25 17:50:20 +0000 | [diff] [blame^] | 7 | import sys |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 8 | import getopt |
Georg Brandl | 856023a | 2010-10-25 17:50:20 +0000 | [diff] [blame^] | 9 | import mailbox |
Benjamin Peterson | d6d63f5 | 2009-01-04 18:53:28 +0000 | [diff] [blame] | 10 | from tkinter import * |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 11 | |
| 12 | from dialog import dialog |
| 13 | |
Georg Brandl | 856023a | 2010-10-25 17:50:20 +0000 | [diff] [blame^] | 14 | MBOXPATH = os.environ['HOME'] + '/Mail' |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 15 | |
| 16 | def main(): |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 17 | global root, tk, top, mid, bot |
| 18 | global folderbox, foldermenu, scanbox, scanmenu, viewer |
| 19 | global folder, seq |
| 20 | global mh, mhf |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 21 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 22 | # Parse command line options |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 23 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 24 | folder = 'inbox' |
| 25 | seq = 'all' |
| 26 | try: |
| 27 | opts, args = getopt.getopt(sys.argv[1:], '') |
Guido van Rossum | b940e11 | 2007-01-10 16:19:56 +0000 | [diff] [blame] | 28 | except getopt.error as msg: |
Collin Winter | 6f2df4d | 2007-07-17 20:59:35 +0000 | [diff] [blame] | 29 | print(msg) |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 30 | sys.exit(2) |
| 31 | for arg in args: |
| 32 | if arg[:1] == '+': |
| 33 | folder = arg[1:] |
| 34 | else: |
| 35 | seq = arg |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 36 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 37 | # Initialize MH |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 38 | |
Georg Brandl | 856023a | 2010-10-25 17:50:20 +0000 | [diff] [blame^] | 39 | mh = mailbox.MH(MBOXPATH) |
| 40 | mhf = mh.get_folder(folder) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 41 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 42 | # Build widget hierarchy |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 43 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 44 | root = Tk() |
| 45 | tk = root.tk |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 46 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 47 | top = Frame(root) |
| 48 | top.pack({'expand': 1, 'fill': 'both'}) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 49 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 50 | # Build right part: folder list |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 51 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 52 | right = Frame(top) |
| 53 | right.pack({'fill': 'y', 'side': 'right'}) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 54 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 55 | folderbar = Scrollbar(right, {'relief': 'sunken', 'bd': 2}) |
| 56 | folderbar.pack({'fill': 'y', 'side': 'right'}) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 57 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 58 | folderbox = Listbox(right, {'exportselection': 0}) |
| 59 | folderbox.pack({'expand': 1, 'fill': 'both', 'side': 'left'}) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 60 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 61 | foldermenu = Menu(root) |
| 62 | foldermenu.add('command', |
| 63 | {'label': 'Open Folder', |
| 64 | 'command': open_folder}) |
| 65 | foldermenu.add('separator') |
| 66 | foldermenu.add('command', |
| 67 | {'label': 'Quit', |
| 68 | 'command': 'exit'}) |
| 69 | foldermenu.bind('<ButtonRelease-3>', folder_unpost) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 70 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 71 | folderbox['yscrollcommand'] = (folderbar, 'set') |
| 72 | folderbar['command'] = (folderbox, 'yview') |
| 73 | folderbox.bind('<Double-1>', open_folder, 1) |
| 74 | folderbox.bind('<3>', folder_post) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 75 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 76 | # Build left part: scan list |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 77 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 78 | left = Frame(top) |
| 79 | left.pack({'expand': 1, 'fill': 'both', 'side': 'left'}) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 80 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 81 | scanbar = Scrollbar(left, {'relief': 'sunken', 'bd': 2}) |
| 82 | scanbar.pack({'fill': 'y', 'side': 'right'}) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 83 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 84 | scanbox = Listbox(left, {'font': 'fixed'}) |
| 85 | scanbox.pack({'expand': 1, 'fill': 'both', 'side': 'left'}) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 86 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 87 | scanmenu = Menu(root) |
| 88 | scanmenu.add('command', |
| 89 | {'label': 'Open Message', |
| 90 | 'command': open_message}) |
| 91 | scanmenu.add('command', |
| 92 | {'label': 'Remove Message', |
| 93 | 'command': remove_message}) |
| 94 | scanmenu.add('command', |
| 95 | {'label': 'Refile Message', |
| 96 | 'command': refile_message}) |
| 97 | scanmenu.add('separator') |
| 98 | scanmenu.add('command', |
| 99 | {'label': 'Quit', |
| 100 | 'command': 'exit'}) |
| 101 | scanmenu.bind('<ButtonRelease-3>', scan_unpost) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 102 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 103 | scanbox['yscrollcommand'] = (scanbar, 'set') |
| 104 | scanbar['command'] = (scanbox, 'yview') |
| 105 | scanbox.bind('<Double-1>', open_message) |
| 106 | scanbox.bind('<3>', scan_post) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 107 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 108 | # Separator between middle and bottom part |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 109 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 110 | rule2 = Frame(root, {'bg': 'black'}) |
| 111 | rule2.pack({'fill': 'x'}) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 112 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 113 | # Build bottom part: current message |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 114 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 115 | bot = Frame(root) |
| 116 | bot.pack({'expand': 1, 'fill': 'both'}) |
| 117 | # |
| 118 | viewer = None |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 119 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 120 | # Window manager commands |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 121 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 122 | root.minsize(800, 1) # Make window resizable |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 123 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 124 | # Fill folderbox with text |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 125 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 126 | setfolders() |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 127 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 128 | # Fill scanbox with text |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 129 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 130 | rescan() |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 131 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 132 | # Enter mainloop |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 133 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 134 | root.mainloop() |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 135 | |
| 136 | def folder_post(e): |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 137 | x, y = e.x_root, e.y_root |
| 138 | foldermenu.post(x - 10, y - 10) |
| 139 | foldermenu.grab_set() |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 140 | |
| 141 | def folder_unpost(e): |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 142 | tk.call('update', 'idletasks') |
| 143 | foldermenu.grab_release() |
| 144 | foldermenu.unpost() |
| 145 | foldermenu.invoke('active') |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 146 | |
| 147 | def scan_post(e): |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 148 | x, y = e.x_root, e.y_root |
| 149 | scanmenu.post(x - 10, y - 10) |
| 150 | scanmenu.grab_set() |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 151 | |
| 152 | def scan_unpost(e): |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 153 | tk.call('update', 'idletasks') |
| 154 | scanmenu.grab_release() |
| 155 | scanmenu.unpost() |
| 156 | scanmenu.invoke('active') |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 157 | |
Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 158 | scanparser = re.compile('^ *([0-9]+)') |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 159 | |
Guido van Rossum | 78b0c82 | 1994-07-13 16:53:32 +0000 | [diff] [blame] | 160 | def open_folder(e=None): |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 161 | global folder, mhf |
| 162 | sel = folderbox.curselection() |
| 163 | if len(sel) != 1: |
| 164 | if len(sel) > 1: |
| 165 | msg = "Please open one folder at a time" |
| 166 | else: |
| 167 | msg = "Please select a folder to open" |
| 168 | dialog(root, "Can't Open Folder", msg, "", 0, "OK") |
| 169 | return |
| 170 | i = sel[0] |
| 171 | folder = folderbox.get(i) |
Georg Brandl | 856023a | 2010-10-25 17:50:20 +0000 | [diff] [blame^] | 172 | mhf = mh.get_folder(folder) |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 173 | rescan() |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 174 | |
Guido van Rossum | 78b0c82 | 1994-07-13 16:53:32 +0000 | [diff] [blame] | 175 | def open_message(e=None): |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 176 | global viewer |
| 177 | sel = scanbox.curselection() |
| 178 | if len(sel) != 1: |
| 179 | if len(sel) > 1: |
| 180 | msg = "Please open one message at a time" |
| 181 | else: |
| 182 | msg = "Please select a message to open" |
| 183 | dialog(root, "Can't Open Message", msg, "", 0, "OK") |
| 184 | return |
| 185 | cursor = scanbox['cursor'] |
| 186 | scanbox['cursor'] = 'watch' |
| 187 | tk.call('update', 'idletasks') |
| 188 | i = sel[0] |
| 189 | line = scanbox.get(i) |
Georg Brandl | 856023a | 2010-10-25 17:50:20 +0000 | [diff] [blame^] | 190 | m = scanparser.match(line) |
| 191 | if m: |
| 192 | num = int(m.group(1)) |
| 193 | m = mhf.get_message(num) |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 194 | if viewer: viewer.destroy() |
| 195 | from MimeViewer import MimeViewer |
| 196 | viewer = MimeViewer(bot, '+%s/%d' % (folder, num), m) |
| 197 | viewer.pack() |
| 198 | viewer.show() |
| 199 | scanbox['cursor'] = cursor |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 200 | |
| 201 | def interestingheader(header): |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 202 | return header != 'received' |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 203 | |
Guido van Rossum | 78b0c82 | 1994-07-13 16:53:32 +0000 | [diff] [blame] | 204 | def remove_message(e=None): |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 205 | itop = scanbox.nearest(0) |
| 206 | sel = scanbox.curselection() |
| 207 | if not sel: |
| 208 | dialog(root, "No Message To Remove", |
| 209 | "Please select a message to remove", "", 0, "OK") |
| 210 | return |
| 211 | todo = [] |
| 212 | for i in sel: |
| 213 | line = scanbox.get(i) |
Georg Brandl | 856023a | 2010-10-25 17:50:20 +0000 | [diff] [blame^] | 214 | m = scanparser.match(line) |
| 215 | if m: |
| 216 | toremove = int(m.group(1)) |
| 217 | todo.append(toremove) |
| 218 | mhf.remove(toremove) |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 219 | rescan() |
| 220 | fixfocus(min(todo), itop) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 221 | |
| 222 | lastrefile = '' |
| 223 | tofolder = None |
Guido van Rossum | 78b0c82 | 1994-07-13 16:53:32 +0000 | [diff] [blame] | 224 | def refile_message(e=None): |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 225 | global lastrefile, tofolder |
| 226 | itop = scanbox.nearest(0) |
| 227 | sel = scanbox.curselection() |
| 228 | if not sel: |
| 229 | dialog(root, "No Message To Refile", |
| 230 | "Please select a message to refile", "", 0, "OK") |
| 231 | return |
| 232 | foldersel = folderbox.curselection() |
| 233 | if len(foldersel) != 1: |
| 234 | if not foldersel: |
| 235 | msg = "Please select a folder to refile to" |
| 236 | else: |
| 237 | msg = "Please select exactly one folder to refile to" |
| 238 | dialog(root, "No Folder To Refile", msg, "", 0, "OK") |
| 239 | return |
| 240 | refileto = folderbox.get(foldersel[0]) |
| 241 | todo = [] |
| 242 | for i in sel: |
| 243 | line = scanbox.get(i) |
Georg Brandl | 856023a | 2010-10-25 17:50:20 +0000 | [diff] [blame^] | 244 | m = scanparser.match(line) |
| 245 | if m: |
| 246 | todo.append(int(m.group(1))) |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 247 | if lastrefile != refileto or not tofolder: |
| 248 | lastrefile = refileto |
| 249 | tofolder = None |
Georg Brandl | 856023a | 2010-10-25 17:50:20 +0000 | [diff] [blame^] | 250 | tofolder = mh.get_folder(lastrefile) |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 251 | mhf.refilemessages(todo, tofolder) |
| 252 | rescan() |
| 253 | fixfocus(min(todo), itop) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 254 | |
| 255 | def fixfocus(near, itop): |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 256 | n = scanbox.size() |
| 257 | for i in range(n): |
| 258 | line = scanbox.get(repr(i)) |
Georg Brandl | 856023a | 2010-10-25 17:50:20 +0000 | [diff] [blame^] | 259 | m = scanparser.match(line) |
| 260 | if m: |
| 261 | num = int(m.group(1)) |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 262 | if num >= near: |
| 263 | break |
| 264 | else: |
| 265 | i = 'end' |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 266 | scanbox.yview(itop) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 267 | |
| 268 | def setfolders(): |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 269 | folderbox.delete(0, 'end') |
Georg Brandl | 856023a | 2010-10-25 17:50:20 +0000 | [diff] [blame^] | 270 | for fn in mh.list_folders(): |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 271 | folderbox.insert('end', fn) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 272 | |
| 273 | def rescan(): |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 274 | global viewer |
| 275 | if viewer: |
| 276 | viewer.destroy() |
| 277 | viewer = None |
| 278 | scanbox.delete(0, 'end') |
| 279 | for line in scanfolder(folder, seq): |
| 280 | scanbox.insert('end', line) |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 281 | |
| 282 | def scanfolder(folder = 'inbox', sequence = 'all'): |
Georg Brandl | 856023a | 2010-10-25 17:50:20 +0000 | [diff] [blame^] | 283 | return [line[:-1] for line in |
| 284 | os.popen('scan +%s %s' % (folder, sequence), 'r').readlines()] |
Guido van Rossum | 1846882 | 1994-06-20 07:49:28 +0000 | [diff] [blame] | 285 | |
| 286 | main() |