diff options
| -rw-r--r-- | mail/changes/bug_3937_fix_ui_freeze | 1 | ||||
| -rw-r--r-- | mail/src/leap/mail/smtp/gateway.py | 80 | 
2 files changed, 47 insertions, 34 deletions
| diff --git a/mail/changes/bug_3937_fix_ui_freeze b/mail/changes/bug_3937_fix_ui_freeze new file mode 100644 index 0000000..b91938c --- /dev/null +++ b/mail/changes/bug_3937_fix_ui_freeze @@ -0,0 +1 @@ +  o Uses deferToThread for sendMail. Closes #3937 diff --git a/mail/src/leap/mail/smtp/gateway.py b/mail/src/leap/mail/smtp/gateway.py index 7e9e420..f6366af 100644 --- a/mail/src/leap/mail/smtp/gateway.py +++ b/mail/src/leap/mail/smtp/gateway.py @@ -72,6 +72,7 @@ generator.Generator = RFC3156CompliantGenerator  LOCAL_FQDN = "bitmask.local" +  def validate_address(address):      """      Validate C{address} as defined in RFC 2822. @@ -98,6 +99,13 @@ def validate_address(address):  #  class SMTPHeloLocalhost(smtp.SMTP): +    """ +    An SMTP class that ensures a proper FQDN +    for localhost. + +    This avoids a problem in which unproperly configured providers +    would complain about the helo not being a fqdn. +    """      def __init__(self, *args):          smtp.SMTP.__init__(self, *args) @@ -388,21 +396,14 @@ class EncryptedMessage(object):          Handle end of message.          This method will encrypt and send the message. + +        :returns: a deferred          """          log.msg("Message data complete.")          self.lines.append('')  # add a trailing newline -        try: -            self._maybe_encrypt_and_sign() -            return self.sendMessage() -        except KeyNotFound: -            return None - -    def parseMessage(self): -        """ -        Separate message headers from body. -        """ -        parser = Parser() -        return parser.parsestr('\r\n'.join(self.lines)) +        d = deferToThread(self._maybe_encrypt_and_sign) +        d.addCallbacks(self.sendMessage, self.skipNoKeyErrBack) +        return d      def connectionLost(self):          """ @@ -414,12 +415,34 @@ class EncryptedMessage(object):          # unexpected loss of connection; don't save          self.lines = [] +    # ends IMessage implementation + +    def skipNoKeyErrBack(self, failure): +        """ +        Errback that ignores a KeyNotFound + +        :param failure: the failure +        :type Failure: Failure +        """ +        err = failure.value +        if failure.check(KeyNotFound): +            pass +        else: +            raise err + +    def parseMessage(self): +        """ +        Separate message headers from body. +        """ +        parser = Parser() +        return parser.parsestr('\r\n'.join(self.lines)) +      def sendQueued(self, r):          """          Callback for the queued message. -        @param r: The result from the last previous callback in the chain. -        @type r: anything +        :param r: The result from the last previous callback in the chain. +        :type r: anything          """          log.msg(r) @@ -445,35 +468,24 @@ class EncryptedMessage(object):          log.err(err)          raise err -    def sendMessage(self): +    def sendMessage(self, *args):          """          Sends the message. -        @return: A deferred with callbacks for error and success of this -            message send. -        @rtype: twisted.internet.defer.Deferred -        """ -        # FIXME this should not be blocking the main ui, since it returns -        # a deferred and it has its own cb set. ???! -        d = deferToThread(self._sendMessage) -        d.addCallbacks(self._route_msg, self.sendError) -        d.addCallbacks(self.sendQueued, self.sendError) -        return d -    def _sendMessage(self): +        :return: A deferred with callbacks for error and success of this +                 #message send. +        :rtype: twisted.internet.defer.Deferred          """ -        Send the message. - -        This method will prepare the message (headers and possibly encrypted -        body) -        """ -        msg = self._msg.as_string(False) -        return msg +        d = deferToThread(self._route_msg) +        d.addCallbacks(self.sendQueued, self.sendError) +        return -    def _route_msg(self, msg): +    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() | 
