annotate mercurial/mail.py @ 51282:9d3721552b6c

pytype: import typing directly First we no longer needs the pycompat layer, second having the types imported in all case will allow to use them more directly in type annotation, something important to upgrade the old "type comment" to proper type annotation. A lot a stupid assert are needed to keep pyflakes happy. We should be able to remove most of them once the type comment have been upgraded.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Wed, 20 Dec 2023 12:51:20 +0100
parents 18c8c18993f0
children f15cb5111a1e
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
1 # mail.py - mail sending bits for mercurial
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
2 #
46819
d4ba4d51f85f contributor: change mentions of mpm to olivia
Rapha?l Gom?s <rgomes@octobus.net>
parents: 46683
diff changeset
3 # Copyright 2006 Olivia Mackall <olivia@selenic.com>
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
4 #
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 7948
diff changeset
5 # This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9715
diff changeset
6 # GNU General Public License version 2 or any later version.
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
7
25957
ae21d51bdc43 mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25842
diff changeset
8
19790
53f16f4aff33 mail: correct import of email module
Augie Fackler <raf@durin42.com>
parents: 19050
diff changeset
9 import email
30089
040f23ed6963 mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents: 30072
diff changeset
10 import email.charset
43156
0e6a7ce81dde py3: use email.generator.BytesGenerator in patch.split()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 43117
diff changeset
11 import email.generator
30072
87b8e40eb812 mail: handle renamed email.Header
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29285
diff changeset
12 import email.header
34310
2d0c306a88c2 mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents: 33499
diff changeset
13 import email.message
38332
7b12a2d2eedc py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents: 37469
diff changeset
14 import email.parser
7b12a2d2eedc py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents: 37469
diff changeset
15 import io
25957
ae21d51bdc43 mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25842
diff changeset
16 import os
ae21d51bdc43 mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25842
diff changeset
17 import smtplib
ae21d51bdc43 mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25842
diff changeset
18 import socket
ae21d51bdc43 mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25842
diff changeset
19 import time
ae21d51bdc43 mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25842
diff changeset
20
51282
9d3721552b6c pytype: import typing directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50926
diff changeset
21 from typing import (
9d3721552b6c pytype: import typing directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50926
diff changeset
22 Any,
9d3721552b6c pytype: import typing directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50926
diff changeset
23 List,
9d3721552b6c pytype: import typing directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50926
diff changeset
24 Tuple,
9d3721552b6c pytype: import typing directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50926
diff changeset
25 Union,
9d3721552b6c pytype: import typing directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50926
diff changeset
26 )
9d3721552b6c pytype: import typing directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50926
diff changeset
27
25957
ae21d51bdc43 mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25842
diff changeset
28 from .i18n import _
43089
c59eb1560c44 py3: manually import getattr where it is needed
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43085
diff changeset
29 from .pycompat import (
c59eb1560c44 py3: manually import getattr where it is needed
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43085
diff changeset
30 open,
c59eb1560c44 py3: manually import getattr where it is needed
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43085
diff changeset
31 )
25957
ae21d51bdc43 mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25842
diff changeset
32 from . import (
ae21d51bdc43 mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25842
diff changeset
33 encoding,
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26098
diff changeset
34 error,
36047
1407c42b302c py3: pass system string to email.message.Message.set_type()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35151
diff changeset
35 pycompat,
25957
ae21d51bdc43 mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25842
diff changeset
36 sslutil,
ae21d51bdc43 mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25842
diff changeset
37 util,
ae21d51bdc43 mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25842
diff changeset
38 )
37084
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36120
diff changeset
39 from .utils import (
37120
a8a902d7176e procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
40 procutil,
37084
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36120
diff changeset
41 stringutil,
46907
ffd3e823a7e5 urlutil: extract `url` related code from `util` into the new module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 46819
diff changeset
42 urlutil,
37084
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36120
diff changeset
43 )
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
44
43625
8d9e2c2b6058 mail: add type hints for pytype
Denis Laxalde <denis@laxalde.org>
parents: 43624
diff changeset
45
51282
9d3721552b6c pytype: import typing directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50926
diff changeset
46 # keep pyflakes happy
9d3721552b6c pytype: import typing directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50926
diff changeset
47 assert [
9d3721552b6c pytype: import typing directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50926
diff changeset
48 Any,
9d3721552b6c pytype: import typing directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50926
diff changeset
49 List,
9d3721552b6c pytype: import typing directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50926
diff changeset
50 Tuple,
9d3721552b6c pytype: import typing directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50926
diff changeset
51 Union,
9d3721552b6c pytype: import typing directly
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50926
diff changeset
52 ]
43625
8d9e2c2b6058 mail: add type hints for pytype
Denis Laxalde <denis@laxalde.org>
parents: 43624
diff changeset
53
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
54
18885
cf1304fbc184 smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17428
diff changeset
55 class STARTTLS(smtplib.SMTP):
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
56 """Derived class to verify the peer certificate for STARTTLS.
18885
cf1304fbc184 smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17428
diff changeset
57
cf1304fbc184 smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17428
diff changeset
58 This class allows to pass any keyword arguments to SSL socket creation.
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
59 """
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
60
29251
31acc78c632a mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29248
diff changeset
61 def __init__(self, ui, host=None, **kwargs):
18885
cf1304fbc184 smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17428
diff changeset
62 smtplib.SMTP.__init__(self, **kwargs)
29248
e6de6ef3e426 sslutil: remove ui from sslkwargs (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29227
diff changeset
63 self._ui = ui
28935
a4c5c23de1d3 mail: retain hostname for sslutil.wrapsocket (issue5203)
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
64 self._host = host
18885
cf1304fbc184 smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17428
diff changeset
65
50373
1c7453f2bb57 mail: add a missing argument to properly override starttls
Matt Harbison <matt_harbison@yahoo.com>
parents: 49051
diff changeset
66 def starttls(self, keyfile=None, certfile=None, context=None):
43169
3941e7063d03 py3: call SMTP.has_extn() with an str
Denis Laxalde <denis@laxalde.org>
parents: 43156
diff changeset
67 if not self.has_extn("starttls"):
50374
174290adfc4a mail: unbyteify the SMTPException message
Matt Harbison <matt_harbison@yahoo.com>
parents: 50373
diff changeset
68 msg = "STARTTLS extension not supported by server"
18885
cf1304fbc184 smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17428
diff changeset
69 raise smtplib.SMTPException(msg)
43170
a1801ee97840 py3: call SMTP.docmd() with an str
Denis Laxalde <denis@laxalde.org>
parents: 43169
diff changeset
70 (resp, reply) = self.docmd("STARTTLS")
18885
cf1304fbc184 smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17428
diff changeset
71 if resp == 220:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
72 self.sock = sslutil.wrapsocket(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
73 self.sock,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
74 keyfile,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
75 certfile,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
76 ui=self._ui,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
77 serverhostname=self._host,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
78 )
43171
54b06bec8914 py3: use socket.makefile() instead of dropped smtplib.SSLFakeFile
Denis Laxalde <denis@laxalde.org>
parents: 43170
diff changeset
79 self.file = self.sock.makefile("rb")
18885
cf1304fbc184 smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17428
diff changeset
80 self.helo_resp = None
cf1304fbc184 smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17428
diff changeset
81 self.ehlo_resp = None
cf1304fbc184 smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17428
diff changeset
82 self.esmtp_features = {}
cf1304fbc184 smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17428
diff changeset
83 self.does_esmtp = 0
cf1304fbc184 smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17428
diff changeset
84 return (resp, reply)
cf1304fbc184 smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17428
diff changeset
85
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
86
26673
ab1af5e7d734 mail: drop python 2.5 support
timeless@mozdev.org
parents: 26587
diff changeset
87 class SMTPS(smtplib.SMTP):
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
88 """Derived class to verify the peer certificate for SMTPS.
18886
14a60a0f7122 smtp: add the class to verify the certificate of the SMTP server for SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 18885
diff changeset
89
26673
ab1af5e7d734 mail: drop python 2.5 support
timeless@mozdev.org
parents: 26587
diff changeset
90 This class allows to pass any keyword arguments to SSL socket creation.
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
91 """
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
92
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
93 def __init__(self, ui, keyfile=None, certfile=None, host=None, **kwargs):
26673
ab1af5e7d734 mail: drop python 2.5 support
timeless@mozdev.org
parents: 26587
diff changeset
94 self.keyfile = keyfile
ab1af5e7d734 mail: drop python 2.5 support
timeless@mozdev.org
parents: 26587
diff changeset
95 self.certfile = certfile
ab1af5e7d734 mail: drop python 2.5 support
timeless@mozdev.org
parents: 26587
diff changeset
96 smtplib.SMTP.__init__(self, **kwargs)
28935
a4c5c23de1d3 mail: retain hostname for sslutil.wrapsocket (issue5203)
timeless <timeless@mozdev.org>
parents: 28341
diff changeset
97 self._host = host
26673
ab1af5e7d734 mail: drop python 2.5 support
timeless@mozdev.org
parents: 26587
diff changeset
98 self.default_port = smtplib.SMTP_SSL_PORT
29248
e6de6ef3e426 sslutil: remove ui from sslkwargs (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29227
diff changeset
99 self._ui = ui
26673
ab1af5e7d734 mail: drop python 2.5 support
timeless@mozdev.org
parents: 26587
diff changeset
100
ab1af5e7d734 mail: drop python 2.5 support
timeless@mozdev.org
parents: 26587
diff changeset
101 def _get_socket(self, host, port, timeout):
ab1af5e7d734 mail: drop python 2.5 support
timeless@mozdev.org
parents: 26587
diff changeset
102 if self.debuglevel > 0:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
103 self._ui.debug(b'connect: %r\n' % ((host, port),))
26673
ab1af5e7d734 mail: drop python 2.5 support
timeless@mozdev.org
parents: 26587
diff changeset
104 new_socket = socket.create_connection((host, port), timeout)
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
105 new_socket = sslutil.wrapsocket(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
106 new_socket,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
107 self.keyfile,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
108 self.certfile,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
109 ui=self._ui,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
110 serverhostname=self._host,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
111 )
43506
9f70512ae2cf cleanup: remove pointless r-prefixes on single-quoted strings
Augie Fackler <augie@google.com>
parents: 43498
diff changeset
112 self.file = new_socket.makefile('rb')
26673
ab1af5e7d734 mail: drop python 2.5 support
timeless@mozdev.org
parents: 26587
diff changeset
113 return new_socket
18886
14a60a0f7122 smtp: add the class to verify the certificate of the SMTP server for SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 18885
diff changeset
114
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
115
39025
569d662816de mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents: 39024
diff changeset
116 def _pyhastls():
43625
8d9e2c2b6058 mail: add type hints for pytype
Denis Laxalde <denis@laxalde.org>
parents: 43624
diff changeset
117 # type: () -> bool
39025
569d662816de mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents: 39024
diff changeset
118 """Returns true iff Python has TLS support, false otherwise."""
569d662816de mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents: 39024
diff changeset
119 try:
569d662816de mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents: 39024
diff changeset
120 import ssl
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
121
39025
569d662816de mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents: 39024
diff changeset
122 getattr(ssl, 'HAS_TLS', False)
569d662816de mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents: 39024
diff changeset
123 return True
569d662816de mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents: 39024
diff changeset
124 except ImportError:
569d662816de mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents: 39024
diff changeset
125 return False
569d662816de mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents: 39024
diff changeset
126
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
127
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
128 def _smtp(ui):
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
129 '''build an smtp connection and return a function to send mail'''
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
130 local_hostname = ui.config(b'smtp', b'local_hostname')
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
131 tls = ui.config(b'smtp', b'tls')
13201
f05250572467 smtp: fix for server doesn't support starttls extension
Zhigang Wang <zhigang.x.wang@oracle.com>
parents: 12091
diff changeset
132 # backward compatible: when tls = true, we use starttls.
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
133 starttls = tls == b'starttls' or stringutil.parsebool(tls)
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
134 smtps = tls == b'smtps'
39025
569d662816de mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents: 39024
diff changeset
135 if (starttls or smtps) and not _pyhastls():
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
136 raise error.Abort(_(b"can't use TLS: Python SSL support not installed"))
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
137 mailhost = ui.config(b'smtp', b'host')
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
138 if not mailhost:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
139 raise error.Abort(_(b'smtp.host not configured - cannot send mail'))
18888
19d489404d79 smtp: verify the certificate of the SMTP server for STARTTLS/SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 18886
diff changeset
140 if smtps:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
141 ui.note(_(b'(using smtps)\n'))
29251
31acc78c632a mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29248
diff changeset
142 s = SMTPS(ui, local_hostname=local_hostname, host=mailhost)
18888
19d489404d79 smtp: verify the certificate of the SMTP server for STARTTLS/SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 18886
diff changeset
143 elif starttls:
29251
31acc78c632a mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29248
diff changeset
144 s = STARTTLS(ui, local_hostname=local_hostname, host=mailhost)
18888
19d489404d79 smtp: verify the certificate of the SMTP server for STARTTLS/SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 18886
diff changeset
145 else:
19d489404d79 smtp: verify the certificate of the SMTP server for STARTTLS/SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 18886
diff changeset
146 s = smtplib.SMTP(local_hostname=local_hostname)
19050
601c1e226889 smtp: use 465 as default port for SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 18916
diff changeset
147 if smtps:
601c1e226889 smtp: use 465 as default port for SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 18916
diff changeset
148 defaultport = 465
601c1e226889 smtp: use 465 as default port for SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 18916
diff changeset
149 else:
601c1e226889 smtp: use 465 as default port for SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 18916
diff changeset
150 defaultport = 25
46907
ffd3e823a7e5 urlutil: extract `url` related code from `util` into the new module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 46819
diff changeset
151 mailport = urlutil.getport(ui.config(b'smtp', b'port', defaultport))
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
152 ui.note(_(b'sending mail: smtp host %s, port %d\n') % (mailhost, mailport))
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
153 s.connect(host=mailhost, port=mailport)
13201
f05250572467 smtp: fix for server doesn't support starttls extension
Zhigang Wang <zhigang.x.wang@oracle.com>
parents: 12091
diff changeset
154 if starttls:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
155 ui.note(_(b'(using starttls)\n'))
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
156 s.ehlo()
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
157 s.starttls()
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
158 s.ehlo()
29285
63a3749147af mail: unsupport smtp.verifycert (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29251
diff changeset
159 if starttls or smtps:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
160 ui.note(_(b'(verifying remote certificate)\n'))
29285
63a3749147af mail: unsupport smtp.verifycert (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29251
diff changeset
161 sslutil.validatesocket(s.sock)
46991
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
162
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
163 try:
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
164 _smtp_login(ui, s, mailhost, mailport)
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
165 except smtplib.SMTPException as inst:
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
166 raise error.Abort(stringutil.forcebytestr(inst))
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
167
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
168 def send(sender, recipients, msg):
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
169 try:
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
170 return s.sendmail(sender, recipients, msg)
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
171 except smtplib.SMTPRecipientsRefused as inst:
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
172 recipients = [r[1] for r in inst.recipients.values()]
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
173 raise error.Abort(b'\n' + b'\n'.join(recipients))
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
174 except smtplib.SMTPException as inst:
46992
5fa019ceb499 mail: force SMTPException to bytes before wrapping in error.Abort
Matt Harbison <matt_harbison@yahoo.com>
parents: 46991
diff changeset
175 raise error.Abort(stringutil.forcebytestr(inst))
46991
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
176
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
177 return send
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
178
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
179
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
180 def _smtp_login(ui, smtp, mailhost, mailport):
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
181 """A hook for the keyring extension to perform the actual SMTP login.
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
182
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
183 An already connected SMTP object of the proper type is provided, based on
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
184 the current configuration. The host and port to which the connection was
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
185 established are provided for accessibility, since the SMTP object doesn't
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
186 provide an accessor. ``smtplib.SMTPException`` is raised on error.
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
187 """
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
188 username = ui.config(b'smtp', b'username')
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
189 password = ui.config(b'smtp', b'password')
43172
9145abd8b96d py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents: 43171
diff changeset
190 if username:
9145abd8b96d py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents: 43171
diff changeset
191 if password:
9145abd8b96d py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents: 43171
diff changeset
192 password = encoding.strfromlocal(password)
9145abd8b96d py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents: 43171
diff changeset
193 else:
9145abd8b96d py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents: 43171
diff changeset
194 password = ui.getpass()
45929
87e7dd8e7734 ui: ensure `getpass()` returns bytes
Matt Harbison <matt_harbison@yahoo.com>
parents: 43825
diff changeset
195 if password is not None:
87e7dd8e7734 ui: ensure `getpass()` returns bytes
Matt Harbison <matt_harbison@yahoo.com>
parents: 43825
diff changeset
196 password = encoding.strfromlocal(password)
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
197 if username and password:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
198 ui.note(_(b'(authenticating to mail server as %s)\n') % username)
43172
9145abd8b96d py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents: 43171
diff changeset
199 username = encoding.strfromlocal(username)
46991
83c0d144ef8d mail: split out the SMTP login to allow the keyring extension to wrap it
Matt Harbison <matt_harbison@yahoo.com>
parents: 46982
diff changeset
200 smtp.login(username, password)
5947
528c986f0162 Backed out changeset dc6ed2736c81
Bryan O'Sullivan <bos@serpentine.com>
parents: 5866
diff changeset
201
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
202
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
203 def _sendmail(ui, sender, recipients, msg):
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
204 '''send mail using sendmail.'''
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
205 program = ui.config(b'email', b'method')
43096
813aa8cc55d4 patchbomb: use procutil.shellquote() instead of shlex to escape email address
Yuya Nishihara <yuya@tcha.org>
parents: 43089
diff changeset
206
813aa8cc55d4 patchbomb: use procutil.shellquote() instead of shlex to escape email address
Yuya Nishihara <yuya@tcha.org>
parents: 43089
diff changeset
207 def stremail(x):
813aa8cc55d4 patchbomb: use procutil.shellquote() instead of shlex to escape email address
Yuya Nishihara <yuya@tcha.org>
parents: 43089
diff changeset
208 return procutil.shellquote(stringutil.email(encoding.strtolocal(x)))
813aa8cc55d4 patchbomb: use procutil.shellquote() instead of shlex to escape email address
Yuya Nishihara <yuya@tcha.org>
parents: 43089
diff changeset
209
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
210 cmdline = b'%s -f %s %s' % (
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
211 program,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
212 stremail(sender),
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
213 b' '.join(map(stremail, recipients)),
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
214 )
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
215 ui.note(_(b'sending mail: %s\n') % cmdline)
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
216 fp = procutil.popen(cmdline, b'wb')
37458
00e4bd97b095 procutil: always popen() in binary mode
Yuya Nishihara <yuya@tcha.org>
parents: 37120
diff changeset
217 fp.write(util.tonativeeol(msg))
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
218 ret = fp.close()
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
219 if ret:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
220 raise error.Abort(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
221 b'%s %s'
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
222 % (
43825
8f26dd09aa78 mail: use procutil.shellsplit instead of bytes.split to parse command
Julien Cristau <jcristau@debian.org>
parents: 43773
diff changeset
223 os.path.basename(procutil.shellsplit(program)[0]),
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
224 procutil.explainexit(ret),
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
225 )
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
226 )
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
227
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
228
15560
cc58c228503e mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents: 14965
diff changeset
229 def _mbox(mbox, sender, recipients, msg):
cc58c228503e mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents: 14965
diff changeset
230 '''write mails to mbox'''
46997
106402245301 mail: add a TODO about proper mbox locking
Matt Harbison <matt_harbison@yahoo.com>
parents: 46992
diff changeset
231 # TODO: use python mbox library for proper locking
46982
d467bae86b2d mail: use a context manager when writing to mbox
Matt Harbison <matt_harbison@yahoo.com>
parents: 46907
diff changeset
232 with open(mbox, b'ab+') as fp:
d467bae86b2d mail: use a context manager when writing to mbox
Matt Harbison <matt_harbison@yahoo.com>
parents: 46907
diff changeset
233 # Should be time.asctime(), but Windows prints 2-characters day
d467bae86b2d mail: use a context manager when writing to mbox
Matt Harbison <matt_harbison@yahoo.com>
parents: 46907
diff changeset
234 # of month instead of one. Make them print the same thing.
d467bae86b2d mail: use a context manager when writing to mbox
Matt Harbison <matt_harbison@yahoo.com>
parents: 46907
diff changeset
235 date = time.strftime('%a %b %d %H:%M:%S %Y', time.localtime())
d467bae86b2d mail: use a context manager when writing to mbox
Matt Harbison <matt_harbison@yahoo.com>
parents: 46907
diff changeset
236 fp.write(
d467bae86b2d mail: use a context manager when writing to mbox
Matt Harbison <matt_harbison@yahoo.com>
parents: 46907
diff changeset
237 b'From %s %s\n'
d467bae86b2d mail: use a context manager when writing to mbox
Matt Harbison <matt_harbison@yahoo.com>
parents: 46907
diff changeset
238 % (encoding.strtolocal(sender), encoding.strtolocal(date))
d467bae86b2d mail: use a context manager when writing to mbox
Matt Harbison <matt_harbison@yahoo.com>
parents: 46907
diff changeset
239 )
d467bae86b2d mail: use a context manager when writing to mbox
Matt Harbison <matt_harbison@yahoo.com>
parents: 46907
diff changeset
240 fp.write(msg)
d467bae86b2d mail: use a context manager when writing to mbox
Matt Harbison <matt_harbison@yahoo.com>
parents: 46907
diff changeset
241 fp.write(b'\n\n')
15560
cc58c228503e mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents: 14965
diff changeset
242
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
243
15560
cc58c228503e mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents: 14965
diff changeset
244 def connect(ui, mbox=None):
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
245 """make a mail connection. return a function to send mail.
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
246 call as sendmail(sender, list-of-recipients, msg)."""
15560
cc58c228503e mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents: 14965
diff changeset
247 if mbox:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
248 open(mbox, b'wb').close()
15560
cc58c228503e mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents: 14965
diff changeset
249 return lambda s, r, m: _mbox(mbox, s, r, m)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
250 if ui.config(b'email', b'method') == b'smtp':
5947
528c986f0162 Backed out changeset dc6ed2736c81
Bryan O'Sullivan <bos@serpentine.com>
parents: 5866
diff changeset
251 return _smtp(ui)
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
252 return lambda s, r, m: _sendmail(ui, s, r, m)
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
253
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
254
15561
ca572e94d8e7 notify: add option for writing to mbox
Mads Kiilerich <mads@kiilerich.com>
parents: 15560
diff changeset
255 def sendmail(ui, sender, recipients, msg, mbox=None):
ca572e94d8e7 notify: add option for writing to mbox
Mads Kiilerich <mads@kiilerich.com>
parents: 15560
diff changeset
256 send = connect(ui, mbox=mbox)
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
257 return send(sender, recipients, msg)
4489
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
258
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
259
4489
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
260 def validateconfig(ui):
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
261 '''determine if we have enough config data to try sending email.'''
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
262 method = ui.config(b'email', b'method')
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
263 if method == b'smtp':
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
264 if not ui.config(b'smtp', b'host'):
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
265 raise error.Abort(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
266 _(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
267 b'smtp specified as email transport, '
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
268 b'but no smtp host configured'
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
269 )
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
270 )
4489
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
271 else:
49051
1d6c6ad645e1 mail: don't complain about a multi-word email.method
Julien Cristau <jcristau@debian.org>
parents: 48883
diff changeset
272 command = procutil.shellsplit(method)
1d6c6ad645e1 mail: don't complain about a multi-word email.method
Julien Cristau <jcristau@debian.org>
parents: 48883
diff changeset
273 command = command[0] if command else b''
1d6c6ad645e1 mail: don't complain about a multi-word email.method
Julien Cristau <jcristau@debian.org>
parents: 48883
diff changeset
274 if not (command and procutil.findexe(command)):
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
275 raise error.Abort(
49051
1d6c6ad645e1 mail: don't complain about a multi-word email.method
Julien Cristau <jcristau@debian.org>
parents: 48883
diff changeset
276 _(b'%r specified as email transport, but not in PATH') % command
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
277 )
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
278
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
279
30089
040f23ed6963 mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents: 30072
diff changeset
280 def codec2iana(cs):
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
281 # type: (str) -> str
47062
f38bf44e077f black: make codebase compatible with black v21.4b2 and v20.8b1
Kyle Lippincott <spectral@google.com>
parents: 46997
diff changeset
282 ''' '''
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
283 cs = email.charset.Charset(cs).input_charset.lower()
30089
040f23ed6963 mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents: 30072
diff changeset
284
040f23ed6963 mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents: 30072
diff changeset
285 # "latin1" normalizes to "iso8859-1", standard calls for "iso-8859-1"
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
286 if cs.startswith("iso") and not cs.startswith("iso-"):
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
287 return "iso-" + cs[3:]
30089
040f23ed6963 mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents: 30072
diff changeset
288 return cs
040f23ed6963 mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents: 30072
diff changeset
289
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
290
43627
af3e341dbf03 mail: use a native string for "subtype" value
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 43626
diff changeset
291 def mimetextpatch(s, subtype='plain', display=False):
af3e341dbf03 mail: use a native string for "subtype" value
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 43626
diff changeset
292 # type: (bytes, str, bool) -> email.message.Message
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
293 """Return MIME message suitable for a patch.
30089
040f23ed6963 mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents: 30072
diff changeset
294 Charset will be detected by first trying to decode as us-ascii, then utf-8,
040f23ed6963 mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents: 30072
diff changeset
295 and finally the global encodings. If all those fail, fall back to
040f23ed6963 mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents: 30072
diff changeset
296 ISO-8859-1, an encoding with that allows all byte sequences.
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
297 Transfer encodings will be used if necessary."""
8332
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
298
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
299 cs = [
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
300 'us-ascii',
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
301 'utf-8',
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
302 pycompat.sysstr(encoding.encoding),
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
303 pycompat.sysstr(encoding.fallbackencoding),
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
304 ]
30089
040f23ed6963 mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents: 30072
diff changeset
305 if display:
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
306 cs = ['us-ascii']
30089
040f23ed6963 mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents: 30072
diff changeset
307 for charset in cs:
8332
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
308 try:
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
309 s.decode(charset)
30089
040f23ed6963 mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents: 30072
diff changeset
310 return mimetextqp(s, subtype, codec2iana(charset))
8332
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
311 except UnicodeDecodeError:
30089
040f23ed6963 mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents: 30072
diff changeset
312 pass
8332
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
313
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
314 return mimetextqp(s, subtype, "iso-8859-1")
15562
a82b6038ff08 mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents: 15561
diff changeset
315
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
316
15562
a82b6038ff08 mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents: 15561
diff changeset
317 def mimetextqp(body, subtype, charset):
43627
af3e341dbf03 mail: use a native string for "subtype" value
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 43626
diff changeset
318 # type: (bytes, str, str) -> email.message.Message
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
319 """Return MIME message.
17424
e7cfe3587ea4 fix trivial spelling errors
Mads Kiilerich <mads@kiilerich.com>
parents: 15562
diff changeset
320 Quoted-printable transfer encoding will be used if necessary.
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
321 """
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
322 cs = email.charset.Charset(charset)
34310
2d0c306a88c2 mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents: 33499
diff changeset
323 msg = email.message.Message()
43627
af3e341dbf03 mail: use a native string for "subtype" value
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 43626
diff changeset
324 msg.set_type('text/' + subtype)
34310
2d0c306a88c2 mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents: 33499
diff changeset
325
15562
a82b6038ff08 mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents: 15561
diff changeset
326 for line in body.splitlines():
a82b6038ff08 mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents: 15561
diff changeset
327 if len(line) > 950:
34310
2d0c306a88c2 mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents: 33499
diff changeset
328 cs.body_encoding = email.charset.QP
15562
a82b6038ff08 mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents: 15561
diff changeset
329 break
a82b6038ff08 mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents: 15561
diff changeset
330
41405
9b3be572ff0c mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39108
diff changeset
331 # On Python 2, this simply assigns a value. Python 3 inspects
9b3be572ff0c mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39108
diff changeset
332 # body and does different things depending on whether it has
9b3be572ff0c mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39108
diff changeset
333 # encode() or decode() attributes. We can get the old behavior
9b3be572ff0c mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39108
diff changeset
334 # if we pass a str and charset is None and we call set_charset().
9b3be572ff0c mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39108
diff changeset
335 # But we may get into trouble later due to Python attempting to
9b3be572ff0c mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39108
diff changeset
336 # encode/decode using the registered charset (or attempting to
9b3be572ff0c mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39108
diff changeset
337 # use ascii in the absence of a charset).
34310
2d0c306a88c2 mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents: 33499
diff changeset
338 msg.set_payload(body, cs)
2d0c306a88c2 mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents: 33499
diff changeset
339
8332
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
340 return msg
7191
d14212218582 mail: mime-encode patches that are utf-8
Christian Ebert <blacktrash@gmx.net>
parents: 7114
diff changeset
341
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
342
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
343 def _charsets(ui):
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
344 # type: (Any) -> List[str]
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
345 '''Obtains charsets to send mail parts not containing patches.'''
43625
8d9e2c2b6058 mail: add type hints for pytype
Denis Laxalde <denis@laxalde.org>
parents: 43624
diff changeset
346 charsets = [
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
347 pycompat.sysstr(cs.lower())
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
348 for cs in ui.configlist(b'email', b'charsets')
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
349 ]
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
350 fallbacks = [
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
351 pycompat.sysstr(encoding.fallbackencoding.lower()),
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
352 pycompat.sysstr(encoding.encoding.lower()),
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
353 'utf-8',
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
354 ]
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
355 for cs in fallbacks: # find unique charsets while keeping order
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
356 if cs not in charsets:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
357 charsets.append(cs)
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
358 return [cs for cs in charsets if not cs.endswith('ascii')]
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
359
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
360
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
361 def _encode(ui, s, charsets):
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
362 # type: (Any, bytes, List[str]) -> Tuple[bytes, str]
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
363 """Returns (converted) string, charset tuple.
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
364 Finds out best charset by cycling through sendcharsets in descending
7948
de377b1a9a84 move encoding bits from util to encoding
Matt Mackall <mpm@selenic.com>
parents: 7195
diff changeset
365 order. Tries both encoding and fallbackencoding for input. Only as
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
366 last resort send as is in fake ascii.
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
367 Caveat: Do not use for mail parts containing patches!"""
39023
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
368 sendcharsets = charsets or _charsets(ui)
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
369 if not isinstance(s, bytes):
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
370 # We have unicode data, which we need to try and encode to
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
371 # some reasonable-ish encoding. Try the encodings the user
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
372 # wants, and fall back to garbage-in-ascii.
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
373 for ocs in sendcharsets:
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
374 try:
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
375 return s.encode(ocs), ocs
39023
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
376 except UnicodeEncodeError:
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
377 pass
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
378 except LookupError:
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
379 ui.warn(
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
380 _(b'ignoring invalid sendcharset: %s\n')
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
381 % pycompat.sysbytes(ocs)
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
382 )
39023
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
383 else:
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
384 # Everything failed, ascii-armor what we've got and send it.
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
385 return s.encode('ascii', 'backslashreplace'), 'us-ascii'
39023
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
386 # We have a bytes of unknown encoding. We'll try and guess a valid
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
387 # encoding, falling back to pretending we had ascii even though we
858fe9625dab mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents: 38332
diff changeset
388 # know that's wrong.
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
389 try:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
390 s.decode('ascii')
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
391 except UnicodeDecodeError:
7948
de377b1a9a84 move encoding bits from util to encoding
Matt Mackall <mpm@selenic.com>
parents: 7195
diff changeset
392 for ics in (encoding.encoding, encoding.fallbackencoding):
43330
910827a2cb20 py3: decode encoding literal before passing to .decode()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 43326
diff changeset
393 ics = pycompat.sysstr(ics)
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
394 try:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
395 u = s.decode(ics)
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
396 except UnicodeDecodeError:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
397 continue
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
398 for ocs in sendcharsets:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
399 try:
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
400 return u.encode(ocs), ocs
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
401 except UnicodeEncodeError:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
402 pass
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
403 except LookupError:
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
404 ui.warn(
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
405 _(b'ignoring invalid sendcharset: %s\n')
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
406 % pycompat.sysbytes(ocs)
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
407 )
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
408 # if ascii, or all conversion attempts fail, send (broken) ascii
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
409 return s, 'us-ascii'
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
410
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
411
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
412 def headencode(ui, s, charsets=None, display=False):
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
413 # type: (Any, Union[bytes, str], List[str], bool) -> str
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
414 '''Returns RFC-2047 compliant header from given string.'''
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
415 if not display:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
416 # split into words?
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
417 s, cs = _encode(ui, s, charsets)
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
418 return email.header.Header(s, cs).encode()
43575
67b4439c09b2 mail: let headencode() return a native string
Denis Laxalde <denis@laxalde.org>
parents: 43506
diff changeset
419 return encoding.strfromlocal(s)
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
420
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
421
9948
e5b44a7986d0 mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents: 9715
diff changeset
422 def _addressencode(ui, name, addr, charsets=None):
43628
ddb5d097d561 mail: move strtolocal call in _addressencode()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 43627
diff changeset
423 # type: (Any, str, str, List[str]) -> str
ddb5d097d561 mail: move strtolocal call in _addressencode()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 43627
diff changeset
424 addr = encoding.strtolocal(addr)
43575
67b4439c09b2 mail: let headencode() return a native string
Denis Laxalde <denis@laxalde.org>
parents: 43506
diff changeset
425 name = headencode(ui, name, charsets)
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
426 try:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
427 acc, dom = addr.split(b'@')
39107
c2327bb3505d mail: call s.decode('ascii') explicitly to see if s is an ascii bytes
Yuya Nishihara <yuya@tcha.org>
parents: 39106
diff changeset
428 acc.decode('ascii')
39108
d2d89d31cbb5 mail: convert encoding.encoding to sysstr
Yuya Nishihara <yuya@tcha.org>
parents: 39107
diff changeset
429 dom = dom.decode(pycompat.sysstr(encoding.encoding)).encode('idna')
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
430 addr = b'%s@%s' % (acc, dom)
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
431 except UnicodeDecodeError:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
432 raise error.Abort(_(b'invalid email address: %s') % addr)
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
433 except ValueError:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
434 try:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
435 # too strict?
39107
c2327bb3505d mail: call s.decode('ascii') explicitly to see if s is an ascii bytes
Yuya Nishihara <yuya@tcha.org>
parents: 39106
diff changeset
436 addr.decode('ascii')
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
437 except UnicodeDecodeError:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
438 raise error.Abort(_(b'invalid local address: %s') % addr)
43576
14b96072797d mail: let addressencode() / addrlistencode() return native strings
Denis Laxalde <denis@laxalde.org>
parents: 43575
diff changeset
439 return email.utils.formataddr((name, encoding.strfromlocal(addr)))
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
440
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
441
9948
e5b44a7986d0 mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents: 9715
diff changeset
442 def addressencode(ui, address, charsets=None, display=False):
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
443 # type: (Any, bytes, List[str], bool) -> str
9948
e5b44a7986d0 mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents: 9715
diff changeset
444 '''Turns address into RFC-2047 compliant header.'''
e5b44a7986d0 mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents: 9715
diff changeset
445 if display or not address:
43576
14b96072797d mail: let addressencode() / addrlistencode() return native strings
Denis Laxalde <denis@laxalde.org>
parents: 43575
diff changeset
446 return encoding.strfromlocal(address or b'')
39024
eabdf3c25b8b mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents: 39023
diff changeset
447 name, addr = email.utils.parseaddr(encoding.strfromlocal(address))
43628
ddb5d097d561 mail: move strtolocal call in _addressencode()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 43627
diff changeset
448 return _addressencode(ui, name, addr, charsets)
9948
e5b44a7986d0 mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents: 9715
diff changeset
449
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
450
9948
e5b44a7986d0 mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents: 9715
diff changeset
451 def addrlistencode(ui, addrs, charsets=None, display=False):
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
452 # type: (Any, List[bytes], List[str], bool) -> List[str]
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
453 """Turns a list of addresses into a list of RFC-2047 compliant headers.
9948
e5b44a7986d0 mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents: 9715
diff changeset
454 A single element of input list may contain multiple addresses, but output
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
455 always has one address per item"""
43577
599e25add437 mail: convert addr to str early in addrlistencode()
Denis Laxalde <denis@laxalde.org>
parents: 43576
diff changeset
456 straddrs = []
39024
eabdf3c25b8b mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents: 39023
diff changeset
457 for a in addrs:
43506
9f70512ae2cf cleanup: remove pointless r-prefixes on single-quoted strings
Augie Fackler <augie@google.com>
parents: 43498
diff changeset
458 assert isinstance(a, bytes), '%r unexpectedly not a bytestr' % a
43577
599e25add437 mail: convert addr to str early in addrlistencode()
Denis Laxalde <denis@laxalde.org>
parents: 43576
diff changeset
459 straddrs.append(encoding.strfromlocal(a))
9948
e5b44a7986d0 mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents: 9715
diff changeset
460 if display:
43577
599e25add437 mail: convert addr to str early in addrlistencode()
Denis Laxalde <denis@laxalde.org>
parents: 43576
diff changeset
461 return [a.strip() for a in straddrs if a.strip()]
9948
e5b44a7986d0 mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents: 9715
diff changeset
462
e5b44a7986d0 mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents: 9715
diff changeset
463 result = []
43577
599e25add437 mail: convert addr to str early in addrlistencode()
Denis Laxalde <denis@laxalde.org>
parents: 43576
diff changeset
464 for name, addr in email.utils.getaddresses(straddrs):
9948
e5b44a7986d0 mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents: 9715
diff changeset
465 if name or addr:
43628
ddb5d097d561 mail: move strtolocal call in _addressencode()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 43627
diff changeset
466 r = _addressencode(ui, name, addr, charsets)
39106
ebf54a34b7b7 mail: pass in addr to _addressencode() in bytes
Yuya Nishihara <yuya@tcha.org>
parents: 39105
diff changeset
467 result.append(r)
39105
f68ad9b4a43b mail: remove redundant bytesurl() from addrlistencode()
Yuya Nishihara <yuya@tcha.org>
parents: 39039
diff changeset
468 return result
9948
e5b44a7986d0 mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents: 9715
diff changeset
469
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
470
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
471 def mimeencode(ui, s, charsets=None, display=False):
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
472 # type: (Any, bytes, List[str], bool) -> email.message.Message
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
473 """creates mime text object, encodes it if needed, and sets
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45929
diff changeset
474 charset and transfer-encoding accordingly."""
43626
bdb0ddab7bb3 mail: let all charset values be native strings
Denis Laxalde <denis@laxalde.org>
parents: 43625
diff changeset
475 cs = 'us-ascii'
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
476 if not display:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
477 s, cs = _encode(ui, s, charsets)
43627
af3e341dbf03 mail: use a native string for "subtype" value
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 43626
diff changeset
478 return mimetextqp(s, 'plain', cs)
28341
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
479
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
480
48883
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
481 Generator = email.generator.BytesGenerator
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
482
43353
fdc3af52305b mail: black wants to add this blank line
Augie Fackler <augie@google.com>
parents: 43330
diff changeset
483
48883
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
484 def parse(fp):
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
485 # type: (Any) -> email.message.Message
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
486 ep = email.parser.Parser()
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
487 # disable the "universal newlines" mode, which isn't binary safe.
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
488 # I have no idea if ascii/surrogateescape is correct, but that's
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
489 # what the standard Python email parser does.
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
490 fp = io.TextIOWrapper(
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
491 fp, encoding='ascii', errors='surrogateescape', newline=chr(10)
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
492 )
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
493 try:
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
494 return ep.parse(fp)
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
495 finally:
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
496 fp.detach()
43156
0e6a7ce81dde py3: use email.generator.BytesGenerator in patch.split()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 43117
diff changeset
497
38332
7b12a2d2eedc py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents: 37469
diff changeset
498
48883
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
499 def parsebytes(data):
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
500 # type: (bytes) -> email.message.Message
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
501 ep = email.parser.BytesParser()
f0c445a8e324 mail: delete conditional code for Python 2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
502 return ep.parsebytes(data)
43326
ef81de93143e py3: use a BytesParser in notify extension
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 43325
diff changeset
503
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43019
diff changeset
504
28341
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
505 def headdecode(s):
43625
8d9e2c2b6058 mail: add type hints for pytype
Denis Laxalde <denis@laxalde.org>
parents: 43624
diff changeset
506 # type: (Union[email.header.Header, bytes]) -> bytes
28341
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
507 '''Decodes RFC-2047 header'''
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
508 uparts = []
30072
87b8e40eb812 mail: handle renamed email.Header
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29285
diff changeset
509 for part, charset in email.header.decode_header(s):
28341
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
510 if charset is not None:
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
511 try:
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
512 uparts.append(part.decode(charset))
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
513 continue
43324
866bd2cf764b mail: catch LookupError in headdecode()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 43172
diff changeset
514 except (UnicodeDecodeError, LookupError):
28341
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
515 pass
37469
7edf68862fe3 py3: work around weird handling of bytes/unicode in decode_header()
Yuya Nishihara <yuya@tcha.org>
parents: 37463
diff changeset
516 # On Python 3, decode_header() may return either bytes or unicode
7edf68862fe3 py3: work around weird handling of bytes/unicode in decode_header()
Yuya Nishihara <yuya@tcha.org>
parents: 37463
diff changeset
517 # depending on whether the header has =?<charset>? or not
7edf68862fe3 py3: work around weird handling of bytes/unicode in decode_header()
Yuya Nishihara <yuya@tcha.org>
parents: 37463
diff changeset
518 if isinstance(part, type(u'')):
7edf68862fe3 py3: work around weird handling of bytes/unicode in decode_header()
Yuya Nishihara <yuya@tcha.org>
parents: 37463
diff changeset
519 uparts.append(part)
7edf68862fe3 py3: work around weird handling of bytes/unicode in decode_header()
Yuya Nishihara <yuya@tcha.org>
parents: 37463
diff changeset
520 continue
28341
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
521 try:
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
522 uparts.append(part.decode('UTF-8'))
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
523 continue
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
524 except UnicodeDecodeError:
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
525 pass
8286f551b7ee patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents: 27619
diff changeset
526 uparts.append(part.decode('ISO-8859-1'))
31447
067add650129 encoding: factor out unicode variants of from/tolocal()
Yuya Nishihara <yuya@tcha.org>
parents: 30325
diff changeset
527 return encoding.unitolocal(u' '.join(uparts))