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
|