[MERGE] Add mail-mode GNU Emacs mail package as a mail_client option.

Xavier Maillard xma at gnu.org
Tue Mar 25 01:00:11 GMT 2008


Hello,

As designed by Bojan earlier today, here is my modified version
of it.

The differences are quite small and simple:

1. we use mail-mode instead of the non default message-mode
2. I renamed the python class name
3. I added tests

Credits go to Bojan Nikolic for the original code and idea.

As this is my first /hack/ in Python, do not expect something
polished from me :)

By the way, all tests test_mail_client passed.

# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: xma at gnu.org-20080324221201-o29kclhm0kbpx6iq
# target_branch: file:///home/xma/usr/src/BZRed/bzr/bzr.dev/
# testament_sha1: 344f620da994c637eee14a2b2f9a6710b34b306e
# timestamp: 2008-03-24 23:20:31 +0100
# base_revision_id: pqm at pqm.ubuntu.com-20080323231145-nh7pyfd19alqp471
# 
# Begin patch
=== modified file 'bzrlib/config.py'
--- bzrlib/config.py	2007-12-02 18:59:28 +0000
+++ bzrlib/config.py	2008-03-24 22:12:01 +0000
@@ -37,7 +37,7 @@
 [/home/robertc/source]
 recurse=False|True(default)
 email= as above
-check_signatures= as above 
+check_signatures= as above
 create_signatures= as above.
 
 explanation of options
@@ -45,9 +45,9 @@
 editor - this option sets the pop up editor to use during commits.
 email - this option sets the user id bzr will use when committing.
 check_signatures - this option controls whether bzr will require good gpg
-                   signatures, ignore them, or check them if they are 
+                   signatures, ignore them, or check them if they are
                    present.
-create_signatures - this option controls whether bzr will always create 
+create_signatures - this option controls whether bzr will always create
                     gpg signatures, never create them, or create them if the
                     branch is configured to require them.
 log_format - this option sets the default log format.  Possible values are
@@ -159,6 +159,7 @@
                 'default': mail_client.DefaultMail,
                 'editor': mail_client.Editor,
                 'mapi': mail_client.MAPIClient,
+                'emacsclient': mail_client.EmacsClient,
                 'xdg-email': mail_client.XDGEmail,
             }[selected_client]
         except KeyError:
@@ -221,16 +222,16 @@
 
     def username(self):
         """Return email-style username.
-    
+
         Something similar to 'Martin Pool <mbp at sourcefrog.net>'
-        
+
         $BZR_EMAIL can be set to override this (as well as the
         deprecated $BZREMAIL), then
         the concrete policy type is checked, and finally
         $EMAIL is examined.
         If none is found, a reasonable default is (hopefully)
         created.
-    
+
         TODO: Check it's reasonably well-formed.
         """
         v = os.environ.get('BZR_EMAIL')
@@ -390,7 +391,7 @@
         super(IniBasedConfig, self).__init__()
         self._get_filename = get_filename
         self._parser = None
-        
+
     def _post_commit(self):
         """See Config.post_commit."""
         return self._get_user_option('post_commit')
@@ -419,7 +420,7 @@
 
     def _get_alias(self, value):
         try:
-            return self._get_parser().get_value("ALIASES", 
+            return self._get_parser().get_value("ALIASES",
                                                 value)
         except KeyError:
             pass
@@ -622,7 +623,7 @@
 
     def _get_safe_value(self, option_name):
         """This variant of get_best_value never returns untrusted values.
-        
+
         It does not return values from the branch data, because the branch may
         not be controlled by the user.
 
@@ -637,18 +638,18 @@
 
     def _get_user_id(self):
         """Return the full user id for the branch.
-    
+
         e.g. "John Hacker <jhacker at foo.org>"
         This is looked up in the email controlfile for the branch.
         """
         try:
-            return (self.branch.control_files.get_utf8("email") 
+            return (self.branch.control_files.get_utf8("email")
                     .read()
                     .decode(bzrlib.user_encoding)
                     .rstrip("\r\n"))
         except errors.NoSuchFile, e:
             pass
-        
+
         return self._get_best_value('_get_user_id')
 
     def _get_signature_checking(self):
@@ -694,14 +695,14 @@
     def _gpg_signing_command(self):
         """See Config.gpg_signing_command."""
         return self._get_safe_value('_gpg_signing_command')
-        
+
     def __init__(self, branch):
         super(BranchConfig, self).__init__()
         self._location_config = None
         self._branch_data_config = None
         self._global_config = None
         self.branch = branch
-        self.option_sources = (self._get_location_config, 
+        self.option_sources = (self._get_location_config,
                                self._get_branch_data_config,
                                self._get_global_config)
 
@@ -749,7 +750,7 @@
     """Return per-user configuration directory.
 
     By default this is ~/.bazaar/
-    
+
     TODO: Global option --config-dir to override this.
     """
     base = os.environ.get('BZR_HOME', None)
@@ -874,7 +875,7 @@
 def extract_email_address(e):
     """Return just the address part of an email string.
 
-    That is just the user at domain part, nothing else. 
+    That is just the user at domain part, nothing else.
     This part is required to contain only ascii characters.
     If it can't be extracted, raises an error.
 

=== modified file 'bzrlib/mail_client.py'
--- bzrlib/mail_client.py	2008-03-16 14:41:10 +0000
+++ bzrlib/mail_client.py	2008-03-24 22:12:01 +0000
@@ -305,6 +305,34 @@
                 self._encode_path(attach_path, 'attachment')])
         return commandline
 
+class EmacsClient (ExternalMailClient):
+    """Call emacsclient in mail-mode. This only work for emacs >= 22.1"""
+    _client_commands = ['emacsclient']
+    def _get_compose_commandline (self, to, subject, attach_path):
+        commandline = ["--eval"]
+        """Ensure we can at least have an empty mail-mode buffer"""
+        _to = "nil"
+        _subject = "nil"
+
+        if to is not None:
+            _to = ("\"%s\"" % self._encode_safe(to))
+        if subject is not None:
+            _subject = ("\"%s\"" % self._encode_safe(subject))
+        mmform = "(mail nil %s %s)" %(_to ,_subject)
+
+        """call mail-mode, move the point to body and insert a new blank line"""
+        """we *must* force this point movement for the case when To is not passed"""
+        """with --mail-to. Without this, the patch could be inserted at the wrong place"""
+        commandline.append(mmform)
+        commandline.append("(mail-text)")
+        commandline.append("(newline)")
+
+        """... and insert the patch as an inline content"""
+        if attach_path is not None:
+            ifform = "(insert-file-contents \"%s\")" % self._encode_path(attach_path,'attachment')
+            commandline.append(ifform)
+        return commandline
+
 
 class MAPIClient(ExternalMailClient):
     """Default Windows mail client launched using MAPI."""

=== modified file 'bzrlib/tests/test_mail_client.py'
--- bzrlib/tests/test_mail_client.py	2008-03-19 20:13:06 +0000
+++ bzrlib/tests/test_mail_client.py	2008-03-24 22:12:01 +0000
@@ -70,6 +70,30 @@
             self.assertFalse(isinstance(item, unicode),
                 'Command-line item %r is unicode!' % item)
 
+class TestEmacsClient(tests.TestCase):
+
+    def test_commandline(self):
+        eclient = mail_client.EmacsClient(None)
+        commandline = eclient._get_compose_commandline(None, None, 'file%')
+        self.assertEqual(['--eval', '(mail nil nil nil)', \
+                              '(mail-text)' , '(newline)', \
+                              '(insert-file-contents "file%")'], commandline)
+
+        commandline = eclient._get_compose_commandline('jrandom at example.org',
+                                                     'Hi there!', None)
+        self.assertEqual(['--eval', '(mail nil "jrandom at example.org" "Hi there!")', \
+                              '(mail-text)' , '(newline)'], commandline)
+
+    def test_commandline_is_8bit(self):
+        eclient = mail_client.EmacsClient(None)
+        commandline = eclient._get_compose_commandline(u'jrandom at example.org',
+            u'Hi there!', u'file%')
+        self.assertEqual(['--eval', '(mail nil "jrandom at example.org" "Hi there!")', \
+                              '(mail-text)' , '(newline)', \
+                          '(insert-file-contents "file%")'], commandline)
+        for item in commandline:
+            self.assertFalse(isinstance(item, unicode),
+                'Command-line item %r is unicode!' % item)
 
 class TestXDGEmail(tests.TestCase):
 

# Begin bundle
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
ZeCpDMqwR0oqT/F3JFOFCQO4eA0A


	Xavier
-- 
http://www.gnu.org
http://www.april.org
http://www.lolica.org



More information about the bazaar mailing list