1 """Various tools used by MIME-reading or MIME-writing programs."""
8 __all__
= ["Message","choose_boundary","encode","decode","copyliteral",
11 class Message(rfc822
.Message
):
12 """A derived class of rfc822.Message that knows about MIME headers and
13 contains some hooks for decoding encoded and multipart messages."""
15 def __init__(self
, fp
, seekable
= 1):
16 rfc822
.Message
.__init
__(self
, fp
, seekable
)
17 self
.encodingheader
= \
18 self
.getheader('content-transfer-encoding')
20 self
.getheader('content-type')
30 self
.plisttext
= str[i
:]
34 fields
= str.split('/')
35 for i
in range(len(fields
)):
36 fields
[i
] = fields
[i
].strip().lower()
37 self
.type = '/'.join(fields
)
38 self
.maintype
= fields
[0]
39 self
.subtype
= '/'.join(fields
[1:])
47 # XXX Should parse quotes!
54 f
= f
[:i
].strip().lower() + \
56 self
.plist
.append(f
.strip())
62 def getparam(self
, name
):
63 name
= name
.lower() + '='
67 return rfc822
.unquote(p
[n
:])
70 def getparamnames(self
):
75 result
.append(p
[:i
].lower())
78 def getencoding(self
):
79 if self
.encodingheader
is None:
81 return self
.encodingheader
.lower()
86 def getmaintype(self
):
101 def choose_boundary():
102 """Return a random string usable as a multipart boundary.
103 The method used is so that it is *very* unlikely that the same
104 string of characters will every occur again in the Universe,
105 so the caller needn't check the data it is packing for the
106 occurrence of the boundary.
108 The boundary contains dots so you have to quote it in the header."""
115 hostid
= socket
.gethostbyname(socket
.gethostname())
118 except AttributeError:
122 except AttributeError:
124 _prefix
= hostid
+ '.' + uid
+ '.' + pid
125 timestamp
= '%.3f' % time
.time()
126 seed
= `random
.randint(0, 32767)`
127 return _prefix
+ '.' + timestamp
+ '.' + seed
130 # Subroutines for decoding some common content-transfer-types
132 def decode(input, output
, encoding
):
133 """Decode common content-transfer-encodings (base64, quopri, uuencode)."""
134 if encoding
== 'base64':
136 return base64
.decode(input, output
)
137 if encoding
== 'quoted-printable':
139 return quopri
.decode(input, output
)
140 if encoding
in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
142 return uu
.decode(input, output
)
143 if encoding
in ('7bit', '8bit'):
144 return output
.write(input.read())
145 if encoding
in decodetab
:
146 pipethrough(input, decodetab
[encoding
], output
)
149 'unknown Content-Transfer-Encoding: %s' % encoding
151 def encode(input, output
, encoding
):
152 """Encode common content-transfer-encodings (base64, quopri, uuencode)."""
153 if encoding
== 'base64':
155 return base64
.encode(input, output
)
156 if encoding
== 'quoted-printable':
158 return quopri
.encode(input, output
, 0)
159 if encoding
in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
161 return uu
.encode(input, output
)
162 if encoding
in ('7bit', '8bit'):
163 return output
.write(input.read())
164 if encoding
in encodetab
:
165 pipethrough(input, encodetab
[encoding
], output
)
168 'unknown Content-Transfer-Encoding: %s' % encoding
170 # The following is no longer used for standard encodings
172 # XXX This requires that uudecode and mmencode are in $PATH
176 sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
182 'uuencode': uudecode_pipe
,
183 'x-uuencode': uudecode_pipe
,
184 'uue': uudecode_pipe
,
185 'x-uue': uudecode_pipe
,
186 'quoted-printable': 'mmencode -u -q',
187 'base64': 'mmencode -u -b',
191 'x-uuencode': 'uuencode tempfile',
192 'uuencode': 'uuencode tempfile',
193 'x-uue': 'uuencode tempfile',
194 'uue': 'uuencode tempfile',
195 'quoted-printable': 'mmencode -q',
196 'base64': 'mmencode -b',
199 def pipeto(input, command
):
200 pipe
= os
.popen(command
, 'w')
201 copyliteral(input, pipe
)
204 def pipethrough(input, command
, output
):
205 (fd
, tempname
) = tempfile
.mkstemp()
206 temp
= os
.fdopen(fd
, 'w')
207 copyliteral(input, temp
)
209 pipe
= os
.popen(command
+ ' <' + tempname
, 'r')
210 copybinary(pipe
, output
)
214 def copyliteral(input, output
):
216 line
= input.readline()
220 def copybinary(input, output
):
223 line
= input.read(BUFSIZE
)