Update of /cvsroot/wpdev/xmlscripts/python-lib/email
In directory sc8-pr-cvs1:/tmp/cvs-serv5168/email
Modified Files:
__init__.py Generator.py Message.py MIMEText.py Parser.py
Utils.py
Log Message:
Updated to Python 2.3.2
Index: __init__.py
===================================================================
RCS file: /cvsroot/wpdev/xmlscripts/python-lib/email/__init__.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** __init__.py 21 Dec 2002 14:52:55 -0000 1.2
--- __init__.py 10 Nov 2003 12:44:16 -0000 1.3
***************
*** 5,9 ****
"""
! __version__ = '2.4.3'
__all__ = [
--- 5,9 ----
"""
! __version__ = '2.5.4'
__all__ = [
Index: Generator.py
===================================================================
RCS file: /cvsroot/wpdev/xmlscripts/python-lib/email/Generator.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** Generator.py 21 Dec 2002 14:52:55 -0000 1.2
--- Generator.py 10 Nov 2003 12:44:16 -0000 1.3
***************
*** 5,10 ****
"""
- import time
import re
import random
--- 5,12 ----
"""
import re
+ import sys
+ import time
+ import locale
import random
***************
*** 13,16 ****
--- 15,19 ----
from email.Header import Header
+ from email.Parser import NLCRE
try:
***************
*** 160,201 ****
def _write_headers(self, msg):
for h, v in msg.items():
! # RFC 2822 says that lines SHOULD be no more than maxheaderlen
! # characters wide, so we're well within our rights to split long
! # headers.
! text = '%s: %s' % (h, v)
! if self.__maxheaderlen > 0 and len(text) > self.__maxheaderlen:
! text = self._split_header(text)
! print >> self._fp, text
# A blank line always separates headers from body
print >> self._fp
- def _split_header(self, text):
- maxheaderlen = self.__maxheaderlen
- # Find out whether any lines in the header are really longer than
- # maxheaderlen characters wide. There could be continuation lines
- # that actually shorten it. Also, replace hard tabs with 8 spaces.
- lines = [s.replace('\t', SPACE8) for s in text.splitlines()]
- for line in lines:
- if len(line) > maxheaderlen:
- break
- else:
- # No line was actually longer than maxheaderlen characters, so
- # just return the original unchanged.
- return text
- # If we have raw 8bit data in a byte string, we have no idea what the
- # encoding is. I think there is no safe way to split this string. If
- # it's ascii-subset, then we could do a normal ascii split, but if
- # it's multibyte then we could break the string. There's no way to
- # know so the least harm seems to be to not split the string and risk
- # it being too long.
- if _is8bitstring(text):
- return text
- # The `text' argument already has the field name prepended, so don't
- # provide it here or the first line will get folded too short.
- h = Header(text, maxlinelen=maxheaderlen,
- # For backwards compatibility, we use a hard tab here
- continuation_ws='\t')
- return h.encode()
-
#
# Handlers for writing types and subtypes
--- 163,189 ----
def _write_headers(self, msg):
for h, v in msg.items():
! print >> self._fp, '%s:' % h,
! if self.__maxheaderlen == 0:
! # Explicit no-wrapping
! print >> self._fp, v
! elif isinstance(v, Header):
! # Header instances know what to do
! print >> self._fp, v.encode()
! elif _is8bitstring(v):
! # If we have raw 8bit data in a byte string, we have no idea
! # what the encoding is. There is no safe way to split this
! # string. If it's ascii-subset, then we could do a normal
! # ascii split, but if it's multibyte then we could break the
! # string. There's no way to know so the least harm seems to
! # be to not split the string and risk it being too long.
! print >> self._fp, v
! else:
! # Header's got lots of smarts, so use it.
! print >> self._fp, Header(
! v, maxlinelen=self.__maxheaderlen,
! header_name=h, continuation_ws='\t').encode()
# A blank line always separates headers from body
print >> self._fp
#
# Handlers for writing types and subtypes
***************
*** 259,262 ****
--- 247,258 ----
if msg.preamble is not None:
self._fp.write(msg.preamble)
+ # If preamble is the empty string, the length of the split will be
+ # 1, but the last element will be the empty string. If it's
+ # anything else but does not end in a line separator, the length
+ # will be > 1 and not end in an empty string. We need to
+ # guarantee a newline after the preamble, but don't add too many.
+ plines = NLCRE.split(msg.preamble)
+ if plines <> [''] and plines[-1] <> '':
+ self._fp.write('\n')
# First boundary is a bit different; it doesn't have a leading extra
# newline.
***************
*** 362,369 ****
# Helper
def _make_boundary(text=None):
# Craft a random boundary. If text is given, ensure that the chosen
# boundary doesn't appear in the text.
! boundary = ('=' * 15) + repr(random.random()).split('.')[1] + '=='
if text is None:
return boundary
--- 358,369 ----
# Helper
+ _width = len(repr(sys.maxint-1))
+ _fmt = '%%0%dd' % _width
+
def _make_boundary(text=None):
# Craft a random boundary. If text is given, ensure that the chosen
# boundary doesn't appear in the text.
! token = random.randrange(sys.maxint)
! boundary = ('=' * 15) + (_fmt % token) + '=='
if text is None:
return boundary
Index: Message.py
===================================================================
RCS file: /cvsroot/wpdev/xmlscripts/python-lib/email/Message.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** Message.py 21 Dec 2002 14:52:55 -0000 1.2
--- Message.py 10 Nov 2003 12:44:16 -0000 1.3
***************
*** 6,9 ****
--- 6,11 ----
import re
+ import uu
+ import binascii
import warnings
from cStringIO import StringIO
***************
*** 11,16 ****
# Intrapackage imports
- from email import Errors
from email import Utils
from email import Charset
--- 13,18 ----
# Intrapackage imports
from email import Utils
+ from email import Errors
from email import Charset
***************
*** 57,60 ****
--- 59,79 ----
return param
+ def _parseparam(s):
+ plist = []
+ while s[:1] == ';':
+ s = s[1:]
+ end = s.find(';')
+ while end > 0 and s.count('"', 0, end) % 2:
+ end = s.find(';', end + 1)
+ if end < 0:
+ end = len(s)
+ f = s[:end]
+ if '=' in f:
+ i = f.index('=')
+ f = f[:i].strip().lower() + '=' + f[i+1:].strip()
+ plist.append(f.strip())
+ s = s[end:]
+ return plist
+
def _unquotevalue(value):
***************
*** 101,104 ****
--- 120,127 ----
Optional `unixfrom' when True, means include the Unix From_ envelope
header.
+
+ This is a convenience method and may not generate the message exactly
+ as you intend. For more flexibility, use the flatten() method of a
+ Generator instance.
"""
from email.Generator import Generator
***************
*** 165,181 ****
i returns that index into the payload.
! Optional decode is a flag (defaulting to False) indicating whether the
! payload should be decoded or not, according to the
! Content-Transfer-Encoding header. When True and the message is not a
! multipart, the payload will be decoded if this header's value is
! `quoted-printable' or `base64'. If some other encoding is used, or
! the header is missing, the payload is returned as-is (undecoded). If
! the message is a multipart and the decode flag is True, then None is
! returned.
"""
if i is None:
payload = self._payload
elif not isinstance(self._payload, ListType):
! raise TypeError, i
else:
payload = self._payload[i]
--- 188,208 ----
i returns that index into the payload.
! Optional decode is a flag indicating whether the payload should be
! decoded or not, according to the Content-Transfer-Encoding header
! (default is False).
!
! When True and the message is not a multipart, the payload will be
! decoded if this header's value is `quoted-printable' or `base64'. If
! some other encoding is used, or the header is missing, or if the
! payload has bogus data (i.e. bogus base64 or uuencoded data), the
! payload is returned as-is.
!
! If the message is a multipart and the decode flag is True, then None
! is returned.
"""
if i is None:
payload = self._payload
elif not isinstance(self._payload, ListType):
! raise TypeError, 'Expected list, got %s' % type(self._payload)
else:
payload = self._payload[i]
***************
*** 183,191 ****
if self.is_multipart():
return None
! cte = self.get('content-transfer-encoding', '')
! if cte.lower() == 'quoted-printable':
return Utils._qdecode(payload)
! elif cte.lower() == 'base64':
! return Utils._bdecode(payload)
# Everything else, including encodings with 8bit or 7bit are returned
# unchanged.
--- 210,230 ----
if self.is_multipart():
return None
! cte = self.get('content-transfer-encoding', '').lower()
! if cte == 'quoted-printable':
return Utils._qdecode(payload)
! elif cte == 'base64':
! try:
! return Utils._bdecode(payload)
! except binascii.Error:
! # Incorrect padding
! return payload
! elif cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
! sfp = StringIO()
! try:
! uu.decode(StringIO(payload+'\n'), sfp)
! payload = sfp.getvalue()
! except uu.Error:
! # Some decoding problem
! return payload
# Everything else, including encodings with 8bit or 7bit are returned
# unchanged.
***************
*** 504,508 ****
return failobj
params = []
! for p in paramre.split(value):
try:
name, val = p.split('=', 1)
--- 543,547 ----
return failobj
params = []
! for p in _parseparam(';' + value):
try:
name, val = p.split('=', 1)
***************
*** 550,560 ****
value can either be a string, or a 3-tuple if the parameter was RFC
2231 encoded. When it's a 3-tuple, the elements of the value are of
! the form (CHARSET, LANGUAGE, VALUE), where LANGUAGE may be the empty
! string. Your application should be prepared to deal with these, and
! can convert the parameter to a Unicode string like so:
param = msg.get_param('foo')
if isinstance(param, tuple):
! param = unicode(param[2], param[0])
In any case, the parameter value (either the returned string, or the
--- 589,602 ----
value can either be a string, or a 3-tuple if the parameter was RFC
2231 encoded. When it's a 3-tuple, the elements of the value are of
! the form (CHARSET, LANGUAGE, VALUE). Note that both CHARSET and
! LANGUAGE can be None, in which case you should consider VALUE to be
! encoded in the us-ascii charset. You can usually ignore LANGUAGE.
!
! Your application should be prepared to deal with 3-tuple return
! values, and can convert the parameter to a Unicode string like so:
param = msg.get_param('foo')
if isinstance(param, tuple):
! param = unicode(param[2], param[0] or 'us-ascii')
In any case, the parameter value (either the returned string, or the
***************
*** 687,691 ****
# It's an RFC 2231 encoded parameter
newvalue = _unquotevalue(filename)
! return unicode(newvalue[2], newvalue[0])
else:
newvalue = _unquotevalue(filename.strip())
--- 729,733 ----
# It's an RFC 2231 encoded parameter
newvalue = _unquotevalue(filename)
! return unicode(newvalue[2], newvalue[0] or 'us-ascii')
else:
newvalue = _unquotevalue(filename.strip())
***************
*** 704,708 ****
if isinstance(boundary, TupleType):
# RFC 2231 encoded, so decode. It better end up as ascii
! return unicode(boundary[2], boundary[0]).encode('us-ascii')
return _unquotevalue(boundary.strip())
--- 746,751 ----
if isinstance(boundary, TupleType):
# RFC 2231 encoded, so decode. It better end up as ascii
! charset = boundary[0] or 'us-ascii'
! return unicode(boundary[2], charset).encode('us-ascii')
return _unquotevalue(boundary.strip())
***************
*** 771,775 ****
if isinstance(charset, TupleType):
# RFC 2231 encoded, so decode it, and it better end up as ascii.
! charset = unicode(charset[2], charset[0]).encode('us-ascii')
# RFC 2046, $4.1.2 says charsets are not case sensitive
return charset.lower()
--- 814,819 ----
if isinstance(charset, TupleType):
# RFC 2231 encoded, so decode it, and it better end up as ascii.
! pcharset = charset[0] or 'us-ascii'
! charset = unicode(charset[2], pcharset).encode('us-ascii')
# RFC 2046, $4.1.2 says charsets are not case sensitive
return charset.lower()
Index: MIMEText.py
===================================================================
RCS file: /cvsroot/wpdev/xmlscripts/python-lib/email/MIMEText.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** MIMEText.py 21 Dec 2002 14:52:55 -0000 1.2
--- MIMEText.py 10 Nov 2003 12:44:16 -0000 1.3
***************
*** 18,23 ****
"""Create a text/* type MIME document.
! _text is the string for this message object. If the text does not end
! in a newline, one is added.
_subtype is the MIME sub content type, defaulting to "plain".
--- 18,22 ----
"""Create a text/* type MIME document.
! _text is the string for this message object.
_subtype is the MIME sub content type, defaulting to "plain".
***************
*** 36,41 ****
MIMENonMultipart.__init__(self, 'text', _subtype,
**{'charset': _charset})
- if _text and not _text.endswith('\n'):
- _text += '\n'
self.set_payload(_text, _charset)
if _encoder is not None:
--- 35,38 ----
Index: Parser.py
===================================================================
RCS file: /cvsroot/wpdev/xmlscripts/python-lib/email/Parser.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** Parser.py 21 Dec 2002 14:52:55 -0000 1.2
--- Parser.py 10 Nov 2003 12:44:16 -0000 1.3
***************
*** 21,25 ****
False = 0
! nlcre = re.compile('\r\n|\r|\n')
--- 21,25 ----
False = 0
! NLCRE = re.compile('\r\n|\r|\n')
***************
*** 60,66 ****
"""
root = self._class()
! self._parseheaders(root, fp)
if not headersonly:
! self._parsebody(root, fp)
return root
--- 60,66 ----
"""
root = self._class()
! firstbodyline = self._parseheaders(root, fp)
if not headersonly:
! self._parsebody(root, fp, firstbodyline)
return root
***************
*** 81,84 ****
--- 81,85 ----
lastvalue = []
lineno = 0
+ firstbodyline = None
while True:
# Don't strip the line before we test for the end condition,
***************
*** 121,131 ****
if self._strict:
raise Errors.HeaderParseError(
! "Not a header, not a continuation: ``%s''"%line)
elif lineno == 1 and line.startswith('--'):
# allow through duplicate boundary tags.
continue
else:
! raise Errors.HeaderParseError(
! "Not a header, not a continuation: ``%s''"%line)
if lastheader:
container[lastheader] = NL.join(lastvalue)
--- 122,135 ----
if self._strict:
raise Errors.HeaderParseError(
! "Not a header, not a continuation: ``%s''" % line)
elif lineno == 1 and line.startswith('--'):
# allow through duplicate boundary tags.
continue
else:
! # There was no separating blank line as mandated by RFC
! # 2822, but we're in non-strict mode. So just offer up
! # this current line as the first body line.
! firstbodyline = line
! break
if lastheader:
container[lastheader] = NL.join(lastvalue)
***************
*** 135,140 ****
if lastheader:
container[lastheader] = NL.join(lastvalue)
! def _parsebody(self, container, fp):
# Parse the body, but first split the payload on the content-type
# boundary if present.
--- 139,145 ----
if lastheader:
container[lastheader] = NL.join(lastvalue)
+ return firstbodyline
! def _parsebody(self, container, fp, firstbodyline=None):
# Parse the body, but first split the payload on the content-type
# boundary if present.
***************
*** 153,156 ****
--- 158,163 ----
separator = '--' + boundary
payload = fp.read()
+ if firstbodyline is not None:
+ payload = firstbodyline + '\n' + payload
# We use an RE here because boundaries can have trailing
# whitespace.
***************
*** 170,174 ****
# Find out what kind of line endings we're using
start += len(mo.group('sep')) + len(mo.group('ws'))
! mo = nlcre.search(payload, start)
if mo:
start += len(mo.group(0))
--- 177,181 ----
# Find out what kind of line endings we're using
start += len(mo.group('sep')) + len(mo.group('ws'))
! mo = NLCRE.search(payload, start)
if mo:
start += len(mo.group(0))
***************
*** 222,228 ****
msgobj = self.parsestr(parthdrs, headersonly=1)
# while submsgobj is the message itself
- submsgobj = self.parsestr(part)
- msgobj.attach(submsgobj)
msgobj.set_default_type('message/rfc822')
else:
msgobj = self.parsestr(part)
--- 229,239 ----
msgobj = self.parsestr(parthdrs, headersonly=1)
# while submsgobj is the message itself
msgobj.set_default_type('message/rfc822')
+ maintype = msgobj.get_content_maintype()
+ if maintype in ('message', 'multipart'):
+ submsgobj = self.parsestr(part)
+ msgobj.attach(submsgobj)
+ else:
+ msgobj.set_payload(part)
else:
msgobj = self.parsestr(part)
***************
*** 257,261 ****
container.attach(msg)
else:
! container.set_payload(fp.read())
--- 268,275 ----
container.attach(msg)
else:
! text = fp.read()
! if firstbodyline is not None:
! text = firstbodyline + '\n' + text
! container.set_payload(text)
***************
*** 271,275 ****
interested in is the message headers.
"""
! def _parsebody(self, container, fp):
# Consume but do not parse, the body
! container.set_payload(fp.read())
--- 285,292 ----
interested in is the message headers.
"""
! def _parsebody(self, container, fp, firstbodyline=None):
# Consume but do not parse, the body
! text = fp.read()
! if firstbodyline is not None:
! text = firstbodyline + '\n' + text
! container.set_payload(text)
Index: Utils.py
===================================================================
RCS file: /cvsroot/wpdev/xmlscripts/python-lib/email/Utils.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** Utils.py 21 Dec 2002 14:52:55 -0000 1.2
--- Utils.py 10 Nov 2003 12:44:16 -0000 1.3
***************
*** 14,24 ****
from types import ListType
! from rfc822 import quote
! from rfc822 import AddressList as _AddressList
! from rfc822 import mktime_tz
# We need wormarounds for bugs in these methods in older Pythons (see below)
! from rfc822 import parsedate as _parsedate
! from rfc822 import parsedate_tz as _parsedate_tz
try:
--- 14,24 ----
from types import ListType
! from email._parseaddr import quote
! from email._parseaddr import AddressList as _AddressList
! from email._parseaddr import mktime_tz
# We need wormarounds for bugs in these methods in older Pythons (see below)
! from email._parseaddr import parsedate as _parsedate
! from email._parseaddr import parsedate_tz as _parsedate_tz
try:
***************
*** 55,60 ****
CRLF = '\r\n'
! specialsre = re.compile(r'[][\()<>@,:;".]')
! escapesre = re.compile(r'[][\()"]')
--- 55,60 ----
CRLF = '\r\n'
! specialsre = re.compile(r'[][\\()<>@,:;".]')
! escapesre = re.compile(r'[][\\()"]')
***************
*** 67,72 ****
def _bdecode(s):
- if not s:
- return s
# We can't quite use base64.encodestring() since it tacks on a "courtesy
# newline". Blech!
--- 67,70 ----
***************
*** 281,287 ****
"""Decode string according to RFC 2231"""
import urllib
! charset, language, s = s.split("'", 2)
! s = urllib.unquote(s)
! return charset, language, s
--- 279,287 ----
"""Decode string according to RFC 2231"""
import urllib
! parts = s.split("'", 2)
! if len(parts) == 1:
! return None, None, urllib.unquote(s)
! charset, language, s = parts
! return charset, language, urllib.unquote(s)
***************
*** 336,340 ****
value.append(continuation)
charset, language, value = decode_rfc2231(EMPTYSTRING.join(value))
! new_params.append((name,
! (charset, language, '"%s"' % quote(value))))
return new_params
--- 336,340 ----
value.append(continuation)
charset, language, value = decode_rfc2231(EMPTYSTRING.join(value))
! new_params.append(
! (name, (charset, language, '"%s"' % quote(value))))
return new_params
|