/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: Jelmer Vernooij
  • Date: 2018-02-18 21:42:57 UTC
  • mto: This revision was merged to the branch mainline in revision 6859.
  • Revision ID: jelmer@jelmer.uk-20180218214257-jpevutp1wa30tz3v
Update TODO to reference Breezy, not Bazaar.

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
28
30
    msgeditor,
29
31
    osutils,
30
32
    urlutils,
31
 
    registry,
 
33
    registry
32
34
    )
33
35
 
34
36
mail_client_registry = registry.Registry()
97
99
        prompt = self._get_merge_prompt("Please describe these changes:", to,
98
100
                                        subject, directive)
99
101
        self.compose(prompt, to, subject, directive,
100
 
                     'x-patch', '.patch', basename, body)
 
102
            'x-patch', '.patch', basename, body)
101
103
 
102
104
    def _get_merge_prompt(self, prompt, to, subject, attachment):
103
105
        """Generate a prompt string.  Overridden by Editor.
138
140
                                        body,
139
141
                                        attachment,
140
142
                                        attachment_mime_subtype=mime_subtype)
141
 
 
142
 
 
143
143
mail_client_registry.register('editor', Editor,
144
144
                              help=Editor.__doc__)
145
145
 
166
166
            basename = 'attachment'
167
167
        pathname = osutils.mkdtemp(prefix='bzr-mail-')
168
168
        attach_path = osutils.pathjoin(pathname, basename + extension)
169
 
        with open(attach_path, 'wb') as outfile:
 
169
        outfile = open(attach_path, 'wb')
 
170
        try:
170
171
            outfile.write(attachment)
 
172
        finally:
 
173
            outfile.close()
171
174
        if body is not None:
172
175
            kwargs = {'body': body}
173
176
        else:
229
232
        :param  u:  possible unicode string.
230
233
        :return:    encoded string if u is unicode, u itself otherwise.
231
234
        """
 
235
        if isinstance(u, unicode):
 
236
            return u.encode(osutils.get_user_encoding(), 'replace')
232
237
        return u
233
238
 
234
239
    def _encode_path(self, path, kind):
240
245
                        path itself otherwise.
241
246
        :raise:         UnableEncodePath.
242
247
        """
 
248
        if isinstance(path, unicode):
 
249
            try:
 
250
                return path.encode(osutils.get_user_encoding())
 
251
            except UnicodeEncodeError:
 
252
                raise errors.UnableEncodePath(path, kind)
243
253
        return path
244
254
 
245
255
 
266
276
        options_list = ['%s=%s' % (k, urlutils.escape(v)) for (k, v) in
267
277
                        sorted(message_options.items())]
268
278
        return ['mailto:%s?%s' % (self._encode_safe(to or ''),
269
 
                                  '&'.join(options_list))]
270
 
 
271
 
 
 
279
            '&'.join(options_list))]
272
280
mail_client_registry.register('evolution', Evolution,
273
281
                              help=Evolution.__doc__)
274
282
 
282
290
        """See ExternalMailClient._get_compose_commandline"""
283
291
        message_options = []
284
292
        if subject is not None:
285
 
            message_options.extend(
286
 
                ['-s', self._encode_safe(subject)])
 
293
            message_options.extend(['-s', self._encode_safe(subject)])
287
294
        if attach_path is not None:
288
 
            message_options.extend(
289
 
                ['-a', self._encode_path(attach_path, 'attachment')])
 
295
            message_options.extend(['-a',
 
296
                self._encode_path(attach_path, 'attachment')])
290
297
        if body is not None:
291
298
            # Store the temp file object in self, so that it does not get
292
299
            # garbage collected and delete the file before mutt can read it.
293
300
            self._temp_file = tempfile.NamedTemporaryFile(
294
 
                prefix="mutt-body-", suffix=".txt", mode="w+")
 
301
                prefix="mutt-body-", suffix=".txt")
295
302
            self._temp_file.write(body)
296
303
            self._temp_file.flush()
297
304
            message_options.extend(['-i', self._temp_file.name])
298
305
        if to is not None:
299
306
            message_options.extend(['--', self._encode_safe(to)])
300
307
        return message_options
301
 
 
302
 
 
303
308
mail_client_registry.register('mutt', Mutt,
304
309
                              help=Mutt.__doc__)
305
310
 
314
319
    send attachments.
315
320
    """
316
321
 
317
 
    _client_commands = [
318
 
        'thunderbird', 'mozilla-thunderbird', 'icedove',
 
322
    _client_commands = ['thunderbird', 'mozilla-thunderbird', 'icedove',
319
323
        '/Applications/Mozilla/Thunderbird.app/Contents/MacOS/thunderbird-bin',
320
324
        '/Applications/Thunderbird.app/Contents/MacOS/thunderbird-bin']
321
325
 
330
334
            message_options['attachment'] = urlutils.local_path_to_url(
331
335
                attach_path)
332
336
        if body is not None:
333
 
            options_list = ['body=%s' %
334
 
                            urlutils.quote(self._encode_safe(body))]
 
337
            options_list = ['body=%s' % urlutils.quote(self._encode_safe(body))]
335
338
        else:
336
339
            options_list = []
337
340
        options_list.extend(["%s='%s'" % (k, v) for k, v in
338
 
                             sorted(message_options.items())])
 
341
                        sorted(message_options.items())])
339
342
        return ['-compose', ','.join(options_list)]
340
 
 
341
 
 
342
343
mail_client_registry.register('thunderbird', Thunderbird,
343
344
                              help=Thunderbird.__doc__)
344
345
 
354
355
        if subject is not None:
355
356
            message_options.extend(['-s', self._encode_safe(subject)])
356
357
        if attach_path is not None:
357
 
            message_options.extend(
358
 
                ['--attach', self._encode_path(attach_path, 'attachment')])
 
358
            message_options.extend(['--attach',
 
359
                self._encode_path(attach_path, 'attachment')])
359
360
        if to is not None:
360
361
            message_options.extend([self._encode_safe(to)])
361
362
        return message_options
362
 
 
363
 
 
364
363
mail_client_registry.register('kmail', KMail,
365
364
                              help=KMail.__doc__)
366
365
 
412
411
 
413
412
 
414
413
class XDGEmail(BodyExternalMailClient):
415
 
    __doc__ = """xdg-email attempts to invoke the preferred mail client"""
 
414
    __doc__ = """xdg-email attempts to invoke the user's preferred mail client"""
416
415
 
417
416
    _client_commands = ['xdg-email']
418
417
 
425
424
            commandline.extend(['--subject', self._encode_safe(subject)])
426
425
        if attach_path is not None:
427
426
            commandline.extend(['--attach',
428
 
                                self._encode_path(attach_path, 'attachment')])
 
427
                self._encode_path(attach_path, 'attachment')])
429
428
        if body is not None:
430
429
            commandline.extend(['--body', self._encode_safe(body)])
431
430
        return commandline
432
 
 
433
 
 
434
431
mail_client_registry.register('xdg-email', XDGEmail,
435
432
                              help=XDGEmail.__doc__)
436
433
 
469
466
        after being read by Emacs.)
470
467
        """
471
468
 
472
 
        _defun = br"""(defun bzr-add-mime-att (file)
 
469
        _defun = r"""(defun bzr-add-mime-att (file)
473
470
  "Attach FILE to a mail buffer as a MIME attachment."
474
471
  (let ((agent mail-user-agent))
475
472
    (if (and file (file-exists-p file))
505
502
        try:
506
503
            os.write(fd, _defun)
507
504
        finally:
508
 
            os.close(fd)  # Just close the handle but do not remove the file.
 
505
            os.close(fd) # Just close the handle but do not remove the file.
509
506
        return temp_file
510
507
 
511
508
    def _get_compose_commandline(self, to, subject, attach_path):
533
530
            elisp = self._prepare_send_function()
534
531
            self.elisp_tmp_file = elisp
535
532
            lmmform = '(load "%s")' % elisp
536
 
            mmform = '(bzr-add-mime-att "%s")' % \
 
533
            mmform  = '(bzr-add-mime-att "%s")' % \
537
534
                self._encode_path(attach_path, 'attachment')
538
535
            rmform = '(delete-file "%s")' % elisp
539
536
            commandline.append(lmmform)
541
538
            commandline.append(rmform)
542
539
 
543
540
        return commandline
544
 
 
545
 
 
546
541
mail_client_registry.register('emacsclient', EmacsMail,
547
542
                              help=EmacsMail.__doc__)
548
543
 
563
558
        except simplemapi.MAPIError as e:
564
559
            if e.code != simplemapi.MAPI_USER_ABORT:
565
560
                raise MailClientNotFound(['MAPI supported mail client'
566
 
                                          ' (error %d)' % (e.code,)])
567
 
 
568
 
 
 
561
                                                 ' (error %d)' % (e.code,)])
569
562
mail_client_registry.register('mapi', MAPIClient,
570
563
                              help=MAPIClient.__doc__)
571
564
 
583
576
    _client_commands = ['osascript']
584
577
 
585
578
    def _get_compose_commandline(self, to, subject, attach_path, body=None,
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'
601
 
                         % from_.replace('"', '\\"'))
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
 
 
 
579
                                from_=None):
 
580
       """See ExternalMailClient._get_compose_commandline"""
 
581
 
 
582
       fd, self.temp_file = tempfile.mkstemp(prefix="bzr-send-",
 
583
                                         suffix=".scpt")
 
584
       try:
 
585
           os.write(fd, 'tell application "Mail"\n')
 
586
           os.write(fd, 'set newMessage to make new outgoing message\n')
 
587
           os.write(fd, 'tell newMessage\n')
 
588
           if to is not None:
 
589
               os.write(fd, 'make new to recipient with properties'
 
590
                   ' {address:"%s"}\n' % to)
 
591
           if from_ is not None:
 
592
               # though from_ doesn't actually seem to be used
 
593
               os.write(fd, 'set sender to "%s"\n'
 
594
                   % sender.replace('"', '\\"'))
 
595
           if subject is not None:
 
596
               os.write(fd, 'set subject to "%s"\n'
 
597
                   % subject.replace('"', '\\"'))
 
598
           if body is not None:
 
599
               # FIXME: would be nice to prepend the body to the
 
600
               # existing content (e.g., preserve signature), but
 
601
               # can't seem to figure out the right applescript
 
602
               # incantation.
 
603
               os.write(fd, 'set content to "%s\\n\n"\n' %
 
604
                   body.replace('"', '\\"').replace('\n', '\\n'))
 
605
 
 
606
           if attach_path is not None:
 
607
               # FIXME: would be nice to first append a newline to
 
608
               # ensure the attachment is on a new paragraph, but
 
609
               # can't seem to figure out the right applescript
 
610
               # incantation.
 
611
               os.write(fd, 'tell content to make new attachment'
 
612
                   ' with properties {file name:"%s"}'
 
613
                   ' at after the last paragraph\n'
 
614
                   % self._encode_path(attach_path, 'attachment'))
 
615
           os.write(fd, 'set visible to true\n')
 
616
           os.write(fd, 'end tell\n')
 
617
           os.write(fd, 'end tell\n')
 
618
       finally:
 
619
           os.close(fd) # Just close the handle but do not remove the file.
 
620
       return [self.temp_file]
630
621
mail_client_registry.register('mail.app', MailApp,
631
622
                              help=MailApp.__doc__)
632
623
 
652
643
                                               attachment, mime_subtype,
653
644
                                               extension, basename, body)
654
645
        except MailClientNotFound:
655
 
            return Editor(self.config).compose(
656
 
                prompt, to, subject, attachment, mime_subtype, extension, body)
 
646
            return Editor(self.config).compose(prompt, to, subject,
 
647
                          attachment, mime_subtype, extension, body)
657
648
 
658
649
    def compose_merge_request(self, to, subject, directive, basename=None,
659
650
                              body=None):
660
651
        """See MailClient.compose_merge_request"""
661
652
        try:
662
 
            return self._mail_client().compose_merge_request(
663
 
                to, subject, directive, basename=basename, body=body)
 
653
            return self._mail_client().compose_merge_request(to, subject,
 
654
                    directive, basename=basename, body=body)
664
655
        except MailClientNotFound:
665
 
            return Editor(self.config).compose_merge_request(
666
 
                to, subject, directive, basename=basename, body=body)
667
 
 
668
 
 
669
 
mail_client_registry.register(u'default', DefaultMail,
 
656
            return Editor(self.config).compose_merge_request(to, subject,
 
657
                          directive, basename=basename, body=body)
 
658
mail_client_registry.register('default', DefaultMail,
670
659
                              help=DefaultMail.__doc__)
671
 
mail_client_registry.default_key = u'default'
 
660
mail_client_registry.default_key = 'default'
672
661
 
673
 
opt_mail_client = _mod_config.RegistryOption(
674
 
    'mail_client', mail_client_registry, help='E-mail client to use.',
675
 
    invalid='error')
 
662
opt_mail_client = _mod_config.RegistryOption('mail_client',
 
663
        mail_client_registry, help='E-mail client to use.', invalid='error')