Mercurial > hg
annotate mercurial/mail.py @ 42454:0eb8c61c306b
tests: show how the dirstate can end up containing wrong information
which can result in bad status output.
Concretely, this seems to be easily triggered by having a build system
watching the filesystem for changes, and rebuilding files that are
both tracked and generated while an update is happening.
Differential Revision: https://phab.mercurial-scm.org/D6474
author | Valentin Gatien-Baron <valentin.gatienbaron@gmail.com> |
---|---|
date | Sun, 19 May 2019 16:06:06 -0400 |
parents | 9b3be572ff0c |
children | 2cc453284d5c |
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 |
30325
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 |
30072
87b8e40eb812
mail: handle renamed email.Header
Pulkit Goyal <7895pulkit@gmail.com>
parents:
29285
diff
changeset
|
12 import email.header |
34310
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
33499
diff
changeset
|
13 import email.message |
38332
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
14 import email.parser |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
15 import io |
25957
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
16 import os |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
17 import smtplib |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
18 import socket |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
19 import time |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
20 |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
21 from .i18n import _ |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
22 from . import ( |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
23 encoding, |
26587
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26098
diff
changeset
|
24 error, |
36047
1407c42b302c
py3: pass system string to email.message.Message.set_type()
Gregory Szorc <gregory.szorc@gmail.com>
parents:
35151
diff
changeset
|
25 pycompat, |
25957
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
26 sslutil, |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
27 util, |
ae21d51bdc43
mail: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25842
diff
changeset
|
28 ) |
37084
f0b6fbea00cf
stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
36120
diff
changeset
|
29 from .utils import ( |
37120
a8a902d7176e
procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
37084
diff
changeset
|
30 procutil, |
37084
f0b6fbea00cf
stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
36120
diff
changeset
|
31 stringutil, |
f0b6fbea00cf
stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
36120
diff
changeset
|
32 ) |
2889
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
33 |
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
|
34 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
|
35 '''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
|
36 |
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
|
37 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
|
38 ''' |
29251
31acc78c632a
mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29248
diff
changeset
|
39 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
|
40 smtplib.SMTP.__init__(self, **kwargs) |
29248
e6de6ef3e426
sslutil: remove ui from sslkwargs (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29227
diff
changeset
|
41 self._ui = ui |
28935
a4c5c23de1d3
mail: retain hostname for sslutil.wrapsocket (issue5203)
timeless <timeless@mozdev.org>
parents:
28341
diff
changeset
|
42 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
|
43 |
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 def starttls(self, keyfile=None, certfile=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
|
45 if not self.has_extn("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
|
46 msg = "STARTTLS extension not supported by server" |
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 raise smtplib.SMTPException(msg) |
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
|
48 (resp, reply) = self.docmd("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
|
49 if resp == 220: |
25429
9d1c61715939
ssl: rename ssl_wrap_socket() to conform to our naming convention
Yuya Nishihara <yuya@tcha.org>
parents:
25205
diff
changeset
|
50 self.sock = sslutil.wrapsocket(self.sock, keyfile, certfile, |
29248
e6de6ef3e426
sslutil: remove ui from sslkwargs (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29227
diff
changeset
|
51 ui=self._ui, |
29251
31acc78c632a
mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29248
diff
changeset
|
52 serverhostname=self._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
|
53 self.file = smtplib.SSLFakeFile(self.sock) |
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 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
|
55 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
|
56 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
|
57 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
|
58 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
|
59 |
26673 | 60 class SMTPS(smtplib.SMTP): |
61 '''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
|
62 |
26673 | 63 This class allows to pass any keyword arguments to SSL socket creation. |
64 ''' | |
29251
31acc78c632a
mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29248
diff
changeset
|
65 def __init__(self, ui, keyfile=None, certfile=None, host=None, |
28935
a4c5c23de1d3
mail: retain hostname for sslutil.wrapsocket (issue5203)
timeless <timeless@mozdev.org>
parents:
28341
diff
changeset
|
66 **kwargs): |
26673 | 67 self.keyfile = keyfile |
68 self.certfile = certfile | |
69 smtplib.SMTP.__init__(self, **kwargs) | |
28935
a4c5c23de1d3
mail: retain hostname for sslutil.wrapsocket (issue5203)
timeless <timeless@mozdev.org>
parents:
28341
diff
changeset
|
70 self._host = host |
26673 | 71 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
|
72 self._ui = ui |
26673 | 73 |
74 def _get_socket(self, host, port, timeout): | |
75 if self.debuglevel > 0: | |
39028
713126389ef2
mail: fix debug print, which appears to have been broken for a long time
Augie Fackler <augie@google.com>
parents:
39026
diff
changeset
|
76 self._ui.debug('connect: %r\n' % ((host, port),)) |
26673 | 77 new_socket = socket.create_connection((host, port), timeout) |
78 new_socket = sslutil.wrapsocket(new_socket, | |
79 self.keyfile, self.certfile, | |
29248
e6de6ef3e426
sslutil: remove ui from sslkwargs (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29227
diff
changeset
|
80 ui=self._ui, |
29251
31acc78c632a
mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29248
diff
changeset
|
81 serverhostname=self._host) |
39026
a5e70c14214a
mail: stop using the smtplib.SSLFakeFile and use socket.socket.makefile
Augie Fackler <augie@google.com>
parents:
39025
diff
changeset
|
82 self.file = new_socket.makefile(r'rb') |
26673 | 83 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
|
84 |
39025
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39024
diff
changeset
|
85 def _pyhastls(): |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39024
diff
changeset
|
86 """Returns true iff Python has TLS support, false otherwise.""" |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39024
diff
changeset
|
87 try: |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39024
diff
changeset
|
88 import ssl |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39024
diff
changeset
|
89 getattr(ssl, 'HAS_TLS', False) |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39024
diff
changeset
|
90 return True |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39024
diff
changeset
|
91 except ImportError: |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39024
diff
changeset
|
92 return False |
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39024
diff
changeset
|
93 |
2889
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
94 def _smtp(ui): |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5947
diff
changeset
|
95 '''build an smtp connection and return a function to send mail''' |
2889
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
96 local_hostname = ui.config('smtp', 'local_hostname') |
33499
0407a51b9d8c
codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents:
32275
diff
changeset
|
97 tls = ui.config('smtp', 'tls') |
13201
f05250572467
smtp: fix for server doesn't support starttls extension
Zhigang Wang <zhigang.x.wang@oracle.com>
parents:
12091
diff
changeset
|
98 # backward compatible: when tls = true, we use starttls. |
37084
f0b6fbea00cf
stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
36120
diff
changeset
|
99 starttls = tls == 'starttls' or stringutil.parsebool(tls) |
13201
f05250572467
smtp: fix for server doesn't support starttls extension
Zhigang Wang <zhigang.x.wang@oracle.com>
parents:
12091
diff
changeset
|
100 smtps = tls == 'smtps' |
39025
569d662816de
mail: modernize check for Python-with-TLS
Augie Fackler <augie@google.com>
parents:
39024
diff
changeset
|
101 if (starttls or smtps) and not _pyhastls(): |
26587
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26098
diff
changeset
|
102 raise error.Abort(_("can't use TLS: Python SSL support not installed")) |
2889
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
103 mailhost = ui.config('smtp', 'host') |
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
104 if not mailhost: |
26587
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26098
diff
changeset
|
105 raise error.Abort(_('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
|
106 if smtps: |
19d489404d79
smtp: verify the certificate of the SMTP server for STARTTLS/SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
18886
diff
changeset
|
107 ui.note(_('(using smtps)\n')) |
29251
31acc78c632a
mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29248
diff
changeset
|
108 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
|
109 elif starttls: |
29251
31acc78c632a
mail: remove use of sslkwargs
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29248
diff
changeset
|
110 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
|
111 else: |
19d489404d79
smtp: verify the certificate of the SMTP server for STARTTLS/SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
18886
diff
changeset
|
112 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
|
113 if smtps: |
601c1e226889
smtp: use 465 as default port for SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
18916
diff
changeset
|
114 defaultport = 465 |
601c1e226889
smtp: use 465 as default port for SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
18916
diff
changeset
|
115 else: |
601c1e226889
smtp: use 465 as default port for SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
18916
diff
changeset
|
116 defaultport = 25 |
601c1e226889
smtp: use 465 as default port for SMTPS
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
18916
diff
changeset
|
117 mailport = util.getport(ui.config('smtp', 'port', defaultport)) |
26778
a95c975f42e3
l10n: use %d instead of %s for numbers
timeless@mozdev.org
parents:
26673
diff
changeset
|
118 ui.note(_('sending mail: smtp host %s, port %d\n') % |
2964
26c8d37496c2
fix typo in mail.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents:
2929
diff
changeset
|
119 (mailhost, mailport)) |
2889
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
120 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
|
121 if starttls: |
f05250572467
smtp: fix for server doesn't support starttls extension
Zhigang Wang <zhigang.x.wang@oracle.com>
parents:
12091
diff
changeset
|
122 ui.note(_('(using starttls)\n')) |
2889
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
123 s.ehlo() |
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
124 s.starttls() |
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
125 s.ehlo() |
29285
63a3749147af
mail: unsupport smtp.verifycert (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29251
diff
changeset
|
126 if starttls or smtps: |
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 ui.note(_('(verifying remote certificate)\n')) |
29285
63a3749147af
mail: unsupport smtp.verifycert (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
29251
diff
changeset
|
128 sslutil.validatesocket(s.sock) |
2889
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
129 username = ui.config('smtp', 'username') |
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
130 password = ui.config('smtp', 'password') |
5749
4fba4fee0718
Patchbomb: Prompt password when using SMTP/TLS and no password in .hgrc.
Arun Thomas <arun.thomas@gmail.com>
parents:
5472
diff
changeset
|
131 if username and not password: |
4fba4fee0718
Patchbomb: Prompt password when using SMTP/TLS and no password in .hgrc.
Arun Thomas <arun.thomas@gmail.com>
parents:
5472
diff
changeset
|
132 password = ui.getpass() |
2889
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
133 if username and password: |
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
134 ui.note(_('(authenticating to mail server as %s)\n') % |
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
135 (username)) |
9246
2de7d96593db
email: Catch exceptions during send.
David Soria Parra <dsp@php.net>
parents:
8343
diff
changeset
|
136 try: |
2de7d96593db
email: Catch exceptions during send.
David Soria Parra <dsp@php.net>
parents:
8343
diff
changeset
|
137 s.login(username, password) |
25660
328739ea70c3
global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25463
diff
changeset
|
138 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
|
139 raise error.Abort(inst) |
2889
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
140 |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5947
diff
changeset
|
141 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
|
142 try: |
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5947
diff
changeset
|
143 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
|
144 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
|
145 recipients = [r[1] for r in inst.recipients.values()] |
26587
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26098
diff
changeset
|
146 raise error.Abort('\n' + '\n'.join(recipients)) |
25660
328739ea70c3
global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25463
diff
changeset
|
147 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
|
148 raise error.Abort(inst) |
5947
528c986f0162
Backed out changeset dc6ed2736c81
Bryan O'Sullivan <bos@serpentine.com>
parents:
5866
diff
changeset
|
149 |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5947
diff
changeset
|
150 return send |
5947
528c986f0162
Backed out changeset dc6ed2736c81
Bryan O'Sullivan <bos@serpentine.com>
parents:
5866
diff
changeset
|
151 |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5947
diff
changeset
|
152 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
|
153 '''send mail using sendmail.''' |
33499
0407a51b9d8c
codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents:
32275
diff
changeset
|
154 program = ui.config('email', 'method') |
39031
2cf3bd4ae55e
mail: properly handle email addresses typically being unicodes
Augie Fackler <augie@google.com>
parents:
39028
diff
changeset
|
155 stremail = lambda x: stringutil.email(encoding.strtolocal(x)) |
2cf3bd4ae55e
mail: properly handle email addresses typically being unicodes
Augie Fackler <augie@google.com>
parents:
39028
diff
changeset
|
156 cmdline = '%s -f %s %s' % (program, stremail(sender), |
2cf3bd4ae55e
mail: properly handle email addresses typically being unicodes
Augie Fackler <augie@google.com>
parents:
39028
diff
changeset
|
157 ' '.join(map(stremail, recipients))) |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5947
diff
changeset
|
158 ui.note(_('sending mail: %s\n') % cmdline) |
37458
00e4bd97b095
procutil: always popen() in binary mode
Yuya Nishihara <yuya@tcha.org>
parents:
37120
diff
changeset
|
159 fp = procutil.popen(cmdline, 'wb') |
00e4bd97b095
procutil: always popen() in binary mode
Yuya Nishihara <yuya@tcha.org>
parents:
37120
diff
changeset
|
160 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
|
161 ret = fp.close() |
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5947
diff
changeset
|
162 if ret: |
26587
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26098
diff
changeset
|
163 raise error.Abort('%s %s' % ( |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5947
diff
changeset
|
164 os.path.basename(program.split(None, 1)[0]), |
37463
bbd240f81ac5
procutil: make explainexit() simply return a message (API)
Yuya Nishihara <yuya@tcha.org>
parents:
37458
diff
changeset
|
165 procutil.explainexit(ret))) |
2889
20b95aef3fe0
Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff
changeset
|
166 |
15560
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14965
diff
changeset
|
167 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
|
168 '''write mails to mbox''' |
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14965
diff
changeset
|
169 fp = open(mbox, 'ab+') |
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14965
diff
changeset
|
170 # 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
|
171 # of month instead of one. Make them print the same thing. |
35151
b45a9d121b53
py3: make sure the first argument of time.strftime() is str
Pulkit Goyal <7895pulkit@gmail.com>
parents:
34310
diff
changeset
|
172 date = time.strftime(r'%a %b %d %H:%M:%S %Y', time.localtime()) |
39031
2cf3bd4ae55e
mail: properly handle email addresses typically being unicodes
Augie Fackler <augie@google.com>
parents:
39028
diff
changeset
|
173 fp.write('From %s %s\n' % (encoding.strtolocal(sender), |
2cf3bd4ae55e
mail: properly handle email addresses typically being unicodes
Augie Fackler <augie@google.com>
parents:
39028
diff
changeset
|
174 encoding.strtolocal(date))) |
15560
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14965
diff
changeset
|
175 fp.write(msg) |
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14965
diff
changeset
|
176 fp.write('\n\n') |
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14965
diff
changeset
|
177 fp.close() |
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14965
diff
changeset
|
178 |
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14965
diff
changeset
|
179 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
|
180 '''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
|
181 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
|
182 if mbox: |
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14965
diff
changeset
|
183 open(mbox, 'wb').close() |
cc58c228503e
mail: mbox handling as a part of mail handling, refactored from patchbomb
Mads Kiilerich <mads@kiilerich.com>
parents:
14965
diff
changeset
|
184 return lambda s, r, m: _mbox(mbox, s, r, m) |
33499
0407a51b9d8c
codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents:
32275
diff
changeset
|
185 if ui.config('email', 'method') == 'smtp': |
5947
528c986f0162
Backed out changeset dc6ed2736c81
Bryan O'Sullivan <bos@serpentine.com>
parents:
5866
diff
changeset
|
186 return _smtp(ui) |
5973
ea77f6f77514
patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents:
5947
diff
changeset
|
187 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
|
188 |
15561
ca572e94d8e7
notify: add option for writing to mbox
Mads Kiilerich <mads@kiilerich.com>
parents:
15560
diff
changeset
|
189 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
|
190 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
|
191 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
|
192 |
a11e13d50645
patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents:
4096
diff
changeset
|
193 def validateconfig(ui): |
a11e13d50645
patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents:
4096
diff
changeset
|
194 '''determine if we have enough config data to try sending email.''' |
33499
0407a51b9d8c
codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents:
32275
diff
changeset
|
195 method = ui.config('email', 'method') |
4489
a11e13d50645
patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents:
4096
diff
changeset
|
196 if method == 'smtp': |
a11e13d50645
patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents:
4096
diff
changeset
|
197 if not ui.config('smtp', 'host'): |
26587
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26098
diff
changeset
|
198 raise error.Abort(_('smtp specified as email transport, ' |
4489
a11e13d50645
patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents:
4096
diff
changeset
|
199 'but no smtp host configured')) |
a11e13d50645
patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents:
4096
diff
changeset
|
200 else: |
37120
a8a902d7176e
procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents:
37084
diff
changeset
|
201 if not procutil.findexe(method): |
26587
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26098
diff
changeset
|
202 raise error.Abort(_('%r specified as email transport, ' |
4489
a11e13d50645
patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents:
4096
diff
changeset
|
203 'but not in PATH') % method) |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
204 |
30089
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
205 def codec2iana(cs): |
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
206 '''''' |
36119
6ea7f1c10c81
py3: cast character set to bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36118
diff
changeset
|
207 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
|
208 |
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
209 # "latin1" normalizes to "iso8859-1", standard calls for "iso-8859-1" |
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
210 if cs.startswith("iso") and not cs.startswith("iso-"): |
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
211 return "iso-" + cs[3:] |
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
212 return cs |
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
213 |
7191
d14212218582
mail: mime-encode patches that are utf-8
Christian Ebert <blacktrash@gmx.net>
parents:
7114
diff
changeset
|
214 def mimetextpatch(s, subtype='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
|
215 '''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
|
216 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
|
217 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
|
218 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
|
219 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
|
220 |
30089
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
221 cs = ['us-ascii', 'utf-8', encoding.encoding, encoding.fallbackencoding] |
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
222 if display: |
39037
ede768cfe83e
mail: always fall back to iso-8859-1 if us-ascii won't work (BC)
Augie Fackler <augie@google.com>
parents:
39031
diff
changeset
|
223 cs = ['us-ascii'] |
30089
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
224 for charset in cs: |
8332
3e544c074459
patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents:
8312
diff
changeset
|
225 try: |
36118
9e47bfbeb723
py3: cast decode() argument to system string
Gregory Szorc <gregory.szorc@gmail.com>
parents:
36047
diff
changeset
|
226 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
|
227 return mimetextqp(s, subtype, codec2iana(charset)) |
8332
3e544c074459
patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents:
8312
diff
changeset
|
228 except UnicodeDecodeError: |
30089
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
229 pass |
8332
3e544c074459
patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents:
8312
diff
changeset
|
230 |
30089
040f23ed6963
mail: take --encoding and HGENCODING into account
Gábor Stefanik <gabor.stefanik@nng.com>
parents:
30072
diff
changeset
|
231 return mimetextqp(s, subtype, "iso-8859-1") |
15562
a82b6038ff08
mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents:
15561
diff
changeset
|
232 |
a82b6038ff08
mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents:
15561
diff
changeset
|
233 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
|
234 '''Return MIME message. |
17424
e7cfe3587ea4
fix trivial spelling errors
Mads Kiilerich <mads@kiilerich.com>
parents:
15562
diff
changeset
|
235 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
|
236 ''' |
34310
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
33499
diff
changeset
|
237 cs = email.charset.Charset(charset) |
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
33499
diff
changeset
|
238 msg = email.message.Message() |
36047
1407c42b302c
py3: pass system string to email.message.Message.set_type()
Gregory Szorc <gregory.szorc@gmail.com>
parents:
35151
diff
changeset
|
239 msg.set_type(pycompat.sysstr('text/' + subtype)) |
34310
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
33499
diff
changeset
|
240 |
15562
a82b6038ff08
mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents:
15561
diff
changeset
|
241 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
|
242 if len(line) > 950: |
34310
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
33499
diff
changeset
|
243 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
|
244 break |
a82b6038ff08
mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents:
15561
diff
changeset
|
245 |
41405
9b3be572ff0c
mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents:
39108
diff
changeset
|
246 # On Python 2, this simply assigns a value. Python 3 inspects |
9b3be572ff0c
mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents:
39108
diff
changeset
|
247 # body and does different things depending on whether it has |
9b3be572ff0c
mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents:
39108
diff
changeset
|
248 # encode() or decode() attributes. We can get the old behavior |
9b3be572ff0c
mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents:
39108
diff
changeset
|
249 # if we pass a str and charset is None and we call set_charset(). |
9b3be572ff0c
mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents:
39108
diff
changeset
|
250 # But we may get into trouble later due to Python attempting to |
9b3be572ff0c
mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents:
39108
diff
changeset
|
251 # encode/decode using the registered charset (or attempting to |
9b3be572ff0c
mail: document behavior of Python 3
Gregory Szorc <gregory.szorc@gmail.com>
parents:
39108
diff
changeset
|
252 # use ascii in the absence of a charset). |
34310
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
33499
diff
changeset
|
253 msg.set_payload(body, cs) |
2d0c306a88c2
mail: encode long unicode lines in emails properly (issue5687)
Igor Ippolitov <iippolitov@gmail.com>
parents:
33499
diff
changeset
|
254 |
8332
3e544c074459
patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents:
8312
diff
changeset
|
255 return msg |
7191
d14212218582
mail: mime-encode patches that are utf-8
Christian Ebert <blacktrash@gmx.net>
parents:
7114
diff
changeset
|
256 |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
257 def _charsets(ui): |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
258 '''Obtains charsets to send mail parts not containing patches.''' |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
259 charsets = [cs.lower() for cs in ui.configlist('email', 'charsets')] |
7948
de377b1a9a84
move encoding bits from util to encoding
Matt Mackall <mpm@selenic.com>
parents:
7195
diff
changeset
|
260 fallbacks = [encoding.fallbackencoding.lower(), |
de377b1a9a84
move encoding bits from util to encoding
Matt Mackall <mpm@selenic.com>
parents:
7195
diff
changeset
|
261 encoding.encoding.lower(), 'utf-8'] |
8343 | 262 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
|
263 if cs not in charsets: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
264 charsets.append(cs) |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
265 return [cs for cs in charsets if not cs.endswith('ascii')] |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
266 |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
267 def _encode(ui, s, charsets): |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
268 '''Returns (converted) string, charset tuple. |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
269 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
|
270 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
|
271 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
|
272 Caveat: Do not use for mail parts containing patches!''' |
39023
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
273 sendcharsets = charsets or _charsets(ui) |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
274 if not isinstance(s, bytes): |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
275 # We have unicode data, which we need to try and encode to |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
276 # some reasonable-ish encoding. Try the encodings the user |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
277 # wants, and fall back to garbage-in-ascii. |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
278 for ocs in sendcharsets: |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
279 try: |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
280 return s.encode(pycompat.sysstr(ocs)), ocs |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
281 except UnicodeEncodeError: |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
282 pass |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
283 except LookupError: |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
284 ui.warn(_('ignoring invalid sendcharset: %s\n') % ocs) |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
285 else: |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
286 # 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:
38332
diff
changeset
|
287 return s.encode('ascii', 'backslashreplace') |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
288 # We have a bytes of unknown encoding. We'll try and guess a valid |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
289 # encoding, falling back to pretending we had ascii even though we |
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
290 # know that's wrong. |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
291 try: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
292 s.decode('ascii') |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
293 except UnicodeDecodeError: |
7948
de377b1a9a84
move encoding bits from util to encoding
Matt Mackall <mpm@selenic.com>
parents:
7195
diff
changeset
|
294 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
|
295 try: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
296 u = s.decode(ics) |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
297 except UnicodeDecodeError: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
298 continue |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
299 for ocs in sendcharsets: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
300 try: |
39023
858fe9625dab
mail: fix _encode to be more correct on Python 3
Augie Fackler <augie@google.com>
parents:
38332
diff
changeset
|
301 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
|
302 except UnicodeEncodeError: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
303 pass |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
304 except LookupError: |
7195
9fabcb1fe68d
mail: correct typo in variable name
Christian Ebert <blacktrash@gmx.net>
parents:
7191
diff
changeset
|
305 ui.warn(_('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
|
306 # if ascii, or all conversion attempts fail, send (broken) ascii |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
307 return s, 'us-ascii' |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
308 |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
309 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
|
310 '''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
|
311 if not display: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
312 # split into words? |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
313 s, cs = _encode(ui, s, charsets) |
30072
87b8e40eb812
mail: handle renamed email.Header
Pulkit Goyal <7895pulkit@gmail.com>
parents:
29285
diff
changeset
|
314 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
|
315 return s |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
316 |
9948
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
317 def _addressencode(ui, name, addr, charsets=None): |
39106
ebf54a34b7b7
mail: pass in addr to _addressencode() in bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39105
diff
changeset
|
318 assert isinstance(addr, bytes) |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
319 name = headencode(ui, name, charsets) |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
320 try: |
39106
ebf54a34b7b7
mail: pass in addr to _addressencode() in bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39105
diff
changeset
|
321 acc, dom = addr.split('@') |
39107
c2327bb3505d
mail: call s.decode('ascii') explicitly to see if s is an ascii bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39106
diff
changeset
|
322 acc.decode('ascii') |
39108
d2d89d31cbb5
mail: convert encoding.encoding to sysstr
Yuya Nishihara <yuya@tcha.org>
parents:
39107
diff
changeset
|
323 dom = dom.decode(pycompat.sysstr(encoding.encoding)).encode('idna') |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
324 addr = '%s@%s' % (acc, dom) |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
325 except UnicodeDecodeError: |
26587
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26098
diff
changeset
|
326 raise error.Abort(_('invalid email address: %s') % addr) |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
327 except ValueError: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
328 try: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
329 # too strict? |
39107
c2327bb3505d
mail: call s.decode('ascii') explicitly to see if s is an ascii bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39106
diff
changeset
|
330 addr.decode('ascii') |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
331 except UnicodeDecodeError: |
26587
56b2bcea2529
error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents:
26098
diff
changeset
|
332 raise error.Abort(_('invalid local address: %s') % addr) |
39024
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39023
diff
changeset
|
333 return pycompat.bytesurl( |
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39023
diff
changeset
|
334 email.utils.formataddr((name, encoding.strfromlocal(addr)))) |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
335 |
9948
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
336 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
|
337 '''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
|
338 if display or not address: |
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
339 return address or '' |
39024
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39023
diff
changeset
|
340 name, addr = email.utils.parseaddr(encoding.strfromlocal(address)) |
39106
ebf54a34b7b7
mail: pass in addr to _addressencode() in bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39105
diff
changeset
|
341 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
|
342 |
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
343 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
|
344 '''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
|
345 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
|
346 always has one address per item''' |
39024
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39023
diff
changeset
|
347 for a in addrs: |
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39023
diff
changeset
|
348 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
|
349 if display: |
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
350 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
|
351 |
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
352 result = [] |
39024
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39023
diff
changeset
|
353 for name, addr in email.utils.getaddresses( |
eabdf3c25b8b
mail: cope with Py3 unicode antics on email addresses
Augie Fackler <augie@google.com>
parents:
39023
diff
changeset
|
354 [encoding.strfromlocal(a) for a in addrs]): |
9948
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
355 if name or addr: |
39106
ebf54a34b7b7
mail: pass in addr to _addressencode() in bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39105
diff
changeset
|
356 r = _addressencode(ui, name, encoding.strtolocal(addr), charsets) |
ebf54a34b7b7
mail: pass in addr to _addressencode() in bytes
Yuya Nishihara <yuya@tcha.org>
parents:
39105
diff
changeset
|
357 result.append(r) |
39105
f68ad9b4a43b
mail: remove redundant bytesurl() from addrlistencode()
Yuya Nishihara <yuya@tcha.org>
parents:
39039
diff
changeset
|
358 return result |
9948
e5b44a7986d0
mail: add parseaddrlist() function for parsing many addresses at once
Marti Raudsepp <marti@juffo.org>
parents:
9715
diff
changeset
|
359 |
7114
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
360 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
|
361 '''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
|
362 charset and transfer-encoding accordingly.''' |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
363 cs = 'us-ascii' |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
364 if not display: |
30e49d54c537
mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents:
6548
diff
changeset
|
365 s, cs = _encode(ui, s, charsets) |
15562
a82b6038ff08
mail: use quoted-printable for mime encoding to avoid too long lines (issue3075)
Mads Kiilerich <mads@kiilerich.com>
parents:
15561
diff
changeset
|
366 return mimetextqp(s, 'plain', cs) |
28341
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
367 |
38332
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
368 if pycompat.ispy3: |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
369 def parse(fp): |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
370 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
|
371 # 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
|
372 # 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
|
373 # what the standard Python email parser does. |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
374 fp = io.TextIOWrapper(fp, encoding=r'ascii', |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
375 errors=r'surrogateescape', newline=chr(10)) |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
376 try: |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
377 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
|
378 finally: |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
379 fp.detach() |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
380 else: |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
381 def parse(fp): |
7b12a2d2eedc
py3: ditch email.parser.BytesParser which appears to be plain crap
Yuya Nishihara <yuya@tcha.org>
parents:
37469
diff
changeset
|
382 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
|
383 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
|
384 |
28341
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
385 def headdecode(s): |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
386 '''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
|
387 uparts = [] |
30072
87b8e40eb812
mail: handle renamed email.Header
Pulkit Goyal <7895pulkit@gmail.com>
parents:
29285
diff
changeset
|
388 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
|
389 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
|
390 try: |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
391 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
|
392 continue |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
393 except UnicodeDecodeError: |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
394 pass |
37469
7edf68862fe3
py3: work around weird handling of bytes/unicode in decode_header()
Yuya Nishihara <yuya@tcha.org>
parents:
37463
diff
changeset
|
395 # 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
|
396 # 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
|
397 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
|
398 uparts.append(part) |
7edf68862fe3
py3: work around weird handling of bytes/unicode in decode_header()
Yuya Nishihara <yuya@tcha.org>
parents:
37463
diff
changeset
|
399 continue |
28341
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
400 try: |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
401 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
|
402 continue |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
403 except UnicodeDecodeError: |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
404 pass |
8286f551b7ee
patch: when importing from email, RFC2047-decode From/Subject headers
Julien Cristau <julien.cristau@logilab.fr>
parents:
27619
diff
changeset
|
405 uparts.append(part.decode('ISO-8859-1')) |
31447
067add650129
encoding: factor out unicode variants of from/tolocal()
Yuya Nishihara <yuya@tcha.org>
parents:
30325
diff
changeset
|
406 return encoding.unitolocal(u' '.join(uparts)) |