1 # Various tools used by MIME-reading or MIME-writing programs.
10 # A derived class of rfc822.Message that knows about MIME headers and
11 # contains some hooks for decoding encoded and multipart messages.
13 class Message(rfc822
.Message
):
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')
29 i
= string
.index(str, ';')
30 self
.plisttext
= str[i
:]
34 fields
= string
.splitfields(str, '/')
35 for i
in range(len(fields
)):
36 fields
[i
] = string
.lower(string
.strip(fields
[i
]))
37 self
.type = string
.joinfields(fields
, '/')
38 self
.maintype
= fields
[0]
39 self
.subtype
= string
.joinfields(fields
[1:], '/')
47 # XXX Should parse quotes!
48 end
= string
.index(str, ';')
53 i
= string
.index(f
, '=')
54 f
= string
.lower(string
.strip(f
[:i
])) + \
55 '=' + string
.strip(f
[i
+1:])
56 self
.plist
.append(string
.strip(f
))
62 def getparam(self
, name
):
63 name
= string
.lower(name
) + '='
67 return rfc822
.unquote(p
[n
:])
70 def getparamnames(self
):
73 i
= string
.find(p
, '=')
75 result
.append(string
.lower(p
[:i
]))
78 def getencoding(self
):
79 if self
.encodingheader
== None:
81 return string
.lower(self
.encodingheader
)
86 def getmaintype(self
):
99 # Return a random string usable as a multipart boundary.
100 # The method used is so that it is *very* unlikely that the same
101 # string of characters will every occur again in the Universe,
102 # so the caller needn't check the data it is packing for the
103 # occurrence of the boundary.
105 # The boundary contains dots so you have to quote it in the header.
109 def choose_boundary():
116 hostid
= socket
.gethostbyname(socket
.gethostname())
125 _prefix
= hostid
+ '.' + uid
+ '.' + pid
126 timestamp
= '%.3f' % time
.time()
127 seed
= `random
.randint(0, 32767)`
128 return _prefix
+ '.' + timestamp
+ '.' + seed
131 # Subroutines for decoding some common content-transfer-types
133 def decode(input, output
, encoding
):
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 if encoding
== 'base64':
152 return base64
.encode(input, output
)
153 if encoding
== 'quoted-printable':
155 return quopri
.encode(input, output
, 0)
156 if encoding
in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
158 return uu
.encode(input, output
)
159 if encodetab
.has_key(encoding
):
160 pipethrough(input, encodetab
[encoding
], output
)
163 'unknown Content-Transfer-Encoding: %s' % encoding
165 # The following is no longer used for standard encodings
167 # XXX This requires that uudecode and mmencode are in $PATH
171 sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
177 'uuencode': uudecode_pipe
,
178 'x-uuencode': uudecode_pipe
,
179 'uue': uudecode_pipe
,
180 'x-uue': uudecode_pipe
,
181 'quoted-printable': 'mmencode -u -q',
182 'base64': 'mmencode -u -b',
186 'x-uuencode': 'uuencode tempfile',
187 'uuencode': 'uuencode tempfile',
188 'x-uue': 'uuencode tempfile',
189 'uue': 'uuencode tempfile',
190 'quoted-printable': 'mmencode -q',
191 'base64': 'mmencode -b',
194 def pipeto(input, command
):
195 pipe
= os
.popen(command
, 'w')
196 copyliteral(input, pipe
)
199 def pipethrough(input, command
, output
):
200 tempname
= tempfile
.mktemp()
202 temp
= open(tempname
, 'w')
204 print '*** Cannot create temp file', `tempname`
206 copyliteral(input, temp
)
208 pipe
= os
.popen(command
+ ' <' + tempname
, 'r')
209 copybinary(pipe
, output
)
213 def copyliteral(input, output
):
215 line
= input.readline()
219 def copybinary(input, output
):
222 line
= input.read(BUFSIZE
)