| 
									
										
										
										
											1996-11-27 19:52:01 +00:00
										 |  |  | #! /usr/bin/env python | 
					
						
							| 
									
										
										
										
											1996-09-17 21:33:15 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | """Classes to handle Unix style, MMDF style, and MH style mailboxes.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | import rfc822 | 
					
						
							| 
									
										
										
										
											1995-10-23 13:59:53 +00:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class _Mailbox: | 
					
						
							| 
									
										
										
										
											1998-03-26 20:56:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 	def __init__(self, fp): | 
					
						
							|  |  |  | 		self.fp = fp | 
					
						
							|  |  |  | 		self.seekp = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-01-25 18:40:41 +00:00
										 |  |  | 	def seek(self, pos, whence=0): | 
					
						
							|  |  |  | 		if whence==1:		# Relative to current position | 
					
						
							|  |  |  | 			self.pos = self.pos + pos | 
					
						
							|  |  |  | 		if whence==2:		# Relative to file's end | 
					
						
							|  |  |  | 			self.pos = self.stop + pos | 
					
						
							|  |  |  | 		else:			# Default - absolute position | 
					
						
							|  |  |  | 			self.pos = self.start + pos | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	def next(self): | 
					
						
							|  |  |  | 		while 1: | 
					
						
							|  |  |  | 			self.fp.seek(self.seekp) | 
					
						
							|  |  |  | 			try: | 
					
						
							|  |  |  | 				self._search_start() | 
					
						
							|  |  |  | 			except EOFError: | 
					
						
							|  |  |  | 				self.seekp = self.fp.tell() | 
					
						
							|  |  |  | 				return None | 
					
						
							|  |  |  | 			start = self.fp.tell() | 
					
						
							|  |  |  | 			self._search_end() | 
					
						
							|  |  |  | 			self.seekp = stop = self.fp.tell() | 
					
						
							|  |  |  | 			if start <> stop: | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 		return rfc822.Message(_Subfile(self.fp, start, stop)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _Subfile: | 
					
						
							| 
									
										
										
										
											1998-03-26 20:56:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 	def __init__(self, fp, start, stop): | 
					
						
							|  |  |  | 		self.fp = fp | 
					
						
							|  |  |  | 		self.start = start | 
					
						
							|  |  |  | 		self.stop = stop | 
					
						
							|  |  |  | 		self.pos = self.start | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1994-05-06 14:28:19 +00:00
										 |  |  | 	def read(self, length = None): | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 		if self.pos >= self.stop: | 
					
						
							|  |  |  | 			return '' | 
					
						
							| 
									
										
										
										
											1998-06-17 18:34:40 +00:00
										 |  |  | 		remaining = self.stop - self.pos | 
					
						
							|  |  |  | 		if length is None or length < 0: | 
					
						
							|  |  |  | 			length = remaining | 
					
						
							|  |  |  | 		elif length > remaining: | 
					
						
							|  |  |  | 			length = remaining | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 		self.fp.seek(self.pos) | 
					
						
							| 
									
										
										
										
											1998-07-20 15:24:01 +00:00
										 |  |  | 		data = self.fp.read(length) | 
					
						
							|  |  |  | 		self.pos = self.fp.tell() | 
					
						
							|  |  |  | 		return data | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1994-05-06 14:28:19 +00:00
										 |  |  | 	def readline(self, length = None): | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 		if self.pos >= self.stop: | 
					
						
							|  |  |  | 			return '' | 
					
						
							| 
									
										
										
										
											1994-05-06 14:28:19 +00:00
										 |  |  | 		if length is None: | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 			length = self.stop - self.pos | 
					
						
							|  |  |  | 		self.fp.seek(self.pos) | 
					
						
							|  |  |  | 		data = self.fp.readline(length) | 
					
						
							| 
									
										
										
										
											1998-07-20 15:24:01 +00:00
										 |  |  | 		self.pos = self.fp.tell() | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 		return data | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-03-24 16:20:45 +00:00
										 |  |  |         def readlines(self, sizehint = -1): | 
					
						
							|  |  |  | 		lines = [] | 
					
						
							|  |  |  | 		while 1: | 
					
						
							|  |  |  | 			line = self.readline() | 
					
						
							|  |  |  | 			if not line: | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			lines.append(line) | 
					
						
							|  |  |  | 			if sizehint >= 0: | 
					
						
							|  |  |  | 				sizehint = sizehint - len(line) | 
					
						
							|  |  |  | 				if sizehint <= 0: | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 		return lines | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 	def tell(self): | 
					
						
							|  |  |  | 		return self.pos - self.start | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1995-10-23 13:59:53 +00:00
										 |  |  | 	def seek(self, pos, whence=0): | 
					
						
							| 
									
										
										
										
											1998-03-26 20:56:10 +00:00
										 |  |  | 		if whence == 0: | 
					
						
							|  |  |  | 			self.pos = self.start + pos | 
					
						
							| 
									
										
										
										
											1995-10-23 13:59:53 +00:00
										 |  |  | 		elif whence == 1: | 
					
						
							| 
									
										
										
										
											1998-03-26 20:56:10 +00:00
										 |  |  | 			self.pos = self.pos + pos | 
					
						
							| 
									
										
										
										
											1995-10-23 13:59:53 +00:00
										 |  |  | 		elif whence == 2: | 
					
						
							| 
									
										
										
										
											1998-03-26 20:56:10 +00:00
										 |  |  | 			self.pos = self.stop + pos | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	def close(self): | 
					
						
							| 
									
										
										
										
											1998-07-20 15:24:01 +00:00
										 |  |  | 		del self.fp | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class UnixMailbox(_Mailbox): | 
					
						
							| 
									
										
										
										
											1998-03-26 20:56:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 	def _search_start(self): | 
					
						
							|  |  |  | 		while 1: | 
					
						
							|  |  |  | 			line = self.fp.readline() | 
					
						
							|  |  |  | 			if not line: | 
					
						
							|  |  |  | 				raise EOFError | 
					
						
							| 
									
										
										
										
											1998-04-03 16:04:05 +00:00
										 |  |  | 			if line[:5] == 'From ' and self._isrealfromline(line): | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 				return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def _search_end(self): | 
					
						
							|  |  |  | 		while 1: | 
					
						
							|  |  |  | 			pos = self.fp.tell() | 
					
						
							|  |  |  | 			line = self.fp.readline() | 
					
						
							|  |  |  | 			if not line: | 
					
						
							|  |  |  | 				return | 
					
						
							| 
									
										
										
										
											1998-04-03 16:04:05 +00:00
										 |  |  | 			if line[:5] == 'From ' and self._isrealfromline(line): | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 				self.fp.seek(pos) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-03 16:04:05 +00:00
										 |  |  | 	# An overridable mechanism to test for From-line-ness. | 
					
						
							|  |  |  | 	# You can either specify a different regular expression | 
					
						
							|  |  |  | 	# or define a whole new _isrealfromline() method. | 
					
						
							|  |  |  | 	# Note that this only gets called for lines starting with | 
					
						
							|  |  |  | 	# the 5 characters "From ". | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_fromlinepattern = r"From \s*[^\s]+\s+\w\w\w\s+\w\w\w\s+\d?\d\s+" \ | 
					
						
							| 
									
										
										
										
											1998-07-02 23:05:32 +00:00
										 |  |  | 			   r"\d?\d:\d\d(:\d\d)?(\s+[^\s]+)?\s+\d\d\d\d\s*$" | 
					
						
							| 
									
										
										
										
											1998-04-03 16:04:05 +00:00
										 |  |  | 	_regexp = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def _isrealfromline(self, line): | 
					
						
							|  |  |  | 		if not self._regexp: | 
					
						
							|  |  |  | 			import re | 
					
						
							|  |  |  | 			self._regexp = re.compile(self._fromlinepattern) | 
					
						
							|  |  |  | 		return self._regexp.match(line) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | class MmdfMailbox(_Mailbox): | 
					
						
							| 
									
										
										
										
											1998-03-26 20:56:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 	def _search_start(self): | 
					
						
							|  |  |  | 		while 1: | 
					
						
							|  |  |  | 			line = self.fp.readline() | 
					
						
							|  |  |  | 			if not line: | 
					
						
							|  |  |  | 				raise EOFError | 
					
						
							|  |  |  | 			if line[:5] == '\001\001\001\001\n': | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def _search_end(self): | 
					
						
							|  |  |  | 		while 1: | 
					
						
							|  |  |  | 			pos = self.fp.tell() | 
					
						
							|  |  |  | 			line = self.fp.readline() | 
					
						
							|  |  |  | 			if not line: | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			if line == '\001\001\001\001\n': | 
					
						
							|  |  |  | 				self.fp.seek(pos) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1995-10-23 13:59:53 +00:00
										 |  |  | class MHMailbox: | 
					
						
							| 
									
										
										
										
											1998-03-26 20:56:10 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	def __init__(self, dirname): | 
					
						
							|  |  |  | 		import re | 
					
						
							|  |  |  | 		pat = re.compile('^[0-9][0-9]*$') | 
					
						
							|  |  |  | 		self.dirname = dirname | 
					
						
							|  |  |  | 		files = os.listdir(self.dirname) | 
					
						
							|  |  |  | 		self.boxes = [] | 
					
						
							|  |  |  | 		for f in files: | 
					
						
							|  |  |  | 			if pat.match(f): | 
					
						
							|  |  |  | 				self.boxes.append(f) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def next(self): | 
					
						
							|  |  |  | 		if not self.boxes: | 
					
						
							|  |  |  | 			return None | 
					
						
							|  |  |  | 		fn = self.boxes[0] | 
					
						
							|  |  |  | 		del self.boxes[0] | 
					
						
							|  |  |  | 		fp = open(os.path.join(self.dirname, fn)) | 
					
						
							|  |  |  | 		return rfc822.Message(fp) | 
					
						
							| 
									
										
										
										
											1998-12-23 22:05:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class Maildir: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	# Qmail directory mailbox | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def __init__(self, dirname): | 
					
						
							|  |  |  | 		import string | 
					
						
							|  |  |  | 		self.dirname = dirname | 
					
						
							|  |  |  | 		self.boxes = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		# check for new mail | 
					
						
							|  |  |  | 		newdir = os.path.join(self.dirname, 'new') | 
					
						
							|  |  |  | 		for file in os.listdir(newdir): | 
					
						
							|  |  |  | 			if len(string.split(file, '.')) > 2: | 
					
						
							|  |  |  | 				self.boxes.append(os.path.join(newdir, file)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		# Now check for current mail in this maildir | 
					
						
							|  |  |  | 		curdir = os.path.join(self.dirname, 'cur') | 
					
						
							|  |  |  | 		for file in os.listdir(curdir): | 
					
						
							|  |  |  | 			if len(string.split(file, '.')) > 2: | 
					
						
							|  |  |  | 				self.boxes.append(os.path.join(curdir, file)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def next(self): | 
					
						
							|  |  |  | 		if not self.boxes: | 
					
						
							|  |  |  | 			return None | 
					
						
							|  |  |  | 		fn = self.boxes[0] | 
					
						
							|  |  |  | 		del self.boxes[0] | 
					
						
							|  |  |  | 		fp = open(os.path.join(self.dirname, fn)) | 
					
						
							|  |  |  | 		return rfc822.Message(fp) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-15 14:33:09 +00:00
										 |  |  | class BabylMailbox(_Mailbox): | 
					
						
							| 
									
										
										
										
											1998-03-26 20:56:10 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	def _search_start(self): | 
					
						
							|  |  |  | 		while 1: | 
					
						
							|  |  |  | 			line = self.fp.readline() | 
					
						
							|  |  |  | 			if not line: | 
					
						
							|  |  |  | 				raise EOFError | 
					
						
							|  |  |  | 			if line == '*** EOOH ***\n': | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def _search_end(self): | 
					
						
							|  |  |  | 		while 1: | 
					
						
							|  |  |  | 			pos = self.fp.tell() | 
					
						
							|  |  |  | 			line = self.fp.readline() | 
					
						
							|  |  |  | 			if not line: | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			if line == '\037\014\n': | 
					
						
							|  |  |  | 				self.fp.seek(pos) | 
					
						
							|  |  |  | 				return | 
					
						
							| 
									
										
										
										
											1997-05-15 14:33:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-09-17 21:33:15 +00:00
										 |  |  | def _test(): | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 	import time | 
					
						
							|  |  |  | 	import sys | 
					
						
							|  |  |  | 	import string | 
					
						
							| 
									
										
										
										
											1996-09-17 21:33:15 +00:00
										 |  |  | 	import os | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	args = sys.argv[1:] | 
					
						
							|  |  |  | 	if not args: | 
					
						
							| 
									
										
										
										
											1998-12-23 22:05:42 +00:00
										 |  |  | 		for key in 'MAILDIR', 'MAIL', 'LOGNAME', 'USER': | 
					
						
							| 
									
										
										
										
											1997-05-08 23:11:52 +00:00
										 |  |  | 			if os.environ.has_key(key): | 
					
						
							|  |  |  | 				mbox = os.environ[key] | 
					
						
							|  |  |  | 				break | 
					
						
							| 
									
										
										
										
											1996-09-17 21:33:15 +00:00
										 |  |  | 		else: | 
					
						
							| 
									
										
										
										
											1997-05-08 23:11:52 +00:00
										 |  |  | 			print "$MAIL, $LOGNAME nor $USER set -- who are you?" | 
					
						
							| 
									
										
										
										
											1996-09-17 21:33:15 +00:00
										 |  |  | 			return | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 		mbox = args[0] | 
					
						
							|  |  |  | 	if mbox[:1] == '+': | 
					
						
							|  |  |  | 		mbox = os.environ['HOME'] + '/Mail/' + mbox[1:] | 
					
						
							|  |  |  | 	elif not '/' in mbox: | 
					
						
							|  |  |  | 		mbox = '/usr/mail/' + mbox | 
					
						
							|  |  |  | 	if os.path.isdir(mbox): | 
					
						
							| 
									
										
										
										
											1998-12-23 22:05:42 +00:00
										 |  |  | 		if os.path.isdir(os.path.join(mbox, 'cur')): | 
					
						
							|  |  |  | 			mb = Maildir(mbox) | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			mb = MHMailbox(mbox) | 
					
						
							| 
									
										
										
										
											1996-09-17 21:33:15 +00:00
										 |  |  | 	else: | 
					
						
							|  |  |  | 		fp = open(mbox, 'r') | 
					
						
							|  |  |  | 		mb = UnixMailbox(fp) | 
					
						
							| 
									
										
										
										
											1995-10-23 13:59:53 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 	msgs = [] | 
					
						
							|  |  |  | 	while 1: | 
					
						
							|  |  |  | 		msg = mb.next() | 
					
						
							| 
									
										
										
										
											1998-04-03 16:04:05 +00:00
										 |  |  | 		if msg is None: | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 			break | 
					
						
							|  |  |  | 		msgs.append(msg) | 
					
						
							| 
									
										
										
										
											1997-10-22 21:00:49 +00:00
										 |  |  | 		msg.fp = None | 
					
						
							| 
									
										
										
										
											1996-09-17 21:33:15 +00:00
										 |  |  | 	if len(args) > 1: | 
					
						
							|  |  |  | 		num = string.atoi(args[1]) | 
					
						
							| 
									
										
										
										
											1994-04-28 09:53:33 +00:00
										 |  |  | 		print 'Message %d body:'%num | 
					
						
							|  |  |  | 		msg = msgs[num-1] | 
					
						
							|  |  |  | 		msg.rewindbody() | 
					
						
							|  |  |  | 		sys.stdout.write(msg.fp.read()) | 
					
						
							| 
									
										
										
										
											1996-09-17 21:33:15 +00:00
										 |  |  | 	else: | 
					
						
							|  |  |  | 		print 'Mailbox',mbox,'has',len(msgs),'messages:' | 
					
						
							|  |  |  | 		for msg in msgs: | 
					
						
							| 
									
										
										
										
											1998-04-03 16:04:05 +00:00
										 |  |  | 			f = msg.getheader('from') or "" | 
					
						
							|  |  |  | 			s = msg.getheader('subject') or "" | 
					
						
							|  |  |  | 			d = msg.getheader('date') or "" | 
					
						
							| 
									
										
										
										
											1996-09-17 21:33:15 +00:00
										 |  |  | 			print '%20.20s   %18.18s   %-30.30s'%(f, d[5:], s) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  | 	_test() |