~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/mail_client.py

  • Committer: Sidnei da Silva
  • Date: 2009-05-29 14:19:29 UTC
  • mto: (4531.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4532.
  • Revision ID: sidnei.da.silva@canonical.com-20090529141929-3heywbvj36po72a5
- Add initial config

Show diffs side-by-side

added added

removed removed

Lines of Context:
155
155
                      extension, **kwargs)
156
156
 
157
157
    def _compose(self, prompt, to, subject, attach_path, mime_subtype,
158
 
                 extension, body=None, from_=None):
 
158
                extension, body=None):
159
159
        """Invoke a mail client as a commandline process.
160
160
 
161
161
        Overridden by MAPIClient.
166
166
            "text", but the precise subtype can be specified here
167
167
        :param extension: A file extension (including period) associated with
168
168
            the attachment type.
169
 
        :param body: Optional body text.
170
 
        :param from_: Optional From: header.
171
169
        """
172
170
        for name in self._get_client_commands():
173
171
            cmdline = [self._encode_path(name, 'executable')]
175
173
                kwargs = {'body': body}
176
174
            else:
177
175
                kwargs = {}
178
 
            if from_ is not None:
179
 
                kwargs['from_'] = from_
180
176
            cmdline.extend(self._get_compose_commandline(to, subject,
181
177
                                                         attach_path,
182
178
                                                         **kwargs))
257
253
                              help=Evolution.__doc__)
258
254
 
259
255
 
260
 
class Mutt(BodyExternalMailClient):
 
256
class Mutt(ExternalMailClient):
261
257
    """Mutt mail client."""
262
258
 
263
259
    _client_commands = ['mutt']
264
260
 
265
 
    def _get_compose_commandline(self, to, subject, attach_path, body=None):
 
261
    def _get_compose_commandline(self, to, subject, attach_path):
266
262
        """See ExternalMailClient._get_compose_commandline"""
267
263
        message_options = []
268
264
        if subject is not None:
270
266
        if attach_path is not None:
271
267
            message_options.extend(['-a',
272
268
                self._encode_path(attach_path, 'attachment')])
273
 
        if body is not None:
274
 
            # Store the temp file object in self, so that it does not get
275
 
            # garbage collected and delete the file before mutt can read it.
276
 
            self._temp_file = tempfile.NamedTemporaryFile(
277
 
                prefix="mutt-body-", suffix=".txt")
278
 
            self._temp_file.write(body)
279
 
            self._temp_file.flush()
280
 
            message_options.extend(['-i', self._temp_file.name])
281
269
        if to is not None:
282
270
            message_options.extend(['--', self._encode_safe(to)])
283
271
        return message_options
343
331
class Claws(ExternalMailClient):
344
332
    """Claws mail client."""
345
333
 
346
 
    supports_body = True
347
 
 
348
334
    _client_commands = ['claws-mail']
349
335
 
350
 
    def _get_compose_commandline(self, to, subject, attach_path, body=None,
351
 
                                 from_=None):
 
336
    def _get_compose_commandline(self, to, subject, attach_path):
352
337
        """See ExternalMailClient._get_compose_commandline"""
353
 
        compose_url = []
354
 
        if from_ is not None:
355
 
            compose_url.append('from=' + urllib.quote(from_))
 
338
        compose_url = ['mailto:']
 
339
        if to is not None:
 
340
            compose_url.append(self._encode_safe(to))
 
341
        compose_url.append('?')
356
342
        if subject is not None:
357
343
            # Don't use urllib.quote_plus because Claws doesn't seem
358
344
            # to recognise spaces encoded as "+".
359
345
            compose_url.append(
360
 
                'subject=' + urllib.quote(self._encode_safe(subject)))
361
 
        if body is not None:
362
 
            compose_url.append(
363
 
                'body=' + urllib.quote(self._encode_safe(body)))
364
 
        # to must be supplied for the claws-mail --compose syntax to work.
365
 
        if to is None:
366
 
            raise errors.NoMailAddressSpecified()
367
 
        compose_url = 'mailto:%s?%s' % (
368
 
            self._encode_safe(to), '&'.join(compose_url))
 
346
                'subject=%s' % urllib.quote(self._encode_safe(subject)))
369
347
        # Collect command-line options.
370
 
        message_options = ['--compose', compose_url]
 
348
        message_options = ['--compose', ''.join(compose_url)]
371
349
        if attach_path is not None:
372
350
            message_options.extend(
373
351
                ['--attach', self._encode_path(attach_path, 'attachment')])
374
352
        return message_options
375
 
 
376
 
    def _compose(self, prompt, to, subject, attach_path, mime_subtype,
377
 
                 extension, body=None, from_=None):
378
 
        """See ExternalMailClient._compose"""
379
 
        if from_ is None:
380
 
            from_ = self.config.get_user_option('email')
381
 
        super(Claws, self)._compose(prompt, to, subject, attach_path,
382
 
                                    mime_subtype, extension, body, from_)
383
 
 
384
 
 
385
353
mail_client_registry.register('claws', Claws,
386
354
                              help=Claws.__doc__)
387
355
 
424
392
 
425
393
    _client_commands = ['emacsclient']
426
394
 
427
 
    def __init__(self, config):
428
 
        super(EmacsMail, self).__init__(config)
429
 
        self.elisp_tmp_file = None
430
 
 
431
395
    def _prepare_send_function(self):
432
396
        """Write our wrapper function into a temporary file.
433
397
 
504
468
        if attach_path is not None:
505
469
            # Do not create a file if there is no attachment
506
470
            elisp = self._prepare_send_function()
507
 
            self.elisp_tmp_file = elisp
508
471
            lmmform = '(load "%s")' % elisp
509
472
            mmform  = '(bzr-add-mime-att "%s")' % \
510
473
                self._encode_path(attach_path, 'attachment')
539
502
                              help=MAPIClient.__doc__)
540
503
 
541
504
 
542
 
class MailApp(BodyExternalMailClient):
543
 
    """Use MacOS X's Mail.app for sending email messages.
544
 
 
545
 
    Although it would be nice to use appscript, it's not installed
546
 
    with the shipped Python installations.  We instead build an
547
 
    AppleScript and invoke the script using osascript(1).  We don't
548
 
    use the _encode_safe() routines as it's not clear what encoding
549
 
    osascript expects the script to be in.
550
 
    """
551
 
 
552
 
    _client_commands = ['osascript']
553
 
 
554
 
    def _get_compose_commandline(self, to, subject, attach_path, body=None,
555
 
                                from_=None):
556
 
       """See ExternalMailClient._get_compose_commandline"""
557
 
 
558
 
       fd, self.temp_file = tempfile.mkstemp(prefix="bzr-send-",
559
 
                                         suffix=".scpt")
560
 
       try:
561
 
           os.write(fd, 'tell application "Mail"\n')
562
 
           os.write(fd, 'set newMessage to make new outgoing message\n')
563
 
           os.write(fd, 'tell newMessage\n')
564
 
           if to is not None:
565
 
               os.write(fd, 'make new to recipient with properties'
566
 
                   ' {address:"%s"}\n' % to)
567
 
           if from_ is not None:
568
 
               # though from_ doesn't actually seem to be used
569
 
               os.write(fd, 'set sender to "%s"\n'
570
 
                   % sender.replace('"', '\\"'))
571
 
           if subject is not None:
572
 
               os.write(fd, 'set subject to "%s"\n'
573
 
                   % subject.replace('"', '\\"'))
574
 
           if body is not None:
575
 
               # FIXME: would be nice to prepend the body to the
576
 
               # existing content (e.g., preserve signature), but
577
 
               # can't seem to figure out the right applescript
578
 
               # incantation.
579
 
               os.write(fd, 'set content to "%s\\n\n"\n' %
580
 
                   body.replace('"', '\\"').replace('\n', '\\n'))
581
 
 
582
 
           if attach_path is not None:
583
 
               # FIXME: would be nice to first append a newline to
584
 
               # ensure the attachment is on a new paragraph, but
585
 
               # can't seem to figure out the right applescript
586
 
               # incantation.
587
 
               os.write(fd, 'tell content to make new attachment'
588
 
                   ' with properties {file name:"%s"}'
589
 
                   ' at after the last paragraph\n'
590
 
                   % self._encode_path(attach_path, 'attachment'))
591
 
           os.write(fd, 'set visible to true\n')
592
 
           os.write(fd, 'end tell\n')
593
 
           os.write(fd, 'end tell\n')
594
 
       finally:
595
 
           os.close(fd) # Just close the handle but do not remove the file.
596
 
       return [self.temp_file]
597
 
mail_client_registry.register('mail.app', MailApp,
598
 
                              help=MailApp.__doc__)
599
 
 
600
 
 
601
505
class DefaultMail(MailClient):
602
506
    """Default mail handling.  Tries XDGEmail (or MAPIClient on Windows),
603
507
    falls back to Editor"""
604
508
 
605
 
    supports_body = True
606
 
 
607
509
    def _mail_client(self):
608
510
        """Determine the preferred mail client for this platform"""
609
511
        if osutils.supports_mapi():
634
536
mail_client_registry.register('default', DefaultMail,
635
537
                              help=DefaultMail.__doc__)
636
538
mail_client_registry.default_key = 'default'
637
 
 
638