/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/mail_client.py

  • Committer: Martin
  • Date: 2018-11-16 16:38:22 UTC
  • mto: This revision was merged to the branch mainline in revision 7172.
  • Revision ID: gzlist@googlemail.com-20181116163822-yg1h1cdng6w7w9kn
Make --profile-imports work on Python 3

Also tweak heading to line up correctly.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
 
17
from __future__ import absolute_import
 
18
 
17
19
import errno
18
20
import os
19
21
import subprocess
20
22
import sys
21
23
import tempfile
22
 
import urllib
23
24
 
24
 
import bzrlib
25
 
from bzrlib import (
 
25
import breezy
 
26
from . import (
 
27
    config as _mod_config,
26
28
    email_message,
27
29
    errors,
28
30
    msgeditor,
29
31
    osutils,
30
32
    urlutils,
31
 
    registry
 
33
    registry,
 
34
    )
 
35
from .sixish import (
 
36
    PY3,
 
37
    text_type,
32
38
    )
33
39
 
34
40
mail_client_registry = registry.Registry()
35
41
 
36
42
 
 
43
class MailClientNotFound(errors.BzrError):
 
44
 
 
45
    _fmt = "Unable to find mail client with the following names:"\
 
46
        " %(mail_command_list_string)s"
 
47
 
 
48
    def __init__(self, mail_command_list):
 
49
        mail_command_list_string = ', '.join(mail_command_list)
 
50
        errors.BzrError.__init__(
 
51
            self, mail_command_list=mail_command_list,
 
52
            mail_command_list_string=mail_command_list_string)
 
53
 
 
54
 
 
55
class NoMessageSupplied(errors.BzrError):
 
56
 
 
57
    _fmt = "No message supplied."
 
58
 
 
59
 
 
60
class NoMailAddressSpecified(errors.BzrError):
 
61
 
 
62
    _fmt = "No mail-to address (--mail-to) or output (-o) specified."
 
63
 
 
64
 
37
65
class MailClient(object):
38
66
    """A mail client that can send messages with attachements."""
39
67
 
105
133
                extension, basename=None, body=None):
106
134
        """See MailClient.compose"""
107
135
        if not to:
108
 
            raise errors.NoMailAddressSpecified()
 
136
            raise NoMailAddressSpecified()
109
137
        body = msgeditor.edit_commit_message(prompt, start_message=body)
110
138
        if body == '':
111
 
            raise errors.NoMessageSupplied()
 
139
            raise NoMessageSupplied()
112
140
        email_message.EmailMessage.send(self.config,
113
 
                                        self.config.username(),
 
141
                                        self.config.get('email'),
114
142
                                        to,
115
143
                                        subject,
116
144
                                        body,
182
210
                                                         **kwargs))
183
211
            try:
184
212
                subprocess.call(cmdline)
185
 
            except OSError, e:
 
213
            except OSError as e:
186
214
                if e.errno != errno.ENOENT:
187
215
                    raise
188
216
            else:
189
217
                break
190
218
        else:
191
 
            raise errors.MailClientNotFound(self._client_commands)
 
219
            raise MailClientNotFound(self._client_commands)
192
220
 
193
221
    def _get_compose_commandline(self, to, subject, attach_path, body):
194
222
        """Determine the commandline to use for composing a message
208
236
        :param  u:  possible unicode string.
209
237
        :return:    encoded string if u is unicode, u itself otherwise.
210
238
        """
211
 
        if isinstance(u, unicode):
 
239
        if not PY3 and isinstance(u, text_type):
212
240
            return u.encode(osutils.get_user_encoding(), 'replace')
213
241
        return u
214
242
 
221
249
                        path itself otherwise.
222
250
        :raise:         UnableEncodePath.
223
251
        """
224
 
        if isinstance(path, unicode):
 
252
        if not PY3 and isinstance(path, text_type):
225
253
            try:
226
254
                return path.encode(osutils.get_user_encoding())
227
255
            except UnicodeEncodeError:
250
278
        if body is not None:
251
279
            message_options['body'] = body
252
280
        options_list = ['%s=%s' % (k, urlutils.escape(v)) for (k, v) in
253
 
                        sorted(message_options.iteritems())]
 
281
                        sorted(message_options.items())]
254
282
        return ['mailto:%s?%s' % (self._encode_safe(to or ''),
255
283
            '&'.join(options_list))]
256
284
mail_client_registry.register('evolution', Evolution,
274
302
            # Store the temp file object in self, so that it does not get
275
303
            # garbage collected and delete the file before mutt can read it.
276
304
            self._temp_file = tempfile.NamedTemporaryFile(
277
 
                prefix="mutt-body-", suffix=".txt")
 
305
                prefix="mutt-body-", suffix=".txt", mode="w+")
278
306
            self._temp_file.write(body)
279
307
            self._temp_file.flush()
280
308
            message_options.extend(['-i', self._temp_file.name])
310
338
            message_options['attachment'] = urlutils.local_path_to_url(
311
339
                attach_path)
312
340
        if body is not None:
313
 
            options_list = ['body=%s' % urllib.quote(self._encode_safe(body))]
 
341
            options_list = ['body=%s' % urlutils.quote(self._encode_safe(body))]
314
342
        else:
315
343
            options_list = []
316
344
        options_list.extend(["%s='%s'" % (k, v) for k, v in
317
 
                        sorted(message_options.iteritems())])
 
345
                        sorted(message_options.items())])
318
346
        return ['-compose', ','.join(options_list)]
319
347
mail_client_registry.register('thunderbird', Thunderbird,
320
348
                              help=Thunderbird.__doc__)
352
380
        """See ExternalMailClient._get_compose_commandline"""
353
381
        compose_url = []
354
382
        if from_ is not None:
355
 
            compose_url.append('from=' + urllib.quote(from_))
 
383
            compose_url.append('from=' + urlutils.quote(from_))
356
384
        if subject is not None:
357
 
            # Don't use urllib.quote_plus because Claws doesn't seem
 
385
            # Don't use urlutils.quote_plus because Claws doesn't seem
358
386
            # to recognise spaces encoded as "+".
359
387
            compose_url.append(
360
 
                'subject=' + urllib.quote(self._encode_safe(subject)))
 
388
                'subject=' + urlutils.quote(self._encode_safe(subject)))
361
389
        if body is not None:
362
390
            compose_url.append(
363
 
                'body=' + urllib.quote(self._encode_safe(body)))
 
391
                'body=' + urlutils.quote(self._encode_safe(body)))
364
392
        # to must be supplied for the claws-mail --compose syntax to work.
365
393
        if to is None:
366
 
            raise errors.NoMailAddressSpecified()
 
394
            raise NoMailAddressSpecified()
367
395
        compose_url = 'mailto:%s?%s' % (
368
396
            self._encode_safe(to), '&'.join(compose_url))
369
397
        # Collect command-line options.
377
405
                 extension, body=None, from_=None):
378
406
        """See ExternalMailClient._compose"""
379
407
        if from_ is None:
380
 
            from_ = self.config.get_user_option('email')
 
408
            from_ = self.config.get('email')
381
409
        super(Claws, self)._compose(prompt, to, subject, attach_path,
382
410
                                    mime_subtype, extension, body, from_)
383
411
 
394
422
    def _get_compose_commandline(self, to, subject, attach_path, body=None):
395
423
        """See ExternalMailClient._get_compose_commandline"""
396
424
        if not to:
397
 
            raise errors.NoMailAddressSpecified()
 
425
            raise NoMailAddressSpecified()
398
426
        commandline = [self._encode_safe(to)]
399
427
        if subject is not None:
400
428
            commandline.extend(['--subject', self._encode_safe(subject)])
442
470
        after being read by Emacs.)
443
471
        """
444
472
 
445
 
        _defun = r"""(defun bzr-add-mime-att (file)
 
473
        _defun = br"""(defun bzr-add-mime-att (file)
446
474
  "Attach FILE to a mail buffer as a MIME attachment."
447
475
  (let ((agent mail-user-agent))
448
476
    (if (and file (file-exists-p file))
527
555
 
528
556
        This implementation uses MAPI via the simplemapi ctypes wrapper
529
557
        """
530
 
        from bzrlib.util import simplemapi
 
558
        from .util import simplemapi
531
559
        try:
532
560
            simplemapi.SendMail(to or '', subject or '', body or '',
533
561
                                attach_path)
534
 
        except simplemapi.MAPIError, e:
 
562
        except simplemapi.MAPIError as e:
535
563
            if e.code != simplemapi.MAPI_USER_ABORT:
536
 
                raise errors.MailClientNotFound(['MAPI supported mail client'
 
564
                raise MailClientNotFound(['MAPI supported mail client'
537
565
                                                 ' (error %d)' % (e.code,)])
538
566
mail_client_registry.register('mapi', MAPIClient,
539
567
                              help=MAPIClient.__doc__)
616
644
        """See MailClient.compose"""
617
645
        try:
618
646
            return self._mail_client().compose(prompt, to, subject,
619
 
                                               attachment, mimie_subtype,
 
647
                                               attachment, mime_subtype,
620
648
                                               extension, basename, body)
621
 
        except errors.MailClientNotFound:
 
649
        except MailClientNotFound:
622
650
            return Editor(self.config).compose(prompt, to, subject,
623
 
                          attachment, mimie_subtype, extension, body)
 
651
                          attachment, mime_subtype, extension, body)
624
652
 
625
653
    def compose_merge_request(self, to, subject, directive, basename=None,
626
654
                              body=None):
628
656
        try:
629
657
            return self._mail_client().compose_merge_request(to, subject,
630
658
                    directive, basename=basename, body=body)
631
 
        except errors.MailClientNotFound:
 
659
        except MailClientNotFound:
632
660
            return Editor(self.config).compose_merge_request(to, subject,
633
661
                          directive, basename=basename, body=body)
634
 
mail_client_registry.register('default', DefaultMail,
 
662
mail_client_registry.register(u'default', DefaultMail,
635
663
                              help=DefaultMail.__doc__)
636
 
mail_client_registry.default_key = 'default'
637
 
 
638
 
 
 
664
mail_client_registry.default_key = u'default'
 
665
 
 
666
opt_mail_client = _mod_config.RegistryOption('mail_client',
 
667
        mail_client_registry, help='E-mail client to use.', invalid='error')