# HG changeset patch # User Matt Harbison # Date 1618867617 14400 # Node ID 83c0d144ef8d929de662dc5cbdead4127251c35c # Parent 0b569c75d1808f05056e3e779993186ceded830f mail: split out the SMTP login to allow the keyring extension to wrap it The keyring extension only needs to tweak this tiny section of the larger function. But without any place to intercept the username/password fetching, it copy/pasted the entire function, and has grown a bunch of compatibility hacks to support older versions of Mercurial as well. Differential Revision: https://phab.mercurial-scm.org/D10471 diff -r 0b569c75d180 -r 83c0d144ef8d mercurial/mail.py --- a/mercurial/mail.py Tue Apr 20 04:27:03 2021 +0200 +++ b/mercurial/mail.py Mon Apr 19 17:26:57 2021 -0400 @@ -151,6 +151,32 @@ if starttls or smtps: ui.note(_(b'(verifying remote certificate)\n')) sslutil.validatesocket(s.sock) + + try: + _smtp_login(ui, s, mailhost, mailport) + except smtplib.SMTPException as inst: + raise error.Abort(stringutil.forcebytestr(inst)) + + def send(sender, recipients, msg): + try: + return s.sendmail(sender, recipients, msg) + except smtplib.SMTPRecipientsRefused as inst: + recipients = [r[1] for r in inst.recipients.values()] + raise error.Abort(b'\n' + b'\n'.join(recipients)) + except smtplib.SMTPException as inst: + raise error.Abort(inst) + + return send + + +def _smtp_login(ui, smtp, mailhost, mailport): + """A hook for the keyring extension to perform the actual SMTP login. + + An already connected SMTP object of the proper type is provided, based on + the current configuration. The host and port to which the connection was + established are provided for accessibility, since the SMTP object doesn't + provide an accessor. ``smtplib.SMTPException`` is raised on error. + """ username = ui.config(b'smtp', b'username') password = ui.config(b'smtp', b'password') if username: @@ -163,21 +189,7 @@ if username and password: ui.note(_(b'(authenticating to mail server as %s)\n') % username) username = encoding.strfromlocal(username) - try: - s.login(username, password) - except smtplib.SMTPException as inst: - raise error.Abort(stringutil.forcebytestr(inst)) - - def send(sender, recipients, msg): - try: - return s.sendmail(sender, recipients, msg) - except smtplib.SMTPRecipientsRefused as inst: - recipients = [r[1] for r in inst.recipients.values()] - raise error.Abort(b'\n' + b'\n'.join(recipients)) - except smtplib.SMTPException as inst: - raise error.Abort(inst) - - return send + smtp.login(username, password) def _sendmail(ui, sender, recipients, msg):