Mercurial > hg > mercurial-source
annotate mercurial/mail.py @ 43959:9145abd8b96d
py3: decode username and password before SMTP login
smtplib.SMTP.login() requires str on Python 3.
For 'password', we only need to decode when value comes from config as
getpass() returns the correct type already.
author | Denis Laxalde <denis@laxalde.org> |
---|---|
date | Thu, 10 Oct 2019 21:37:12 +0200 |
parents | 54b06bec8914 |
children |
rev | line source |
---|---|
2909
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 # |
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
3 # Copyright 2006 Matt Mackall <mpm@selenic.com> |
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 | 6 # GNU General Public License version 2 or any later version. |
2909
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
7 |
31104
f6369544bf85
mail: do not print(), use ui.debug() instead
Yuya Nishihara <yuya@tcha.org>
parents:
30868
diff
changeset
|
8 from __future__ import absolute_import |
26541
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
26402
diff
changeset
|
9 |
19790
53f16f4aff33
mail: correct import of email module
Augie Fackler <raf@durin42.com>
parents:
19050
diff
changeset
|
10 import email |
30868
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30851
diff
changeset
|
11 import email.charset |
43943
0e6a7ce81dde
py3: use email.generator.BytesGenerator in patch.split()
Denis Laxalde <denis.laxalde@logilab.fr>
parents:
43904
diff
changeset
|
12 import email.generator |
30851
87b8e40eb812
mail: handle renamed email.Header
Pulkit Goyal <7895pulkit@gmail.com>
parents:
30035
diff
changeset
|
13 import email.header |
35093
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
34282
diff
changeset
|
14 import email.message |
39118
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
15 import email.parser |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
16 import io |
26541
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
26402
diff
changeset
|
17 import os |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
26402
diff
changeset
|
18 import smtplib |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
26402
diff
changeset
|
19 import socket |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
26402
diff
changeset
|
20 import time |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
26402
diff
changeset
|
21 |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
26402
diff
changeset
|
22 from .i18n import _ |
43876
c59eb1560c44
py3: manually import getattr where it is needed
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43872
diff
changeset
|
23 from .pycompat import ( |
c59eb1560c44
py3: manually import getattr where it is needed
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43872
diff
changeset
|
24 getattr, |
c59eb1560c44
py3: manually import getattr where it is needed
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43872
diff
changeset
|
25 open, |
c59eb1560c44
py3: manually import getattr where it is needed
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43872
diff
changeset
|
26 ) |
26541
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
26402
diff
changeset
|
27 from . import ( |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
26402
diff
changeset
|
28 encoding, |
27227
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26685
diff
changeset
|
29 error, |
36833
1407c42b302c
py3: pass system string to email.message.Message.set_type()
Gregory Szorc <gregory.szorc@gmail.com>
parents:
35934
diff
changeset
|
30 pycompat, |
26541
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
26402
diff
changeset
|
31 sslutil, |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
26402
diff
changeset
|
32 util, |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
26402
diff
changeset
|
33 ) |
37870
f0b6fbea00cf
stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
36906
diff
changeset
|
34 from .utils import ( |
37906
a8a902d7176e
procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
37870
diff
changeset
|
35 procutil, |
37870
f0b6fbea00cf
stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
36906
diff
changeset
|
36 stringutil, |
f0b6fbea00cf
stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
36906
diff
changeset
|
37 ) |
2909
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
38 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
39 |
18885
cf1304fbc184
smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
17411
diff
changeset
|
40 class STARTTLS(smtplib.SMTP): |
cf1304fbc184
smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
17411
diff
changeset
|
41 '''Derived class to verify the peer certificate for STARTTLS. |
cf1304fbc184
smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
17411
diff
changeset
|
42 |
cf1304fbc184
smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
17411
diff
changeset
|
43 This class allows to pass any keyword arguments to SSL socket creation. |
cf1304fbc184
smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
17411
diff
changeset
|
44 ''' |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
45 |
30001
31acc78c632a
mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29998
diff
changeset
|
46 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:
17411
diff
changeset
|
47 smtplib.SMTP.__init__(self, **kwargs) |
29998
e6de6ef3e426
sslutil: remove ui from sslkwargs (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29977
diff
changeset
|
48 self._ui = ui |
29685
a4c5c23de1d3
mail: retain hostname for sslutil.wrapsocket (issue5203)
timeless <timeless@mozdev.org>
parents:
29012
diff
changeset
|
49 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:
17411
diff
changeset
|
50 |
cf1304fbc184
smtp: add the class to verify the certificate of the SMTP server for STARTTLS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
17411
diff
changeset
|
51 def starttls(self, keyfile=None, certfile=None): |
43956
3941e7063d03
py3: call SMTP.has_extn() with an str
Denis Laxalde <denis@laxalde.org>
parents:
43943
diff
changeset
|
52 if not self.has_extn("starttls"): |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
53 msg = b"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:
17411
diff
changeset
|
54 raise smtplib.SMTPException(msg) |
43957
a1801ee97840
py3: call SMTP.docmd() with an str
Denis Laxalde <denis@laxalde.org>
parents:
43956
diff
changeset
|
55 (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:
17411
diff
changeset
|
56 if resp == 220: |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
57 self.sock = sslutil.wrapsocket( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
58 self.sock, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
59 keyfile, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
60 certfile, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
61 ui=self._ui, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
62 serverhostname=self._host, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
63 ) |
43958
54b06bec8914
py3: use socket.makefile() instead of dropped smtplib.SSLFakeFile
Denis Laxalde <denis@laxalde.org>
parents:
43957
diff
changeset
|
64 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:
17411
diff
changeset
|
65 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:
17411
diff
changeset
|
66 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:
17411
diff
changeset
|
67 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:
17411
diff
changeset
|
68 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:
17411
diff
changeset
|
69 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:
17411
diff
changeset
|
70 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
71 |
27313 | 72 class SMTPS(smtplib.SMTP): |
73 '''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
|
74 |
27313 | 75 This class allows to pass any keyword arguments to SSL socket creation. |
76 ''' | |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
77 |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
78 def __init__(self, ui, keyfile=None, certfile=None, host=None, **kwargs): |
27313 | 79 self.keyfile = keyfile |
80 self.certfile = certfile | |
81 smtplib.SMTP.__init__(self, **kwargs) | |
29685
a4c5c23de1d3
mail: retain hostname for sslutil.wrapsocket (issue5203)
timeless <timeless@mozdev.org>
parents:
29012
diff
changeset
|
82 self._host = host |
27313 | 83 self.default_port = smtplib.SMTP_SSL_PORT |
29998
e6de6ef3e426
sslutil: remove ui from sslkwargs (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29977
diff
changeset
|
84 self._ui = ui |
27313 | 85 |
86 def _get_socket(self, host, port, timeout): | |
87 if self.debuglevel > 0: | |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
88 self._ui.debug(b'connect: %r\n' % ((host, port),)) |
27313 | 89 new_socket = socket.create_connection((host, port), timeout) |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
90 new_socket = sslutil.wrapsocket( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
91 new_socket, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
92 self.keyfile, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
93 self.certfile, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
94 ui=self._ui, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
95 serverhostname=self._host, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
96 ) |
39812
a5e70c14214a
mail: stop using the smtplib.SSLFakeFile and use socket.socket.makefile
Augie Fackler <augie@google.com>
parents:
39811
diff
changeset
|
97 self.file = new_socket.makefile(r'rb') |
27313 | 98 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
|
99 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
100 |
39811
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39810
diff
changeset
|
101 def _pyhastls(): |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39810
diff
changeset
|
102 """Returns true iff Python has TLS support, false otherwise.""" |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39810
diff
changeset
|
103 try: |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39810
diff
changeset
|
104 import ssl |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
105 |
39811
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39810
diff
changeset
|
106 getattr(ssl, 'HAS_TLS', False) |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39810
diff
changeset
|
107 return True |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39810
diff
changeset
|
108 except ImportError: |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39810
diff
changeset
|
109 return False |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39810
diff
changeset
|
110 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
111 |
2909
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
112 def _smtp(ui): |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5945
diff
changeset
|
113 '''build an smtp connection and return a function to send mail''' |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
114 local_hostname = ui.config(b'smtp', b'local_hostname') |
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
115 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
|
116 # backward compatible: when tls = true, we use starttls. |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
117 starttls = tls == b'starttls' or stringutil.parsebool(tls) |
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
118 smtps = tls == b'smtps' |
39811
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39810
diff
changeset
|
119 if (starttls or smtps) and not _pyhastls(): |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
120 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:
43863
diff
changeset
|
121 mailhost = ui.config(b'smtp', b'host') |
2909
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
122 if not mailhost: |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
123 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
|
124 if smtps: |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
125 ui.note(_(b'(using smtps)\n')) |
30001
31acc78c632a
mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29998
diff
changeset
|
126 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
|
127 elif starttls: |
30001
31acc78c632a
mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29998
diff
changeset
|
128 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
|
129 else: |
19d489404d79
smtp: verify the certificate of the SMTP server for STARTTLS/SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
18886
diff
changeset
|
130 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
|
131 if smtps: |
601c1e226889
smtp: use 465 as default port for SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
18916
diff
changeset
|
132 defaultport = 465 |
601c1e226889
smtp: use 465 as default port for SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
18916
diff
changeset
|
133 else: |
601c1e226889
smtp: use 465 as default port for SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
18916
diff
changeset
|
134 defaultport = 25 |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
135 mailport = util.getport(ui.config(b'smtp', b'port', defaultport)) |
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
136 ui.note(_(b'sending mail: smtp host %s, port %d\n') % (mailhost, mailport)) |
2909
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
137 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
|
138 if starttls: |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
139 ui.note(_(b'(using starttls)\n')) |
2909
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
140 s.ehlo() |
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
141 s.starttls() |
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
142 s.ehlo() |
30035
63a3749147af
mail: unsupport smtp.verifycert (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
30001
diff
changeset
|
143 if starttls or smtps: |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
144 ui.note(_(b'(verifying remote certificate)\n')) |
30035
63a3749147af
mail: unsupport smtp.verifycert (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
30001
diff
changeset
|
145 sslutil.validatesocket(s.sock) |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
146 username = ui.config(b'smtp', b'username') |
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
147 password = ui.config(b'smtp', b'password') |
43959
9145abd8b96d
py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents:
43958
diff
changeset
|
148 if username: |
9145abd8b96d
py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents:
43958
diff
changeset
|
149 if password: |
9145abd8b96d
py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents:
43958
diff
changeset
|
150 password = encoding.strfromlocal(password) |
9145abd8b96d
py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents:
43958
diff
changeset
|
151 else: |
9145abd8b96d
py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents:
43958
diff
changeset
|
152 password = ui.getpass() |
2909
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
153 if username and password: |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
154 ui.note(_(b'(authenticating to mail server as %s)\n') % username) |
43959
9145abd8b96d
py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents:
43958
diff
changeset
|
155 username = encoding.strfromlocal(username) |
9279
2de7d96593db
email: Catch exceptions during send.
David Soria Parra <dsp@php.net>
parents:
8343
diff
changeset
|
156 try: |
2de7d96593db
email: Catch exceptions during send.
David Soria Parra <dsp@php.net>
parents:
8343
diff
changeset
|
157 s.login(username, password) |
26214
328739ea70c3
global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25999
diff
changeset
|
158 except smtplib.SMTPException as inst: |
27227
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26685
diff
changeset
|
159 raise error.Abort(inst) |
2909
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
160 |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5945
diff
changeset
|
161 def send(sender, recipients, msg): |
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5945
diff
changeset
|
162 try: |
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5945
diff
changeset
|
163 return s.sendmail(sender, recipients, msg) |
26214
328739ea70c3
global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25999
diff
changeset
|
164 except smtplib.SMTPRecipientsRefused as inst: |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5945
diff
changeset
|
165 recipients = [r[1] for r in inst.recipients.values()] |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
166 raise error.Abort(b'\n' + b'\n'.join(recipients)) |
26214
328739ea70c3
global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25999
diff
changeset
|
167 except smtplib.SMTPException as inst: |
27227
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26685
diff
changeset
|
168 raise error.Abort(inst) |
5945
528c986f0162
Backed out changeset dc6ed2736c81
Bryan O'Sullivan <bos@serpentine.com>
parents:
5873
diff
changeset
|
169 |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5945
diff
changeset
|
170 return send |
5945
528c986f0162
Backed out changeset dc6ed2736c81
Bryan O'Sullivan <bos@serpentine.com>
parents:
5873
diff
changeset
|
171 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
172 |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5945
diff
changeset
|
173 def _sendmail(ui, sender, recipients, msg): |
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5945
diff
changeset
|
174 '''send mail using sendmail.''' |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
175 program = ui.config(b'email', b'method') |
43883
813aa8cc55d4
patchbomb: use procutil.shellquote() instead of shlex to escape email address
Yuya Nishihara <yuya@tcha.org>
parents:
43876
diff
changeset
|
176 |
813aa8cc55d4
patchbomb: use procutil.shellquote() instead of shlex to escape email address
Yuya Nishihara <yuya@tcha.org>
parents:
43876
diff
changeset
|
177 def stremail(x): |
813aa8cc55d4
patchbomb: use procutil.shellquote() instead of shlex to escape email address
Yuya Nishihara <yuya@tcha.org>
parents:
43876
diff
changeset
|
178 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:
43876
diff
changeset
|
179 |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
180 cmdline = b'%s -f %s %s' % ( |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
181 program, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
182 stremail(sender), |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
183 b' '.join(map(stremail, recipients)), |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
184 ) |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
185 ui.note(_(b'sending mail: %s\n') % cmdline) |
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
186 fp = procutil.popen(cmdline, b'wb') |
38244
00e4bd97b095
procutil: always popen() in binary mode
Yuya Nishihara <yuya@tcha.org>
parents:
37906
diff
changeset
|
187 fp.write(util.tonativeeol(msg)) |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5945
diff
changeset
|
188 ret = fp.close() |
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5945
diff
changeset
|
189 if ret: |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
190 raise error.Abort( |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
191 b'%s %s' |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
192 % ( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
193 os.path.basename(program.split(None, 1)[0]), |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
194 procutil.explainexit(ret), |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
195 ) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
196 ) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
197 |
2909
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
198 |
15560
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14966
diff
changeset
|
199 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:
14966
diff
changeset
|
200 '''write mails to mbox''' |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
201 fp = open(mbox, b'ab+') |
15560
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14966
diff
changeset
|
202 # Should be time.asctime(), but Windows prints 2-characters day |
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14966
diff
changeset
|
203 # of month instead of one. Make them print the same thing. |
35934
b45a9d121b53
py3: make sure the first argument of time.strftime() is str
Pulkit Goyal <7895pulkit@gmail.com>
parents:
35093
diff
changeset
|
204 date = time.strftime(r'%a %b %d %H:%M:%S %Y', time.localtime()) |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
205 fp.write( |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
206 b'From %s %s\n' |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
207 % (encoding.strtolocal(sender), encoding.strtolocal(date)) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
208 ) |
15560
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14966
diff
changeset
|
209 fp.write(msg) |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
210 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:
14966
diff
changeset
|
211 fp.close() |
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14966
diff
changeset
|
212 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
213 |
15560
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14966
diff
changeset
|
214 def connect(ui, mbox=None): |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5945
diff
changeset
|
215 '''make a mail connection. return a function to send mail. |
2909
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
216 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:
14966
diff
changeset
|
217 if mbox: |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
218 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:
14966
diff
changeset
|
219 return lambda s, r, m: _mbox(mbox, s, r, m) |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
220 if ui.config(b'email', b'method') == b'smtp': |
5945
528c986f0162
Backed out changeset dc6ed2736c81
Bryan O'Sullivan <bos@serpentine.com>
parents:
5873
diff
changeset
|
221 return _smtp(ui) |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5945
diff
changeset
|
222 return lambda s, r, m: _sendmail(ui, s, r, m) |
2909
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
223 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
224 |
15561
ca572e94d8e7
notify: add option for writing to mbox
Mads Kiilerich <mads@kiilerich.com>
parents:
15560
diff
changeset
|
225 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
|
226 send = connect(ui, mbox=mbox) |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5945
diff
changeset
|
227 return send(sender, recipients, msg) |
4483
a11e13d50645
patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents:
4096
diff
changeset
|
228 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
229 |
4483
a11e13d50645
patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents:
4096
diff
changeset
|
230 def validateconfig(ui): |
a11e13d50645
patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents:
4096
diff
changeset
|
231 '''determine if we have enough config data to try sending email.''' |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
232 method = ui.config(b'email', b'method') |
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
233 if method == b'smtp': |
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
234 if not ui.config(b'smtp', b'host'): |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
235 raise error.Abort( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
236 _( |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
237 b'smtp specified as email transport, ' |
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
238 b'but no smtp host configured' |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
239 ) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
240 ) |
4483
a11e13d50645
patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents:
4096
diff
changeset
|
241 else: |
37906
a8a902d7176e
procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
37870
diff
changeset
|
242 if not procutil.findexe(method): |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
243 raise error.Abort( |
43904
8ff1ecfadcd1
cleanup: join string literals that are already on one line
Martin von Zweigbergk <martinvonz@google.com>
parents:
43883
diff
changeset
|
244 _(b'%r specified as email transport, but not in PATH') % method |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
245 ) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
246 |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
247 |
30868
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30851
diff
changeset
|
248 def codec2iana(cs): |
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30851
diff
changeset
|
249 '''''' |
36905
6ea7f1c10c81
py3: cast character set to bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36904
diff
changeset
|
250 cs = pycompat.sysbytes(email.charset.Charset(cs).input_charset.lower()) |
30868
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30851
diff
changeset
|
251 |
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30851
diff
changeset
|
252 # "latin1" normalizes to "iso8859-1", standard calls for "iso-8859-1" |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
253 if cs.startswith(b"iso") and not cs.startswith(b"iso-"): |
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
254 return b"iso-" + cs[3:] |
30868
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30851
diff
changeset
|
255 return cs |
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30851
diff
changeset
|
256 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
257 |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
258 def mimetextpatch(s, subtype=b'plain', display=False): |
15562
a82b6038ff08
mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents:
15561
diff
changeset
|
259 '''Return MIME message suitable for a patch. |
30868
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30851
diff
changeset
|
260 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:
30851
diff
changeset
|
261 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:
30851
diff
changeset
|
262 ISO-8859-1, an encoding with that allows all byte sequences. |
15562
a82b6038ff08
mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents:
15561
diff
changeset
|
263 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
|
264 |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
265 cs = [b'us-ascii', b'utf-8', encoding.encoding, encoding.fallbackencoding] |
30868
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30851
diff
changeset
|
266 if display: |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
267 cs = [b'us-ascii'] |
30868
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30851
diff
changeset
|
268 for charset in cs: |
8332
3e544c074459
patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents:
8312
diff
changeset
|
269 try: |
36904
9e47bfbeb723
py3: cast decode() argument to system string
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36833
diff
changeset
|
270 s.decode(pycompat.sysstr(charset)) |
30868
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30851
diff
changeset
|
271 return mimetextqp(s, subtype, codec2iana(charset)) |
8332
3e544c074459
patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents:
8312
diff
changeset
|
272 except UnicodeDecodeError: |
30868
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30851
diff
changeset
|
273 pass |
8332
3e544c074459
patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents:
8312
diff
changeset
|
274 |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
275 return mimetextqp(s, subtype, b"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
|
276 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
277 |
15562
a82b6038ff08
mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents:
15561
diff
changeset
|
278 def mimetextqp(body, subtype, charset): |
a82b6038ff08
mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents:
15561
diff
changeset
|
279 '''Return MIME message. |
17407
e7cfe3587ea4
fix trivial spelling errors
Mads Kiilerich <mads@kiilerich.com>
parents:
15562
diff
changeset
|
280 Quoted-printable transfer encoding will be used if necessary. |
15562
a82b6038ff08
mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents:
15561
diff
changeset
|
281 ''' |
35093
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
34282
diff
changeset
|
282 cs = email.charset.Charset(charset) |
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
34282
diff
changeset
|
283 msg = email.message.Message() |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
284 msg.set_type(pycompat.sysstr(b'text/' + subtype)) |
35093
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
34282
diff
changeset
|
285 |
15562
a82b6038ff08
mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents:
15561
diff
changeset
|
286 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
|
287 if len(line) > 950: |
35093
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
34282
diff
changeset
|
288 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
|
289 break |
a82b6038ff08
mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents:
15561
diff
changeset
|
290 |
42191
9b3be572ff0c
mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents:
39894
diff
changeset
|
291 # 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:
39894
diff
changeset
|
292 # body and does different things depending on whether it has |
9b3be572ff0c
mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents:
39894
diff
changeset
|
293 # encode() or decode() attributes. We can get the old behavior |
9b3be572ff0c
mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents:
39894
diff
changeset
|
294 # 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:
39894
diff
changeset
|
295 # 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:
39894
diff
changeset
|
296 # encode/decode using the registered charset (or attempting to |
9b3be572ff0c
mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents:
39894
diff
changeset
|
297 # use ascii in the absence of a charset). |
35093
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
34282
diff
changeset
|
298 msg.set_payload(body, cs) |
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
34282
diff
changeset
|
299 |
8332
3e544c074459
patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents:
8312
diff
changeset
|
300 return msg |
7191
d14212218582
mail: mime-encode patches that are utf-8
Christian Ebert <blacktrash@gmx.net>
parents:
7114
diff
changeset
|
301 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
302 |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
303 def _charsets(ui): |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
304 '''Obtains charsets to send mail parts not containing patches.''' |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
305 charsets = [cs.lower() for cs in ui.configlist(b'email', b'charsets')] |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
306 fallbacks = [ |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
307 encoding.fallbackencoding.lower(), |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
308 encoding.encoding.lower(), |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
309 b'utf-8', |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
310 ] |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
311 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:
6534
diff
changeset
|
312 if cs not in charsets: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
313 charsets.append(cs) |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
314 return [cs for cs in charsets if not cs.endswith(b'ascii')] |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
315 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
316 |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
317 def _encode(ui, s, charsets): |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
318 '''Returns (converted) string, charset tuple. |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
319 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
|
320 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:
6534
diff
changeset
|
321 last resort send as is in fake ascii. |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
322 Caveat: Do not use for mail parts containing patches!''' |
39809
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
39118
diff
changeset
|
323 sendcharsets = charsets or _charsets(ui) |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
39118
diff
changeset
|
324 if not isinstance(s, bytes): |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
39118
diff
changeset
|
325 # 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:
39118
diff
changeset
|
326 # 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:
39118
diff
changeset
|
327 # 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:
39118
diff
changeset
|
328 for ocs in sendcharsets: |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
39118
diff
changeset
|
329 try: |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
39118
diff
changeset
|
330 return s.encode(pycompat.sysstr(ocs)), ocs |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
39118
diff
changeset
|
331 except UnicodeEncodeError: |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
39118
diff
changeset
|
332 pass |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
39118
diff
changeset
|
333 except LookupError: |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
334 ui.warn(_(b'ignoring invalid sendcharset: %s\n') % ocs) |
39809
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
39118
diff
changeset
|
335 else: |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
39118
diff
changeset
|
336 # Everything failed, ascii-armor what we've got and send it. |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
39118
diff
changeset
|
337 return s.encode('ascii', 'backslashreplace') |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
39118
diff
changeset
|
338 # 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:
39118
diff
changeset
|
339 # 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:
39118
diff
changeset
|
340 # know that's wrong. |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
341 try: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
342 s.decode('ascii') |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
343 except UnicodeDecodeError: |
7948
de377b1a9a84
move encoding bits from util to encoding
Matt Mackall <mpm@selenic.com>
parents:
7195
diff
changeset
|
344 for ics in (encoding.encoding, encoding.fallbackencoding): |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
345 try: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
346 u = s.decode(ics) |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
347 except UnicodeDecodeError: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
348 continue |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
349 for ocs in sendcharsets: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
350 try: |
39809
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
39118
diff
changeset
|
351 return u.encode(pycompat.sysstr(ocs)), ocs |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
352 except UnicodeEncodeError: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
353 pass |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
354 except LookupError: |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
355 ui.warn(_(b'ignoring invalid sendcharset: %s\n') % ocs) |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
356 # if ascii, or all conversion attempts fail, send (broken) ascii |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
357 return s, b'us-ascii' |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
358 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
359 |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
360 def headencode(ui, s, charsets=None, display=False): |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
361 '''Returns RFC-2047 compliant header from given string.''' |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
362 if not display: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
363 # split into words? |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
364 s, cs = _encode(ui, s, charsets) |
30851
87b8e40eb812
mail: handle renamed email.Header
Pulkit Goyal <7895pulkit@gmail.com>
parents:
30035
diff
changeset
|
365 return str(email.header.Header(s, cs)) |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
366 return s |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
367 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
368 |
9948
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
369 def _addressencode(ui, name, addr, charsets=None): |
39892
ebf54a34b7b7
mail: pass in addr to _addressencode() in bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39891
diff
changeset
|
370 assert isinstance(addr, bytes) |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
371 name = headencode(ui, name, charsets) |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
372 try: |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
373 acc, dom = addr.split(b'@') |
39893
c2327bb3505d
mail: call s.decode('ascii') explicitly to see if s is an ascii bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39892
diff
changeset
|
374 acc.decode('ascii') |
39894
d2d89d31cbb5
mail: convert encoding.encoding to sysstr
Yuya Nishihara <yuya@tcha.org>
parents:
39893
diff
changeset
|
375 dom = dom.decode(pycompat.sysstr(encoding.encoding)).encode('idna') |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
376 addr = b'%s@%s' % (acc, dom) |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
377 except UnicodeDecodeError: |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
378 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:
6534
diff
changeset
|
379 except ValueError: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
380 try: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
381 # too strict? |
39893
c2327bb3505d
mail: call s.decode('ascii') explicitly to see if s is an ascii bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39892
diff
changeset
|
382 addr.decode('ascii') |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
383 except UnicodeDecodeError: |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
384 raise error.Abort(_(b'invalid local address: %s') % addr) |
39810
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39809
diff
changeset
|
385 return pycompat.bytesurl( |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
386 email.utils.formataddr((name, encoding.strfromlocal(addr))) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
387 ) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
388 |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
389 |
9948
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
390 def addressencode(ui, address, charsets=None, display=False): |
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
391 '''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
|
392 if display or not address: |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
393 return address or b'' |
39810
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39809
diff
changeset
|
394 name, addr = email.utils.parseaddr(encoding.strfromlocal(address)) |
39892
ebf54a34b7b7
mail: pass in addr to _addressencode() in bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39891
diff
changeset
|
395 return _addressencode(ui, name, encoding.strtolocal(addr), charsets) |
9948
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
396 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
397 |
9948
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
398 def addrlistencode(ui, addrs, charsets=None, display=False): |
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
399 '''Turns a list of addresses into a list of RFC-2047 compliant headers. |
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
400 A single element of input list may contain multiple addresses, but output |
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
401 always has one address per item''' |
39810
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39809
diff
changeset
|
402 for a in addrs: |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
403 assert isinstance(a, bytes), r'%r unexpectedly not a bytestr' % a |
9948
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
404 if display: |
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
405 return [a.strip() for a in addrs if a.strip()] |
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
406 |
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
407 result = [] |
39810
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39809
diff
changeset
|
408 for name, addr in email.utils.getaddresses( |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
409 [encoding.strfromlocal(a) for a in addrs] |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
410 ): |
9948
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
411 if name or addr: |
39892
ebf54a34b7b7
mail: pass in addr to _addressencode() in bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39891
diff
changeset
|
412 r = _addressencode(ui, name, encoding.strtolocal(addr), charsets) |
ebf54a34b7b7
mail: pass in addr to _addressencode() in bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39891
diff
changeset
|
413 result.append(r) |
39891
f68ad9b4a43b
mail: remove redundant bytesurl() from addrlistencode()
Yuya Nishihara <yuya@tcha.org>
parents:
39825
diff
changeset
|
414 return result |
9948
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
415 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
416 |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
417 def mimeencode(ui, s, charsets=None, display=False): |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
418 '''creates mime text object, encodes it if needed, and sets |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
419 charset and transfer-encoding accordingly.''' |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
420 cs = b'us-ascii' |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
421 if not display: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6534
diff
changeset
|
422 s, cs = _encode(ui, s, charsets) |
43864
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43863
diff
changeset
|
423 return mimetextqp(s, b'plain', cs) |
29012
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
424 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
425 |
39118
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
426 if pycompat.ispy3: |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
427 |
43943
0e6a7ce81dde
py3: use email.generator.BytesGenerator in patch.split()
Denis Laxalde <denis.laxalde@logilab.fr>
parents:
43904
diff
changeset
|
428 Generator = email.generator.BytesGenerator |
0e6a7ce81dde
py3: use email.generator.BytesGenerator in patch.split()
Denis Laxalde <denis.laxalde@logilab.fr>
parents:
43904
diff
changeset
|
429 |
39118
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
430 def parse(fp): |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
431 ep = email.parser.Parser() |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
432 # disable the "universal newlines" mode, which isn't binary safe. |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
433 # I have no idea if ascii/surrogateescape is correct, but that's |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
434 # what the standard Python email parser does. |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
435 fp = io.TextIOWrapper( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
436 fp, encoding=r'ascii', errors=r'surrogateescape', newline=chr(10) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
437 ) |
39118
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
438 try: |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
439 return ep.parse(fp) |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
440 finally: |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
441 fp.detach() |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
442 |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
443 |
39118
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
444 else: |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
445 |
43943
0e6a7ce81dde
py3: use email.generator.BytesGenerator in patch.split()
Denis Laxalde <denis.laxalde@logilab.fr>
parents:
43904
diff
changeset
|
446 Generator = email.generator.Generator |
0e6a7ce81dde
py3: use email.generator.BytesGenerator in patch.split()
Denis Laxalde <denis.laxalde@logilab.fr>
parents:
43904
diff
changeset
|
447 |
39118
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
448 def parse(fp): |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
449 ep = email.parser.Parser() |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
450 return ep.parse(fp) |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
38255
diff
changeset
|
451 |
43863
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43806
diff
changeset
|
452 |
29012
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
453 def headdecode(s): |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
454 '''Decodes RFC-2047 header''' |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
455 uparts = [] |
30851
87b8e40eb812
mail: handle renamed email.Header
Pulkit Goyal <7895pulkit@gmail.com>
parents:
30035
diff
changeset
|
456 for part, charset in email.header.decode_header(s): |
29012
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
457 if charset is not None: |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
458 try: |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
459 uparts.append(part.decode(charset)) |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
460 continue |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
461 except UnicodeDecodeError: |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
462 pass |
38255
7edf68862fe3
py3: work around weird handling of bytes/unicode in decode_header()
Yuya Nishihara <yuya@tcha.org>
parents:
38249
diff
changeset
|
463 # 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:
38249
diff
changeset
|
464 # 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:
38249
diff
changeset
|
465 if isinstance(part, type(u'')): |
7edf68862fe3
py3: work around weird handling of bytes/unicode in decode_header()
Yuya Nishihara <yuya@tcha.org>
parents:
38249
diff
changeset
|
466 uparts.append(part) |
7edf68862fe3
py3: work around weird handling of bytes/unicode in decode_header()
Yuya Nishihara <yuya@tcha.org>
parents:
38249
diff
changeset
|
467 continue |
29012
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
468 try: |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
469 uparts.append(part.decode('UTF-8')) |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
470 continue |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
471 except UnicodeDecodeError: |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
472 pass |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
28274
diff
changeset
|
473 uparts.append(part.decode('ISO-8859-1')) |
32226
067add650129
encoding: factor out unicode variants of from/tolocal()
Yuya Nishihara <yuya@tcha.org>
parents:
31104
diff
changeset
|
474 return encoding.unitolocal(u' '.join(uparts)) |