#!/usr/bin/env python2.3
'''Classes implementing retrievers (message sources getmail can retrieve mail
from).
Currently implemented:
SimplePOP3Retriever
SimplePOP3SSLRetriever
BrokenUIDLPOP3Retriever
BrokenUIDLPOP3SSLRetriever
MultidropPOP3Retriever
MultidropPOP3SSLRetriever
MultidropSDPSRetriever
SimpleIMAPRetriever -- IMAP, as a protocol, is a FPOS, and it shows.
The Python standard library module imaplib leaves much up to
the user because of this.
SimpleIMAPSSLRetriever - the above, for IMAP-over-SSL.
MultidropIMAPRetriever
MultidropIMAPSSLRetriever
'''
__all__ = [
'SimplePOP3Retriever',
'SimplePOP3SSLRetriever',
'BrokenUIDLPOP3Retriever',
'BrokenUIDLPOP3SSLRetriever',
'MultidropPOP3Retriever',
'MultidropPOP3SSLRetriever',
'MultidropSDPSRetriever',
'SimpleIMAPRetriever',
'SimpleIMAPSSLRetriever',
'MultidropIMAPRetriever',
'MultidropIMAPSSLRetriever',
]
import os
import poplib
import imaplib
import types
from getmailcore.exceptions import *
from getmailcore.constants import *
from getmailcore.utilities import *
from getmailcore.baseclasses import *
from getmailcore._retrieverbases import *
#
# Functional classes
#
#######################################
class SimplePOP3Retriever(POP3RetrieverBase, POP3initMixIn):
'''Retriever class for single-user POP3 mailboxes.
'''
_confitems = (
ConfInstance(name='configparser', required=False),
ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
ConfInt(name='timeout', required=False, default=180),
ConfString(name='server'),
ConfInt(name='port', required=False, default=110),
ConfString(name='username'),
ConfPassword(name='password', required=False, default=None),
ConfBool(name='use_apop', required=False, default=False),
ConfBool(name='delete_dup_msgids', required=False, default=False),
)
received_from = None
received_with = 'POP3'
received_by = localhostname()
def __str__(self):
self.log.trace()
return 'SimplePOP3Retriever:%s@%s:%s' % (
self.conf.get('username', 'username'),
self.conf.get('server', 'server'),
self.conf.get('port', 'port')
)
def showconf(self):
self.log.trace()
self.log.info('SimplePOP3Retriever(%s)' % self._confstring()
+ os.linesep)
#######################################
class SimplePOP3SSLRetriever(POP3RetrieverBase, POP3SSLinitMixIn):
'''Retriever class for single-user POP3-over-SSL mailboxes.
'''
_confitems = (
ConfInstance(name='configparser', required=False),
ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
ConfInt(name='timeout', required=False, default=180),
ConfString(name='server'),
ConfInt(name='port', required=False, default=POP3_ssl_port),
ConfString(name='username'),
ConfPassword(name='password', required=False, default=None),
ConfBool(name='use_apop', required=False, default=False),
ConfBool(name='delete_dup_msgids', required=False, default=False),
ConfFile(name='keyfile', required=False, default=None),
ConfFile(name='certfile', required=False, default=None),
)
received_from = None
received_with = 'POP3-SSL'
received_by = localhostname()
def __str__(self):
self.log.trace()
return 'SimplePOP3SSLRetriever:%s@%s:%s' % (
self.conf.get('username', 'username'),
self.conf.get('server', 'server'),
self.conf.get('port', 'port')
)
def showconf(self):
self.log.trace()
self.log.info('SimplePOP3SSLRetriever(%s)' % self._confstring()
+ os.linesep)
#######################################
class BrokenUIDLPOP3RetrieverBase(POP3RetrieverBase):
'''Retriever base class for single-user POP3 mailboxes on servers that do
not properly assign unique IDs to messages. Since with these broken servers
we cannot rely on UIDL, we have to use message numbers, which are unique
within a POP3 session, but which change across sessions. This class
therefore can not be used to leave old mail on the server and download only
new mail.
'''
received_from = None
received_by = localhostname()
def _read_oldmailfile(self):
'''Force list of old messages to be empty by making this a no-op, so
duplicated IDs are always treated as new messages.'''
self.log.trace()
def write_oldmailfile(self, **kwargs):
'''Short-circuit writing the oldmail file.'''
self.log.trace()
def _getmsglist(self):
'''Don't rely on UIDL; instead, use just the message number.'''
self.log.trace()
try:
response, msglist, octets = self.conn.list()
for line in msglist:
msgnum = int(line.split()[0])
msgsize = int(line.split()[1])
self.msgnum_by_msgid[msgnum] = msgnum
self.msgid_by_msgnum[msgnum] = msgnum
self.msgsizes[msgnum] = msgsize
except poplib.error_proto, o:
raise getmailOperationError('POP error (%s)' % o)
self.gotmsglist = True
#######################################
class BrokenUIDLPOP3Retriever(BrokenUIDLPOP3RetrieverBase, POP3initMixIn):
'''For broken POP3 servers without SSL.
'''
_confitems = (
ConfInstance(name='configparser', required=False),
ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
ConfInt(name='timeout', required=False, default=180),
ConfString(name='server'),
ConfInt(name='port', required=False, default=110),
ConfString(name='username'),
ConfPassword(name='password', required=False, default=None),
ConfBool(name='use_apop', required=False, default=False),
)
received_with = 'POP3'
def __str__(self):
self.log.trace()
return 'BrokenUIDLPOP3Retriever:%s@%s:%s' % (
self.conf.get('username', 'username'),
self.conf.get('server', 'server'),
self.conf.get('port', 'port')
)
def showconf(self):
self.log.trace()
self.log.info('BrokenUIDLPOP3Retriever(%s)' % self._confstring()
+ os.linesep)
#######################################
class BrokenUIDLPOP3SSLRetriever(BrokenUIDLPOP3RetrieverBase, POP3SSLinitMixIn):
'''For broken POP3 servers with SSL.
'''
_confitems = (
ConfInstance(name='configparser', required=False),
ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
ConfInt(name='timeout', required=False, default=180),
ConfString(name='server'),
ConfInt(name='port', required=False, default=POP3_ssl_port),
ConfString(name='username'),
ConfPassword(name='password', required=False, default=None),
ConfBool(name='use_apop', required=False, default=False),
ConfFile(name='keyfile', required=False, default=None),
ConfFile(name='certfile', required=False, default=None),
)
received_with = 'POP3-SSL'
def __str__(self):
self.log.trace()
return 'BrokenUIDLPOP3SSLRetriever:%s@%s:%s' % (
self.conf.get('username', 'username'),
self.conf.get('server', 'server'),
self.conf.get('port', 'port')
)
def showconf(self):
self.log.trace()
self.log.info('BrokenUIDLPOP3SSLRetriever(%s)' % self._confstring()
+ os.linesep)
#######################################
class MultidropPOP3Retriever(MultidropPOP3RetrieverBase, POP3initMixIn):
'''Retriever class for multi-drop POP3 mailboxes.
'''
_confitems = (
ConfInstance(name='configparser', required=False),
ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
ConfInt(name='timeout', required=False, default=180),
ConfString(name='server'),
ConfInt(name='port', required=False, default=110),
ConfString(name='username'),
ConfPassword(name='password', required=False, default=None),
ConfBool(name='use_apop', required=False, default=False),
ConfString(name='envelope_recipient'),
)
received_from = None
received_with = 'POP3'
received_by = localhostname()
def __str__(self):
self.log.trace()
return 'MultidropPOP3Retriever:%s@%s:%s' % (
self.conf.get('username', 'username'),
self.conf.get('server', 'server'),
self.conf.get('port', 'port')
)
def showconf(self):
self.log.trace()
self.log.info('MultidropPOP3Retriever(%s)' % self._confstring()
+ os.linesep)
#######################################
class MultidropPOP3SSLRetriever(MultidropPOP3RetrieverBase, POP3SSLinitMixIn):
'''Retriever class for multi-drop POP3-over-SSL mailboxes.
'''
_confitems = (
ConfInstance(name='configparser', required=False),
ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
ConfInt(name='timeout', required=False, default=180),
ConfString(name='server'),
ConfInt(name='port', required=False, default=POP3_ssl_port),
ConfString(name='username'),
ConfPassword(name='password', required=False, default=None),
ConfBool(name='use_apop', required=False, default=False),
ConfString(name='envelope_recipient'),
ConfFile(name='keyfile', required=False, default=None),
ConfFile(name='certfile', required=False, default=None),
)
received_from = None
received_with = 'POP3-SSL'
received_by = localhostname()
def __str__(self):
self.log.trace()
return 'MultidropPOP3SSLRetriever:%s@%s:%s' % (
self.conf.get('username', 'username'),
self.conf.get('server', 'server'),
self.conf.get('port', 'port')
)
def showconf(self):
self.log.trace()
self.log.info('MultidropPOP3SSLRetriever(%s)' % self._confstring()
+ os.linesep)
#######################################
class MultidropSDPSRetriever(SimplePOP3Retriever, POP3initMixIn):
'''Retriever class for multi-drop SDPS (demon.co.uk) mailboxes.
Extend POP3 class to include support for Demon's protocol extensions, known
as SDPS. A non-standard command (*ENV) is used to retrieve the message
envelope. See http://www.demon.net/helpdesk/products/mail/sdps-tech.shtml
for details.
Support originally requested by Paul Clifford for getmail v.2/3.
'''
_confitems = (
ConfInstance(name='configparser', required=False),
ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
ConfInt(name='timeout', required=False, default=180),
ConfString(name='server'),
ConfInt(name='port', required=False, default=110),
ConfString(name='username'),
ConfPassword(name='password', required=False, default=None),
# Demon apparently doesn't support APOP
ConfBool(name='use_apop', required=False, default=False),
)
received_from = None
received_with = 'SDPS'
received_by = localhostname()
def __str__(self):
self.log.trace()
return 'MultidropSDPSRetriever:%s@%s:%s' % (
self.conf.get('username', 'username'),
self.conf.get('server', 'server'),
self.conf.get('port', 'port')
)
def showconf(self):
self.log.trace()
self.log.info('MultidropSDPSRetriever(%s)' % self._confstring()
+ os.linesep)
def _getmsgbyid(self, msgid):
self.log.trace()
msg = SimplePOP3Retriever._getmsgbyid(self, msgid)
# The magic of SDPS is the "*ENV" command. Implement it:
try:
msgnum = self._getmsgnumbyid(msgid)
resp, lines, octets = self.conn._longcmd('*ENV %i' % msgnum)
except poplib.error_proto, o:
raise getmailConfigurationError('server does not support *ENV (%s)'
% o)
if len(lines) < 4:
raise getmailOperationError('short *ENV response (%s)' % lines)
msg.sender = lines[2]
msg.recipient = lines[3]
return msg
#######################################
class SimpleIMAPRetriever(IMAPRetrieverBase, IMAPinitMixIn):
'''Retriever class for single-user IMAPv4 mailboxes.
'''
_confitems = (
ConfInstance(name='configparser', required=False),
ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
ConfInt(name='timeout', required=False, default=180),
ConfString(name='server'),
ConfInt(name='port', required=False, default=imaplib.IMAP4_PORT),
ConfString(name='username'),
ConfPassword(name='password', required=False, default=None),
ConfTupleOfStrings(name='mailboxes', required=False, default="('INBOX', )"),
ConfString(name='move_on_delete', required=False, default=None),
# imaplib.IMAP4.login_cram_md5() requires the (unimplemented)
# .authenticate(), so we can't do this yet (?).
ConfBool(name='use_cram_md5', required=False, default=False),
)
received_from = None
received_with = 'IMAP4'
received_by = localhostname()
def __str__(self):
self.log.trace()
return 'SimpleIMAPRetriever:%s@%s:%s' % (
self.conf.get('username', 'username'),
self.conf.get('server', 'server'),
self.conf.get('port', 'port')
)
def showconf(self):
self.log.trace()
self.log.info('SimpleIMAPRetriever(%s)' % self._confstring()
+ os.linesep)
#######################################
class SimpleIMAPSSLRetriever(IMAPRetrieverBase, IMAPSSLinitMixIn):
'''Retriever class for single-user IMAPv4-over-SSL mailboxes.
'''
_confitems = (
ConfInstance(name='configparser', required=False),
ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
# socket.ssl() and socket timeouts are incompatible in Python 2.3
#ConfInt(name='timeout', required=False, default=180),
ConfString(name='server'),
ConfInt(name='port', required=False, default=imaplib.IMAP4_SSL_PORT),
ConfString(name='username'),
ConfPassword(name='password', required=False, default=None),
ConfTupleOfStrings(name='mailboxes', required=False, default="('INBOX', )"),
ConfString(name='move_on_delete', required=False, default=None),
ConfFile(name='keyfile', required=False, default=None),
ConfFile(name='certfile', required=False, default=None),
# imaplib.IMAP4.login_cram_md5() requires the (unimplemented)
# .authenticate(), so we can't do this yet (?).
ConfBool(name='use_cram_md5', required=False, default=False),
)
received_from = None
received_with = 'IMAP4-SSL'
received_by = localhostname()
def __str__(self):
self.log.trace()
return 'SimpleIMAPSSLRetriever:%s@%s:%s' % (
self.conf.get('username', 'username'),
self.conf.get('server', 'server'),
self.conf.get('port', 'port')
)
def showconf(self):
self.log.trace()
self.log.info('SimpleIMAPSSLRetriever(%s)' % self._confstring()
+ os.linesep)
#######################################
class MultidropIMAPRetriever(MultidropIMAPRetrieverBase, IMAPinitMixIn):
'''Retriever class for multi-drop IMAPv4 mailboxes.
'''
_confitems = (
ConfInstance(name='configparser', required=False),
ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
ConfInt(name='timeout', required=False, default=180),
ConfString(name='server'),
ConfInt(name='port', required=False, default=imaplib.IMAP4_PORT),
ConfString(name='username'),
ConfPassword(name='password', required=False, default=None),
ConfTupleOfStrings(name='mailboxes', required=False, default="('INBOX', )"),
ConfString(name='move_on_delete', required=False, default=None),
# imaplib.IMAP4.login_cram_md5() requires the (unimplemented)
# .authenticate(), so we can't do this yet (?).
ConfBool(name='use_cram_md5', required=False, default=False),
ConfString(name='envelope_recipient'),
)
received_from = None
received_with = 'IMAP4'
received_by = localhostname()
def __str__(self):
self.log.trace()
return 'MultidropIMAPRetriever:%s@%s:%s' % (
self.conf.get('username', 'username'),
self.conf.get('server', 'server'),
self.conf.get('port', 'port')
)
def showconf(self):
self.log.trace()
self.log.info('MultidropIMAPRetriever(%s)' % self._confstring()
+ os.linesep)
#######################################
class MultidropIMAPSSLRetriever(MultidropIMAPRetrieverBase, IMAPSSLinitMixIn):
'''Retriever class for multi-drop IMAPv4-over-SSL mailboxes.
'''
_confitems = (
ConfInstance(name='configparser', required=False),
ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
# socket.ssl() and socket timeouts are incompatible in Python 2.3
#ConfInt(name='timeout', required=False, default=180),
ConfString(name='server'),
ConfInt(name='port', required=False, default=110),
ConfString(name='username'),
ConfPassword(name='password', required=False, default=None),
ConfTupleOfStrings(name='mailboxes', required=False, default="('INBOX', )"),
ConfString(name='move_on_delete', required=False, default=None),
ConfFile(name='keyfile', required=False, default=None),
ConfFile(name='certfile', required=False, default=None),
# imaplib.IMAP4.login_cram_md5() requires the (unimplemented)
# .authenticate(), so we can't do this yet (?).
ConfBool(name='use_cram_md5', required=False, default=False),
ConfString(name='envelope_recipient'),
)
received_from = None
received_with = 'IMAP4-SSL'
received_by = localhostname()
def __str__(self):
self.log.trace()
return 'MultidropIMAPSSLRetriever:%s@%s:%s' % (
self.conf.get('username', 'username'),
self.conf.get('server', 'server'),
self.conf.get('port', 'port')
)
def showconf(self):
self.log.trace()
self.log.info('MultidropIMAPSSLRetriever(%s)' % self._confstring()
+ os.linesep)
syntax highlighted by Code2HTML, v. 0.9.1