~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/mail_client.py

  • Committer: Ian Clatworthy
  • Date: 2008-03-27 07:51:10 UTC
  • mto: (3311.1.1 ianc-integration)
  • mto: This revision was merged to the branch mainline in revision 3312.
  • Revision ID: ian.clatworthy@canonical.com-20080327075110-afgd7x03ybju06ez
Reduce evangelism in the User Guide

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
    msgeditor,
28
28
    osutils,
29
29
    urlutils,
30
 
    registry
31
30
    )
32
31
 
33
 
mail_client_registry = registry.Registry()
34
 
 
35
32
 
36
33
class MailClient(object):
37
34
    """A mail client that can send messages with attachements."""
112
109
                                        body,
113
110
                                        attachment,
114
111
                                        attachment_mime_subtype=mime_subtype)
115
 
mail_client_registry.register('editor', Editor,
116
 
                              help=Editor.__doc__)
117
112
 
118
113
 
119
114
class ExternalMailClient(MailClient):
135
130
        """
136
131
        if basename is None:
137
132
            basename = 'attachment'
138
 
        pathname = osutils.mkdtemp(prefix='bzr-mail-')
 
133
        pathname = tempfile.mkdtemp(prefix='bzr-mail-')
139
134
        attach_path = osutils.pathjoin(pathname, basename + extension)
140
135
        outfile = open(attach_path, 'wb')
141
136
        try:
191
186
        :return:    encoded string if u is unicode, u itself otherwise.
192
187
        """
193
188
        if isinstance(u, unicode):
194
 
            return u.encode(osutils.get_user_encoding(), 'replace')
 
189
            return u.encode(bzrlib.user_encoding, 'replace')
195
190
        return u
196
191
 
197
192
    def _encode_path(self, path, kind):
205
200
        """
206
201
        if isinstance(path, unicode):
207
202
            try:
208
 
                return path.encode(osutils.get_user_encoding())
 
203
                return path.encode(bzrlib.user_encoding)
209
204
            except UnicodeEncodeError:
210
205
                raise errors.UnableEncodePath(path, kind)
211
206
        return path
227
222
                        sorted(message_options.iteritems())]
228
223
        return ['mailto:%s?%s' % (self._encode_safe(to or ''),
229
224
            '&'.join(options_list))]
230
 
mail_client_registry.register('evolution', Evolution,
231
 
                              help=Evolution.__doc__)
232
225
 
233
226
 
234
227
class Mutt(ExternalMailClient):
247
240
        if to is not None:
248
241
            message_options.append(self._encode_safe(to))
249
242
        return message_options
250
 
mail_client_registry.register('mutt', Mutt,
251
 
                              help=Mutt.__doc__)
252
243
 
253
244
 
254
245
class Thunderbird(ExternalMailClient):
262
253
    """
263
254
 
264
255
    _client_commands = ['thunderbird', 'mozilla-thunderbird', 'icedove',
265
 
        '/Applications/Mozilla/Thunderbird.app/Contents/MacOS/thunderbird-bin',
266
 
        '/Applications/Thunderbird.app/Contents/MacOS/thunderbird-bin']
 
256
        '/Applications/Mozilla/Thunderbird.app/Contents/MacOS/thunderbird-bin']
267
257
 
268
258
    def _get_compose_commandline(self, to, subject, attach_path):
269
259
        """See ExternalMailClient._get_compose_commandline"""
278
268
        options_list = ["%s='%s'" % (k, v) for k, v in
279
269
                        sorted(message_options.iteritems())]
280
270
        return ['-compose', ','.join(options_list)]
281
 
mail_client_registry.register('thunderbird', Thunderbird,
282
 
                              help=Thunderbird.__doc__)
283
271
 
284
272
 
285
273
class KMail(ExternalMailClient):
298
286
        if to is not None:
299
287
            message_options.extend([self._encode_safe(to)])
300
288
        return message_options
301
 
mail_client_registry.register('kmail', KMail,
302
 
                              help=KMail.__doc__)
303
289
 
304
290
 
305
291
class XDGEmail(ExternalMailClient):
318
304
            commandline.extend(['--attach',
319
305
                self._encode_path(attach_path, 'attachment')])
320
306
        return commandline
321
 
mail_client_registry.register('xdg-email', XDGEmail,
322
 
                              help=XDGEmail.__doc__)
323
 
 
324
 
 
325
 
class EmacsMail(ExternalMailClient):
326
 
    """Call emacsclient to have a mail buffer.
327
 
 
328
 
    This only work for emacs >= 22.1 due to recent -e/--eval support.
329
 
 
330
 
    The good news is that this implementation will work with all mail
331
 
    agents registered against ``mail-user-agent``. So there is no need
332
 
    to instantiate ExternalMailClient for each and every GNU Emacs
333
 
    MUA.
334
 
 
335
 
    Users just have to ensure that ``mail-user-agent`` is set according
336
 
    to their tastes.
337
 
    """
338
 
 
339
 
    _client_commands = ['emacsclient']
340
 
 
341
 
    def _prepare_send_function(self):
342
 
        """Write our wrapper function into a temporary file.
343
 
 
344
 
        This temporary file will be loaded at runtime in
345
 
        _get_compose_commandline function.
346
 
 
347
 
        This function does not remove the file.  That's a wanted
348
 
        behaviour since _get_compose_commandline won't run the send
349
 
        mail function directly but return the eligible command line.
350
 
        Removing our temporary file here would prevent our sendmail
351
 
        function to work.  (The file is deleted by some elisp code
352
 
        after being read by Emacs.)
353
 
        """
354
 
 
355
 
        _defun = r"""(defun bzr-add-mime-att (file)
356
 
  "Attach FILE to a mail buffer as a MIME attachment."
357
 
  (let ((agent mail-user-agent))
358
 
    (if (and file (file-exists-p file))
359
 
        (cond
360
 
         ((eq agent 'sendmail-user-agent)
361
 
          (progn
362
 
            (mail-text)
363
 
            (newline)
364
 
            (if (functionp 'etach-attach)
365
 
              (etach-attach file)
366
 
              (mail-attach-file file))))
367
 
         ((or (eq agent 'message-user-agent)(eq agent 'gnus-user-agent))
368
 
          (progn
369
 
            (mml-attach-file file "text/x-patch" "BZR merge" "inline")))
370
 
         ((eq agent 'mew-user-agent)
371
 
          (progn
372
 
            (mew-draft-prepare-attachments)
373
 
            (mew-attach-link file (file-name-nondirectory file))
374
 
            (let* ((nums (mew-syntax-nums))
375
 
                   (syntax (mew-syntax-get-entry mew-encode-syntax nums)))
376
 
              (mew-syntax-set-cd syntax "BZR merge")
377
 
              (mew-encode-syntax-print mew-encode-syntax))
378
 
            (mew-header-goto-body)))
379
 
         (t
380
 
          (message "Unhandled MUA, report it on bazaar@lists.canonical.com")))
381
 
      (error "File %s does not exist." file))))
382
 
"""
383
 
 
384
 
        fd, temp_file = tempfile.mkstemp(prefix="emacs-bzr-send-",
385
 
                                         suffix=".el")
386
 
        try:
387
 
            os.write(fd, _defun)
388
 
        finally:
389
 
            os.close(fd) # Just close the handle but do not remove the file.
390
 
        return temp_file
391
 
 
392
 
    def _get_compose_commandline(self, to, subject, attach_path):
393
 
        commandline = ["--eval"]
394
 
 
395
 
        _to = "nil"
396
 
        _subject = "nil"
397
 
 
398
 
        if to is not None:
399
 
            _to = ("\"%s\"" % self._encode_safe(to).replace('"', '\\"'))
400
 
        if subject is not None:
401
 
            _subject = ("\"%s\"" %
402
 
                        self._encode_safe(subject).replace('"', '\\"'))
403
 
 
404
 
        # Funcall the default mail composition function
405
 
        # This will work with any mail mode including default mail-mode
406
 
        # User must tweak mail-user-agent variable to tell what function
407
 
        # will be called inside compose-mail.
408
 
        mail_cmd = "(compose-mail %s %s)" % (_to, _subject)
409
 
        commandline.append(mail_cmd)
410
 
 
411
 
        # Try to attach a MIME attachment using our wrapper function
412
 
        if attach_path is not None:
413
 
            # Do not create a file if there is no attachment
414
 
            elisp = self._prepare_send_function()
415
 
            lmmform = '(load "%s")' % elisp
416
 
            mmform  = '(bzr-add-mime-att "%s")' % \
417
 
                self._encode_path(attach_path, 'attachment')
418
 
            rmform = '(delete-file "%s")' % elisp
419
 
            commandline.append(lmmform)
420
 
            commandline.append(mmform)
421
 
            commandline.append(rmform)
422
 
 
423
 
        return commandline
424
 
mail_client_registry.register('emacsclient', EmacsMail,
425
 
                              help=EmacsMail.__doc__)
426
307
 
427
308
 
428
309
class MAPIClient(ExternalMailClient):
441
322
            if e.code != simplemapi.MAPI_USER_ABORT:
442
323
                raise errors.MailClientNotFound(['MAPI supported mail client'
443
324
                                                 ' (error %d)' % (e.code,)])
444
 
mail_client_registry.register('mapi', MAPIClient,
445
 
                              help=MAPIClient.__doc__)
446
325
 
447
326
 
448
327
class DefaultMail(MailClient):
475
354
        except errors.MailClientNotFound:
476
355
            return Editor(self.config).compose_merge_request(to, subject,
477
356
                          directive, basename=basename)
478
 
mail_client_registry.register('default', DefaultMail,
479
 
                              help=DefaultMail.__doc__)
480
 
mail_client_registry.default_key = 'default'