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 import dummy_thread
as thread
102 _counter_lock
= thread
.allocate_lock()
106 def _get_next_counter():
108 _counter_lock
.acquire()
111 _counter_lock
.release()
116 def choose_boundary():
117 """Return a string usable as a multipart boundary.
119 The string chosen is unique within a single program run, and
120 incorporates the user id (if available), process id (if available),
121 and current time. So it's very unlikely the returned string appears
122 in message text, but there's no guarantee.
124 The boundary contains dots so you have to quote it in the header."""
131 hostid
= socket
.gethostbyname(socket
.gethostname())
132 except socket
.gaierror
:
135 uid
= repr(os
.getuid())
136 except AttributeError:
139 pid
= repr(os
.getpid())
140 except AttributeError:
142 _prefix
= hostid
+ '.' + uid
+ '.' + pid
143 return "%s.%.3f.%d" % (_prefix
, time
.time(), _get_next_counter())
146 # Subroutines for decoding some common content-transfer-types
148 def decode(input, output
, encoding
):
149 """Decode common content-transfer-encodings (base64, quopri, uuencode)."""
150 if encoding
== 'base64':
152 return base64
.decode(input, output
)
153 if encoding
== 'quoted-printable':
155 return quopri
.decode(input, output
)
156 if encoding
in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
158 return uu
.decode(input, output
)
159 if encoding
in ('7bit', '8bit'):
160 return output
.write(input.read())
161 if encoding
in decodetab
:
162 pipethrough(input, decodetab
[encoding
], output
)
165 'unknown Content-Transfer-Encoding: %s' % encoding
167 def encode(input, output
, encoding
):
168 """Encode common content-transfer-encodings (base64, quopri, uuencode)."""
169 if encoding
== 'base64':
171 return base64
.encode(input, output
)
172 if encoding
== 'quoted-printable':
174 return quopri
.encode(input, output
, 0)
175 if encoding
in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
177 return uu
.encode(input, output
)
178 if encoding
in ('7bit', '8bit'):
179 return output
.write(input.read())
180 if encoding
in encodetab
:
181 pipethrough(input, encodetab
[encoding
], output
)
184 'unknown Content-Transfer-Encoding: %s' % encoding
186 # The following is no longer used for standard encodings
188 # XXX This requires that uudecode and mmencode are in $PATH
192 sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
198 'uuencode': uudecode_pipe
,
199 'x-uuencode': uudecode_pipe
,
200 'uue': uudecode_pipe
,
201 'x-uue': uudecode_pipe
,
202 'quoted-printable': 'mmencode -u -q',
203 'base64': 'mmencode -u -b',
207 'x-uuencode': 'uuencode tempfile',
208 'uuencode': 'uuencode tempfile',
209 'x-uue': 'uuencode tempfile',
210 'uue': 'uuencode tempfile',
211 'quoted-printable': 'mmencode -q',
212 'base64': 'mmencode -b',
215 def pipeto(input, command
):
216 pipe
= os
.popen(command
, 'w')
217 copyliteral(input, pipe
)
220 def pipethrough(input, command
, output
):
221 (fd
, tempname
) = tempfile
.mkstemp()
222 temp
= os
.fdopen(fd
, 'w')
223 copyliteral(input, temp
)
225 pipe
= os
.popen(command
+ ' <' + tempname
, 'r')
226 copybinary(pipe
, output
)
230 def copyliteral(input, output
):
232 line
= input.readline()
236 def copybinary(input, output
):
239 line
= input.read(BUFSIZE
)