Moved IMAP and POP3 related code to backends from account module.

Added backend creation to account dialog so that the folder request can be done.
This commit is contained in:
Timo Kankare
2016-09-04 22:54:39 +03:00
parent 211105d979
commit b6cbf7b9de
4 changed files with 170 additions and 109 deletions

View File

@@ -23,6 +23,94 @@
# MA 02110-1301, USA.
#
class ImapBackend:
pass
import logging
import re
import Mailnag.common.imaplib2 as imaplib
class ImapBackend:
"""Implementation of IMAP mail boxes."""
def __init__(self, name = '', user = '', password = '', oauth2string = '',
server = '', port = '', ssl = True, folders = []):
self.name = name
self.user = user
self.password = password
self.oauth2string = oauth2string
self.server = server
self.port = port
self.ssl = ssl # bool
self.folders = folders
self._conn = None
def get_connection(self, use_existing):
# try to reuse existing connection
if use_existing and self.has_connection():
return self._conn
self._conn = conn = None
try:
if self.ssl:
if self.port == '':
conn = imaplib.IMAP4_SSL(self.server)
else:
conn = imaplib.IMAP4_SSL(self.server, int(self.port))
else:
if self.port == '':
conn = imaplib.IMAP4(self.server)
else:
conn = imaplib.IMAP4(self.server, int(self.port))
if 'STARTTLS' in conn.capabilities:
conn.starttls()
else:
logging.warning("Using unencrypted connection for account '%s'" % self.name)
if self.oauth2string != '':
conn.authenticate('XOAUTH2', lambda x: self.oauth2string)
else:
conn.login(self.user, self.password)
self._conn = conn
except:
try:
if conn != None:
# conn.close() # allowed in SELECTED state only
conn.logout()
except: pass
raise # re-throw exception
return self._conn
def has_connection(self):
return (self._conn != None) and \
(self._conn.state != imaplib.LOGOUT) and \
(not self._conn.Terminate)
def request_folders(self):
lst = []
# Always create a new connection as an existing one may
# be used for IMAP IDLE.
conn = self.get_connection(use_existing = False)
try:
status, data = conn.list('', '*')
finally:
# conn.close() # allowed in SELECTED state only
conn.logout()
for d in data:
match = re.match('.+\s+("."|"?NIL"?)\s+"?([^"]+)"?$', d)
if match == None:
logging.warning("Folder format not supported.")
else:
folder = match.group(2)
lst.append(folder)
return lst

View File

@@ -23,6 +23,68 @@
# MA 02110-1301, USA.
#
class Pop3Backend:
pass
import logging
import poplib
class Pop3Backend:
"""Implementation of POP3 mail boxes."""
def __init__(self, name = '', user = '', password = '', oauth2string = '',
server = '', port = '', ssl = True):
self.name = name
self.user = user
self.password = password
self.oauth2string = oauth2string
self.server = server
self.port = port
self.ssl = ssl # bool
self._conn = None
def get_connection(self, use_existing):
# try to reuse existing connection
if use_existing and self.has_connection():
return self._conn
self._conn = conn = None
try:
if self.ssl:
if self.port == '':
conn = poplib.POP3_SSL(self.server)
else:
conn = poplib.POP3_SSL(self.server, int(self.port))
else:
if self.port == '':
conn = poplib.POP3(self.server)
else:
conn = poplib.POP3(self.server, int(self.port))
# TODO : Use STARTTLS when Mailnag has been migrated to python 3
# (analogous to get_connection in imap backend).
logging.warning("Using unencrypted connection for account '%s'" % self.name)
conn.getwelcome()
conn.user(self.user)
conn.pass_(self.password)
self._conn = conn
except:
try:
if conn != None:
conn.quit()
except: pass
raise # re-throw exception
return self._conn
def has_connection(self):
return (self._conn != None) and \
('sock' in self._conn.__dict__)
def request_folders(self):
lst = []
return lst

View File

@@ -24,10 +24,8 @@
#
import re
import poplib
import logging
import json
import Mailnag.common.imaplib2 as imaplib
from Mailnag.backends.imap import ImapBackend
from Mailnag.backends.pop3 import Pop3Backend
from Mailnag.common.utils import splitstr
@@ -95,31 +93,7 @@ class Account:
# Relevant for IMAP accounts only.
# Returns an empty list when used on POP3 accounts.
def request_server_folders(self):
lst = []
if not self.imap:
return lst
# Always create a new connection as an existing one may
# be used for IMAP IDLE.
conn = self._get_IMAP_connection(use_existing = False)
try:
status, data = conn.list('', '*')
finally:
# conn.close() # allowed in SELECTED state only
conn.logout()
for d in data:
match = re.match('.+\s+("."|"?NIL"?)\s+"?([^"]+)"?$', d)
if match == None:
logging.warning("Folder format not supported.")
else:
folder = match.group(2)
lst.append(folder)
return lst
return self.backend.request_folders()
def get_id(self):
@@ -128,92 +102,20 @@ class Account:
def _has_IMAP_connection(self):
return (self._conn != None) and \
(self._conn.state != imaplib.LOGOUT) and \
(not self._conn.Terminate)
return self.backend.has_connection()
def _get_IMAP_connection(self, use_existing):
# try to reuse existing connection
if use_existing and self._has_IMAP_connection():
return self._conn
self._conn = conn = None
try:
if self.ssl:
if self.port == '':
conn = imaplib.IMAP4_SSL(self.server)
else:
conn = imaplib.IMAP4_SSL(self.server, int(self.port))
else:
if self.port == '':
conn = imaplib.IMAP4(self.server)
else:
conn = imaplib.IMAP4(self.server, int(self.port))
if 'STARTTLS' in conn.capabilities:
conn.starttls()
else:
logging.warning("Using unencrypted connection for account '%s'" % self.name)
if self.oauth2string != '':
conn.authenticate('XOAUTH2', lambda x: self.oauth2string)
else:
conn.login(self.user, self.password)
self._conn = conn
except:
try:
if conn != None:
# conn.close() # allowed in SELECTED state only
conn.logout()
except: pass
raise # re-throw exception
self._conn = self.backend.get_connection(use_existing)
return self._conn
def _has_POP3_connection(self):
return (self._conn != None) and \
('sock' in self._conn.__dict__)
return self.backend.has_connection()
def _get_POP3_connection(self, use_existing):
# try to reuse existing connection
if use_existing and self._has_POP3_connection():
return self._conn
self._conn = conn = None
try:
if self.ssl:
if self.port == '':
conn = poplib.POP3_SSL(self.server)
else:
conn = poplib.POP3_SSL(self.server, int(self.port))
else:
if self.port == '':
conn = poplib.POP3(self.server)
else:
conn = poplib.POP3(self.server, int(self.port))
# TODO : Use STARTTLS when Mailnag has been migrated to python 3
# (analogous to get_IMAP_connection).
logging.warning("Using unencrypted connection for account '%s'" % self.name)
conn.getwelcome()
conn.user(self.user)
conn.pass_(self.password)
self._conn = conn
except:
try:
if conn != None:
conn.quit()
except: pass
raise # re-throw exception
self._conn = self.backend.get_connection(use_existing)
return self._conn
@@ -291,9 +193,9 @@ class AccountManager:
password = self._credentialstore.get(CREDENTIAL_KEY % (protocol, user, server))
if imap:
backend = ImapBackend()
backend = ImapBackend(name, user, password, '', server, port, ssl, folders)
else:
bakcend = Pop3Backend()
backend = Pop3Backend(name, user, password, '', server, port, ssl)
acc = Account(enabled, name, user, password, '', server, port, ssl, imap, idle, folders, backend)
self._accounts.append(acc)

View File

@@ -27,6 +27,8 @@ gi.require_version('GLib', '2.0')
from gi.repository import GObject, GLib, Gtk
from thread import start_new_thread
from Mailnag.backends.imap import ImapBackend
from Mailnag.backends.pop3 import Pop3Backend
from Mailnag.common.dist_cfg import PACKAGE_NAME
from Mailnag.common.i18n import _
from Mailnag.common.utils import get_data_file, splitstr
@@ -165,6 +167,13 @@ class AccountDialog:
acc.port = p[2]
else:
raise Exception('Unknown account type')
# Create backend
# TODO: This is duplicate code with AccountManager.
if acc.imap:
acc.backend = ImapBackend(acc.name, acc.user, acc.password, '', acc.server, acc.port, acc.ssl, acc.folders)
else:
acc.backend = Pop3Backend(acc.name, acc.user, acc.password, '', acc.server, acc.port, acc.ssl)
def _get_selected_folders(self):