diff --git a/src/calibre/utils/smtp.py b/src/calibre/utils/smtp.py index 5455b9896c..4bbd421075 100644 --- a/src/calibre/utils/smtp.py +++ b/src/calibre/utils/smtp.py @@ -12,6 +12,7 @@ This module implements a simple commandline SMTP client that supports: import sys, traceback, os, socket, encodings.idna as idna from calibre import isbytestring, force_unicode +from calibre.constants import ispy3 def safe_localhost(): @@ -24,7 +25,7 @@ def safe_localhost(): # https://bugs.launchpad.net/bugs/1256549 try: local_hostname = idna.ToASCII(force_unicode(fqdn)) - except: + except Exception: local_hostname = 'localhost.localdomain' else: # We can't find an fqdn hostname, so use a domain literal @@ -104,7 +105,7 @@ def get_mx(host, verbose=0): def sendmail_direct(from_, to, msg, timeout, localhost, verbose, debug_output=None): - import calibre.utils.smtplib as smtplib + import polyglot.smtplib as smtplib hosts = get_mx(to.split('@')[-1].strip(), verbose) timeout=None # Non blocking sockets sometimes don't work kwargs = dict(timeout=timeout, local_hostname=localhost or safe_localhost()) @@ -133,7 +134,7 @@ def sendmail(msg, from_, to, localhost=None, verbose=0, timeout=None, if relay is None: for x in to: return sendmail_direct(from_, x, msg, timeout, localhost, verbose) - import calibre.utils.smtplib as smtplib + import polyglot.smtplib as smtplib cls = smtplib.SMTP_SSL if encryption == 'SSL' else smtplib.SMTP timeout = None # Non-blocking sockets sometimes don't work port = int(port) @@ -153,7 +154,7 @@ def sendmail(msg, from_, to, localhost=None, verbose=0, timeout=None, s.starttls(context=context) s.ehlo() if username is not None and password is not None: - if encryption == 'SSL': + if encryption == 'SSL' and not ispy3: s.sock = s.file.sslobj s.login(username, password) ret = None diff --git a/src/calibre/utils/smtplib.py b/src/calibre/utils/smtplib.py index b15bc6988c..42ff37d3b0 100755 --- a/src/calibre/utils/smtplib.py +++ b/src/calibre/utils/smtplib.py @@ -48,7 +48,7 @@ import re import email.utils import base64 import hmac -from email.base64mime import encode as encode_base64 +from email.base64mime import body_encode as encode_base64 from sys import stderr from functools import partial @@ -282,7 +282,7 @@ class SMTP: # if that can't be calculated, that we should use a domain literal # instead (essentially an encoded IP address like [A.B.C.D]). fqdn = socket.getfqdn() - if '.' in fqdn and fqdn != '.': # Changed by Kovid + if '.' in fqdn: self.local_hostname = fqdn else: # We can't find an fqdn hostname, so use a domain literal @@ -345,11 +345,6 @@ class SMTP: """Send `str' to the server.""" if self.debuglevel > 0: raw = repr(str) - if self.debuglevel < 2: - if len(raw) > 100: - raw = raw[:100] + '...' - if 'AUTH' in raw: - raw = 'AUTH ' self.debug('send:', raw) if hasattr(self, 'sock') and self.sock: try: diff --git a/src/polyglot/smtplib.py b/src/polyglot/smtplib.py new file mode 100644 index 0000000000..0ee340a85f --- /dev/null +++ b/src/polyglot/smtplib.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python2 +# vim:fileencoding=utf-8 +# License: GPL v3 Copyright: 2019, Kovid Goyal + +from __future__ import absolute_import, division, print_function, unicode_literals + +import sys +from functools import partial + +from polyglot.builtins import is_py3 + + +class FilteredLog(object): + + ' Hide AUTH credentials from the log ' + + def __init__(self, debug_to=None): + self.debug_to = debug_to or partial(print, file=sys.stderr) + + def __call__(self, *a): + if a and len(a) == 2 and a[0] == 'send:': + a = list(a) + raw = a[1] + if len(raw) > 100: + raw = raw[:100] + (b'...' if isinstance(raw, bytes) else '...') + q = b'AUTH ' if isinstance(raw, bytes) else 'AUTH ' + if q in raw: + raw = 'AUTH ' + a[1] = raw + self.debug_to(*a) + + +if is_py3: + import smtplib + + class SMTP(smtplib.SMTP): + + def __init__(self, *a, **kw): + self.debug_to = FilteredLog(kw.pop('debug_to', None)) + super().__init__(*a, **kw) + + def _print_debug(self, *a): + if self.debug_to is not None: + self.debug_to(*a) + else: + super()._print_debug(*a) + + class SMTP_SSL(smtplib.SMTP_SSL): + + def __init__(self, *a, **kw): + self.debug_to = FilteredLog(kw.pop('debug_to', None)) + super().__init__(*a, **kw) + + def _print_debug(self, *a): + if self.debug_to is not None: + self.debug_to(*a) + else: + super()._print_debug(*a) + +else: + import calibre.utils.smtplib as smtplib + + class SMTP(smtplib.SMTP): + + def __init__(self, *a, **kw): + kw['debug_to'] = FilteredLog(kw.get('debug_to')) + smtplib.SMTP.__init__(self, *a, **kw) + + class SMTP_SSL(smtplib.SMTP_SSL): + + def __init__(self, *a, **kw): + kw['debug_to'] = FilteredLog(kw.get('debug_to')) + smtplib.SMTP_SSL.__init__(self, *a, **kw)