/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5177.1.1 by Vincent Ladeuil
Manually assign docstrings to command objects, so that they work with python -OO
1
# Copyright (C) 2007-2010 Canonical Ltd
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
16
2681.3.4 by Lukáš Lalinsky
- Rename 'windows' to 'mapi'
17
import errno
2681.3.1 by Lukáš Lalinsky
Support for sending bundles using MAPI on Windows.
18
import os
2681.3.4 by Lukáš Lalinsky
- Rename 'windows' to 'mapi'
19
import subprocess
2681.4.1 by Alexander Belchenko
win32: looking for full path of mail client executable in registry
20
import sys
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
21
import tempfile
22
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
23
import breezy
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
24
from . import (
6449.5.1 by Jelmer Vernooij
Migrate mail_client to config stacks.
25
    config as _mod_config,
2681.1.9 by Aaron Bentley
Add support for mail-from-editor
26
    email_message,
27
    errors,
28
    msgeditor,
2681.3.4 by Lukáš Lalinsky
- Rename 'windows' to 'mapi'
29
    osutils,
2681.1.9 by Aaron Bentley
Add support for mail-from-editor
30
    urlutils,
6973.5.10 by Jelmer Vernooij
Random bunch of python3 bee-improvements.
31
    registry,
32
    )
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
33
3638.2.1 by Neil Martinsen-Burrell
Use a registry for mail clients.
34
mail_client_registry = registry.Registry()
35
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
36
6734.1.1 by Jelmer Vernooij
Fix more imports.
37
class MailClientNotFound(errors.BzrError):
38
39
    _fmt = "Unable to find mail client with the following names:"\
40
        " %(mail_command_list_string)s"
41
42
    def __init__(self, mail_command_list):
43
        mail_command_list_string = ', '.join(mail_command_list)
44
        errors.BzrError.__init__(
45
            self, mail_command_list=mail_command_list,
46
            mail_command_list_string=mail_command_list_string)
47
48
49
class NoMessageSupplied(errors.BzrError):
50
51
    _fmt = "No message supplied."
52
53
54
class NoMailAddressSpecified(errors.BzrError):
55
56
    _fmt = "No mail-to address (--mail-to) or output (-o) specified."
57
58
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
59
class MailClient(object):
2681.1.11 by Aaron Bentley
Add docstrings, add compose_merge_request
60
    """A mail client that can send messages with attachements."""
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
61
2681.1.9 by Aaron Bentley
Add support for mail-from-editor
62
    def __init__(self, config):
63
        self.config = config
64
2681.1.11 by Aaron Bentley
Add docstrings, add compose_merge_request
65
    def compose(self, prompt, to, subject, attachment, mime_subtype,
4098.5.2 by Aaron Bentley
Push body support through bzr send.
66
                extension, basename=None, body=None):
2681.1.36 by Aaron Bentley
Update docs
67
        """Compose (and possibly send) an email message
68
69
        Must be implemented by subclasses.
70
71
        :param prompt: A message to tell the user what to do.  Supported by
72
            the Editor client, but ignored by others
73
        :param to: The address to send the message to
74
        :param subject: The contents of the subject line
75
        :param attachment: An email attachment, as a bytestring
76
        :param mime_subtype: The attachment is assumed to be a subtype of
77
            Text.  This allows the precise subtype to be specified, e.g.
78
            "plain", "x-patch", etc.
79
        :param extension: The file extension associated with the attachment
80
            type, e.g. ".patch"
3251.2.1 by Aaron Bentley
Use nick/revno-based names for merge directives
81
        :param basename: The name to use for the attachment, e.g.
82
            "send-nick-3252"
2681.1.36 by Aaron Bentley
Update docs
83
        """
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
84
        raise NotImplementedError
85
4098.5.2 by Aaron Bentley
Push body support through bzr send.
86
    def compose_merge_request(self, to, subject, directive, basename=None,
87
                              body=None):
2681.1.36 by Aaron Bentley
Update docs
88
        """Compose (and possibly send) a merge request
89
90
        :param to: The address to send the request to
91
        :param subject: The subject line to use for the request
92
        :param directive: A merge directive representing the merge request, as
93
            a bytestring.
3251.2.1 by Aaron Bentley
Use nick/revno-based names for merge directives
94
        :param basename: The name to use for the attachment, e.g.
95
            "send-nick-3252"
2681.1.36 by Aaron Bentley
Update docs
96
        """
2681.1.21 by Aaron Bentley
Refactor prompt generation to make it testable, test it with unicode
97
        prompt = self._get_merge_prompt("Please describe these changes:", to,
98
                                        subject, directive)
99
        self.compose(prompt, to, subject, directive,
7143.15.2 by Jelmer Vernooij
Run autopep8.
100
                     'x-patch', '.patch', basename, body)
2681.1.11 by Aaron Bentley
Add docstrings, add compose_merge_request
101
2681.1.21 by Aaron Bentley
Refactor prompt generation to make it testable, test it with unicode
102
    def _get_merge_prompt(self, prompt, to, subject, attachment):
2681.1.36 by Aaron Bentley
Update docs
103
        """Generate a prompt string.  Overridden by Editor.
104
105
        :param prompt: A string suggesting what user should do
106
        :param to: The address the mail will be sent to
107
        :param subject: The subject line of the mail
108
        :param attachment: The attachment that will be used
109
        """
2681.1.21 by Aaron Bentley
Refactor prompt generation to make it testable, test it with unicode
110
        return ''
111
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
112
113
class Editor(MailClient):
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
114
    __doc__ = """DIY mail client that uses commit message editor"""
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
115
4098.5.4 by Aaron Bentley
Cleaner support for mail clients lacking body support.
116
    supports_body = True
117
2681.1.21 by Aaron Bentley
Refactor prompt generation to make it testable, test it with unicode
118
    def _get_merge_prompt(self, prompt, to, subject, attachment):
2681.1.37 by Aaron Bentley
Update docstrings and string formatting
119
        """See MailClient._get_merge_prompt"""
120
        return (u"%s\n\n"
121
                u"To: %s\n"
122
                u"Subject: %s\n\n"
123
                u"%s" % (prompt, to, subject,
124
                         attachment.decode('utf-8', 'replace')))
2681.1.21 by Aaron Bentley
Refactor prompt generation to make it testable, test it with unicode
125
2681.1.11 by Aaron Bentley
Add docstrings, add compose_merge_request
126
    def compose(self, prompt, to, subject, attachment, mime_subtype,
4098.5.2 by Aaron Bentley
Push body support through bzr send.
127
                extension, basename=None, body=None):
2681.1.37 by Aaron Bentley
Update docstrings and string formatting
128
        """See MailClient.compose"""
3042.1.1 by Lukáš Lalinský
Make mail-to address in ``bzr send`` optional for interactive mail clients.
129
        if not to:
6734.1.1 by Jelmer Vernooij
Fix more imports.
130
            raise NoMailAddressSpecified()
4098.5.2 by Aaron Bentley
Push body support through bzr send.
131
        body = msgeditor.edit_commit_message(prompt, start_message=body)
2681.1.9 by Aaron Bentley
Add support for mail-from-editor
132
        if body == '':
6734.1.1 by Jelmer Vernooij
Fix more imports.
133
            raise NoMessageSupplied()
2681.1.9 by Aaron Bentley
Add support for mail-from-editor
134
        email_message.EmailMessage.send(self.config,
6449.5.1 by Jelmer Vernooij
Migrate mail_client to config stacks.
135
                                        self.config.get('email'),
2681.1.9 by Aaron Bentley
Add support for mail-from-editor
136
                                        to,
137
                                        subject,
138
                                        body,
139
                                        attachment,
2681.1.11 by Aaron Bentley
Add docstrings, add compose_merge_request
140
                                        attachment_mime_subtype=mime_subtype)
7143.15.2 by Jelmer Vernooij
Run autopep8.
141
142
3638.2.5 by Neil Martinsen-Burrell
use docstrings as help messages for registered mail clients
143
mail_client_registry.register('editor', Editor,
144
                              help=Editor.__doc__)
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
145
146
4098.5.4 by Aaron Bentley
Cleaner support for mail clients lacking body support.
147
class BodyExternalMailClient(MailClient):
148
149
    supports_body = True
2681.1.18 by Aaron Bentley
Refactor to increase code sharing, allow multiple command names for tbird
150
2681.4.1 by Alexander Belchenko
win32: looking for full path of mail client executable in registry
151
    def _get_client_commands(self):
2681.1.36 by Aaron Bentley
Update docs
152
        """Provide a list of commands that may invoke the mail client"""
2681.4.1 by Alexander Belchenko
win32: looking for full path of mail client executable in registry
153
        if sys.platform == 'win32':
2681.1.29 by Aaron Bentley
Make conditional import explicit
154
            import win32utils
2681.4.1 by Alexander Belchenko
win32: looking for full path of mail client executable in registry
155
            return [win32utils.get_app_path(i) for i in self._client_commands]
156
        else:
157
            return self._client_commands
158
2681.1.18 by Aaron Bentley
Refactor to increase code sharing, allow multiple command names for tbird
159
    def compose(self, prompt, to, subject, attachment, mime_subtype,
4098.5.2 by Aaron Bentley
Push body support through bzr send.
160
                extension, basename=None, body=None):
2681.1.36 by Aaron Bentley
Update docs
161
        """See MailClient.compose.
162
163
        Writes the attachment to a temporary file, invokes _compose.
164
        """
3251.2.1 by Aaron Bentley
Use nick/revno-based names for merge directives
165
        if basename is None:
166
            basename = 'attachment'
3638.3.2 by Vincent Ladeuil
Fix all calls to tempfile.mkdtemp to osutils.mkdtemp.
167
        pathname = osutils.mkdtemp(prefix='bzr-mail-')
3251.2.1 by Aaron Bentley
Use nick/revno-based names for merge directives
168
        attach_path = osutils.pathjoin(pathname, basename + extension)
7356.1.5 by Jelmer Vernooij
Use more ExitStacks.
169
        with open(attach_path, 'wb') as outfile:
3251.2.1 by Aaron Bentley
Use nick/revno-based names for merge directives
170
            outfile.write(attachment)
4282.2.4 by Neil Martinsen-Burrell
a better fix that doesn't break backwards compatibility
171
        if body is not None:
172
            kwargs = {'body': body}
173
        else:
174
            kwargs = {}
3251.2.1 by Aaron Bentley
Use nick/revno-based names for merge directives
175
        self._compose(prompt, to, subject, attach_path, mime_subtype,
4282.2.4 by Neil Martinsen-Burrell
a better fix that doesn't break backwards compatibility
176
                      extension, **kwargs)
2681.3.1 by Lukáš Lalinsky
Support for sending bundles using MAPI on Windows.
177
178
    def _compose(self, prompt, to, subject, attach_path, mime_subtype,
4401.2.2 by Barry Warsaw
Much simpler approach to support From: in Claws, after discussion with
179
                 extension, body=None, from_=None):
2681.1.36 by Aaron Bentley
Update docs
180
        """Invoke a mail client as a commandline process.
181
182
        Overridden by MAPIClient.
183
        :param to: The address to send the mail to
184
        :param subject: The subject line for the mail
185
        :param pathname: The path to the attachment
186
        :param mime_subtype: The attachment is assumed to have a major type of
187
            "text", but the precise subtype can be specified here
188
        :param extension: A file extension (including period) associated with
189
            the attachment type.
4401.2.2 by Barry Warsaw
Much simpler approach to support From: in Claws, after discussion with
190
        :param body: Optional body text.
191
        :param from_: Optional From: header.
2681.1.36 by Aaron Bentley
Update docs
192
        """
2681.4.1 by Alexander Belchenko
win32: looking for full path of mail client executable in registry
193
        for name in self._get_client_commands():
3234.2.6 by Alexander Belchenko
because every mail client has different rules to compose command line we should encode arguments to 8 bit string only when needed.
194
            cmdline = [self._encode_path(name, 'executable')]
4098.5.4 by Aaron Bentley
Cleaner support for mail clients lacking body support.
195
            if body is not None:
196
                kwargs = {'body': body}
197
            else:
198
                kwargs = {}
4401.2.2 by Barry Warsaw
Much simpler approach to support From: in Claws, after discussion with
199
            if from_ is not None:
200
                kwargs['from_'] = from_
3234.2.6 by Alexander Belchenko
because every mail client has different rules to compose command line we should encode arguments to 8 bit string only when needed.
201
            cmdline.extend(self._get_compose_commandline(to, subject,
4098.5.4 by Aaron Bentley
Cleaner support for mail clients lacking body support.
202
                                                         attach_path,
203
                                                         **kwargs))
2681.1.18 by Aaron Bentley
Refactor to increase code sharing, allow multiple command names for tbird
204
            try:
205
                subprocess.call(cmdline)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
206
            except OSError as e:
2681.1.18 by Aaron Bentley
Refactor to increase code sharing, allow multiple command names for tbird
207
                if e.errno != errno.ENOENT:
208
                    raise
209
            else:
210
                break
211
        else:
6734.1.1 by Jelmer Vernooij
Fix more imports.
212
            raise MailClientNotFound(self._client_commands)
2681.1.18 by Aaron Bentley
Refactor to increase code sharing, allow multiple command names for tbird
213
4098.5.2 by Aaron Bentley
Push body support through bzr send.
214
    def _get_compose_commandline(self, to, subject, attach_path, body):
2681.1.36 by Aaron Bentley
Update docs
215
        """Determine the commandline to use for composing a message
216
217
        Implemented by various subclasses
218
        :param to: The address to send the mail to
219
        :param subject: The subject line for the mail
220
        :param attach_path: The path to the attachment
221
        """
2681.3.4 by Lukáš Lalinsky
- Rename 'windows' to 'mapi'
222
        raise NotImplementedError
2681.1.18 by Aaron Bentley
Refactor to increase code sharing, allow multiple command names for tbird
223
3234.2.6 by Alexander Belchenko
because every mail client has different rules to compose command line we should encode arguments to 8 bit string only when needed.
224
    def _encode_safe(self, u):
225
        """Encode possible unicode string argument to 8-bit string
226
        in user_encoding. Unencodable characters will be replaced
227
        with '?'.
228
229
        :param  u:  possible unicode string.
230
        :return:    encoded string if u is unicode, u itself otherwise.
231
        """
232
        return u
233
234
    def _encode_path(self, path, kind):
235
        """Encode unicode path in user encoding.
236
237
        :param  path:   possible unicode path.
238
        :param  kind:   path kind ('executable' or 'attachment').
239
        :return:        encoded path if path is unicode,
240
                        path itself otherwise.
241
        :raise:         UnableEncodePath.
242
        """
243
        return path
3234.2.3 by Alexander Belchenko
mail_client.py: provide new private method ExternalMailClient._get_compose_8bit_commandline to make bug #139318 testable (as Aaron requested).
244
2681.1.18 by Aaron Bentley
Refactor to increase code sharing, allow multiple command names for tbird
245
4098.5.4 by Aaron Bentley
Cleaner support for mail clients lacking body support.
246
class ExternalMailClient(BodyExternalMailClient):
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
247
    __doc__ = """An external mail client."""
4098.5.4 by Aaron Bentley
Cleaner support for mail clients lacking body support.
248
249
    supports_body = False
250
251
252
class Evolution(BodyExternalMailClient):
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
253
    __doc__ = """Evolution mail client."""
2681.3.1 by Lukáš Lalinsky
Support for sending bundles using MAPI on Windows.
254
255
    _client_commands = ['evolution']
256
4098.5.1 by Aaron Bentley
Allow specifying body for t-bird, evo and xdg
257
    def _get_compose_commandline(self, to, subject, attach_path, body=None):
2681.1.36 by Aaron Bentley
Update docs
258
        """See ExternalMailClient._get_compose_commandline"""
2681.3.1 by Lukáš Lalinsky
Support for sending bundles using MAPI on Windows.
259
        message_options = {}
260
        if subject is not None:
261
            message_options['subject'] = subject
262
        if attach_path is not None:
263
            message_options['attach'] = attach_path
4098.5.1 by Aaron Bentley
Allow specifying body for t-bird, evo and xdg
264
        if body is not None:
265
            message_options['body'] = body
2681.3.1 by Lukáš Lalinsky
Support for sending bundles using MAPI on Windows.
266
        options_list = ['%s=%s' % (k, urlutils.escape(v)) for (k, v) in
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
267
                        sorted(message_options.items())]
3234.2.6 by Alexander Belchenko
because every mail client has different rules to compose command line we should encode arguments to 8 bit string only when needed.
268
        return ['mailto:%s?%s' % (self._encode_safe(to or ''),
7143.15.2 by Jelmer Vernooij
Run autopep8.
269
                                  '&'.join(options_list))]
270
271
3638.2.5 by Neil Martinsen-Burrell
use docstrings as help messages for registered mail clients
272
mail_client_registry.register('evolution', Evolution,
273
                              help=Evolution.__doc__)
2681.3.1 by Lukáš Lalinsky
Support for sending bundles using MAPI on Windows.
274
275
4416.1.1 by Edwin Grubbs
Added ability to pass the body into mutt.
276
class Mutt(BodyExternalMailClient):
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
277
    __doc__ = """Mutt mail client."""
2790.2.1 by Keir Mierle
Add Mutt as a supported client email program. Also rearranges various listings
278
279
    _client_commands = ['mutt']
280
4416.1.1 by Edwin Grubbs
Added ability to pass the body into mutt.
281
    def _get_compose_commandline(self, to, subject, attach_path, body=None):
2790.2.1 by Keir Mierle
Add Mutt as a supported client email program. Also rearranges various listings
282
        """See ExternalMailClient._get_compose_commandline"""
283
        message_options = []
284
        if subject is not None:
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
285
            message_options.extend(
286
                ['-s', self._encode_safe(subject)])
2790.2.1 by Keir Mierle
Add Mutt as a supported client email program. Also rearranges various listings
287
        if attach_path is not None:
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
288
            message_options.extend(
289
                ['-a', self._encode_path(attach_path, 'attachment')])
4416.1.1 by Edwin Grubbs
Added ability to pass the body into mutt.
290
        if body is not None:
4416.1.3 by Edwin Grubbs
Stored temp file in self to allow using NamedTemporaryFile.
291
            # Store the temp file object in self, so that it does not get
292
            # garbage collected and delete the file before mutt can read it.
293
            self._temp_file = tempfile.NamedTemporaryFile(
7045.2.12 by Jelmer Vernooij
Fix some mail client tests.
294
                prefix="mutt-body-", suffix=".txt", mode="w+")
4416.1.3 by Edwin Grubbs
Stored temp file in self to allow using NamedTemporaryFile.
295
            self._temp_file.write(body)
296
            self._temp_file.flush()
297
            message_options.extend(['-i', self._temp_file.name])
2790.2.1 by Keir Mierle
Add Mutt as a supported client email program. Also rearranges various listings
298
        if to is not None:
4292.1.1 by Jelmer Vernooij
Mutt requires -- before the recipient address if -a is being used.
299
            message_options.extend(['--', self._encode_safe(to)])
2790.2.1 by Keir Mierle
Add Mutt as a supported client email program. Also rearranges various listings
300
        return message_options
7143.15.2 by Jelmer Vernooij
Run autopep8.
301
302
3638.2.5 by Neil Martinsen-Burrell
use docstrings as help messages for registered mail clients
303
mail_client_registry.register('mutt', Mutt,
304
                              help=Mutt.__doc__)
2790.2.1 by Keir Mierle
Add Mutt as a supported client email program. Also rearranges various listings
305
306
4098.5.4 by Aaron Bentley
Cleaner support for mail clients lacking body support.
307
class Thunderbird(BodyExternalMailClient):
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
308
    __doc__ = """Mozilla Thunderbird (or Icedove)
2681.1.11 by Aaron Bentley
Add docstrings, add compose_merge_request
309
310
    Note that Thunderbird 1.5 is buggy and does not support setting
311
    "to" simultaneously with including a attachment.
312
313
    There is a workaround if no attachment is present, but we always need to
314
    send attachments.
315
    """
316
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
317
    _client_commands = [
318
        'thunderbird', 'mozilla-thunderbird', 'icedove',
319
        '/Applications/Mozilla/Thunderbird.app/Contents/MacOS/thunderbird-bin',
320
        '/Applications/Thunderbird.app/Contents/MacOS/thunderbird-bin']
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
321
4098.5.1 by Aaron Bentley
Allow specifying body for t-bird, evo and xdg
322
    def _get_compose_commandline(self, to, subject, attach_path, body=None):
2681.1.36 by Aaron Bentley
Update docs
323
        """See ExternalMailClient._get_compose_commandline"""
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
324
        message_options = {}
325
        if to is not None:
3234.2.6 by Alexander Belchenko
because every mail client has different rules to compose command line we should encode arguments to 8 bit string only when needed.
326
            message_options['to'] = self._encode_safe(to)
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
327
        if subject is not None:
3234.2.6 by Alexander Belchenko
because every mail client has different rules to compose command line we should encode arguments to 8 bit string only when needed.
328
            message_options['subject'] = self._encode_safe(subject)
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
329
        if attach_path is not None:
3234.2.2 by Alexander Belchenko
[merge] URL is always ascii.
330
            message_options['attachment'] = urlutils.local_path_to_url(
331
                attach_path)
4098.5.1 by Aaron Bentley
Allow specifying body for t-bird, evo and xdg
332
        if body is not None:
7143.15.2 by Jelmer Vernooij
Run autopep8.
333
            options_list = ['body=%s' %
334
                            urlutils.quote(self._encode_safe(body))]
4098.5.1 by Aaron Bentley
Allow specifying body for t-bird, evo and xdg
335
        else:
336
            options_list = []
337
        options_list.extend(["%s='%s'" % (k, v) for k, v in
7143.15.2 by Jelmer Vernooij
Run autopep8.
338
                             sorted(message_options.items())])
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
339
        return ['-compose', ','.join(options_list)]
7143.15.2 by Jelmer Vernooij
Run autopep8.
340
341
3638.2.5 by Neil Martinsen-Burrell
use docstrings as help messages for registered mail clients
342
mail_client_registry.register('thunderbird', Thunderbird,
343
                              help=Thunderbird.__doc__)
2681.1.23 by Aaron Bentley
Add support for xdg-email
344
345
2681.5.3 by ghigo
Add KMail mail client
346
class KMail(ExternalMailClient):
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
347
    __doc__ = """KDE mail client."""
2681.5.1 by ghigo
Add KMail support to bzr send
348
349
    _client_commands = ['kmail']
350
351
    def _get_compose_commandline(self, to, subject, attach_path):
2681.1.36 by Aaron Bentley
Update docs
352
        """See ExternalMailClient._get_compose_commandline"""
2681.5.1 by ghigo
Add KMail support to bzr send
353
        message_options = []
354
        if subject is not None:
3234.2.6 by Alexander Belchenko
because every mail client has different rules to compose command line we should encode arguments to 8 bit string only when needed.
355
            message_options.extend(['-s', self._encode_safe(subject)])
2681.5.1 by ghigo
Add KMail support to bzr send
356
        if attach_path is not None:
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
357
            message_options.extend(
358
                ['--attach', self._encode_path(attach_path, 'attachment')])
2681.5.1 by ghigo
Add KMail support to bzr send
359
        if to is not None:
3234.2.6 by Alexander Belchenko
because every mail client has different rules to compose command line we should encode arguments to 8 bit string only when needed.
360
            message_options.extend([self._encode_safe(to)])
2681.5.1 by ghigo
Add KMail support to bzr send
361
        return message_options
7143.15.2 by Jelmer Vernooij
Run autopep8.
362
363
3638.2.5 by Neil Martinsen-Burrell
use docstrings as help messages for registered mail clients
364
mail_client_registry.register('kmail', KMail,
365
                              help=KMail.__doc__)
2681.5.1 by ghigo
Add KMail support to bzr send
366
367
3921.2.1 by Gavin Panella
Support Claws.
368
class Claws(ExternalMailClient):
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
369
    __doc__ = """Claws mail client."""
3921.2.1 by Gavin Panella
Support Claws.
370
4401.2.1 by Barry Warsaw
Make Claws mail client work, with bodies and setting the From field.
371
    supports_body = True
372
3921.2.1 by Gavin Panella
Support Claws.
373
    _client_commands = ['claws-mail']
374
4401.2.2 by Barry Warsaw
Much simpler approach to support From: in Claws, after discussion with
375
    def _get_compose_commandline(self, to, subject, attach_path, body=None,
376
                                 from_=None):
3921.2.1 by Gavin Panella
Support Claws.
377
        """See ExternalMailClient._get_compose_commandline"""
4401.2.1 by Barry Warsaw
Make Claws mail client work, with bodies and setting the From field.
378
        compose_url = []
4401.2.2 by Barry Warsaw
Much simpler approach to support From: in Claws, after discussion with
379
        if from_ is not None:
6379.4.2 by Jelmer Vernooij
Add urlutils.quote / urlutils.unquote.
380
            compose_url.append('from=' + urlutils.quote(from_))
3921.2.1 by Gavin Panella
Support Claws.
381
        if subject is not None:
6379.4.2 by Jelmer Vernooij
Add urlutils.quote / urlutils.unquote.
382
            # Don't use urlutils.quote_plus because Claws doesn't seem
3921.2.4 by Gavin Panella
Use the --attach option, and don't specify a From: header.
383
            # to recognise spaces encoded as "+".
384
            compose_url.append(
6379.4.2 by Jelmer Vernooij
Add urlutils.quote / urlutils.unquote.
385
                'subject=' + urlutils.quote(self._encode_safe(subject)))
4401.2.1 by Barry Warsaw
Make Claws mail client work, with bodies and setting the From field.
386
        if body is not None:
387
            compose_url.append(
6379.4.2 by Jelmer Vernooij
Add urlutils.quote / urlutils.unquote.
388
                'body=' + urlutils.quote(self._encode_safe(body)))
4401.2.1 by Barry Warsaw
Make Claws mail client work, with bodies and setting the From field.
389
        # to must be supplied for the claws-mail --compose syntax to work.
390
        if to is None:
6734.1.1 by Jelmer Vernooij
Fix more imports.
391
            raise NoMailAddressSpecified()
4401.2.1 by Barry Warsaw
Make Claws mail client work, with bodies and setting the From field.
392
        compose_url = 'mailto:%s?%s' % (
393
            self._encode_safe(to), '&'.join(compose_url))
3921.2.4 by Gavin Panella
Use the --attach option, and don't specify a From: header.
394
        # Collect command-line options.
4401.2.1 by Barry Warsaw
Make Claws mail client work, with bodies and setting the From field.
395
        message_options = ['--compose', compose_url]
3921.2.1 by Gavin Panella
Support Claws.
396
        if attach_path is not None:
3921.2.4 by Gavin Panella
Use the --attach option, and don't specify a From: header.
397
            message_options.extend(
398
                ['--attach', self._encode_path(attach_path, 'attachment')])
399
        return message_options
4401.2.2 by Barry Warsaw
Much simpler approach to support From: in Claws, after discussion with
400
401
    def _compose(self, prompt, to, subject, attach_path, mime_subtype,
402
                 extension, body=None, from_=None):
403
        """See ExternalMailClient._compose"""
404
        if from_ is None:
6449.5.1 by Jelmer Vernooij
Migrate mail_client to config stacks.
405
            from_ = self.config.get('email')
4401.2.2 by Barry Warsaw
Much simpler approach to support From: in Claws, after discussion with
406
        super(Claws, self)._compose(prompt, to, subject, attach_path,
407
                                    mime_subtype, extension, body, from_)
408
409
3921.2.1 by Gavin Panella
Support Claws.
410
mail_client_registry.register('claws', Claws,
411
                              help=Claws.__doc__)
412
413
4098.5.4 by Aaron Bentley
Cleaner support for mail clients lacking body support.
414
class XDGEmail(BodyExternalMailClient):
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
415
    __doc__ = """xdg-email attempts to invoke the preferred mail client"""
2681.1.23 by Aaron Bentley
Add support for xdg-email
416
417
    _client_commands = ['xdg-email']
418
4098.5.1 by Aaron Bentley
Allow specifying body for t-bird, evo and xdg
419
    def _get_compose_commandline(self, to, subject, attach_path, body=None):
2681.1.36 by Aaron Bentley
Update docs
420
        """See ExternalMailClient._get_compose_commandline"""
3042.1.1 by Lukáš Lalinský
Make mail-to address in ``bzr send`` optional for interactive mail clients.
421
        if not to:
6734.1.1 by Jelmer Vernooij
Fix more imports.
422
            raise NoMailAddressSpecified()
3234.2.6 by Alexander Belchenko
because every mail client has different rules to compose command line we should encode arguments to 8 bit string only when needed.
423
        commandline = [self._encode_safe(to)]
2681.1.23 by Aaron Bentley
Add support for xdg-email
424
        if subject is not None:
3234.2.6 by Alexander Belchenko
because every mail client has different rules to compose command line we should encode arguments to 8 bit string only when needed.
425
            commandline.extend(['--subject', self._encode_safe(subject)])
2681.1.23 by Aaron Bentley
Add support for xdg-email
426
        if attach_path is not None:
3234.2.6 by Alexander Belchenko
because every mail client has different rules to compose command line we should encode arguments to 8 bit string only when needed.
427
            commandline.extend(['--attach',
7143.15.2 by Jelmer Vernooij
Run autopep8.
428
                                self._encode_path(attach_path, 'attachment')])
4098.5.1 by Aaron Bentley
Allow specifying body for t-bird, evo and xdg
429
        if body is not None:
430
            commandline.extend(['--body', self._encode_safe(body)])
2681.1.23 by Aaron Bentley
Add support for xdg-email
431
        return commandline
7143.15.2 by Jelmer Vernooij
Run autopep8.
432
433
3638.2.5 by Neil Martinsen-Burrell
use docstrings as help messages for registered mail clients
434
mail_client_registry.register('xdg-email', XDGEmail,
435
                              help=XDGEmail.__doc__)
2681.1.24 by Aaron Bentley
Handle default mail client by trying xdg-email, falling back to editor
436
437
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
438
class EmacsMail(ExternalMailClient):
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
439
    __doc__ = """Call emacsclient to have a mail buffer.
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
440
441
    This only work for emacs >= 22.1 due to recent -e/--eval support.
442
443
    The good news is that this implementation will work with all mail
444
    agents registered against ``mail-user-agent``. So there is no need
445
    to instantiate ExternalMailClient for each and every GNU Emacs
446
    MUA.
447
448
    Users just have to ensure that ``mail-user-agent`` is set according
449
    to their tastes.
3322.1.1 by Ian Clatworthy
Add mail-mode GNU Emacs mail package as a mail client option (Xavier Maillard)
450
    """
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
451
3302.6.1 by Xavier Maillard
Add mail-mode GNU Emacs mail package as a mail_client option.
452
    _client_commands = ['emacsclient']
453
4659.2.1 by Vincent Ladeuil
Cleanup emacs-bzr-send-XXXXXX.el leaks in /tmp during selftest.
454
    def __init__(self, config):
455
        super(EmacsMail, self).__init__(config)
456
        self.elisp_tmp_file = None
457
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
458
    def _prepare_send_function(self):
459
        """Write our wrapper function into a temporary file.
460
461
        This temporary file will be loaded at runtime in
462
        _get_compose_commandline function.
463
3506.1.6 by Christophe Troestler
EmacsMail: _prepare_send_function: corrected doc and proper handling of
464
        This function does not remove the file.  That's a wanted
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
465
        behaviour since _get_compose_commandline won't run the send
466
        mail function directly but return the eligible command line.
467
        Removing our temporary file here would prevent our sendmail
3506.1.6 by Christophe Troestler
EmacsMail: _prepare_send_function: corrected doc and proper handling of
468
        function to work.  (The file is deleted by some elisp code
469
        after being read by Emacs.)
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
470
        """
471
7045.2.12 by Jelmer Vernooij
Fix some mail client tests.
472
        _defun = br"""(defun bzr-add-mime-att (file)
3506.1.1 by Christophe Troestler
Handled the MUA "mew" in the class EmacsMail.
473
  "Attach FILE to a mail buffer as a MIME attachment."
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
474
  (let ((agent mail-user-agent))
475
    (if (and file (file-exists-p file))
476
        (cond
477
         ((eq agent 'sendmail-user-agent)
3506.1.1 by Christophe Troestler
Handled the MUA "mew" in the class EmacsMail.
478
          (progn
3506.1.10 by Christophe Troestler
Removed TABS in mail_client.py and added a NEWS entry.
479
            (mail-text)
480
            (newline)
481
            (if (functionp 'etach-attach)
482
              (etach-attach file)
483
              (mail-attach-file file))))
4056.3.1 by epg at pretzelnet
Support MH-E in EmacsMail, using mml.
484
         ((or (eq agent 'message-user-agent)
485
              (eq agent 'gnus-user-agent)
486
              (eq agent 'mh-e-user-agent))
3506.1.1 by Christophe Troestler
Handled the MUA "mew" in the class EmacsMail.
487
          (progn
3506.1.10 by Christophe Troestler
Removed TABS in mail_client.py and added a NEWS entry.
488
            (mml-attach-file file "text/x-patch" "BZR merge" "inline")))
489
         ((eq agent 'mew-user-agent)
490
          (progn
491
            (mew-draft-prepare-attachments)
492
            (mew-attach-link file (file-name-nondirectory file))
493
            (let* ((nums (mew-syntax-nums))
494
                   (syntax (mew-syntax-get-entry mew-encode-syntax nums)))
495
              (mew-syntax-set-cd syntax "BZR merge")
496
              (mew-encode-syntax-print mew-encode-syntax))
497
            (mew-header-goto-body)))
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
498
         (t
3506.1.8 by Christophe Troestler
When the Emacs MUA is not supported, the error message encourage to report it.
499
          (message "Unhandled MUA, report it on bazaar@lists.canonical.com")))
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
500
      (error "File %s does not exist." file))))
501
"""
502
503
        fd, temp_file = tempfile.mkstemp(prefix="emacs-bzr-send-",
504
                                         suffix=".el")
505
        try:
506
            os.write(fd, _defun)
507
        finally:
7143.15.2 by Jelmer Vernooij
Run autopep8.
508
            os.close(fd)  # Just close the handle but do not remove the file.
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
509
        return temp_file
510
3322.1.1 by Ian Clatworthy
Add mail-mode GNU Emacs mail package as a mail client option (Xavier Maillard)
511
    def _get_compose_commandline(self, to, subject, attach_path):
3302.6.1 by Xavier Maillard
Add mail-mode GNU Emacs mail package as a mail_client option.
512
        commandline = ["--eval"]
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
513
3302.6.1 by Xavier Maillard
Add mail-mode GNU Emacs mail package as a mail_client option.
514
        _to = "nil"
515
        _subject = "nil"
516
517
        if to is not None:
3506.1.3 by Christophe Troestler
Better escaping of To and Subject in the class EmacsMail.
518
            _to = ("\"%s\"" % self._encode_safe(to).replace('"', '\\"'))
3302.6.1 by Xavier Maillard
Add mail-mode GNU Emacs mail package as a mail_client option.
519
        if subject is not None:
3506.1.3 by Christophe Troestler
Better escaping of To and Subject in the class EmacsMail.
520
            _subject = ("\"%s\"" %
521
                        self._encode_safe(subject).replace('"', '\\"'))
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
522
523
        # Funcall the default mail composition function
524
        # This will work with any mail mode including default mail-mode
525
        # User must tweak mail-user-agent variable to tell what function
526
        # will be called inside compose-mail.
527
        mail_cmd = "(compose-mail %s %s)" % (_to, _subject)
528
        commandline.append(mail_cmd)
529
530
        # Try to attach a MIME attachment using our wrapper function
3302.6.1 by Xavier Maillard
Add mail-mode GNU Emacs mail package as a mail_client option.
531
        if attach_path is not None:
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
532
            # Do not create a file if there is no attachment
3506.1.4 by Christophe Troestler
Remove the temporary elisp file created for attachments by EmacsMail.
533
            elisp = self._prepare_send_function()
4659.2.1 by Vincent Ladeuil
Cleanup emacs-bzr-send-XXXXXX.el leaks in /tmp during selftest.
534
            self.elisp_tmp_file = elisp
3506.1.4 by Christophe Troestler
Remove the temporary elisp file created for attachments by EmacsMail.
535
            lmmform = '(load "%s")' % elisp
7143.15.2 by Jelmer Vernooij
Run autopep8.
536
            mmform = '(bzr-add-mime-att "%s")' % \
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
537
                self._encode_path(attach_path, 'attachment')
3506.1.4 by Christophe Troestler
Remove the temporary elisp file created for attachments by EmacsMail.
538
            rmform = '(delete-file "%s")' % elisp
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
539
            commandline.append(lmmform)
540
            commandline.append(mmform)
3506.1.4 by Christophe Troestler
Remove the temporary elisp file created for attachments by EmacsMail.
541
            commandline.append(rmform)
3324.4.1 by Xavier Maillard
Replace mail-mode call with compose-mail from GNU Emacs.
542
3302.6.1 by Xavier Maillard
Add mail-mode GNU Emacs mail package as a mail_client option.
543
        return commandline
7143.15.2 by Jelmer Vernooij
Run autopep8.
544
545
3638.2.5 by Neil Martinsen-Burrell
use docstrings as help messages for registered mail clients
546
mail_client_registry.register('emacsclient', EmacsMail,
547
                              help=EmacsMail.__doc__)
3302.6.1 by Xavier Maillard
Add mail-mode GNU Emacs mail package as a mail_client option.
548
549
4098.5.4 by Aaron Bentley
Cleaner support for mail clients lacking body support.
550
class MAPIClient(BodyExternalMailClient):
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
551
    __doc__ = """Default Windows mail client launched using MAPI."""
2681.3.1 by Lukáš Lalinsky
Support for sending bundles using MAPI on Windows.
552
553
    def _compose(self, prompt, to, subject, attach_path, mime_subtype,
4282.2.4 by Neil Martinsen-Burrell
a better fix that doesn't break backwards compatibility
554
                 extension, body=None):
2681.1.36 by Aaron Bentley
Update docs
555
        """See ExternalMailClient._compose.
556
557
        This implementation uses MAPI via the simplemapi ctypes wrapper
558
        """
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
559
        from .util import simplemapi
2681.3.4 by Lukáš Lalinsky
- Rename 'windows' to 'mapi'
560
        try:
4098.5.3 by Aaron Bentley
Add Windows MAPI support for send --body
561
            simplemapi.SendMail(to or '', subject or '', body or '',
562
                                attach_path)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
563
        except simplemapi.MAPIError as e:
2681.3.6 by Lukáš Lalinsky
New version of simplemapi.py with MIT license.
564
            if e.code != simplemapi.MAPI_USER_ABORT:
6734.1.1 by Jelmer Vernooij
Fix more imports.
565
                raise MailClientNotFound(['MAPI supported mail client'
7143.15.2 by Jelmer Vernooij
Run autopep8.
566
                                          ' (error %d)' % (e.code,)])
567
568
3638.2.5 by Neil Martinsen-Burrell
use docstrings as help messages for registered mail clients
569
mail_client_registry.register('mapi', MAPIClient,
570
                              help=MAPIClient.__doc__)
2681.3.1 by Lukáš Lalinsky
Support for sending bundles using MAPI on Windows.
571
572
4715.3.1 by Brian de Alwis
Introduce new mailer to support MacOS X's Mail.app
573
class MailApp(BodyExternalMailClient):
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
574
    __doc__ = """Use MacOS X's Mail.app for sending email messages.
4715.3.1 by Brian de Alwis
Introduce new mailer to support MacOS X's Mail.app
575
576
    Although it would be nice to use appscript, it's not installed
577
    with the shipped Python installations.  We instead build an
578
    AppleScript and invoke the script using osascript(1).  We don't
579
    use the _encode_safe() routines as it's not clear what encoding
580
    osascript expects the script to be in.
581
    """
582
583
    _client_commands = ['osascript']
584
585
    def _get_compose_commandline(self, to, subject, attach_path, body=None,
7143.15.2 by Jelmer Vernooij
Run autopep8.
586
                                 from_=None):
587
        """See ExternalMailClient._get_compose_commandline"""
588
589
        fd, self.temp_file = tempfile.mkstemp(prefix="bzr-send-",
590
                                              suffix=".scpt")
591
        try:
592
            os.write(fd, 'tell application "Mail"\n')
593
            os.write(fd, 'set newMessage to make new outgoing message\n')
594
            os.write(fd, 'tell newMessage\n')
595
            if to is not None:
596
                os.write(fd, 'make new to recipient with properties'
597
                         ' {address:"%s"}\n' % to)
598
            if from_ is not None:
599
                # though from_ doesn't actually seem to be used
600
                os.write(fd, 'set sender to "%s"\n'
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
601
                         % from_.replace('"', '\\"'))
7143.15.2 by Jelmer Vernooij
Run autopep8.
602
            if subject is not None:
603
                os.write(fd, 'set subject to "%s"\n'
604
                         % subject.replace('"', '\\"'))
605
            if body is not None:
606
                # FIXME: would be nice to prepend the body to the
607
                # existing content (e.g., preserve signature), but
608
                # can't seem to figure out the right applescript
609
                # incantation.
610
                os.write(fd, 'set content to "%s\\n\n"\n' %
611
                         body.replace('"', '\\"').replace('\n', '\\n'))
612
613
            if attach_path is not None:
614
                # FIXME: would be nice to first append a newline to
615
                # ensure the attachment is on a new paragraph, but
616
                # can't seem to figure out the right applescript
617
                # incantation.
618
                os.write(fd, 'tell content to make new attachment'
619
                         ' with properties {file name:"%s"}'
620
                         ' at after the last paragraph\n'
621
                         % self._encode_path(attach_path, 'attachment'))
622
            os.write(fd, 'set visible to true\n')
623
            os.write(fd, 'end tell\n')
624
            os.write(fd, 'end tell\n')
625
        finally:
626
            os.close(fd)  # Just close the handle but do not remove the file.
627
        return [self.temp_file]
628
629
4715.3.1 by Brian de Alwis
Introduce new mailer to support MacOS X's Mail.app
630
mail_client_registry.register('mail.app', MailApp,
631
                              help=MailApp.__doc__)
632
633
2681.1.24 by Aaron Bentley
Handle default mail client by trying xdg-email, falling back to editor
634
class DefaultMail(MailClient):
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
635
    __doc__ = """Default mail handling.  Tries XDGEmail (or MAPIClient on Windows),
2681.3.1 by Lukáš Lalinsky
Support for sending bundles using MAPI on Windows.
636
    falls back to Editor"""
637
4273.2.2 by Aaron Bentley
Indicate that DefaultMail supports message bodies.
638
    supports_body = True
639
2681.3.1 by Lukáš Lalinsky
Support for sending bundles using MAPI on Windows.
640
    def _mail_client(self):
2681.1.36 by Aaron Bentley
Update docs
641
        """Determine the preferred mail client for this platform"""
2681.3.4 by Lukáš Lalinsky
- Rename 'windows' to 'mapi'
642
        if osutils.supports_mapi():
2681.3.1 by Lukáš Lalinsky
Support for sending bundles using MAPI on Windows.
643
            return MAPIClient(self.config)
644
        else:
645
            return XDGEmail(self.config)
2681.1.25 by Aaron Bentley
Cleanup
646
2681.1.24 by Aaron Bentley
Handle default mail client by trying xdg-email, falling back to editor
647
    def compose(self, prompt, to, subject, attachment, mime_subtype,
4098.5.2 by Aaron Bentley
Push body support through bzr send.
648
                extension, basename=None, body=None):
2681.1.36 by Aaron Bentley
Update docs
649
        """See MailClient.compose"""
2681.1.24 by Aaron Bentley
Handle default mail client by trying xdg-email, falling back to editor
650
        try:
2681.3.1 by Lukáš Lalinsky
Support for sending bundles using MAPI on Windows.
651
            return self._mail_client().compose(prompt, to, subject,
6449.5.1 by Jelmer Vernooij
Migrate mail_client to config stacks.
652
                                               attachment, mime_subtype,
4098.5.2 by Aaron Bentley
Push body support through bzr send.
653
                                               extension, basename, body)
6734.1.1 by Jelmer Vernooij
Fix more imports.
654
        except MailClientNotFound:
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
655
            return Editor(self.config).compose(
656
                prompt, to, subject, attachment, mime_subtype, extension, body)
2681.1.24 by Aaron Bentley
Handle default mail client by trying xdg-email, falling back to editor
657
4098.5.2 by Aaron Bentley
Push body support through bzr send.
658
    def compose_merge_request(self, to, subject, directive, basename=None,
659
                              body=None):
2681.1.36 by Aaron Bentley
Update docs
660
        """See MailClient.compose_merge_request"""
2681.1.24 by Aaron Bentley
Handle default mail client by trying xdg-email, falling back to editor
661
        try:
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
662
            return self._mail_client().compose_merge_request(
663
                to, subject, directive, basename=basename, body=body)
6734.1.1 by Jelmer Vernooij
Fix more imports.
664
        except MailClientNotFound:
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
665
            return Editor(self.config).compose_merge_request(
666
                to, subject, directive, basename=basename, body=body)
7143.15.2 by Jelmer Vernooij
Run autopep8.
667
668
6973.10.9 by Jelmer Vernooij
Merge trunk.
669
mail_client_registry.register(u'default', DefaultMail,
3638.2.5 by Neil Martinsen-Burrell
use docstrings as help messages for registered mail clients
670
                              help=DefaultMail.__doc__)
6973.11.8 by Jelmer Vernooij
Merge python3-i.
671
mail_client_registry.default_key = u'default'
4715.3.1 by Brian de Alwis
Introduce new mailer to support MacOS X's Mail.app
672
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
673
opt_mail_client = _mod_config.RegistryOption(
674
    'mail_client', mail_client_registry, help='E-mail client to use.',
675
    invalid='error')