Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

"""Various tools used by MIME-reading or MIME-writing programs.""" 

 

 

import os 

import sys 

import tempfile 

from warnings import filterwarnings, catch_warnings 

with catch_warnings(): 

    if sys.py3kwarning: 

        filterwarnings("ignore", ".*rfc822 has been removed", DeprecationWarning) 

    import rfc822 

 

from warnings import warnpy3k 

warnpy3k("in 3.x, mimetools has been removed in favor of the email package", 

         stacklevel=2) 

 

__all__ = ["Message","choose_boundary","encode","decode","copyliteral", 

           "copybinary"] 

 

class Message(rfc822.Message): 

    """A derived class of rfc822.Message that knows about MIME headers and 

    contains some hooks for decoding encoded and multipart messages.""" 

 

    def __init__(self, fp, seekable = 1): 

        rfc822.Message.__init__(self, fp, seekable) 

        self.encodingheader = \ 

                self.getheader('content-transfer-encoding') 

        self.typeheader = \ 

                self.getheader('content-type') 

        self.parsetype() 

        self.parseplist() 

 

    def parsetype(self): 

        str = self.typeheader 

        if str is None: 

            str = 'text/plain' 

        if ';' in str: 

            i = str.index(';') 

            self.plisttext = str[i:] 

            str = str[:i] 

        else: 

            self.plisttext = '' 

        fields = str.split('/') 

        for i in range(len(fields)): 

            fields[i] = fields[i].strip().lower() 

        self.type = '/'.join(fields) 

        self.maintype = fields[0] 

        self.subtype = '/'.join(fields[1:]) 

 

    def parseplist(self): 

        str = self.plisttext 

        self.plist = [] 

        while str[:1] == ';': 

            str = str[1:] 

            if ';' in str: 

                # XXX Should parse quotes! 

                end = str.index(';') 

            else: 

                end = len(str) 

            f = str[:end] 

            if '=' in f: 

                i = f.index('=') 

                f = f[:i].strip().lower() + \ 

                        '=' + f[i+1:].strip() 

            self.plist.append(f.strip()) 

            str = str[end:] 

 

    def getplist(self): 

        return self.plist 

 

    def getparam(self, name): 

        name = name.lower() + '=' 

        n = len(name) 

        for p in self.plist: 

            if p[:n] == name: 

                return rfc822.unquote(p[n:]) 

        return None 

 

    def getparamnames(self): 

        result = [] 

        for p in self.plist: 

            i = p.find('=') 

            if i >= 0: 

                result.append(p[:i].lower()) 

        return result 

 

    def getencoding(self): 

        if self.encodingheader is None: 

            return '7bit' 

        return self.encodingheader.lower() 

 

    def gettype(self): 

        return self.type 

 

    def getmaintype(self): 

        return self.maintype 

 

    def getsubtype(self): 

        return self.subtype 

 

 

 

 

# Utility functions 

# ----------------- 

 

try: 

    import thread 

except ImportError: 

    import dummy_thread as thread 

_counter_lock = thread.allocate_lock() 

del thread 

 

_counter = 0 

def _get_next_counter(): 

    global _counter 

    _counter_lock.acquire() 

    _counter += 1 

    result = _counter 

    _counter_lock.release() 

    return result 

 

_prefix = None 

 

def choose_boundary(): 

    """Return a string usable as a multipart boundary. 

 

    The string chosen is unique within a single program run, and 

    incorporates the user id (if available), process id (if available), 

    and current time.  So it's very unlikely the returned string appears 

    in message text, but there's no guarantee. 

 

    The boundary contains dots so you have to quote it in the header.""" 

 

    global _prefix 

    import time 

    if _prefix is None: 

        import socket 

        try: 

            hostid = socket.gethostbyname(socket.gethostname()) 

        except socket.gaierror: 

            hostid = '127.0.0.1' 

        try: 

            uid = repr(os.getuid()) 

        except AttributeError: 

            uid = '1' 

        try: 

            pid = repr(os.getpid()) 

        except AttributeError: 

            pid = '1' 

        _prefix = hostid + '.' + uid + '.' + pid 

    return "%s.%.3f.%d" % (_prefix, time.time(), _get_next_counter()) 

 

 

# Subroutines for decoding some common content-transfer-types 

 

def decode(input, output, encoding): 

    """Decode common content-transfer-encodings (base64, quopri, uuencode).""" 

    if encoding == 'base64': 

        import base64 

        return base64.decode(input, output) 

    if encoding == 'quoted-printable': 

        import quopri 

        return quopri.decode(input, output) 

    if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'): 

        import uu 

        return uu.decode(input, output) 

    if encoding in ('7bit', '8bit'): 

        return output.write(input.read()) 

    if encoding in decodetab: 

        pipethrough(input, decodetab[encoding], output) 

    else: 

        raise ValueError, \ 

              'unknown Content-Transfer-Encoding: %s' % encoding 

 

def encode(input, output, encoding): 

    """Encode common content-transfer-encodings (base64, quopri, uuencode).""" 

    if encoding == 'base64': 

        import base64 

        return base64.encode(input, output) 

    if encoding == 'quoted-printable': 

        import quopri 

        return quopri.encode(input, output, 0) 

    if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'): 

        import uu 

        return uu.encode(input, output) 

    if encoding in ('7bit', '8bit'): 

        return output.write(input.read()) 

    if encoding in encodetab: 

        pipethrough(input, encodetab[encoding], output) 

    else: 

        raise ValueError, \ 

              'unknown Content-Transfer-Encoding: %s' % encoding 

 

# The following is no longer used for standard encodings 

 

# XXX This requires that uudecode and mmencode are in $PATH 

 

uudecode_pipe = '''( 

TEMP=/tmp/@uu.$$ 

sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode 

cat $TEMP 

rm $TEMP 

)''' 

 

decodetab = { 

        'uuencode':             uudecode_pipe, 

        'x-uuencode':           uudecode_pipe, 

        'uue':                  uudecode_pipe, 

        'x-uue':                uudecode_pipe, 

        'quoted-printable':     'mmencode -u -q', 

        'base64':               'mmencode -u -b', 

} 

 

encodetab = { 

        'x-uuencode':           'uuencode tempfile', 

        'uuencode':             'uuencode tempfile', 

        'x-uue':                'uuencode tempfile', 

        'uue':                  'uuencode tempfile', 

        'quoted-printable':     'mmencode -q', 

        'base64':               'mmencode -b', 

} 

 

def pipeto(input, command): 

    pipe = os.popen(command, 'w') 

    copyliteral(input, pipe) 

    pipe.close() 

 

def pipethrough(input, command, output): 

    (fd, tempname) = tempfile.mkstemp() 

    temp = os.fdopen(fd, 'w') 

    copyliteral(input, temp) 

    temp.close() 

    pipe = os.popen(command + ' <' + tempname, 'r') 

    copybinary(pipe, output) 

    pipe.close() 

    os.unlink(tempname) 

 

def copyliteral(input, output): 

    while 1: 

        line = input.readline() 

        if not line: break 

        output.write(line) 

 

def copybinary(input, output): 

    BUFSIZE = 8192 

    while 1: 

        line = input.read(BUFSIZE) 

        if not line: break 

        output.write(line)