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