changeset 63:d1333236adba

backward compability with 1.3 mail_from configuration, update example configuration, add tests imported from: moin--main--1.5--patch-65
author Nir Soffer <nirs@freeshell.org>
date Fri, 30 Sep 2005 22:13:58 +0000
parents 3de67d5c26b7
children 6483a586208d
files MoinMoin/_tests/test_util_mail.py MoinMoin/multiconfig.py MoinMoin/util/mail.py docs/CHANGES wiki/config/farmconfig.py wiki/config/wikiconfig.py
diffstat 6 files changed, 148 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/_tests/test_util_mail.py	Fri Sep 30 19:13:50 2005 +0000
+++ b/MoinMoin/_tests/test_util_mail.py	Fri Sep 30 22:13:58 2005 +0000
@@ -1,13 +1,17 @@
-# -*- coding: iso-8859-1 -*-
+# -*- coding: utf-8 -*-
 """
     MoinMoin - MoinMoin.util.mail Tests
 
-    @copyright: 2003-2004 by Jürgen Hermann <jh@web.de>
+    @copyright: 2003-2004 by Jürgen Hermann <jh@web.de>
     @license: GNU GPL, see COPYING for details.
 """
 
 import unittest
+from email.Charset import Charset, QP
+from email.Header import Header
 from MoinMoin.util import mail
+from MoinMoin import config
+
 
 class decodeSpamSafeEmailTestCase(unittest.TestCase):
     """util.mail: testing mail"""
@@ -37,4 +41,74 @@
         for coded, expected in self._tests:
             result = mail.decodeSpamSafeEmail(coded)
             self.assertEqual(result, expected,
-                             'Expected "%(expected)s" but got "%(result)s"' % locals())
+                             'Expected "%(expected)s" but got "%(result)s"' %
+                             locals())
+
+
+class EncodeAddressTests(unittest.TestCase):
+    """ Address encoding tests
+    
+    See http://www.faqs.org/rfcs/rfc2822.html section 3.4. 
+    Address Specification.
+            
+    mailbox     =   name-addr / addr-spec
+    name-addr   =   [display-name] angle-addr
+    angle-addr  =   [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
+    """    
+    charset = Charset(config.charset)
+    charset.header_encoding = QP
+    charset.body_encoding = QP
+
+    def testSimpleAddress(self):
+        """ util.mail: encode simple address: local@domain """
+        address = u'local@domain'
+        expected = address.encode(config.charset)
+        self.failUnlessEqual(mail.encodeAddress(address, self.charset),
+                             expected)
+
+    def testComposite(self):
+        """ util.mail: encode address: 'Phrase <local@domain>' """
+        address = u'Phrase <local@domain>'
+        phrase = str(Header(u'Phrase '.encode('utf-8'), self.charset))
+        expected = phrase + '<local@domain>'
+        self.failUnlessEqual(mail.encodeAddress(address, self.charset),
+                             expected)
+                             
+    def testCompositeUnicode(self):
+        """ util.mail: encode Uncode address: 'ויקי <local@domain>' """
+        address = u'ויקי <local@domain>'
+        phrase = str(Header(u'ויקי '.encode('utf-8'), self.charset))
+        expected = phrase + '<local@domain>'
+        self.failUnlessEqual(mail.encodeAddress(address, self.charset),
+                             expected)
+                             
+    def testEmptyPhrase(self):
+        """ util.mail: encode address with empty phrase: '<local@domain>' """
+        address = u'<local@domain>'
+        expected = address.encode(config.charset)
+        self.failUnlessEqual(mail.encodeAddress(address, self.charset),
+                             expected)
+                             
+    def testEmptyAddress(self):
+        """ util.mail: encode address with empty address: 'Phrase <>' 
+        
+        Let the smtp server handle this. We may raise error in such
+        case, but we don't do error checking for mail addresses.
+        """
+        address = u'Phrase <>'
+        phrase = str(Header(u'Phrase '.encode('utf-8'), self.charset))
+        expected = phrase + '<>'
+        self.failUnlessEqual(mail.encodeAddress(address, self.charset),
+                             expected)
+
+    def testInvalidAddress(self):
+        """ util.mail: encode invalid address 'Phrase <blah' 
+        
+        Assume that this is a simple address. This address will
+        probably cause an error when trying to send mail. Junk in, junk
+        out.
+        """
+        address = u'Phrase <blah'
+        expected = address.encode(config.charset)
+        self.failUnlessEqual(mail.encodeAddress(address, self.charset),
+                             expected)
--- a/MoinMoin/multiconfig.py	Fri Sep 30 19:13:50 2005 +0000
+++ b/MoinMoin/multiconfig.py	Fri Sep 30 22:13:58 2005 +0000
@@ -226,8 +226,10 @@
     mail_login = None # or "user pwd" if you need to use SMTP AUTH
     mail_sendmail = None # "/usr/sbin/sendmail -t -i" to not use SMTP, but sendmail
     mail_smarthost = None
-    mail_from = None
-    navi_bar = [ u'%(page_front_page)s', u'RecentChanges', u'FindPage', u'HelpContents', ]
+    mail_from = None # u'Jürgen Wiki <noreply@jhwiki.org>'
+    
+    navi_bar = [u'%(page_front_page)s', u'RecentChanges', u'FindPage', 
+                u'HelpContents', ]
     nonexist_qm = 0
 
     page_credits = [
@@ -490,7 +492,7 @@
             'page_category_regex', 'page_dict_regex', 'page_form_regex',
             'page_group_regex', 'page_template_regex', 'page_license_page',
             'page_local_spelling_words', 'acl_rights_default',
-            'acl_rights_before', 'acl_rights_after',
+            'acl_rights_before', 'acl_rights_after', 'mail_from'
             )
         
         for name in decode_names:
--- a/MoinMoin/util/mail.py	Fri Sep 30 19:13:50 2005 +0000
+++ b/MoinMoin/util/mail.py	Fri Sep 30 22:13:58 2005 +0000
@@ -6,11 +6,39 @@
     @license: GNU GPL, see COPYING for details.
 """
 
-import os
+import os, re
+from email.Header import Header
+from MoinMoin import config
 
 _transdict = {"AT": "@", "DOT": ".", "DASH": "-"}
 
 
+def encodeAddress(address, charset):
+    """ Encode email address to enable non ascii names 
+    
+    e.g. '"Jürgen Hermann" <jh@web.de>'. According to the RFC, the name
+    part should be encoded, the address should not.
+    
+    @param address: email address, posibly using '"name" <address>' format
+    @type address: unicode
+    @param charset: sepcifying both the charset and the encoding, e.g
+        quoted printble or base64.
+    @type charset: email.Charset.Charset instance
+    @rtype: string
+    @return: encoded address
+    """   
+    composite = re.compile(r'(?P<phrase>.+)(?P<angle_addr>\<.*\>)', 
+                           re.UNICODE)
+    match = composite.match(address)
+    if match:
+        phrase = match.group('phrase').encode(config.charset)
+        phrase = str(Header(phrase, charset))
+        angle_addr = match.group('angle_addr').encode(config.charset)       
+        return phrase + angle_addr
+    else:
+        return address.encode(config.charset)
+
+
 def sendmail(request, to, subject, text, **kw):
     """ Create and send a text/plain message
         
@@ -20,7 +48,8 @@
     @param to: recipients (list)
     @param subject: subject of email (unicode)
     @param text: email body text (unicode)
-    @keyword mail_from: override default mail_from (string)
+    @keyword mail_from: override default mail_from
+    @type mail_from: unicode
     @rtype: tuple
     @return: (is_ok, Description of error or OK message)
     """
@@ -28,9 +57,6 @@
     from email.Message import Message
     from email.Charset import Charset, QP
     from email.Utils import formatdate, make_msgid
-    from email.Header import Header
-    
-    from MoinMoin import config
 
     _ = request.getText
     cfg = request.cfg    
@@ -53,9 +79,8 @@
     
     # Create message headers
     # Don't expose emails addreses of the other subscribers, instead we
-    # use the same mail_from, e.g. "My Wiki <noreply@mywiki.org>"
-    sitename = Header(request.cfg.sitename.encode(config.charset), charset)
-    address = '"%s" <%s>' % (sitename, mail_from) 
+    # use the same mail_from, e.g. u"Jürgen Wiki <noreply@mywiki.org>"
+    address = encodeAddress(mail_from, charset) 
     msg['From'] = address
     msg['To'] = address
     msg['Date'] = formatdate()
@@ -66,7 +91,7 @@
         # Set the BCC.  This will be stripped later by sendmail.
         msg['BCC'] = ','.join(to)
         # Set Return-Path so that it isn't set (generally incorrectly) for us.
-        msg['Return-Path'] = mail_from
+        msg['Return-Path'] = address
 
     # Send the message
     if not cfg.mail_sendmail:
--- a/docs/CHANGES	Fri Sep 30 19:13:50 2005 +0000
+++ b/docs/CHANGES	Fri Sep 30 22:13:58 2005 +0000
@@ -2,15 +2,15 @@
 ========================
 
 Version moin--main--1.5:
-    * Requirements changed to require Python >= 2.3. We recommend that you use
-      the latest Python release you can get. The reason we dropped 2.2.2
-      support is because no developer or tester uses this old version any more,
-      so incompatibilities crept in the code without anybody noticing.
-      Using some recent Python usually is no real problem, see there for some
-      hints in case you still run an old python:
-      http://moinmoin.wikiwikiweb.de/NewPythonOnOldLinux
-      The hint also does apply to other POSIX style operating systems, not only
-      Linux.
+    * Requirements changed to require Python >= 2.3. We recommend that
+      you use the latest Python release you can get. The reason we
+      dropped 2.2.2 support is because no developer or tester uses this
+      old version any more, so incompatibilities crept in the code
+      without anybody noticing. Using some recent Python usually is no
+      real problem, see there for some hints in case you still run an
+      old python: http://moinmoin.wikiwikiweb.de/NewPythonOnOldLinux
+      The hint also does apply to other POSIX style operating systems,
+      not only Linux.
 
   Config Changes:
      * there is a file CHANGES.config with just the recently changed stuff
@@ -37,11 +37,12 @@
       to Fred CK for his great work). See http://fckeditor.net/ for details.
      * config for FCKeditor is at wiki/htdocs/applets/moinfckeditor.js
      * added cfg.interwiki_preferred (default = []) to set a list of wikis to
-       show at the top of the wiki selection list when inserting an interwiki
-       link (just use the same wiki name as in interwiki map). If the last list
-       item is None, then the preferred wikis will not be followed by the entries
-       of the interwiki map.
-    * moved save/preview/... buttons to the top so that they can be easily reached
+       show at the top of the wiki selection list when inserting an
+       interwiki link (just use the same wiki name as in interwiki
+       map). If the last list item is None, then the preferred wikis
+       will not be followed by the entries of the interwiki map.
+    * moved save/preview/... buttons to the top so that they can be
+      easily reached
     * reduced edit_rows default to 20 lines
     * Added support for edit by doubleclick in the diff view
 
@@ -120,10 +121,10 @@
      * @ME@ expands to just the plain username (no markup added) on save
     
     * User homepages
-     * when a user accesses his own non-existing homepage (pagename == username),
-       the wiki will present the MissingHomePage system page content, explaining
-       what a user homepage is good for and offer one-click editing it with
-       content loaded from HomepageTemplate
+     * when a user accesses his own non-existing homepage (pagename ==
+       username), the wiki will present the MissingHomePage system page
+       content, explaining what a user homepage is good for and offer
+       one-click editing it with content loaded from HomepageTemplate
      * creation of homepage subpages is assisted by the MyPages action, which
        offers rw, ro page creation (and a related group) or creation of private
        pages. If you are not in the user_homewiki, you will get redirected
@@ -142,8 +143,6 @@
     * Added 'moin' daemon script, that let you run moin standalone
       server as daemon and control the server with simple command line
       intreface: moin start | stop | restart | kill
-    * Added a "daemon" option to standalone server. Useful if you want
-      to start if at system startup.    
     * Add 'restart' option to mointwisted script
     * Add properties option to standalone server config. Allow
       overriding any request property like in other server types.
@@ -151,17 +150,20 @@
       manual url mapping.
       See HelpOnConfiguration/IntegratingWithApache
     * added a WikiBackup action, configure it similar to this:
-      data_dir = "...."
+      data_dir = "/path/to/data"
       backup_include = [data_dir, ] # you can add other dirs here
-      backup_users = ["BackupUserName", ] # some VERY trusted guys
+      backup_users = ["BackupUserName", ] # only TRUSTED users!
       You usually don't need to change the default backup_exclude setting.
       The default backup_include list is EMPTY and so will be your
       backup in case you don't configure it correctly.
       If you put your data_dir there, the backup will contain private
-      user data like email addresses and crypted passwords.
+      user data like email addresses and encrypted passwords.
 
-Developer notes:
-    
+  International support:    
+    * mail_from can be now a unicode name-address 
+      e.g u'Jürgen wiki <noreply@jhwiki.org'
+
+  Developer notes:    
     * Plugin API was improved. When plugin module is missing,
       wikiutil.PluginMissingError is raised. When trying to import a
       missing name from a plugin module, wikiutil.PluginMissingError is
--- a/wiki/config/farmconfig.py	Fri Sep 30 19:13:50 2005 +0000
+++ b/wiki/config/farmconfig.py	Fri Sep 30 22:13:58 2005 +0000
@@ -105,8 +105,8 @@
     # SMTP server, e.g. "mail.provider.com" (empty or None to disable mail)
     mail_smarthost = ""
 
-    # The return address, e.g "My Wiki <noreply@mywiki.org>"
-    mail_from = ""
+    # The return address, e.g u"Jürgen Wiki <noreply@mywiki.org>" [Unicode]
+    mail_from = u""
 
     # "user pwd" if you need to use SMTP AUTH
     mail_login = ""
--- a/wiki/config/wikiconfig.py	Fri Sep 30 19:13:50 2005 +0000
+++ b/wiki/config/wikiconfig.py	Fri Sep 30 22:13:58 2005 +0000
@@ -93,11 +93,11 @@
     # Configure to enable subscribing to pages (disabled by default)
     # or sending forgotten passwords.
 
-    # SMTP server, e.g. "mail.provider.com" (empty or None to disable mail)
+    # SMTP server, e.g. "mail.provider.com" (None to disable mail)
     mail_smarthost = ""
 
-    # The return address, e.g "My Wiki <noreply@mywiki.org>"
-    mail_from = ""
+    # The return address, e.g u"Jürgen Wiki <noreply@mywiki.org>" [Unicode]
+    mail_from = u""
 
     # "user pwd" if you need to use SMTP AUTH
     mail_login = ""