mhlib.py: delay opening of sequences file so we don't overwrite it when
putsequences is called with a bad argument
rfc822.py: better handling of dates with no or bad timezones
uu.py: contributed by Lance -- uu{en,de}code
diff --git a/Lib/mhlib.py b/Lib/mhlib.py
index b24695c..5bdda72 100644
--- a/Lib/mhlib.py
+++ b/Lib/mhlib.py
@@ -36,6 +36,7 @@
 # f.putsequences(dict)    # write sequences back to folder
 #
 # m = f.openmessage(n)    # new open message object (costs a file descriptor)
+# m is a derived class of mimetools.Message(rfc822.Message), with:
 # s = m.getheadertext()   # text of message's headers
 # s = m.getheadertext(pred) # text of message's headers, filtered by pred
 # s = m.getbodytext()     # text of message's body, decoded
@@ -299,11 +300,19 @@
 	# Write the set of sequences back to the folder
 	def putsequences(self, sequences):
 		fullname = self.getsequencesfilename()
-		f = open(fullname, 'w')
+		f = None
 		for key in sequences.keys():
 			s = IntSet('', ' ')
 			s.fromlist(sequences[key])
+			if not f: f = open(fullname, 'w')
 			f.write('%s: %s\n' % (key, s.tostring()))
+		if not f:
+			try:
+				os.unlink(fullname)
+			except os.error:
+				pass
+		else:
+			f.close()
 
 	# Return the current message.  Raise KeyError when there is none
 	def getcurrent(self):
@@ -313,7 +322,7 @@
 	def setcurrent(self, n):
 		updateline(self.getsequencesfilename(), 'cur', str(n), 0)
 
-	# Open a message -- returns a mimetools.Message object
+	# Open a message -- returns a Message object
 	def openmessage(self, n):
 		path = self.getmessagefilename(n)
 		return Message(self, n)
diff --git a/Lib/rfc822.py b/Lib/rfc822.py
index 886098c..fcf31fb 100644
--- a/Lib/rfc822.py
+++ b/Lib/rfc822.py
@@ -329,11 +329,18 @@
 	  'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
 
 def parsedate(data):
-	# XXX This completely ignores timezone matters at the moment...
+	# XXX This still mostly ignores timezone matters at the moment...
 	data = string.split(data)
 	if data[0][-1] == ',':
 		# There's a dayname here. Skip it
 		del data[0]
+	if len(data) == 4:
+		s = data[3]
+		i = string.find(s, '+')
+		if i > 0:
+			data[3:] = [s[:i], s[i+1:]]
+		else:
+			data.append('') # Dummy tz
 	if len(data) < 5:
 		return None
 	data = data[:5]
diff --git a/Lib/uu.py b/Lib/uu.py
new file mode 100755
index 0000000..7f0783d
--- /dev/null
+++ b/Lib/uu.py
@@ -0,0 +1,214 @@
+# uu.py
+# Copyright 1994 by Lance Ellinghouse
+# Cathedral City, California Republic, United States of America.
+#                        All Rights Reserved
+# Permission to use, copy, modify, and distribute this software and its 
+# documentation for any purpose and without fee is hereby granted, 
+# provided that the above copyright notice appear in all copies and that
+# both that copyright notice and this permission notice appear in 
+# supporting documentation, and that the name of Lance Ellinghouse
+# not be used in advertising or publicity pertaining to distribution 
+# of the software without specific, written prior permission.
+# LANCE ELLINGHOUSE DISCLAIMS ALL WARRANTIES WITH REGARD TO
+# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS, IN NO EVENT SHALL LANCE ELLINGHOUSE CENTRUM BE LIABLE
+# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# This file implements the UUencode and UUdecode functions.
+
+# encode(filename, mode, in_file, out_file)
+# decode(filename, mode, in_file)
+# decode(in_file, out_file)
+# decode(in_file)
+
+# encode a single char to always be printable
+def _ENC(ch):
+    if type(ch) == type(''):
+	a = ch[:1] # only 1 char
+	if len(a) == 0:
+	    raise ValueError, 'need to pass in at least 1 char'
+	a = ord(a)
+    elif type(ch) == type(0):
+	a = ch
+    else:
+	raise TypeError, 'must pass in an integer or single character'
+    return chr((a & 077) + ord(' '))
+
+# input 3 chars, output 4 encoded chars
+def _outenc(str):
+    if len(str) > 3:
+	raise ValueError, 'can only accept strings of 3 chars'
+    p0, p1, p2 = 0, 0, 0
+    if len(str) > 2:
+	p2 = ord(str[2])
+    if len(str) > 1:
+	p1 = ord(str[1])
+    if len(str) > 0:
+	p0 = ord(str[0])
+    c1 = p0 >> 2
+    c2 = (p0 << 4) & 060 | (p1 >> 4) & 017
+    c3 = (p1 << 2) & 074 | (p2 >> 6) & 03
+    c4 = p2 & 077
+    rtn = _ENC(c1)
+    rtn = rtn + _ENC(c2)
+    rtn = rtn + _ENC(c3)
+    rtn = rtn + _ENC(c4)
+    return rtn
+
+# pass in 45 bytes max, returns 62 bytes encoded
+def _encode(str):
+    if len(str) > 45:
+	raise ValueError, 'cannot handle more than 45 chars at once'
+    length = len(str)
+    rtn = _ENC(length)
+    i = 0
+    while i < length:
+	rtn = rtn + _outenc(str[i:(i+3)])
+	i = i + 3
+    rtn = rtn + '\n'
+    return rtn
+    
+# encode a fileobject and write out to a file object
+def encode(filename, mode, in_file, out_file):
+    out_file.write('begin %o %s\n' % ((mode&0777),filename))
+    str = in_file.read(45)
+    while len(str) > 0:
+	out_file.write(_encode(str))
+	str = in_file.read(45)
+    out_file.write(' \nend\n')
+    return None
+
+# def decode a single char from printable to possibly non-printable
+def _DEC(ch):
+    if type(ch) != type('') or len(ch) != 1:
+	raise ValueError, 'need to pass in a single char'
+    a = ord(ch[0:1])
+    return (a - ord(' '))
+
+# input 4 chars encoded, output 3 chars unencoded
+def _outdec(str):
+    if len(str) > 4:
+	raise ValueError, 'can only accept strings of 4 chars'
+    p0, p1, p2, p3 = 0, 0, 0, 0
+    if len(str) > 3:
+	p3 = _DEC(str[3])
+    if len(str) > 2:
+	p2 = _DEC(str[2])
+    if len(str) > 1:
+	p1 = _DEC(str[1])
+    if len(str) > 0:
+	p0 = _DEC(str[0])
+    c1 = p0 << 2 | (p1 & 060) >> 4
+    c2 = (p1 & 017) << 4 | (p2 & 074) >> 2
+    c3 = (p2 & 03) << 6 | (p3 & 077)
+    rtn = chr(c1)
+    rtn = rtn + chr(c2)
+    rtn = rtn + chr(c3)
+    return rtn
+
+# pass in 62 bytes and return 45 bytes unencoded
+def _decode(str):
+    if len(str) > 62:
+	raise ValueError, 'cannot handle more than 62 chars at once'
+    length = _DEC(str[0])
+    i = 1
+    rtn = ''
+    while len(rtn) < length:
+	rtn = rtn + _outdec(str[i:(i+4)])
+	i = i + 4
+    return rtn[0:length]
+
+# decode(filename, mode, in_file)
+# decode(in_file, out_file)
+# decode(in_file)
+def decode(*args):
+    ok = 1
+    _setup = None
+    out_file = None
+    if len(args) == 3:
+	filename, mode, in_file = args
+	if type(filename) != type(''):
+	    ok = 0
+	if type(mode) != type(0):
+	    ok = 0
+	try:
+	    _ = getattr(in_file,'readline')
+	except AttributeError:
+	    ok = 0
+	def _setup(out_file,args):
+	    filename, mode, in_file = args
+	    # open file as specified and assign out_file for later use
+	    out_file = open(filename,'w',mode)
+	    _out_file_orig = 0
+	    _ = in_file.readline()
+	    return (out_file,_out_file_orig)
+    elif len(args) == 2:
+	in_file, out_file = args
+	try:
+	    _ = getattr(in_file,'readline')
+	    _ = getattr(out_file,'write')
+	except AttributeError:
+	    ok = 0
+	def _setup(out_file, args):
+	    in_file, out_file = args
+	    # Toss the 'begin mode filename' part.. not needed
+	    _ = in_file.readline()
+	    _out_file_orig = 1
+	    return (out_file,_out_file_orig)
+    elif len(args) == 1:
+	in_file = args[0]
+	try:
+	    _ = getattr(in_file,'readline')
+	except AttributeError:
+	    ok = 0
+	def _setup(out_file, args):
+	    import strop
+	    in_file = args[0]
+	    # open file as specified in uu file and 
+	    # assign out_file for later use
+	    i = in_file.readline()
+	    i = strop.strip(i)
+	    if 'begin' != i[:5]:
+		raise IOError, 'input file not in UUencoded format'
+	    [dummy, mode, filename] = strop.split(i)
+	    mode = strop.atoi(mode, 8)
+	    out_file = open(filename,'w',mode)
+	    _out_file_orig = 0
+	    return (out_file,_out_file_orig)
+    if ok != 1:
+	raise SyntaxError, 'must be (filename, mode, in_file) or (in_file,out_file) or (in_file)'
+    out_file, _out_file_orig = _setup(out_file, args)
+    str = in_file.readline()
+    while len(str) > 0 and str != ' \n' and str != 'end\n':
+	out_file.write(_decode(str))
+	str = in_file.readline()
+    if _out_file_orig == 0:
+	out_file.close()
+	del out_file
+    return None
+
+def test():
+    import sys
+    if sys.argv[1:2] == ['-d']:
+	if sys.argv[2:]:
+	    decode(open(sys.argv[2]), sys.stdout)
+	else:
+	    decode(sys.stdin, sys.stdout)
+    elif sys.argv[1:2] == ['-e']:
+	if sys.argv[2:]:
+	    file = sys.argv[2]
+	    fp = open(file)
+	else:
+	    file = '-'
+	    fp = sys.stdin
+	encode(file, 0644, fp, sys.stdout)
+    else:
+	print 'usage: uu -d [file]; (to decode)'
+	print 'or:    uu -e [file]; (to encode)'
+	sys.exit(2)
+
+if __name__ == '__main__':
+    test()