def _route_msg(self): """ Sends the msg using the ESMTPSenderFactory. """ log.msg("Connecting to SMTP server %s:%s" % (self._host, self._port)) msg = self._msg.as_string(False) # we construct a defer to pass to the ESMTPSenderFactory d = defer.Deferred() d.addCallbacks(self.sendSuccess, self.sendError) # we don't pass an ssl context factory to the ESMTPSenderFactory # because ssl will be handled by reactor.connectSSL() below. factory = smtp.ESMTPSenderFactory( "", # username is blank because server does not use auth. "", # password is blank because server does not use auth. self._fromAddress.addrstr, self._user.dest.addrstr, StringIO(msg), d, heloFallback=True, requireAuthentication=False, requireTransportSecurity=True) factory.domain = __version__ signal(proto.SMTP_SEND_MESSAGE_START, self._user.dest.addrstr) reactor.connectSSL(self._host, self._port, factory, contextFactory=SSLContextFactory( self._cert, self._key))
def __cb_signal_unread_to_ui(self, unseen): """ Send the unread signal to UI. :param unseen: number of unseen messages. :type unseen: int """ leap_events.signal(IMAP_UNREAD_MAIL, str(unseen))
def _decrypt_doc(self, doc): """ Decrypt the contents of a document. :param doc: A document containing an encrypted message. :type doc: SoledadDocument :return: A tuple containing the document and the decrypted message. :rtype: (SoledadDocument, str) """ log.msg('decrypting msg') success = False try: decrdata = self._keymanager.decrypt( doc.content[ENC_JSON_KEY], self._pkey) success = True except Exception as exc: # XXX move this to errback !!! logger.error("Error while decrypting msg: %r" % (exc,)) decrdata = "" leap_events.signal(IMAP_MSG_DECRYPTED, "1" if success else "0") data = self._process_decrypted_doc((doc, decrdata)) return (doc, data)
def _route_msg(self): """ Sends the msg using the ESMTPSenderFactory. """ log.msg("Connecting to SMTP server %s:%s" % (self._host, self._port)) msg = self._msg.as_string(False) # we construct a defer to pass to the ESMTPSenderFactory d = defer.Deferred() d.addCallbacks(self.sendSuccess, self.sendError) # we don't pass an ssl context factory to the ESMTPSenderFactory # because ssl will be handled by reactor.connectSSL() below. factory = smtp.ESMTPSenderFactory( "", # username is blank because server does not use auth. "", # password is blank because server does not use auth. self._fromAddress.addrstr, self._user.dest.addrstr, StringIO(msg), d, heloFallback=True, requireAuthentication=False, requireTransportSecurity=True) factory.domain = __version__ signal(proto.SMTP_SEND_MESSAGE_START, self._user.dest.addrstr) reactor.connectSSL( self._host, self._port, factory, contextFactory=SSLContextFactory(self._cert, self._key))
def send_key(self, ktype): """ Send user's key of type C{ktype} to provider. Public key bound to user's is sent to provider, which will sign it and replace any prior keys for the same address in its database. If C{send_private} is True, then the private key is encrypted with C{password} and sent to server in the same request, together with a hash string of user's address and password. The encrypted private key will be saved in the server in a way it is publicly retrievable through the hash string. :param ktype: The type of the key. :type ktype: KeyType @raise KeyNotFound: If the key was not found in local database. """ leap_assert( ktype is OpenPGPKey, 'For now we only know how to send OpenPGP public keys.') # prepare the public key bound to address pubkey = self.get_key( self._address, ktype, private=False, fetch_remote=False) data = { self.PUBKEY_KEY: pubkey.key_data } uri = "%s/%s/users/%s.json" % ( self._api_uri, self._api_version, self._uid) self._put(uri, data) signal(proto.KEYMANAGER_DONE_UPLOADING_KEYS, self._address)
def connectionLost(self): """ Log an error when the connection is lost. """ log.msg("Connection lost unexpectedly!") log.err() signal(proto.SMTP_CONNECTION_LOST, self._user.dest.addrstr) # unexpected loss of connection; don't save self.lines = []
def sendSuccess(self, r): """ Callback for a successful send. :param r: The result from the last previous callback in the chain. :type r: anything """ log.msg(r) signal(proto.SMTP_SEND_MESSAGE_SUCCESS, self._user.dest.addrstr)
def sendError(self, failure): """ Callback for an unsuccessfull send. :param e: The result from the last errback. :type e: anything """ signal(proto.SMTP_SEND_MESSAGE_ERROR, self._user.dest.addrstr) err = failure.value log.err(err) raise err
def setup_smtp_relay(port, keymanager, smtp_host, smtp_port, smtp_cert, smtp_key, encrypted_only): """ Setup SMTP relay to run with Twisted. This function sets up the SMTP relay configuration and the Twisted reactor. @param port: The port in which to run the server. @type port: int @param keymanager: A Key Manager from where to get recipients' public keys. @type keymanager: leap.common.keymanager.KeyManager @param smtp_host: The hostname of the remote SMTP server. @type smtp_host: str @param smtp_port: The port of the remote SMTP server. @type smtp_port: int @param smtp_cert: The client certificate for authentication. @type smtp_cert: str @param smtp_key: The client key for authentication. @type smtp_key: str @param encrypted_only: Whether the SMTP relay should send unencrypted mail or not. @type encrypted_only: bool """ # The configuration for the SMTP relay is a dict with the following # format: # # { # 'host': '<host>', # 'port': <int>, # 'cert': '<cert path>', # 'key': '<key path>', # 'encrypted_only': <True/False> # } config = { 'host': smtp_host, 'port': smtp_port, 'cert': smtp_cert, 'key': smtp_key, 'encrypted_only': encrypted_only } # configure the use of this service with twistd factory = SMTPFactory(keymanager, config) try: reactor.listenTCP(port, factory) signal(proto.SMTP_SERVICE_STARTED, str(smtp_port)) except CannotListenError: logger.error("STMP Service failed to start: " "cannot listen in port %s" % ( smtp_port,)) signal(proto.SMTP_SERVICE_FAILED_TO_START, str(smtp_port))
def _decrypt_msg(self, doc, encdata): log.msg('decrypting msg') key = self._pkey try: decrdata = (self._keymanager.decrypt( encdata, key, passphrase=self._soledad.passphrase)) ok = True except Exception as exc: # XXX move this to errback !!! logger.warning("Error while decrypting msg: %r" % (exc,)) decrdata = "" ok = False leap_events.signal(IMAP_MSG_DECRYPTED, "1" if ok else "0") return doc, decrdata
def gen_key(self, ktype): """ Generate a key of type C{ktype} bound to the user's address. :param ktype: The type of the key. :type ktype: KeyType :return: The generated key. :rtype: EncryptionKey """ signal(proto.KEYMANAGER_STARTED_KEY_GENERATION, self._address) key = self._wrapper_map[ktype].gen_key(self._address) signal(proto.KEYMANAGER_FINISHED_KEY_GENERATION, self._address) return key
def _signal_fetch_to_ui(self, doclist): """ Sends leap events to ui. :param doclist: iterable with msg documents. :type doclist: iterable. :returns: doclist :rtype: iterable """ fetched_ts = time.mktime(time.gmtime()) num_mails = len(doclist) log.msg("there are %s mails" % (num_mails,)) leap_events.signal( IMAP_FETCHED_INCOMING, str(num_mails), str(fetched_ts)) self._signal_unread_to_ui() return doclist
def _sync_soledad(self): """ Synchronize with remote soledad. :returns: a list of LeapDocuments, or None. :rtype: iterable or None """ with self.fetching_lock: try: log.msg('FETCH: syncing soledad...') self._soledad.sync() log.msg('FETCH soledad SYNCED.') except InvalidAuthTokenError: # if the token is invalid, send an event so the GUI can # disable mail and show an error message. leap_events.signal(SOLEDAD_INVALID_AUTH_TOKEN)
def test_component_send_signal(self): """ Ensure components can send signals. """ sig = 8 response = events.signal(sig) self.assertTrue(response.status == response.OK, 'Received wrong response status when signaling.')
def test_client_send_signal(self): """ Ensure clients can send signals. """ sig = 8 response = events.signal(sig) self.assertTrue(response.status == response.OK, 'Received wrong response status when signaling.')
def _add_message_locally(self, msgtuple): """ Adds a message to local inbox and delete it from the incoming db in soledad. :param msgtuple: a tuple consisting of a SoledadDocument instance containing the incoming message and data, the json-encoded, decrypted content of the incoming message :type msgtuple: (SoledadDocument, str) """ doc, data = msgtuple self._inbox.addMessage(data, (self.RECENT_FLAG,)) leap_events.signal(IMAP_MSG_SAVED_LOCALLY) doc_id = doc.doc_id self._soledad.delete_doc(doc) log.msg("deleted doc %s from incoming" % doc_id) leap_events.signal(IMAP_MSG_DELETED_INCOMING)
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 _signal_fetch_to_ui(self, doclist): """ Send leap events to ui. :param doclist: iterable with msg documents. :type doclist: iterable. :returns: doclist :rtype: iterable """ doclist = first(doclist) # gatherResults pass us a list if doclist: fetched_ts = time.mktime(time.gmtime()) num_mails = len(doclist) if doclist is not None else 0 if num_mails != 0: log.msg("there are %s mails" % (num_mails,)) leap_events.signal( IMAP_FETCHED_INCOMING, str(num_mails), str(fetched_ts)) return doclist
def _process_doclist(self, doclist): """ Iterates through the doclist, checks if each doc looks like a message, and yields a deferred that will decrypt and process the message. :param doclist: iterable with msg documents. :type doclist: iterable. :returns: a list of deferreds for individual messages. """ log.msg('processing doclist') if not doclist: logger.debug("no docs found") return num_mails = len(doclist) for index, doc in enumerate(doclist): logger.debug("processing doc %d of %d" % (index + 1, num_mails)) leap_events.signal( IMAP_MSG_PROCESSING, str(index), str(num_mails)) keys = doc.content.keys() # TODO Compatibility check with the index in pre-0.6 mx # that does not write the ERROR_DECRYPTING_KEY # This should be removed in 0.7 has_errors = doc.content.get(fields.ERROR_DECRYPTING_KEY, None) if has_errors is None: warnings.warn("JUST_MAIL_COMPAT_IDX will be deprecated!", DeprecationWarning) if has_errors: logger.debug("skipping msg with decrypting errors...") if self._is_msg(keys) and not has_errors: # Evaluating to bool of has_errors is intentional here. # We don't mind at this point if it's None or False. # Ok, this looks like a legit msg, and with no errors. # Let's process it! d1 = self._decrypt_doc(doc) d = defer.gatherResults([d1], consumeErrors=True) d.addCallbacks(self._add_message_locally, self._errback)
def get_key(self, address, ktype, private=False, fetch_remote=True): """ Return a key of type C{ktype} bound to C{address}. First, search for the key in local storage. If it is not available, then try to fetch from nickserver. :param address: The address bound to the key. :type address: str :param ktype: The type of the key. :type ktype: KeyType :param private: Look for a private key instead of a public one? :type private: bool :return: A key of type C{ktype} bound to C{address}. :rtype: EncryptionKey @raise KeyNotFound: If the key was not found both locally and in keyserver. """ leap_assert( ktype in self._wrapper_map, 'Unkown key type: %s.' % str(ktype)) try: signal(proto.KEYMANAGER_LOOKING_FOR_KEY, address) # return key if it exists in local database key = self._wrapper_map[ktype].get_key(address, private=private) signal(proto.KEYMANAGER_KEY_FOUND, address) return key except KeyNotFound: signal(proto.KEYMANAGER_KEY_NOT_FOUND, address) # we will only try to fetch a key from nickserver if fetch_remote # is True and the key is not private. if fetch_remote is False or private is True: raise signal(proto.KEYMANAGER_LOOKING_FOR_KEY, address) self._fetch_keys_from_server(address) key = self._wrapper_map[ktype].get_key(address, private=False) signal(proto.KEYMANAGER_KEY_FOUND, address) return key
def setup_smtp_gateway(port, userid, keymanager, smtp_host, smtp_port, smtp_cert, smtp_key, encrypted_only): """ Setup SMTP gateway to run with Twisted. This function sets up the SMTP gateway configuration and the Twisted reactor. :param port: The port in which to run the server. :type port: int :param userid: The user currently logged in :type userid: unicode :param keymanager: A Key Manager from where to get recipients' public keys. :type keymanager: leap.common.keymanager.KeyManager :param smtp_host: The hostname of the remote SMTP server. :type smtp_host: str :param smtp_port: The port of the remote SMTP server. :type smtp_port: int :param smtp_cert: The client certificate for authentication. :type smtp_cert: str :param smtp_key: The client key for authentication. :type smtp_key: str :param encrypted_only: Whether the SMTP gateway should send unencrypted mail or not. :type encrypted_only: bool :returns: tuple of SMTPFactory, twisted.internet.tcp.Port """ # configure the use of this service with twistd factory = SMTPFactory(userid, keymanager, smtp_host, smtp_port, smtp_cert, smtp_key, encrypted_only) try: tport = reactor.listenTCP(port, factory, interface="localhost") signal(proto.SMTP_SERVICE_STARTED, str(port)) return factory, tport except CannotListenError: logger.error("STMP Service failed to start: " "cannot listen in port %s" % port) signal(proto.SMTP_SERVICE_FAILED_TO_START, str(port)) except Exception as exc: logger.error("Unhandled error while launching smtp gateway service") logger.exception(exc)
def run_service(*args, **kwargs): """ Main entry point to run the service from the client. :returns: the LoopingCall instance that will have to be stoppped before shutting down the client. """ leap_assert(len(args) == 2) soledad, keymanager = args leap_assert_type(soledad, Soledad) leap_assert_type(keymanager, KeyManager) port = kwargs.get('port', IMAP_PORT) check_period = kwargs.get('check_period', INCOMING_CHECK_PERIOD) uuid = soledad._get_uuid() factory = LeapIMAPFactory(uuid, soledad) from twisted.internet import reactor try: reactor.listenTCP(port, factory, interface="localhost") fetcher = LeapIncomingMail( keymanager, soledad, factory.theAccount, check_period) except CannotListenError: logger.error("IMAP Service failed to start: " "cannot listen in port %s" % (port,)) except Exception as exc: logger.error("Error launching IMAP service: %r" % (exc,)) else: # all good. fetcher.start_loop() logger.debug("IMAP4 Server is RUNNING in port %s" % (port,)) leap_events.signal(IMAP_SERVICE_STARTED, str(port)) return fetcher # not ok, signal error. leap_events.signal(IMAP_SERVICE_FAILED_TO_START, str(port))
def test_async_register(self): """ Test asynchronous registering of callbacks. """ flag = Mock() # executed after async register, when response is received from server def reqcbk(request, response): flag(request.event, response.status) # callback registered by application def callback(request): pass # passing a callback as reqcbk param makes the call asynchronous result = events.register(CLIENT_UID, callback, reqcbk=reqcbk) self.assertIsNone(result) events.signal(CLIENT_UID) time.sleep(1) # wait for signal to arrive from server flag.assert_called_once_with(CLIENT_UID, EventResponse.OK)
def run(self): """ Check for updates periodically """ if not self.mirrors: return while True: try: tuf.conf.repository_directory = os.path.join( self.bundle_path, 'repo') updater = tuf.client.updater.Updater('leap-updater', self.mirrors) updater.refresh() targets = updater.all_targets() updated_targets = updater.updated_targets( targets, self.source_path) if updated_targets: print "There is updates needed. Start downloading updates." for target in updated_targets: updater.download_target(target, self.dest_path) self._set_permissions(target) if os.path.isdir(self.dest_path): if os.path.isdir(self.update_path): shutil.rmtree(self.update_path) shutil.move(self.dest_path, self.update_path) filepath = sorted([f['filepath'] for f in updated_targets]) signal(proto.UPDATER_NEW_UPDATES, content=", ".join(filepath)) print "Updates ready: ", filepath return except NotImplemented as e: print "NotImplemented: ", e return except Exception as e: print "ERROR:", e finally: time.sleep(self.delay)
def _process_doclist(self, doclist): """ Iterates through the doclist, checks if each doc looks like a message, and yields a deferred that will decrypt and process the message. :param doclist: iterable with msg documents. :type doclist: iterable. :returns: a list of deferreds for individual messages. """ log.msg('processing doclist') if not doclist: logger.debug("no docs found") return num_mails = len(doclist) docs_cb = [] for index, doc in enumerate(doclist): logger.debug("processing doc %d of %d: %s" % ( index, num_mails, doc)) leap_events.signal( IMAP_MSG_PROCESSING, str(index), str(num_mails)) keys = doc.content.keys() if self._is_msg(keys): # Ok, this looks like a legit msg. # Let's process it! encdata = doc.content[ENC_JSON_KEY] # Deferred chain for individual messages d = deferToThread(self._decrypt_msg, doc, encdata) d.addCallback(self._process_decrypted) d.addCallback(self._add_message_locally) docs_cb.append(d) else: # Ooops, this does not. logger.debug('This does not look like a proper msg.') return docs_cb
def validateTo(self, user): """ Validate the address of C{user}, a recipient of the message. This method is called once for each recipient and validates the C{user}'s address against the RFC 2822 definition. If the configuration option ENCRYPTED_ONLY_KEY is True, it also asserts the existence of the user's key. In the end, it returns an encrypted message object that is able to send itself to the C{user}'s address. :param user: The user whose address we wish to validate. :type: twisted.mail.smtp.User @return: A Deferred which becomes, or a callable which takes no arguments and returns an object implementing IMessage. This will be called and the returned object used to deliver the message when it arrives. @rtype: no-argument callable @raise SMTPBadRcpt: Raised if messages to the address are not to be accepted. """ # try to find recipient's public key try: address = validate_address(user.dest.addrstr) # verify if recipient key is available in keyring self._km.get_key(address, OpenPGPKey) # might raise KeyNotFound log.msg("Accepting mail for %s..." % user.dest.addrstr) signal(proto.SMTP_RECIPIENT_ACCEPTED_ENCRYPTED, user.dest.addrstr) except KeyNotFound: # if key was not found, check config to see if will send anyway. if self._encrypted_only: signal(proto.SMTP_RECIPIENT_REJECTED, user.dest.addrstr) raise smtp.SMTPBadRcpt(user.dest.addrstr) log.msg("Warning: will send an unencrypted message (because " "encrypted_only' is set to False).") signal( proto.SMTP_RECIPIENT_ACCEPTED_UNENCRYPTED, user.dest.addrstr) return lambda: EncryptedMessage( self._origin, user, self._km, self._host, self._port, self._cert, self._key)
def validateTo(self, user): """ Validate the address of C{user}, a recipient of the message. This method is called once for each recipient and validates the C{user}'s address against the RFC 2822 definition. If the configuration option ENCRYPTED_ONLY_KEY is True, it also asserts the existence of the user's key. In the end, it returns an encrypted message object that is able to send itself to the C{user}'s address. :param user: The user whose address we wish to validate. :type: twisted.mail.smtp.User @return: A Deferred which becomes, or a callable which takes no arguments and returns an object implementing IMessage. This will be called and the returned object used to deliver the message when it arrives. @rtype: no-argument callable @raise SMTPBadRcpt: Raised if messages to the address are not to be accepted. """ # try to find recipient's public key try: address = validate_address(user.dest.addrstr) # verify if recipient key is available in keyring self._km.get_key(address, OpenPGPKey) # might raise KeyNotFound log.msg("Accepting mail for %s..." % user.dest.addrstr) signal(proto.SMTP_RECIPIENT_ACCEPTED_ENCRYPTED, user.dest.addrstr) except KeyNotFound: # if key was not found, check config to see if will send anyway. if self._encrypted_only: signal(proto.SMTP_RECIPIENT_REJECTED, user.dest.addrstr) raise smtp.SMTPBadRcpt(user.dest.addrstr) log.msg("Warning: will send an unencrypted message (because " "encrypted_only' is set to False).") signal(proto.SMTP_RECIPIENT_ACCEPTED_UNENCRYPTED, user.dest.addrstr) return lambda: EncryptedMessage(self._origin, user, self._km, self. _host, self._port, self._cert, self. _key)
def _signal_unread_to_ui(self): """ Sends unread event to ui. """ leap_events.signal( IMAP_UNREAD_MAIL, str(self.getUnseenCount()))
def _maybe_encrypt_and_sign(self): """ Attempt to encrypt and sign the outgoing message. The behaviour of this method depends on: 1. the original message's content-type, and 2. the availability of the recipient's public key. If the original message's content-type is "multipart/encrypted", then the original message is not altered. For any other content-type, the method attempts to fetch the recipient's public key. If the recipient's public key is available, the message is encrypted and signed; otherwise it is only signed. Note that, if the C{encrypted_only} configuration is set to True and the recipient's public key is not available, then the recipient address would have been rejected in SMTPDelivery.validateTo(). The following table summarizes the overall behaviour of the gateway: +---------------------------------------------------+----------------+ | content-type | rcpt pubkey | enforce encr. | action | +---------------------+-------------+---------------+----------------+ | multipart/encrypted | any | any | pass | | other | available | any | encrypt + sign | | other | unavailable | yes | reject | | other | unavailable | no | sign | +---------------------+-------------+---------------+----------------+ """ # pass if the original message's content-type is "multipart/encrypted" self._origmsg = self.parseMessage() if self._origmsg.get_content_type() == 'multipart/encrypted': self._msg = self._origmsg return from_address = validate_address(self._fromAddress.addrstr) username, domain = from_address.split('@') # add a nice footer to the outgoing message if self._origmsg.get_content_type() == 'text/plain': self.lines.append('--') self.lines.append('%s - https://%s/key/%s' % (self.FOOTER_STRING, domain, username)) self.lines.append('') self._origmsg = self.parseMessage() # get sender and recipient data signkey = self._km.get_key(from_address, OpenPGPKey, private=True) log.msg("Will sign the message with %s." % signkey.fingerprint) to_address = validate_address(self._user.dest.addrstr) try: # try to get the recipient pubkey pubkey = self._km.get_key(to_address, OpenPGPKey) log.msg("Will encrypt the message to %s." % pubkey.fingerprint) signal(proto.SMTP_START_ENCRYPT_AND_SIGN, "%s,%s" % (self._fromAddress.addrstr, to_address)) self._encrypt_and_sign(pubkey, signkey) signal(proto.SMTP_END_ENCRYPT_AND_SIGN, "%s,%s" % (self._fromAddress.addrstr, to_address)) except KeyNotFound: # at this point we _can_ send unencrypted mail, because if the # configuration said the opposite the address would have been # rejected in SMTPDelivery.validateTo(). log.msg('Will send unencrypted message to %s.' % to_address) signal(proto.SMTP_START_SIGN, self._fromAddress.addrstr) self._sign(signkey) signal(proto.SMTP_END_SIGN, self._fromAddress.addrstr)
def msgSavedCallback(result): if not empty(result): leap_events.signal(IMAP_MSG_SAVED_LOCALLY) deferLater(reactor, 0, self._delete_incoming_message, doc) leap_events.signal(IMAP_MSG_DELETED_INCOMING)
def _signal_unread_to_ui(self, *args): """ Sends unread event to ui. """ leap_events.signal( IMAP_UNREAD_MAIL, str(self._inbox.getUnseenCount()))
def run_service(*args, **kwargs): """ Main entry point to run the service from the client. :returns: the LoopingCall instance that will have to be stoppped before shutting down the client, the port as returned by the reactor when starts listening, and the factory for the protocol. """ from twisted.internet import reactor # it looks like qtreactor does not honor this, # but other reactors should. reactor.suggestThreadPoolSize(20) leap_assert(len(args) == 2) soledad, keymanager = args leap_assert_type(soledad, Soledad) leap_assert_type(keymanager, KeyManager) port = kwargs.get('port', IMAP_PORT) check_period = kwargs.get('check_period', INCOMING_CHECK_PERIOD) userid = kwargs.get('userid', None) leap_check(userid is not None, "need an user id") offline = kwargs.get('offline', False) uuid = soledad._get_uuid() factory = LeapIMAPFactory(uuid, userid, soledad) try: tport = reactor.listenTCP(port, factory, interface="localhost") if not offline: fetcher = LeapIncomingMail( keymanager, soledad, factory.theAccount, check_period, userid) else: fetcher = None except CannotListenError: logger.error("IMAP Service failed to start: " "cannot listen in port %s" % (port,)) except Exception as exc: logger.error("Error launching IMAP service: %r" % (exc,)) else: # all good. # (the caller has still to call fetcher.start_loop) if DO_MANHOLE: # TODO get pass from env var.too. manhole_factory = manhole.getManholeFactory( {'f': factory, 'a': factory.theAccount, 'gm': factory.theAccount.getMailbox}, "boss", "leap") reactor.listenTCP(manhole.MANHOLE_PORT, manhole_factory, interface="127.0.0.1") logger.debug("IMAP4 Server is RUNNING in port %s" % (port,)) leap_events.signal(IMAP_SERVICE_STARTED, str(port)) return fetcher, tport, factory # not ok, signal error. leap_events.signal(IMAP_SERVICE_FAILED_TO_START, str(port))
def authenticateLogin(self, username, password): # all is allowed so far. use realm instead leap_events.signal(IMAP_CLIENT_LOGIN, "1") return imap4.IAccount, self.theAccount, lambda: None