File: getmail_classes.py

package info (click to toggle)
getmail 3.2.5-3
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 428 kB
  • ctags: 161
  • sloc: python: 1,777; sh: 31; makefile: 12
file content (167 lines) | stat: -rw-r--r-- 5,353 bytes parent folder | download
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
#!/usr/bin/python

import os
import string
import cStringIO
import rfc822
import poplib

# Try importing timeoutsocket.  If it does not exist, just skip it.
try:
    import timeoutsocket
    Timeout = timeoutsocket.Timeout
except ImportError:
    # Prevent errors later for references to timeoutsocket
    Timeout = None
    class null_timeoutsocket:
        def getDefaultSocketTimeout(self):
            return 0
        def setDefaultSocketTimeout(self, val):
            pass
    timeoutsocket = null_timeoutsocket()

#
# Exception classes
#

# Base class for all getmail exceptions
class getmailException(Exception):
    pass

# Specific exception classes
class getmailConfigException(getmailException):
    pass

class getmailDeliveryException(getmailException):
    pass

class getmailNetworkError(getmailException):
    pass

class getmailDataFormatException(getmailException):
    pass

class getmailUnhandledException(Exception):
    pass

#
# Functional classes
#

#######################################
class updatefile:
    def __init__(self, filename):
        self.closed = 0
        self.filename = filename
        self.tmpname = filename + '.tmp.%d' % os.getpid()
        try:
            f = open(self.tmpname, 'w')
        except IOError, (code, msg):
            raise IOError('%s, opening output file "%s"' % (msg, self.tmpname))
        self.file = f
        self.write = f.write
        self.flush = f.flush

    def __del__(self):
        self.close()

    def close(self):
        if self.closed:
            return
        self.file.flush()
        self.file.close()
        os.rename(self.tmpname, self.filename)
        self.closed = 1

#######################################
class getmailMessage(rfc822.Message):
    '''Provide a way of obtaining a specific header field (i.e. the first
    Delivered-To: field, or the second Received: field, etc).
    It's an enormous oversight that the Python standard library doesn't
    provide this type of functionality.  Also change the constructor to take
    a string, as it's far more useful this way.
    '''
    ###################################
    def __init__(self, msg):
        f = cStringIO.StringIO(msg)
        rfc822.Message.__init__(self, f, 1)
        self._parsed_headers = 0
        self.getmailheaders = {}

    ###################################
    def get_specific_header(self, name, num):
        self.getmail_parse_headers()
        if num < 1:
            raise getmailConfigException('num must be positive')
        name = string.lower(name)
        if not self.getmailheaders.has_key(name):
            raise getmailConfigException('no matching header fields (%s)' % name)
        if len(self.getmailheaders[name]) < num:
            raise getmailConfigException('not enough matching header fields (%s:%i)' % (name, num))
        return self.getmailheaders[name][num - 1]

    ###################################
    def getmail_parse_headers(self):
        if self._parsed_headers:
            return

        current = ''
        for line in self.headers:
            if not line:
                # Can't happen?
                raise getmailUnhandledException('got empty line (%s)' % self.headers)
            if line[0] in string.whitespace:
                # This is a continuation line
                if not current:
                    raise getmailDataFormatException('got continuation line with no previous header field (%s)' % self.headers)
                current = current + ' ' + string.strip(line)
                continue
            # Not a continuation line
            if current:
                # We're currently working on a header field
                name, val = string.split(current, ':', 1)
                name = string.lower(name)
                val = string.strip(val)
                if self.getmailheaders.has_key(name):
                    self.getmailheaders[name].append(val)
                else:
                    self.getmailheaders[name] = [val]
            # Store current value
            current = string.strip(line)
        # Process last header field stored
        if current:
            name, val = string.split(current, ':', 1)
            name = string.lower(name)
            val = string.strip(val)
            if self.getmailheaders.has_key(name):
                self.getmailheaders[name].append(val)
            else:
                self.getmailheaders[name] = [val]

        self._parsed_headers = 1

#######################################

SPDS_error_proto = poplib.error_proto

#######################################
class SPDS(poplib.POP3):
    '''Extend POP3 class to include support for Demon's protocol extensions,
    known as SPDS.
    See http://www.demon.net/helpdesk/products/mail/sdps-tech.shtml
    for details.  Requested by Paul Clifford.
    '''
    ###################################
    def star_env(self, msgnum):
        '''Implement *ENV command.
        '''
        try:
            resp, lines, octets = self._longcmd('*ENV %i' % msgnum)
        except poplib.error_proto:
            raise getmailConfigException('server does not support *ENV')
        if len(lines) < 4:
            raise SPDS_error_proto('short *ENV response (%s)' % lines)
        env_sender = lines[2]
        env_recipient = lines[3]
        return env_sender, env_recipient