/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 bzrlib/mail_client.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

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