Mercurial > public > mercurial-scm > hg-stable
annotate mercurial/mail.py @ 43172: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 | 866bd2cf764b |
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 # |
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. |
2889
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
7 |
30335
f6369544bf85
mail: do not print(), use ui.debug() instead
Yuya Nishihara <yuya@tcha.org>
parents:
30089
diff
changeset
|
8 from __future__ import absolute_import |
25957
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
9 |
19790
53f16f4aff33
mail: correct import of email module
Augie Fackler <raf@durin42.com>
parents:
19050
diff
changeset
|
10 import email |
30089
040f23ed6963
mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
11 import email.charset |
43156
0e6a7ce81dde
py3: use email.generator.BytesGenerator in patch.split()
Denis Laxalde <denis.laxalde@logilab.fr>
parents:
43117
diff
changeset
|
12 import email.generator |
30072
87b8e40eb812
mail: handle renamed email.Header
Pulkit Goyal <7895pulkit@gmail.com>
parents:
29285
diff
changeset
|
13 import email.header |
34317
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
33499
diff
changeset
|
14 import email.message |
38341
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
15 import email.parser |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
16 import io |
25957
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
17 import os |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
18 import smtplib |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
19 import socket |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
20 import time |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
21 |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
22 from .i18n import _ |
43089
c59eb1560c44
py3: manually import getattr where it is needed
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43085
diff
changeset
|
23 from .pycompat import ( |
c59eb1560c44
py3: manually import getattr where it is needed
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43085
diff
changeset
|
24 getattr, |
c59eb1560c44
py3: manually import getattr where it is needed
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43085
diff
changeset
|
25 open, |
c59eb1560c44
py3: manually import getattr where it is needed
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43085
diff
changeset
|
26 ) |
25957
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
27 from . import ( |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
28 encoding, |
26587
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26098
diff
changeset
|
29 error, |
36085
1407c42b302c
py3: pass system string to email.message.Message.set_type()
Gregory Szorc <gregory.szorc@gmail.com>
parents:
35172
diff
changeset
|
30 pycompat, |
25957
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
31 sslutil, |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
32 util, |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
33 ) |
37087
f0b6fbea00cf
stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
36158
diff
changeset
|
34 from .utils import ( |
37123
a8a902d7176e
procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
37087
diff
changeset
|
35 procutil, |
37087
f0b6fbea00cf
stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
36158
diff
changeset
|
36 stringutil, |
f0b6fbea00cf
stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
36158
diff
changeset
|
37 ) |
2889
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
38 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
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:
17428
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:
17428
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:
17428
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:
17428
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:
17428
diff
changeset
|
44 ''' |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
45 |
29251
31acc78c632a
mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29248
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:
17428
diff
changeset
|
47 smtplib.SMTP.__init__(self, **kwargs) |
29248
e6de6ef3e426
sslutil: remove ui from sslkwargs (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29227
diff
changeset
|
48 self._ui = ui |
28935
a4c5c23de1d3
mail: retain hostname for sslutil.wrapsocket (issue5203)
timeless <timeless@mozdev.org>
parents:
28341
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:
17428
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:
17428
diff
changeset
|
51 def starttls(self, keyfile=None, certfile=None): |
43169
3941e7063d03
py3: call SMTP.has_extn() with an str
Denis Laxalde <denis@laxalde.org>
parents:
43156
diff
changeset
|
52 if not self.has_extn("starttls"): |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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:
17428
diff
changeset
|
54 raise smtplib.SMTPException(msg) |
43170
a1801ee97840
py3: call SMTP.docmd() with an str
Denis Laxalde <denis@laxalde.org>
parents:
43169
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:
17428
diff
changeset
|
56 if resp == 220: |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
57 self.sock = sslutil.wrapsocket( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
58 self.sock, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
59 keyfile, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
60 certfile, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
61 ui=self._ui, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
62 serverhostname=self._host, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
63 ) |
43171
54b06bec8914
py3: use socket.makefile() instead of dropped smtplib.SSLFakeFile
Denis Laxalde <denis@laxalde.org>
parents:
43170
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:
17428
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:
17428
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:
17428
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:
17428
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:
17428
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:
17428
diff
changeset
|
70 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
71 |
26673 | 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 |
26673 | 75 This class allows to pass any keyword arguments to SSL socket creation. |
76 ''' | |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
77 |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
78 def __init__(self, ui, keyfile=None, certfile=None, host=None, **kwargs): |
26673 | 79 self.keyfile = keyfile |
80 self.certfile = certfile | |
81 smtplib.SMTP.__init__(self, **kwargs) | |
28935
a4c5c23de1d3
mail: retain hostname for sslutil.wrapsocket (issue5203)
timeless <timeless@mozdev.org>
parents:
28341
diff
changeset
|
82 self._host = host |
26673 | 83 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
|
84 self._ui = ui |
26673 | 85 |
86 def _get_socket(self, host, port, timeout): | |
87 if self.debuglevel > 0: | |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
88 self._ui.debug(b'connect: %r\n' % ((host, port),)) |
26673 | 89 new_socket = socket.create_connection((host, port), timeout) |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
90 new_socket = sslutil.wrapsocket( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
91 new_socket, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
92 self.keyfile, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
93 self.certfile, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
94 ui=self._ui, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
95 serverhostname=self._host, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
96 ) |
39063
a5e70c14214a
mail: stop using the smtplib.SSLFakeFile and use socket.socket.makefile
Augie Fackler <augie@google.com>
parents:
39062
diff
changeset
|
97 self.file = new_socket.makefile(r'rb') |
26673 | 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 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
100 |
39062
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39061
diff
changeset
|
101 def _pyhastls(): |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39061
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:
39061
diff
changeset
|
103 try: |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39061
diff
changeset
|
104 import ssl |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
105 |
39062
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39061
diff
changeset
|
106 getattr(ssl, 'HAS_TLS', False) |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39061
diff
changeset
|
107 return True |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39061
diff
changeset
|
108 except ImportError: |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39061
diff
changeset
|
109 return False |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39061
diff
changeset
|
110 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
111 |
2889
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:
5947
diff
changeset
|
113 '''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
|
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:
43076
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. |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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:
43076
diff
changeset
|
118 smtps = tls == b'smtps' |
39062
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39061
diff
changeset
|
119 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
|
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:
43076
diff
changeset
|
121 mailhost = ui.config(b'smtp', b'host') |
2889
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
122 if not mailhost: |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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: |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
125 ui.note(_(b'(using smtps)\n')) |
29251
31acc78c632a
mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29248
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: |
29251
31acc78c632a
mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29248
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 |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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:
43076
diff
changeset
|
136 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
|
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: |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
139 ui.note(_(b'(using starttls)\n')) |
2889
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() |
29285
63a3749147af
mail: unsupport smtp.verifycert (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29251
diff
changeset
|
143 if starttls or smtps: |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
144 ui.note(_(b'(verifying remote certificate)\n')) |
29285
63a3749147af
mail: unsupport smtp.verifycert (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29251
diff
changeset
|
145 sslutil.validatesocket(s.sock) |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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:
43076
diff
changeset
|
147 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
|
148 if username: |
9145abd8b96d
py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents:
43171
diff
changeset
|
149 if password: |
9145abd8b96d
py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents:
43171
diff
changeset
|
150 password = encoding.strfromlocal(password) |
9145abd8b96d
py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents:
43171
diff
changeset
|
151 else: |
9145abd8b96d
py3: decode username and password before SMTP login
Denis Laxalde <denis@laxalde.org>
parents:
43171
diff
changeset
|
152 password = ui.getpass() |
2889
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
153 if username and password: |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
154 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
|
155 username = encoding.strfromlocal(username) |
9246
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) |
25660
328739ea70c3
global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25463
diff
changeset
|
158 except smtplib.SMTPException as inst: |
26587
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26098
diff
changeset
|
159 raise error.Abort(inst) |
2889
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:
5947
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:
5947
diff
changeset
|
162 try: |
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5947
diff
changeset
|
163 return s.sendmail(sender, recipients, msg) |
25660
328739ea70c3
global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25463
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:
5947
diff
changeset
|
165 recipients = [r[1] for r in inst.recipients.values()] |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
166 raise error.Abort(b'\n' + b'\n'.join(recipients)) |
25660
328739ea70c3
global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25463
diff
changeset
|
167 except smtplib.SMTPException as inst: |
26587
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26098
diff
changeset
|
168 raise error.Abort(inst) |
5947
528c986f0162
Backed out changeset dc6ed2736c81
Bryan O'Sullivan <bos@serpentine.com>
parents:
5866
diff
changeset
|
169 |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5947
diff
changeset
|
170 return send |
5947
528c986f0162
Backed out changeset dc6ed2736c81
Bryan O'Sullivan <bos@serpentine.com>
parents:
5866
diff
changeset
|
171 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
172 |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5947
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:
5947
diff
changeset
|
174 '''send mail using sendmail.''' |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
175 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
|
176 |
813aa8cc55d4
patchbomb: use procutil.shellquote() instead of shlex to escape email address
Yuya Nishihara <yuya@tcha.org>
parents:
43089
diff
changeset
|
177 def stremail(x): |
813aa8cc55d4
patchbomb: use procutil.shellquote() instead of shlex to escape email address
Yuya Nishihara <yuya@tcha.org>
parents:
43089
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:
43089
diff
changeset
|
179 |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
180 cmdline = b'%s -f %s %s' % ( |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
181 program, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
182 stremail(sender), |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
183 b' '.join(map(stremail, recipients)), |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
184 ) |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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:
43076
diff
changeset
|
186 fp = procutil.popen(cmdline, b'wb') |
37458
00e4bd97b095
procutil: always popen() in binary mode
Yuya Nishihara <yuya@tcha.org>
parents:
37123
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:
5947
diff
changeset
|
188 ret = fp.close() |
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5947
diff
changeset
|
189 if ret: |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
190 raise error.Abort( |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
191 b'%s %s' |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
192 % ( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
193 os.path.basename(program.split(None, 1)[0]), |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
194 procutil.explainexit(ret), |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
195 ) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
196 ) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
197 |
2889
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:
14965
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:
14965
diff
changeset
|
200 '''write mails to mbox''' |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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:
14965
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:
14965
diff
changeset
|
203 # of month instead of one. Make them print the same thing. |
35172
b45a9d121b53
py3: make sure the first argument of time.strftime() is str
Pulkit Goyal <7895pulkit@gmail.com>
parents:
34317
diff
changeset
|
204 date = time.strftime(r'%a %b %d %H:%M:%S %Y', time.localtime()) |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
205 fp.write( |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
206 b'From %s %s\n' |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
207 % (encoding.strtolocal(sender), encoding.strtolocal(date)) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
208 ) |
15560
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14965
diff
changeset
|
209 fp.write(msg) |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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:
14965
diff
changeset
|
211 fp.close() |
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14965
diff
changeset
|
212 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
213 |
15560
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14965
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:
5947
diff
changeset
|
215 '''make a mail connection. return a function to send mail. |
2889
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:
14965
diff
changeset
|
217 if mbox: |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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:
14965
diff
changeset
|
219 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
|
220 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
|
221 return _smtp(ui) |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5947
diff
changeset
|
222 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
|
223 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
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:
5947
diff
changeset
|
227 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
|
228 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
229 |
4489
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.''' |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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:
43076
diff
changeset
|
233 if method == b'smtp': |
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
234 if not ui.config(b'smtp', b'host'): |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
235 raise error.Abort( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
236 _( |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
237 b'smtp specified as email transport, ' |
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
238 b'but no smtp host configured' |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
239 ) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
240 ) |
4489
a11e13d50645
patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents:
4096
diff
changeset
|
241 else: |
37123
a8a902d7176e
procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
37087
diff
changeset
|
242 if not procutil.findexe(method): |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
243 raise error.Abort( |
43117
8ff1ecfadcd1
cleanup: join string literals that are already on one line
Martin von Zweigbergk <martinvonz@google.com>
parents:
43096
diff
changeset
|
244 _(b'%r specified as email transport, but not in PATH') % method |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
245 ) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
246 |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
247 |
30089
040f23ed6963
mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
248 def codec2iana(cs): |
040f23ed6963
mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
249 '''''' |
36157
6ea7f1c10c81
py3: cast character set to bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36156
diff
changeset
|
250 cs = pycompat.sysbytes(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
|
251 |
040f23ed6963
mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
252 # "latin1" normalizes to "iso8859-1", standard calls for "iso-8859-1" |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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:
43076
diff
changeset
|
254 return b"iso-" + cs[3:] |
30089
040f23ed6963
mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
255 return cs |
040f23ed6963
mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
256 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
257 |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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. |
30089
040f23ed6963
mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents:
30072
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:
30072
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:
30072
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 |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
265 cs = [b'us-ascii', b'utf-8', encoding.encoding, encoding.fallbackencoding] |
30089
040f23ed6963
mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
266 if display: |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
267 cs = [b'us-ascii'] |
30089
040f23ed6963
mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents:
30072
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: |
36156
9e47bfbeb723
py3: cast decode() argument to system string
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36085
diff
changeset
|
270 s.decode(pycompat.sysstr(charset)) |
30089
040f23ed6963
mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents:
30072
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: |
30089
040f23ed6963
mail: take --encoding and HGENCODING into account
G?bor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
273 pass |
8332
3e544c074459
patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents:
8312
diff
changeset
|
274 |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
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. |
17424
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 ''' |
34317
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
33499
diff
changeset
|
282 cs = email.charset.Charset(charset) |
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
33499
diff
changeset
|
283 msg = email.message.Message() |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
284 msg.set_type(pycompat.sysstr(b'text/' + subtype)) |
34317
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
33499
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: |
34317
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
33499
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 |
41427
9b3be572ff0c
mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents:
39145
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:
39145
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:
39145
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:
39145
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:
39145
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:
39145
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:
39145
diff
changeset
|
297 # use ascii in the absence of a charset). |
34317
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
33499
diff
changeset
|
298 msg.set_payload(body, cs) |
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
33499
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 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
302 |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
303 def _charsets(ui): |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
304 '''Obtains charsets to send mail parts not containing patches.''' |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
305 charsets = [cs.lower() for cs in ui.configlist(b'email', b'charsets')] |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
306 fallbacks = [ |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
307 encoding.fallbackencoding.lower(), |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
308 encoding.encoding.lower(), |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
309 b'utf-8', |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
310 ] |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
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:
6548
diff
changeset
|
312 if cs not in charsets: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
313 charsets.append(cs) |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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:
6548
diff
changeset
|
315 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
316 |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
317 def _encode(ui, s, charsets): |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
318 '''Returns (converted) string, charset tuple. |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
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:
6548
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:
6548
diff
changeset
|
322 Caveat: Do not use for mail parts containing patches!''' |
39060
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38341
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:
38341
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:
38341
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:
38341
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:
38341
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:
38341
diff
changeset
|
328 for ocs in sendcharsets: |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38341
diff
changeset
|
329 try: |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38341
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:
38341
diff
changeset
|
331 except UnicodeEncodeError: |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38341
diff
changeset
|
332 pass |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38341
diff
changeset
|
333 except LookupError: |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
334 ui.warn(_(b'ignoring invalid sendcharset: %s\n') % ocs) |
39060
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38341
diff
changeset
|
335 else: |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38341
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:
38341
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:
38341
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:
38341
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:
38341
diff
changeset
|
340 # know that's wrong. |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
341 try: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
342 s.decode('ascii') |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
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:
6548
diff
changeset
|
345 try: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
346 u = s.decode(ics) |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
347 except UnicodeDecodeError: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
348 continue |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
349 for ocs in sendcharsets: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
350 try: |
39060
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38341
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:
6548
diff
changeset
|
352 except UnicodeEncodeError: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
353 pass |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
354 except LookupError: |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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:
6548
diff
changeset
|
356 # if ascii, or all conversion attempts fail, send (broken) ascii |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
357 return s, b'us-ascii' |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
358 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
359 |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
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:
6548
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:
6548
diff
changeset
|
362 if not display: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
363 # split into words? |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
364 s, cs = _encode(ui, s, charsets) |
30072
87b8e40eb812
mail: handle renamed email.Header
Pulkit Goyal <7895pulkit@gmail.com>
parents:
29285
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:
6548
diff
changeset
|
366 return s |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
367 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
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): |
39143
ebf54a34b7b7
mail: pass in addr to _addressencode() in bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39142
diff
changeset
|
370 assert isinstance(addr, bytes) |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
371 name = headencode(ui, name, charsets) |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
372 try: |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
373 acc, dom = addr.split(b'@') |
39144
c2327bb3505d
mail: call s.decode('ascii') explicitly to see if s is an ascii bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39143
diff
changeset
|
374 acc.decode('ascii') |
39145
d2d89d31cbb5
mail: convert encoding.encoding to sysstr
Yuya Nishihara <yuya@tcha.org>
parents:
39144
diff
changeset
|
375 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
|
376 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
|
377 except UnicodeDecodeError: |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
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:
6548
diff
changeset
|
379 except ValueError: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
380 try: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
381 # too strict? |
39144
c2327bb3505d
mail: call s.decode('ascii') explicitly to see if s is an ascii bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39143
diff
changeset
|
382 addr.decode('ascii') |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
383 except UnicodeDecodeError: |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
384 raise error.Abort(_(b'invalid local address: %s') % addr) |
39061
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39060
diff
changeset
|
385 return pycompat.bytesurl( |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
386 email.utils.formataddr((name, encoding.strfromlocal(addr))) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
387 ) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
388 |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
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: |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
393 return address or b'' |
39061
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39060
diff
changeset
|
394 name, addr = email.utils.parseaddr(encoding.strfromlocal(address)) |
39143
ebf54a34b7b7
mail: pass in addr to _addressencode() in bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39142
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 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
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''' |
39061
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39060
diff
changeset
|
402 for a in addrs: |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
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 = [] |
39061
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39060
diff
changeset
|
408 for name, addr in email.utils.getaddresses( |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
409 [encoding.strfromlocal(a) for a in addrs] |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
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: |
39143
ebf54a34b7b7
mail: pass in addr to _addressencode() in bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39142
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:
39142
diff
changeset
|
413 result.append(r) |
39142
f68ad9b4a43b
mail: remove redundant bytesurl() from addrlistencode()
Yuya Nishihara <yuya@tcha.org>
parents:
39076
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 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
416 |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
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:
6548
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:
6548
diff
changeset
|
419 charset and transfer-encoding accordingly.''' |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
420 cs = b'us-ascii' |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
421 if not display: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
422 s, cs = _encode(ui, s, charsets) |
43077
687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents:
43076
diff
changeset
|
423 return mimetextqp(s, b'plain', cs) |
28341
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
424 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
425 |
38341
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
426 if pycompat.ispy3: |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
427 |
43156
0e6a7ce81dde
py3: use email.generator.BytesGenerator in patch.split()
Denis Laxalde <denis.laxalde@logilab.fr>
parents:
43117
diff
changeset
|
428 Generator = email.generator.BytesGenerator |
0e6a7ce81dde
py3: use email.generator.BytesGenerator in patch.split()
Denis Laxalde <denis.laxalde@logilab.fr>
parents:
43117
diff
changeset
|
429 |
38341
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
430 def parse(fp): |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
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:
37469
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:
37469
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:
37469
diff
changeset
|
434 # what the standard Python email parser does. |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
435 fp = io.TextIOWrapper( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
436 fp, encoding=r'ascii', errors=r'surrogateescape', newline=chr(10) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
437 ) |
38341
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
438 try: |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
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:
37469
diff
changeset
|
440 finally: |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
441 fp.detach() |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
442 |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
443 |
38341
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
444 else: |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
445 |
43156
0e6a7ce81dde
py3: use email.generator.BytesGenerator in patch.split()
Denis Laxalde <denis.laxalde@logilab.fr>
parents:
43117
diff
changeset
|
446 Generator = email.generator.Generator |
0e6a7ce81dde
py3: use email.generator.BytesGenerator in patch.split()
Denis Laxalde <denis.laxalde@logilab.fr>
parents:
43117
diff
changeset
|
447 |
38341
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
448 def parse(fp): |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
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:
37469
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:
37469
diff
changeset
|
451 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
43021
diff
changeset
|
452 |
28341
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
453 def headdecode(s): |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
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:
27619
diff
changeset
|
455 uparts = [] |
30072
87b8e40eb812
mail: handle renamed email.Header
Pulkit Goyal <7895pulkit@gmail.com>
parents:
29285
diff
changeset
|
456 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
|
457 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
|
458 try: |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
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:
27619
diff
changeset
|
460 continue |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
461 except UnicodeDecodeError: |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
462 pass |
37469
7edf68862fe3
py3: work around weird handling of bytes/unicode in decode_header()
Yuya Nishihara <yuya@tcha.org>
parents:
37463
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:
37463
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:
37463
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:
37463
diff
changeset
|
466 uparts.append(part) |
7edf68862fe3
py3: work around weird handling of bytes/unicode in decode_header()
Yuya Nishihara <yuya@tcha.org>
parents:
37463
diff
changeset
|
467 continue |
28341
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
468 try: |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
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:
27619
diff
changeset
|
470 continue |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
471 except UnicodeDecodeError: |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
472 pass |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
473 uparts.append(part.decode('ISO-8859-1')) |
31456
067add650129
encoding: factor out unicode variants of from/tolocal()
Yuya Nishihara <yuya@tcha.org>
parents:
30335
diff
changeset
|
474 return encoding.unitolocal(u' '.join(uparts)) |