summaryrefslogtreecommitdiff
path: root/src/leap/mail/imap/service
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap/mail/imap/service')
-rw-r--r--src/leap/mail/imap/service/imap-server.tac182
-rw-r--r--src/leap/mail/imap/service/imap.py37
2 files changed, 170 insertions, 49 deletions
diff --git a/src/leap/mail/imap/service/imap-server.tac b/src/leap/mail/imap/service/imap-server.tac
index da72cae..b65bb17 100644
--- a/src/leap/mail/imap/service/imap-server.tac
+++ b/src/leap/mail/imap/service/imap-server.tac
@@ -1,69 +1,157 @@
+# -*- coding: utf-8 -*-
+# imap-server.tac
+# Copyright (C) 2013,2014 LEAP
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+TAC file for initialization of the imap service using twistd.
+
+Use this for debugging and testing the imap server using a native reactor.
+
+For now, and for debugging/testing purposes, you need
+to pass a config file with the following structure:
+
+[leap_mail]
+userid = "user@provider"
+uuid = "deadbeefdeadabad"
+passwd = "supersecret" # optional, will get prompted if not found.
+"""
import ConfigParser
+import getpass
import os
+import sys
-from leap.soledad.client import Soledad
+from leap.keymanager import KeyManager
from leap.mail.imap.service import imap
-from leap.common.config import get_path_prefix
-
-
-config = ConfigParser.ConfigParser()
-config.read([os.path.expanduser('~/.config/leap/mail/mail.conf')])
-
-userID = config.get('mail', 'address')
-privkey = open(os.path.expanduser('~/.config/leap/mail/privkey')).read()
-nickserver_url = ""
+from leap.soledad.client import Soledad
-d = {}
+from twisted.application import service, internet
-for key in ('uid', 'passphrase', 'server', 'pemfile', 'token'):
- d[key] = config.get('mail', key)
+# TODO should get this initializers from some authoritative mocked source
+# We might want to put them the soledad itself.
-def initialize_soledad_mailbox(user_uuid, soledad_pass, server_url,
- server_pemfile, token):
+def initialize_soledad(uuid, email, passwd,
+ secrets, localdb,
+ gnupg_home, tempdir):
"""
Initializes soledad by hand
- :param user_uuid:
- :param soledad_pass:
- :param server_url:
- :param server_pemfile:
- :param token:
-
+ :param email: ID for the user
+ :param gnupg_home: path to home used by gnupg
+ :param tempdir: path to temporal dir
:rtype: Soledad instance
"""
+ # XXX TODO unify with an authoritative source of mocks
+ # for soledad (or partial initializations).
+ # This is copied from the imap tests.
+
+ server_url = "http://provider"
+ cert_file = ""
- base_config = get_path_prefix()
+ class Mock(object):
+ def __init__(self, return_value=None):
+ self._return = return_value
- secret_path = os.path.join(
- base_config, "leap", "soledad", "%s.secret" % user_uuid)
- soledad_path = os.path.join(
- base_config, "leap", "soledad", "%s-mailbox.db" % user_uuid)
+ def __call__(self, *args, **kwargs):
+ return self._return
- _soledad = Soledad(
- user_uuid,
- soledad_pass,
- secret_path,
- soledad_path,
+ class MockSharedDB(object):
+
+ get_doc = Mock()
+ put_doc = Mock()
+ lock = Mock(return_value=('atoken', 300))
+ unlock = Mock(return_value=True)
+
+ def __call__(self):
+ return self
+
+ Soledad._shared_db = MockSharedDB()
+ soledad = Soledad(
+ uuid,
+ passwd,
+ secrets,
+ localdb,
server_url,
- server_pemfile,
- token)
+ cert_file)
+
+ return soledad
+
+######################################################################
+# Remember to set your config files, see module documentation above!
+######################################################################
+
+print "[+] Running LEAP IMAP Service"
+
+
+bmconf = os.environ.get("LEAP_MAIL_CONF", "")
+if not bmconf:
+ print "[-] Please set LEAP_MAIL_CONF environment variable pointing to your config."
+ sys.exit(1)
+SECTION = "leap_mail"
+cp = ConfigParser.ConfigParser()
+cp.read(bmconf)
+
+userid = cp.get(SECTION, "userid")
+uuid = cp.get(SECTION, "uuid")
+passwd = unicode(cp.get(SECTION, "passwd"))
+
+# XXX get this right from the environment variable !!!
+port = 1984
+
+if not userid or not uuid:
+ print "[-] Config file missing userid or uuid field"
+ sys.exit(1)
+
+if not passwd:
+ passwd = unicode(getpass.getpass("Soledad passphrase: "))
+
+
+secrets = os.path.expanduser("~/.config/leap/soledad/%s.secret" % (uuid,))
+localdb = os.path.expanduser("~/.config/leap/soledad/%s.db" % (uuid,))
+
+# XXX Is this really used? Should point it to user var dirs defined in xdg?
+gnupg_home = "/tmp/"
+tempdir = "/tmp/"
+
+###################################################
+
+# Ad-hoc soledad/keymanager initialization.
+
+soledad = initialize_soledad(uuid, userid, passwd, secrets, localdb, gnupg_home, tempdir)
+km_args = (userid, "https://localhost", soledad)
+km_kwargs = {
+ "session_id": "",
+ "ca_cert_path": "",
+ "api_uri": "",
+ "api_version": "",
+ "uid": uuid,
+ "gpgbinary": "/usr/bin/gpg"
+}
+keymanager = KeyManager(*km_args, **km_kwargs)
+
+##################################################
- return _soledad
+# Ok, let's expose the application object for the twistd application
+# framework to pick up from here...
-soledad = initialize_soledad_mailbox(
- d['uid'],
- d['passphrase'],
- d['server'],
- d['pemfile'],
- d['token'])
-# import the private key ---- should sync it from remote!
-from leap.common.keymanager.openpgp import OpenPGPScheme
-opgp = OpenPGPScheme(soledad)
-opgp.put_ascii_key(privkey)
+def getIMAPService():
+ factory = imap.LeapIMAPFactory(uuid, userid, soledad)
+ return internet.TCPServer(port, factory, interface="localhost")
-from leap.common.keymanager import KeyManager
-keymanager = KeyManager(userID, nickserver_url, soledad, d['token'])
-imap.run_service(soledad, keymanager)
+application = service.Application("LEAP IMAP Application")
+service = getIMAPService()
+service.setServiceParent(application)
diff --git a/src/leap/mail/imap/service/imap.py b/src/leap/mail/imap/service/imap.py
index c48e5c5..e877869 100644
--- a/src/leap/mail/imap/service/imap.py
+++ b/src/leap/mail/imap/service/imap.py
@@ -22,6 +22,7 @@ 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.mail import imap4
from twisted.python import log
@@ -78,7 +79,6 @@ class LeapIMAPServer(imap4.IMAP4Server):
:param line: the line from the server, without the line delimiter.
:type line: str
"""
- print "RECV: STATE (%s)" % self.state
if self.theAccount.closed is True and self.state != "unauth":
log.msg("Closing the session. State: unauth")
self.state = "unauth"
@@ -89,7 +89,7 @@ class LeapIMAPServer(imap4.IMAP4Server):
msg = line[:7] + " [...]"
else:
msg = copy(line)
- log.msg('rcv: %s' % msg)
+ log.msg('rcv (%s): %s' % (self.state, msg))
imap4.IMAP4Server.lineReceived(self, line)
def authenticateLogin(self, username, password):
@@ -111,6 +111,39 @@ class LeapIMAPServer(imap4.IMAP4Server):
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
+ """
+ log.msg("LEAP Overwritten fetch...")
+ if not query:
+ self.sendPositiveResponse(tag, 'FETCH complete')
+ return # XXX ???
+
+ cbFetch = self._IMAP4Server__cbFetch
+ ebFetch = self._IMAP4Server__ebFetch
+
+ if 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)
+ 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)
+
+ select_FETCH = (do_FETCH, imap4.IMAP4Server.arg_seqset,
+ imap4.IMAP4Server.arg_fetchatt)
+
class IMAPAuthRealm(object):
"""