Mercurial > cpython-lru_cache-weakref
annotate Lib/mailbox.py @ 25838:8540887bcec6 2.2
Backport of 2.183:
Fix memory leak in add_subclass() found by NealN with valgrind.
| author | Guido van Rossum <guido@python.org> |
|---|---|
| date | Fri, 18 Oct 2002 13:42:21 +0000 |
| parents | 7e188140b618 |
| children | d4f541467b6d |
| rev | line source |
|---|---|
|
4573
73758db2f464
/usr/local/bin/python -> /usr/bin/env python
Guido van Rossum <guido@python.org>
parents:
4316
diff
changeset
|
1 #! /usr/bin/env python |
|
4316
772828c1b1f6
Revamped test case and updated doc string.
Guido van Rossum <guido@python.org>
parents:
3360
diff
changeset
|
2 |
|
772828c1b1f6
Revamped test case and updated doc string.
Guido van Rossum <guido@python.org>
parents:
3360
diff
changeset
|
3 """Classes to handle Unix style, MMDF style, and MH style mailboxes.""" |
|
772828c1b1f6
Revamped test case and updated doc string.
Guido van Rossum <guido@python.org>
parents:
3360
diff
changeset
|
4 |
|
772828c1b1f6
Revamped test case and updated doc string.
Guido van Rossum <guido@python.org>
parents:
3360
diff
changeset
|
5 |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
6 import rfc822 |
| 3230 | 7 import os |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
8 |
|
22136
7e188140b618
backport bwarsaw's checkin of
Michael W. Hudson <mwh@python.net>
parents:
19893
diff
changeset
|
9 __all__ = ["UnixMailbox","MmdfMailbox","MHMailbox","Maildir","BabylMailbox", |
|
7e188140b618
backport bwarsaw's checkin of
Michael W. Hudson <mwh@python.net>
parents:
19893
diff
changeset
|
10 "PortableUnixMailbox"] |
|
16198
32755b456369
a few more modules get __all__
Skip Montanaro <skip@pobox.com>
parents:
15543
diff
changeset
|
11 |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
12 class _Mailbox: |
| 16372 | 13 def __init__(self, fp, factory=rfc822.Message): |
| 13475 | 14 self.fp = fp |
| 15 self.seekp = 0 | |
| 16372 | 16 self.factory = factory |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
17 |
|
17660
30d7518e17e5
Make the Mailbox objects support iteration -- they already had the
Fred Drake <fdrake@acm.org>
parents:
17530
diff
changeset
|
18 def __iter__(self): |
|
19893
3af006503678
SF bug #461073: mailbox __iter__ bug, by Andrew Dalke.
Guido van Rossum <guido@python.org>
parents:
19228
diff
changeset
|
19 return iter(self.next, None) |
|
17660
30d7518e17e5
Make the Mailbox objects support iteration -- they already had the
Fred Drake <fdrake@acm.org>
parents:
17530
diff
changeset
|
20 |
| 13475 | 21 def next(self): |
| 22 while 1: | |
| 23 self.fp.seek(self.seekp) | |
| 24 try: | |
| 25 self._search_start() | |
| 26 except EOFError: | |
| 27 self.seekp = self.fp.tell() | |
| 28 return None | |
| 29 start = self.fp.tell() | |
| 30 self._search_end() | |
| 31 self.seekp = stop = self.fp.tell() | |
|
15543
785155e2cfca
Update the code to better reflect recommended style:
Fred Drake <fdrake@acm.org>
parents:
15297
diff
changeset
|
32 if start != stop: |
| 13475 | 33 break |
| 16372 | 34 return self.factory(_Subfile(self.fp, start, stop)) |
| 13475 | 35 |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
36 |
|
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
37 class _Subfile: |
| 13475 | 38 def __init__(self, fp, start, stop): |
| 39 self.fp = fp | |
| 40 self.start = start | |
| 41 self.stop = stop | |
| 42 self.pos = self.start | |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
43 |
| 13475 | 44 def read(self, length = None): |
| 45 if self.pos >= self.stop: | |
| 46 return '' | |
| 47 remaining = self.stop - self.pos | |
| 48 if length is None or length < 0: | |
| 49 length = remaining | |
| 50 elif length > remaining: | |
| 51 length = remaining | |
| 52 self.fp.seek(self.pos) | |
| 53 data = self.fp.read(length) | |
| 54 self.pos = self.fp.tell() | |
| 55 return data | |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
56 |
| 13475 | 57 def readline(self, length = None): |
| 58 if self.pos >= self.stop: | |
| 59 return '' | |
| 60 if length is None: | |
| 61 length = self.stop - self.pos | |
| 62 self.fp.seek(self.pos) | |
| 63 data = self.fp.readline(length) | |
| 64 self.pos = self.fp.tell() | |
| 65 return data | |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
66 |
| 13475 | 67 def readlines(self, sizehint = -1): |
| 68 lines = [] | |
| 69 while 1: | |
| 70 line = self.readline() | |
| 71 if not line: | |
| 72 break | |
| 73 lines.append(line) | |
| 74 if sizehint >= 0: | |
| 75 sizehint = sizehint - len(line) | |
| 76 if sizehint <= 0: | |
| 77 break | |
| 78 return lines | |
|
10452
c9e10ed26d9a
Add readlines() to _Subfile class. Not clear who would need it, but
Guido van Rossum <guido@python.org>
parents:
9725
diff
changeset
|
79 |
| 13475 | 80 def tell(self): |
| 81 return self.pos - self.start | |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
82 |
| 13475 | 83 def seek(self, pos, whence=0): |
| 84 if whence == 0: | |
| 85 self.pos = self.start + pos | |
| 86 elif whence == 1: | |
| 87 self.pos = self.pos + pos | |
| 88 elif whence == 2: | |
| 89 self.pos = self.stop + pos | |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
90 |
| 13475 | 91 def close(self): |
| 92 del self.fp | |
| 93 | |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
94 |
|
22136
7e188140b618
backport bwarsaw's checkin of
Michael W. Hudson <mwh@python.net>
parents:
19893
diff
changeset
|
95 # Recommended to use PortableUnixMailbox instead! |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
96 class UnixMailbox(_Mailbox): |
| 13475 | 97 def _search_start(self): |
| 98 while 1: | |
| 99 pos = self.fp.tell() | |
| 100 line = self.fp.readline() | |
| 101 if not line: | |
| 102 raise EOFError | |
| 103 if line[:5] == 'From ' and self._isrealfromline(line): | |
| 104 self.fp.seek(pos) | |
| 105 return | |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
106 |
| 13475 | 107 def _search_end(self): |
| 108 self.fp.readline() # Throw away header line | |
| 109 while 1: | |
| 110 pos = self.fp.tell() | |
| 111 line = self.fp.readline() | |
| 112 if not line: | |
| 113 return | |
| 114 if line[:5] == 'From ' and self._isrealfromline(line): | |
| 115 self.fp.seek(pos) | |
| 116 return | |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
117 |
| 16372 | 118 # An overridable mechanism to test for From-line-ness. You can either |
| 119 # specify a different regular expression or define a whole new | |
| 120 # _isrealfromline() method. Note that this only gets called for lines | |
| 121 # starting with the 5 characters "From ". | |
| 122 # | |
| 123 # BAW: According to | |
| 124 #http://home.netscape.com/eng/mozilla/2.0/relnotes/demo/content-length.html | |
| 125 # the only portable, reliable way to find message delimiters in a BSD (i.e | |
| 126 # Unix mailbox) style folder is to search for "\n\nFrom .*\n", or at the | |
| 127 # beginning of the file, "^From .*\n". While _fromlinepattern below seems | |
| 128 # like a good idea, in practice, there are too many variations for more | |
| 129 # strict parsing of the line to be completely accurate. | |
| 130 # | |
| 131 # _strict_isrealfromline() is the old version which tries to do stricter | |
| 132 # parsing of the From_ line. _portable_isrealfromline() simply returns | |
| 133 # true, since it's never called if the line doesn't already start with | |
| 134 # "From ". | |
| 135 # | |
| 136 # This algorithm, and the way it interacts with _search_start() and | |
| 137 # _search_end() may not be completely correct, because it doesn't check | |
| 138 # that the two characters preceding "From " are \n\n or the beginning of | |
| 139 # the file. Fixing this would require a more extensive rewrite than is | |
| 140 # necessary. For convenience, we've added a StrictUnixMailbox class which | |
| 141 # uses the older, more strict _fromlinepattern regular expression. | |
|
7838
fc950433d158
UnixMailbox: don't be fooled by lines that begin with "From " but
Guido van Rossum <guido@python.org>
parents:
7752
diff
changeset
|
142 |
| 13475 | 143 _fromlinepattern = r"From \s*[^\s]+\s+\w\w\w\s+\w\w\w\s+\d?\d\s+" \ |
| 144 r"\d?\d:\d\d(:\d\d)?(\s+[^\s]+)?\s+\d\d\d\d\s*$" | |
| 145 _regexp = None | |
|
7838
fc950433d158
UnixMailbox: don't be fooled by lines that begin with "From " but
Guido van Rossum <guido@python.org>
parents:
7752
diff
changeset
|
146 |
| 16372 | 147 def _strict_isrealfromline(self, line): |
| 13475 | 148 if not self._regexp: |
| 149 import re | |
| 150 self._regexp = re.compile(self._fromlinepattern) | |
| 151 return self._regexp.match(line) | |
| 152 | |
| 16372 | 153 def _portable_isrealfromline(self, line): |
| 154 return 1 | |
| 155 | |
| 156 _isrealfromline = _strict_isrealfromline | |
| 157 | |
| 158 | |
| 159 class PortableUnixMailbox(UnixMailbox): | |
| 160 _isrealfromline = UnixMailbox._portable_isrealfromline | |
| 161 | |
|
7838
fc950433d158
UnixMailbox: don't be fooled by lines that begin with "From " but
Guido van Rossum <guido@python.org>
parents:
7752
diff
changeset
|
162 |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
163 class MmdfMailbox(_Mailbox): |
| 13475 | 164 def _search_start(self): |
| 165 while 1: | |
| 166 line = self.fp.readline() | |
| 167 if not line: | |
| 168 raise EOFError | |
| 169 if line[:5] == '\001\001\001\001\n': | |
| 170 return | |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
171 |
| 13475 | 172 def _search_end(self): |
| 173 while 1: | |
| 174 pos = self.fp.tell() | |
| 175 line = self.fp.readline() | |
| 176 if not line: | |
| 177 return | |
| 178 if line == '\001\001\001\001\n': | |
| 179 self.fp.seek(pos) | |
| 180 return | |
| 181 | |
|
1596
2197dd241d8d
Jack's module for parsing UNIX mailbox files
Guido van Rossum <guido@python.org>
parents:
diff
changeset
|
182 |
| 3230 | 183 class MHMailbox: |
| 16372 | 184 def __init__(self, dirname, factory=rfc822.Message): |
| 13475 | 185 import re |
|
13911
6bf1281ec763
Improve MHMailbox: messages are now sorted in numerical order.
Guido van Rossum <guido@python.org>
parents:
13475
diff
changeset
|
186 pat = re.compile('^[1-9][0-9]*$') |
| 13475 | 187 self.dirname = dirname |
|
13916
bc0153a739ae
Use built in function filter instead of doing it laboriously by hand.
Sjoerd Mullender <sjoerd@acm.org>
parents:
13911
diff
changeset
|
188 # the three following lines could be combined into: |
|
bc0153a739ae
Use built in function filter instead of doing it laboriously by hand.
Sjoerd Mullender <sjoerd@acm.org>
parents:
13911
diff
changeset
|
189 # list = map(long, filter(pat.match, os.listdir(self.dirname))) |
|
bc0153a739ae
Use built in function filter instead of doing it laboriously by hand.
Sjoerd Mullender <sjoerd@acm.org>
parents:
13911
diff
changeset
|
190 list = os.listdir(self.dirname) |
|
bc0153a739ae
Use built in function filter instead of doing it laboriously by hand.
Sjoerd Mullender <sjoerd@acm.org>
parents:
13911
diff
changeset
|
191 list = filter(pat.match, list) |
|
13911
6bf1281ec763
Improve MHMailbox: messages are now sorted in numerical order.
Guido van Rossum <guido@python.org>
parents:
13475
diff
changeset
|
192 list = map(long, list) |
|
6bf1281ec763
Improve MHMailbox: messages are now sorted in numerical order.
Guido van Rossum <guido@python.org>
parents:
13475
diff
changeset
|
193 list.sort() |
|
6bf1281ec763
Improve MHMailbox: messages are now sorted in numerical order.
Guido van Rossum <guido@python.org>
parents:
13475
diff
changeset
|
194 # This only works in Python 1.6 or later; |
|
6bf1281ec763
Improve MHMailbox: messages are now sorted in numerical order.
Guido van Rossum <guido@python.org>
parents:
13475
diff
changeset
|
195 # before that str() added 'L': |
|
6bf1281ec763
Improve MHMailbox: messages are now sorted in numerical order.
Guido van Rossum <guido@python.org>
parents:
13475
diff
changeset
|
196 self.boxes = map(str, list) |
| 16372 | 197 self.factory = factory |
| 3230 | 198 |
|
17660
30d7518e17e5
Make the Mailbox objects support iteration -- they already had the
Fred Drake <fdrake@acm.org>
parents:
17530
diff
changeset
|
199 def __iter__(self): |
|
19893
3af006503678
SF bug #461073: mailbox __iter__ bug, by Andrew Dalke.
Guido van Rossum <guido@python.org>
parents:
19228
diff
changeset
|
200 return iter(self.next, None) |
|
17660
30d7518e17e5
Make the Mailbox objects support iteration -- they already had the
Fred Drake <fdrake@acm.org>
parents:
17530
diff
changeset
|
201 |
| 13475 | 202 def next(self): |
| 203 if not self.boxes: | |
| 204 return None | |
| 205 fn = self.boxes[0] | |
| 206 del self.boxes[0] | |
| 207 fp = open(os.path.join(self.dirname, fn)) | |
| 16372 | 208 return self.factory(fp) |
|
7752
b4b0e4e759c5
A few lines were indented using spaces instead of tabs -- fix them.
Guido van Rossum <guido@python.org>
parents:
6519
diff
changeset
|
209 |
| 9725 | 210 |
| 211 class Maildir: | |
| 13475 | 212 # Qmail directory mailbox |
| 9725 | 213 |
| 16372 | 214 def __init__(self, dirname, factory=rfc822.Message): |
| 13475 | 215 self.dirname = dirname |
| 16372 | 216 self.factory = factory |
| 9725 | 217 |
| 13475 | 218 # check for new mail |
| 219 newdir = os.path.join(self.dirname, 'new') | |
|
14771
133007646fb4
Maildir.__init__(): Use the correct filter for filenames, so that this
Fred Drake <fdrake@acm.org>
parents:
14548
diff
changeset
|
220 boxes = [os.path.join(newdir, f) |
|
133007646fb4
Maildir.__init__(): Use the correct filter for filenames, so that this
Fred Drake <fdrake@acm.org>
parents:
14548
diff
changeset
|
221 for f in os.listdir(newdir) if f[0] != '.'] |
| 9725 | 222 |
| 13475 | 223 # Now check for current mail in this maildir |
| 224 curdir = os.path.join(self.dirname, 'cur') | |
|
14771
133007646fb4
Maildir.__init__(): Use the correct filter for filenames, so that this
Fred Drake <fdrake@acm.org>
parents:
14548
diff
changeset
|
225 boxes += [os.path.join(curdir, f) |
|
133007646fb4
Maildir.__init__(): Use the correct filter for filenames, so that this
Fred Drake <fdrake@acm.org>
parents:
14548
diff
changeset
|
226 for f in os.listdir(curdir) if f[0] != '.'] |
| 9725 | 227 |
|
15297
f20deaeaf8b9
Maildir.__init__(): Make sure self.boxes is set.
Fred Drake <fdrake@acm.org>
parents:
14954
diff
changeset
|
228 self.boxes = boxes |
|
f20deaeaf8b9
Maildir.__init__(): Make sure self.boxes is set.
Fred Drake <fdrake@acm.org>
parents:
14954
diff
changeset
|
229 |
|
17660
30d7518e17e5
Make the Mailbox objects support iteration -- they already had the
Fred Drake <fdrake@acm.org>
parents:
17530
diff
changeset
|
230 def __iter__(self): |
|
19893
3af006503678
SF bug #461073: mailbox __iter__ bug, by Andrew Dalke.
Guido van Rossum <guido@python.org>
parents:
19228
diff
changeset
|
231 return iter(self.next, None) |
|
17660
30d7518e17e5
Make the Mailbox objects support iteration -- they already had the
Fred Drake <fdrake@acm.org>
parents:
17530
diff
changeset
|
232 |
| 13475 | 233 def next(self): |
| 234 if not self.boxes: | |
| 235 return None | |
| 236 fn = self.boxes[0] | |
| 237 del self.boxes[0] | |
|
14548
e9c313745302
Detlef Lannert <lannert@uni-duesseldorf.de>:
Fred Drake <fdrake@acm.org>
parents:
13916
diff
changeset
|
238 fp = open(fn) |
| 16372 | 239 return self.factory(fp) |
| 13475 | 240 |
| 9725 | 241 |
|
5531
5454fe4925d3
Added BabylMailbox class by Fred Lundh (untested).
Guido van Rossum <guido@python.org>
parents:
5443
diff
changeset
|
242 class BabylMailbox(_Mailbox): |
| 13475 | 243 def _search_start(self): |
| 244 while 1: | |
| 245 line = self.fp.readline() | |
| 246 if not line: | |
| 247 raise EOFError | |
| 248 if line == '*** EOOH ***\n': | |
| 249 return | |
|
5531
5454fe4925d3
Added BabylMailbox class by Fred Lundh (untested).
Guido van Rossum <guido@python.org>
parents:
5443
diff
changeset
|
250 |
| 13475 | 251 def _search_end(self): |
| 252 while 1: | |
| 253 pos = self.fp.tell() | |
| 254 line = self.fp.readline() | |
| 255 if not line: | |
| 256 return | |
| 257 if line == '\037\014\n': | |
| 258 self.fp.seek(pos) | |
| 259 return | |
|
5531
5454fe4925d3
Added BabylMailbox class by Fred Lundh (untested).
Guido van Rossum <guido@python.org>
parents:
5443
diff
changeset
|
260 |
|
5454fe4925d3
Added BabylMailbox class by Fred Lundh (untested).
Guido van Rossum <guido@python.org>
parents:
5443
diff
changeset
|
261 |
|
4316
772828c1b1f6
Revamped test case and updated doc string.
Guido van Rossum <guido@python.org>
parents:
3360
diff
changeset
|
262 def _test(): |
| 13475 | 263 import sys |
| 3230 | 264 |
| 13475 | 265 args = sys.argv[1:] |
| 266 if not args: | |
| 267 for key in 'MAILDIR', 'MAIL', 'LOGNAME', 'USER': | |
| 268 if os.environ.has_key(key): | |
| 269 mbox = os.environ[key] | |
| 270 break | |
| 271 else: | |
| 272 print "$MAIL, $LOGNAME nor $USER set -- who are you?" | |
| 273 return | |
| 274 else: | |
| 275 mbox = args[0] | |
| 276 if mbox[:1] == '+': | |
| 277 mbox = os.environ['HOME'] + '/Mail/' + mbox[1:] | |
| 278 elif not '/' in mbox: | |
| 279 mbox = '/usr/mail/' + mbox | |
| 280 if os.path.isdir(mbox): | |
| 281 if os.path.isdir(os.path.join(mbox, 'cur')): | |
| 282 mb = Maildir(mbox) | |
|
11742
840e18eec07f
Untabify to pass the -tt test.
Fred Drake <fdrake@acm.org>
parents:
11571
diff
changeset
|
283 else: |
| 13475 | 284 mb = MHMailbox(mbox) |
| 285 else: | |
| 286 fp = open(mbox, 'r') | |
|
22136
7e188140b618
backport bwarsaw's checkin of
Michael W. Hudson <mwh@python.net>
parents:
19893
diff
changeset
|
287 mb = PortableUnixMailbox(fp) |
| 13475 | 288 |
| 289 msgs = [] | |
| 290 while 1: | |
| 291 msg = mb.next() | |
| 292 if msg is None: | |
| 293 break | |
| 294 msgs.append(msg) | |
| 295 if len(args) <= 1: | |
| 296 msg.fp = None | |
| 297 if len(args) > 1: | |
|
15297
f20deaeaf8b9
Maildir.__init__(): Make sure self.boxes is set.
Fred Drake <fdrake@acm.org>
parents:
14954
diff
changeset
|
298 num = int(args[1]) |
| 13475 | 299 print 'Message %d body:'%num |
| 300 msg = msgs[num-1] | |
| 301 msg.rewindbody() | |
| 302 sys.stdout.write(msg.fp.read()) | |
| 303 else: | |
| 304 print 'Mailbox',mbox,'has',len(msgs),'messages:' | |
| 305 for msg in msgs: | |
| 306 f = msg.getheader('from') or "" | |
| 307 s = msg.getheader('subject') or "" | |
| 308 d = msg.getheader('date') or "" | |
|
14954
342497ad8fec
Add missing "s" from format string.
Fred Drake <fdrake@acm.org>
parents:
14771
diff
changeset
|
309 print '-%20.20s %20.20s %-30.30s'%(f, d[5:], s) |
|
4316
772828c1b1f6
Revamped test case and updated doc string.
Guido van Rossum <guido@python.org>
parents:
3360
diff
changeset
|
310 |
|
772828c1b1f6
Revamped test case and updated doc string.
Guido van Rossum <guido@python.org>
parents:
3360
diff
changeset
|
311 |
|
772828c1b1f6
Revamped test case and updated doc string.
Guido van Rossum <guido@python.org>
parents:
3360
diff
changeset
|
312 if __name__ == '__main__': |
| 13475 | 313 _test() |
