summaryrefslogtreecommitdiff
path: root/src/leap/mail/imap/service/imap.py
diff options
context:
space:
mode:
authorKali Kaneko <kali@leap.se>2014-01-23 00:27:19 -0400
committerKali Kaneko <kali@leap.se>2014-01-28 19:38:09 -0400
commit23b2a2c10ddd6dbb15e3f532d526ac0a53bd788b (patch)
tree9725db273ac7440603fbeb1352f40b232442daab /src/leap/mail/imap/service/imap.py
parent4ae6ad57a0f80143e3ded867c1fdd2264804a775 (diff)
move server to its own file
Diffstat (limited to 'src/leap/mail/imap/service/imap.py')
-rw-r--r--src/leap/mail/imap/service/imap.py180
1 files changed, 3 insertions, 177 deletions
diff --git a/src/leap/mail/imap/service/imap.py b/src/leap/mail/imap/service/imap.py
index 71b9950..3f99da6 100644
--- a/src/leap/mail/imap/service/imap.py
+++ b/src/leap/mail/imap/service/imap.py
@@ -17,17 +17,11 @@
"""
Imap service initialization
"""
-from copy import copy
-
import logging
from twisted.internet.protocol import ServerFactory
-from twisted.internet.defer import maybeDeferred
from twisted.internet.error import CannotListenError
-from twisted.internet.task import deferLater
from twisted.mail import imap4
-from twisted.python import log
-from twisted import cred
logger = logging.getLogger(__name__)
@@ -37,6 +31,7 @@ from leap.keymanager import KeyManager
from leap.mail.imap.account import SoledadBackedAccount
from leap.mail.imap.fetch import LeapIncomingMail
from leap.mail.imap.memorystore import MemoryStore
+from leap.mail.imap.server import LeapIMAPServer
from leap.soledad.client import Soledad
# The default port in which imap service will run
@@ -48,7 +43,6 @@ INCOMING_CHECK_PERIOD = 60
from leap.common.events.events_pb2 import IMAP_SERVICE_STARTED
from leap.common.events.events_pb2 import IMAP_SERVICE_FAILED_TO_START
-from leap.common.events.events_pb2 import IMAP_CLIENT_LOGIN
######################################################
# Temporary workaround for RecursionLimit when using
@@ -70,163 +64,6 @@ except Exception:
######################################################
-# TODO move this to imap.server
-
-class LeapIMAPServer(imap4.IMAP4Server):
- """
- An IMAP4 Server with mailboxes backed by soledad
- """
- def __init__(self, *args, **kwargs):
- # pop extraneous arguments
- soledad = kwargs.pop('soledad', None)
- uuid = kwargs.pop('uuid', None)
- userid = kwargs.pop('userid', None)
- leap_assert(soledad, "need a soledad instance")
- leap_assert_type(soledad, Soledad)
- leap_assert(uuid, "need a user in the initialization")
-
- self._userid = userid
-
- # initialize imap server!
- imap4.IMAP4Server.__init__(self, *args, **kwargs)
-
- # we should initialize the account here,
- # but we move it to the factory so we can
- # populate the test account properly (and only once
- # per session)
-
- def lineReceived(self, line):
- """
- Attempt to parse a single line from the server.
-
- :param line: the line from the server, without the line delimiter.
- :type line: str
- """
- if self.theAccount.closed is True and self.state != "unauth":
- log.msg("Closing the session. State: unauth")
- self.state = "unauth"
-
- if "login" in line.lower():
- # avoid to log the pass, even though we are using a dummy auth
- # by now.
- msg = line[:7] + " [...]"
- else:
- msg = copy(line)
- log.msg('rcv (%s): %s' % (self.state, msg))
- imap4.IMAP4Server.lineReceived(self, line)
-
- def authenticateLogin(self, username, password):
- """
- Lookup the account with the given parameters, and deny
- the improper combinations.
-
- :param username: the username that is attempting authentication.
- :type username: str
- :param password: the password to authenticate with.
- :type password: str
- """
- # XXX this should use portal:
- # return portal.login(cred.credentials.UsernamePassword(user, pass)
- if username != self._userid:
- # bad username, reject.
- raise cred.error.UnauthorizedLogin()
- # any dummy password is allowed so far. use realm instead!
- leap_events.signal(IMAP_CLIENT_LOGIN, "1")
- return imap4.IAccount, self.theAccount, lambda: None
-
- def do_FETCH(self, tag, messages, query, uid=0):
- """
- Overwritten fetch dispatcher to use the fast fetch_flags
- method
- """
- from twisted.internet import reactor
- if not query:
- self.sendPositiveResponse(tag, 'FETCH complete')
- return # XXX ???
-
- cbFetch = self._IMAP4Server__cbFetch
- ebFetch = self._IMAP4Server__ebFetch
-
- if len(query) == 1 and str(query[0]) == "flags":
- self._oldTimeout = self.setTimeout(None)
- # no need to call iter, we get a generator
- maybeDeferred(
- self.mbox.fetch_flags, messages, uid=uid
- ).addCallback(
- cbFetch, tag, query, uid
- ).addErrback(ebFetch, tag)
- elif len(query) == 1 and str(query[0]) == "rfc822.header":
- self._oldTimeout = self.setTimeout(None)
- # no need to call iter, we get a generator
- maybeDeferred(
- self.mbox.fetch_headers, messages, uid=uid
- ).addCallback(
- cbFetch, tag, query, uid
- ).addErrback(ebFetch, tag)
- else:
- self._oldTimeout = self.setTimeout(None)
- # no need to call iter, we get a generator
- maybeDeferred(
- self.mbox.fetch, messages, uid=uid
- ).addCallback(
- cbFetch, tag, query, uid
- ).addErrback(
- ebFetch, tag)
-
- deferLater(reactor,
- 2, self.mbox.unset_recent_flags, messages)
- deferLater(reactor, 1, self.mbox.signal_unread_to_ui)
-
- select_FETCH = (do_FETCH, imap4.IMAP4Server.arg_seqset,
- imap4.IMAP4Server.arg_fetchatt)
-
- def do_COPY(self, tag, messages, mailbox, uid=0):
- from twisted.internet import reactor
- imap4.IMAP4Server.do_COPY(self, tag, messages, mailbox, uid)
- deferLater(reactor,
- 2, self.mbox.unset_recent_flags, messages)
- deferLater(reactor, 1, self.mbox.signal_unread_to_ui)
-
- select_COPY = (do_COPY, imap4.IMAP4Server.arg_seqset,
- imap4.IMAP4Server.arg_astring)
-
- def notifyNew(self, ignored):
- """
- Notify new messages to listeners.
- """
- self.mbox.notify_new()
-
- def _cbSelectWork(self, mbox, cmdName, tag):
- """
- Callback for selectWork, patched to avoid conformance errors due to
- incomplete UIDVALIDITY line.
- """
- if mbox is None:
- self.sendNegativeResponse(tag, 'No such mailbox')
- return
- if '\\noselect' in [s.lower() for s in mbox.getFlags()]:
- self.sendNegativeResponse(tag, 'Mailbox cannot be selected')
- return
-
- flags = mbox.getFlags()
- self.sendUntaggedResponse(str(mbox.getMessageCount()) + ' EXISTS')
- self.sendUntaggedResponse(str(mbox.getRecentCount()) + ' RECENT')
- self.sendUntaggedResponse('FLAGS (%s)' % ' '.join(flags))
-
- # Patched -------------------------------------------------------
- # imaptest was complaining about the incomplete line, we're adding
- # "UIDs valid" here.
- self.sendPositiveResponse(
- None, '[UIDVALIDITY %d] UIDs valid' % mbox.getUIDValidity())
- # ----------------------------------------------------------------
-
- s = mbox.isWriteable() and 'READ-WRITE' or 'READ-ONLY'
- mbox.addListener(self)
- self.sendPositiveResponse(tag, '[%s] %s successful' % (s, cmdName))
- self.state = 'select'
- self.mbox = mbox
-
-
class IMAPAuthRealm(object):
"""
Dummy authentication realm. Do not use in production!
@@ -288,6 +125,8 @@ def run_service(*args, **kwargs):
the reactor when starts listening, and the factory for
the protocol.
"""
+ from twisted.internet import reactor
+
leap_assert(len(args) == 2)
soledad, keymanager = args
leap_assert_type(soledad, Soledad)
@@ -302,8 +141,6 @@ def run_service(*args, **kwargs):
uuid = soledad._get_uuid()
factory = LeapIMAPFactory(uuid, userid, soledad)
- from twisted.internet import reactor
-
try:
tport = reactor.listenTCP(port, factory,
interface="localhost")
@@ -330,14 +167,3 @@ def run_service(*args, **kwargs):
# not ok, signal error.
leap_events.signal(IMAP_SERVICE_FAILED_TO_START, str(port))
-
- def checkpoint(self):
- """
- Called when the client issues a CHECK command.
-
- This should perform any checkpoint operations required by the server.
- It may be a long running operation, but may not block. If it returns
- a deferred, the client will only be informed of success (or failure)
- when the deferred's callback (or errback) is invoked.
- """
- return None