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
--- 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):