1 """Various tools used by MIME-reading or MIME-writing programs."""
10 class Message(rfc822
.Message
):
11 """A derived class of rfc822.Message that knows about MIME headers and
12 contains some hooks for decoding encoded and multipart messages."""
14 def __init__(self
, fp
, seekable
= 1):
15 rfc822
.Message
.__init
__(self
, fp
, seekable
)
16 self
.encodingheader
= \
17 self
.getheader('content-transfer-encoding')
19 self
.getheader('content-type')
28 i
= string
.index(str, ';')
29 self
.plisttext
= str[i
:]
33 fields
= string
.splitfields(str, '/')
34 for i
in range(len(fields
)):
35 fields
[i
] = string
.lower(string
.strip(fields
[i
]))
36 self
.type = string
.joinfields(fields
, '/')
37 self
.maintype
= fields
[0]
38 self
.subtype
= string
.joinfields(fields
[1:], '/')
46 # XXX Should parse quotes!
47 end
= string
.index(str, ';')
52 i
= string
.index(f
, '=')
53 f
= string
.lower(string
.strip(f
[:i
])) + \
54 '=' + string
.strip(f
[i
+1:])
55 self
.plist
.append(string
.strip(f
))
61 def getparam(self
, name
):
62 name
= string
.lower(name
) + '='
66 return rfc822
.unquote(p
[n
:])
69 def getparamnames(self
):
72 i
= string
.find(p
, '=')
74 result
.append(string
.lower(p
[:i
]))
77 def getencoding(self
):
78 if self
.encodingheader
== None:
80 return string
.lower(self
.encodingheader
)
85 def getmaintype(self
):
100 def choose_boundary():
101 """Return a random string usable as a multipart boundary.
102 The method used is so that it is *very* unlikely that the same
103 string of characters will every occur again in the Universe,
104 so the caller needn't check the data it is packing for the
105 occurrence of the boundary.
107 The boundary contains dots so you have to quote it in the header."""
115 hostid
= socket
.gethostbyname(socket
.gethostname())
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 decodetab
.has_key(encoding
):
144 pipethrough(input, decodetab
[encoding
], output
)
147 'unknown Content-Transfer-Encoding: %s' % encoding
149 def encode(input, output
, encoding
):
150 """Encode common content-transfer-encodings (base64, quopri, uuencode)."""
151 if encoding
== 'base64':
153 return base64
.encode(input, output
)
154 if encoding
== 'quoted-printable':
156 return quopri
.encode(input, output
, 0)
157 if encoding
in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
159 return uu
.encode(input, output
)
160 if encodetab
.has_key(encoding
):
161 pipethrough(input, encodetab
[encoding
], output
)
164 'unknown Content-Transfer-Encoding: %s' % encoding
166 # The following is no longer used for standard encodings
168 # XXX This requires that uudecode and mmencode are in $PATH
172 sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
178 'uuencode': uudecode_pipe
,
179 'x-uuencode': uudecode_pipe
,
180 'uue': uudecode_pipe
,
181 'x-uue': uudecode_pipe
,
182 'quoted-printable': 'mmencode -u -q',
183 'base64': 'mmencode -u -b',
187 'x-uuencode': 'uuencode tempfile',
188 'uuencode': 'uuencode tempfile',
189 'x-uue': 'uuencode tempfile',
190 'uue': 'uuencode tempfile',
191 'quoted-printable': 'mmencode -q',
192 'base64': 'mmencode -b',
195 def pipeto(input, command
):
196 pipe
= os
.popen(command
, 'w')
197 copyliteral(input, pipe
)
200 def pipethrough(input, command
, output
):
201 tempname
= tempfile
.mktemp()
203 temp
= open(tempname
, 'w')
205 print '*** Cannot create temp file', `tempname`
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
)