changeset 4457:415cbfc3817b

merged moin/1.7
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sat, 13 Dec 2008 19:27:41 +0100
parents b77726872b1f (diff) 956f6f4aa936 (current diff)
children 1772b4d6ea11
files .hgtags MoinMoin/__init__.py MoinMoin/i18n/fr.MoinMoin.po MoinMoin/i18n/it.MoinMoin.po MoinMoin/i18n/lt.MoinMoin.po MoinMoin/i18n/pl.MoinMoin.po MoinMoin/i18n/sl.MoinMoin.po MoinMoin/i18n/sv.MoinMoin.po MoinMoin/i18n/zh.MoinMoin.po MoinMoin/script/migration/1070200.py MoinMoin/script/migration/1070300.py MoinMoin/script/migration/1080000.py MoinMoin/version.py docs/CHANGES moin.spec wiki/config/more_samples/ui_wikiconfig_snippet wiki/config/wikiconfig.py wiki/config/wikifarm/farmconfig.py wiki/data/meta wiki/server/moin.wsgi wiki/server/mointwisted.py wiki/underlay.tar wikiconfig.py
diffstat 1251 files changed, 107460 insertions(+), 77806 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Wed Dec 10 11:09:30 2008 +0100
+++ b/.hgtags	Sat Dec 13 19:27:41 2008 +0100
@@ -22,6 +22,12 @@
 9901ffff5280b81d0476e8d1e434ea70e3a6fbdc 1.7.0rc2
 01ef230fb671b0f0636328b04ade9b44c5548327 1.7.0rc3
 761c3a503be2b97d8e7beb902751dbb5e60f3127 1.7.0
+b1e192a3651a57aa451fefca06f5a849e1e4b422 SOC2008-END
 da9e664b3f518f0cab89f7ebf22b99ecac0eaaa1 1.7.1
 ae9bf455eec6a080dd6aafacdaf30fb881b1ca68 1.7.2
 ffdb44bf3b7391f660735fd509015819e8feaad2 1.7.3
+2907390f9d4630f5459506d3d3352c96f75e67b3 1.8.0beta1
+117a21659358defd880baaccf5c73e7b1a71ea1e 1.8.0beta2
+df1ba1ddf05061d6451797869c159b3c60319470 1.8.0beta3
+4186e90ead069aad4b739f278eb8599dc00ff6a4 1.8.0rc1
+7fee549f435d119801075f0d18fc57822f78f0eb 1.8.0
--- a/Makefile	Wed Dec 10 11:09:30 2008 +0100
+++ b/Makefile	Sat Dec 13 19:27:41 2008 +0100
@@ -3,7 +3,7 @@
 #
 
 # location for the wikiconfig.py we use for testing:
-export PYTHONPATH=$(PWD)/tests:$(PWD)
+export PYTHONPATH=$(PWD)
 
 testwiki := ./tests/wiki
 share := ./wiki
@@ -13,9 +13,9 @@
 
 install-docs:
 	-mkdir build
-	wget -U MoinMoin/Makefile -O build/INSTALL.html "http://master17.moinmo.in/MoinMoin/InstallDocs?action=print"
+	wget -U MoinMoin/Makefile -O build/INSTALL.html "http://master18.moinmo.in/MoinMoin/InstallDocs?action=print"
 	sed \
-		-e 's#href="/#href="http://master17.moinmo.in/#g' \
+		-e 's#href="/#href="http://master18.moinmo.in/#g' \
 		-e 's#http://[a-z\.]*/wiki/classic/#/wiki/classic/#g' \
 		-e 's#http://[a-z\.]*/wiki/modern/#/wiki/modern/#g' \
 		-e 's#http://[a-z\.]*/wiki/rightsidebar/#/wiki/rightsidebar/#g' \
@@ -25,9 +25,9 @@
         build/INSTALL.html >docs/INSTALL.html
 	-rm build/INSTALL.html
 
-	wget -U MoinMoin/Makefile -O build/UPDATE.html "http://master17.moinmo.in/HelpOnUpdating?action=print"
+	wget -U MoinMoin/Makefile -O build/UPDATE.html "http://master18.moinmo.in/HelpOnUpdating?action=print"
 	sed \
-		-e 's#href="/#href="http://master17.moinmo.in/#g' \
+		-e 's#href="/#href="http://master18.moinmo.in/#g' \
 		-e 's#http://[a-z\.]*/wiki/classic/#/wiki/classic/#g' \
 		-e 's#http://[a-z\.]*/wiki/modern/#/wiki/modern/#g' \
 		-e 's#http://[a-z\.]*/wiki/rightsidebar/#/wiki/rightsidebar/#g' \
@@ -39,7 +39,7 @@
 	-rmdir build
 
 interwiki:
-	wget -U MoinMoin/Makefile -O $(share)/data/intermap.txt "http://master17.moinmo.in/InterWikiMap?action=raw"
+	wget -U MoinMoin/Makefile -O $(share)/data/intermap.txt "http://master18.moinmo.in/InterWikiMap?action=raw"
 	chmod 664 $(share)/data/intermap.txt
 
 check-tabs:
@@ -47,21 +47,21 @@
 
 # Create documentation
 epydoc: patchlevel
-	@epydoc -o ../html-1.7 --name=MoinMoin --url=http://moinmo.in/ --graph=all --graph-font=Arial MoinMoin
+	@epydoc -o ../html-1.8 --name=MoinMoin --url=http://moinmo.in/ --graph=all --graph-font=Arial MoinMoin
 
 # Create new underlay directory from MoinMaster
 # Should be used only on TW machine
 underlay:
 	rm -rf $(share)/underlay
-	MoinMoin/script/moin.py --config-dir=/srv/moin/cfg/1.7 --wiki-url=master17.moinmo.in/ maint globaledit
-	MoinMoin/script/moin.py --config-dir=/srv/moin/cfg/1.7 --wiki-url=master17.moinmo.in/ maint reducewiki --target-dir=$(share)/underlay
+	MoinMoin/script/moin.py --config-dir=/srv/moin/cfg/1.8 --wiki-url=master18.moinmo.in/ maint globaledit
+	MoinMoin/script/moin.py --config-dir=/srv/moin/cfg/1.8 --wiki-url=master18.moinmo.in/ maint reducewiki --target-dir=$(share)/underlay
 	rm -rf $(share)/underlay/pages/InterWikiMap
 	rm -rf $(share)/underlay/pages/MoinPagesEditorGroup
 	cd $(share); rm -f underlay.tar; tar cf underlay.tar underlay
 
 pagepacks:
 	@python MoinMoin/_tests/maketestwiki.py
-	@MoinMoin/script/moin.py --config-dir=$(testwiki)/.. maint mkpagepacks
+	@MoinMoin/script/moin.py --config-dir=MoinMoin/_tests maint mkpagepacks
 	cd $(share) ; rm -rf underlay
 	cp -a $(testwiki)/underlay $(share)/
 	
--- a/MoinMoin/PageEditor.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/PageEditor.py	Sat Dec 13 19:27:41 2008 +0100
@@ -24,6 +24,7 @@
 from MoinMoin.widget import html
 from MoinMoin.widget.dialog import Status
 from MoinMoin.logfile import editlog, eventlog
+from MoinMoin.mail.sendmail import encodeSpamSafeEmail
 from MoinMoin.support.python_compatibility import set
 from MoinMoin.util import filesys, timefuncs, web
 from MoinMoin.events import PageDeletedEvent, PageRenamedEvent, PageCopiedEvent, PageRevertedEvent
@@ -483,7 +484,8 @@
 
         # QuickHelp originally by Georg Mischler <schorsch@lightingwiki.com>
         markup = self.pi['format'] or request.cfg.default_markup
-        quickhelp = request.cfg.editor_quickhelp.get(markup, "")
+        parser = wikiutil.searchAndImportPlugin(self.request.cfg, "parser", markup)
+        quickhelp = getattr(parser, 'quickhelp', None)
         if quickhelp:
             request.write(request.formatter.div(1, id="editor-help"))
             request.write(_(quickhelp, wiki=True))
@@ -763,6 +765,7 @@
         request = self.request
         now = self._get_local_timestamp()
         u = request.user
+        obfuscated_email_address = encodeSpamSafeEmail(u.email)
         signature = u.signature()
         variables = {
             'PAGE': self.page_name,
@@ -772,6 +775,7 @@
             'USERNAME': signature,
             'USER': "-- %s" % signature,
             'SIG': "-- %s <<DateTime(%s)>>" % (signature, now),
+            'EMAIL': "<<MailTo(%s)>>" % (obfuscated_email_address)
         }
 
         if u.valid and u.name:
--- a/MoinMoin/__init__.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/__init__.py	Sat Dec 13 19:27:41 2008 +0100
@@ -1,6 +1,6 @@
 # -*- coding: iso-8859-1 -*-
 """
-MoinMoin Version 1.7.3
+MoinMoin Version 1.8.0
 
 @copyright: 2000-2006 by Juergen Hermann <jh@web.de>,
             2002-2008 MoinMoin:ThomasWaldmann
--- a/MoinMoin/_tests/_test_template.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/_tests/_test_template.py	Sat Dec 13 19:27:41 2008 +0100
@@ -45,19 +45,17 @@
         ('Line break',  '<<BR>>',        '<br>'),
     )
 
+    from MoinMoin._tests import wikiconfig
+    class Config(wikiconfig.Config):
+        foo = 'bar'  # we want to have this non-default setting
+
     def setup_class(self):
         """ Stuff that should be run to init the state of this test class
-
-        Some test needs specific config values, or they will fail.
         """
-        self.config = self.TestConfig(defaults=['this option', 'that option'],
-                                      another_option='non default value')
 
     def teardown_class(self):
         """ Stuff that should run to clean up the state of this test class
-
         """
-        self.config.reset()
 
     def testFunction(self):
         """ module_tested: function should... """
--- a/MoinMoin/_tests/compat.py	Wed Dec 10 11:09:30 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-""" UnitTest compatiblity code, from the py lib. MIT licensed originally, copyright Holger Krekel. """
-
-import py
-from py.__.test.outcome import Failed, Passed
-
-
-class TestCaseUnit(py.test.collect.Function):
-    """ compatibility Unit executor for TestCase methods
-        honouring setUp and tearDown semantics.
-    """
-    def execute(self, session):
-        boundmethod = self.obj
-        instance = boundmethod.im_self
-        instance.setUp()
-        try:
-            boundmethod()
-        finally:
-            instance.tearDown()
-        return Passed()
-
-class TestCase(object):
-    """compatibility class of unittest's TestCase. """
-    Function = TestCaseUnit
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def fail(self, msg=None):
-        """ fail immediate with given message. """
-        raise Failed(msg=msg)
-
-    def assertRaises(self, excclass, func, *args, **kwargs):
-        py.test.raises(excclass, func, *args, **kwargs)
-    failUnlessRaises = assertRaises
-
-    # dynamically construct (redundant) methods
-    aliasmap = [
-        ('x',   'not x', 'assert_, failUnless'),
-        ('x',   'x',     'failIf'),
-        ('x,y', 'x!=y',  'failUnlessEqual,assertEqual, assertEquals'),
-        ('x,y', 'x==y',  'failIfEqual,assertNotEqual, assertNotEquals'),
-        ]
-    items = []
-    for sig, expr, names in aliasmap:
-        names = map(str.strip, names.split(','))
-        sigsubst = expr.replace('y', '%s').replace('x', '%s')
-        for name in names:
-            items.append("""
-                def %(name)s(self, %(sig)s, msg=""):
-                    __tracebackhide__ = True
-                    if %(expr)s:
-                        raise Failed(msg=msg + (%(sigsubst)r %% (%(sig)s)))
-            """ % locals() )
-
-    source = "".join(items)
-    exec py.code.Source(source).compile()
-
-__all__ = ['TestCase']
--- a/MoinMoin/_tests/test_PageEditor.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/_tests/test_PageEditor.py	Sat Dec 13 19:27:41 2008 +0100
@@ -73,11 +73,7 @@
 
     def testExtendedNamesEnabled(self):
         """ PageEditor: expand @USERNAME@ extended name - enabled """
-        try:
-            config = self.TestConfig()
-            assert self.expand() == u'[[%s]]' % self.name
-        finally:
-            del config
+        assert self.expand() == u'[[%s]]' % self.name
 
 
 class TestExpandMailto(TestExpandUserName):
@@ -210,6 +206,7 @@
         """
         simple test if it is possible to delete a Dict page after creation
         """
+        become_trusted(self.request)
         pagename = u'SomeDict'
         page = PageEditor(self.request, pagename, do_editor_backup=0)
         body = u"This is an example text"
--- a/MoinMoin/_tests/test_sourcecode.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/_tests/test_sourcecode.py	Sat Dec 13 19:27:41 2008 +0100
@@ -32,6 +32,8 @@
 
 try:
     import xattr
+    if not hasattr(xattr, "xattr"): # there seem to be multiple modules with that name
+        raise ImportError
     def mark_file_ok(path, mtime):
         x = xattr.xattr(path)
         try:
--- a/MoinMoin/_tests/test_user.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/_tests/test_user.py	Sat Dec 13 19:27:41 2008 +0100
@@ -19,17 +19,17 @@
     def testAscii(self):
         """user: encode ascii password"""
         # u'MoinMoin' and 'MoinMoin' should be encoded to same result
-        expected = "{SHA}X+lk6KR7JuJEH43YnmettCwICdU="
+        expected = "{SSHA}xkDIIx1I7A4gC98Vt/+UelIkTDYxMjM0NQ=="
 
-        result = user.encodePassword("MoinMoin")
+        result = user.encodePassword("MoinMoin", salt='12345')
         assert result == expected
-        result = user.encodePassword(u"MoinMoin")
+        result = user.encodePassword(u"MoinMoin", salt='12345')
         assert result == expected
 
     def testUnicode(self):
         """ user: encode unicode password """
-        result = user.encodePassword(u'סיסמה סודית בהחלט') # Hebrew
-        expected = "{SHA}GvvkgYzv5MoF9Ljivv2oc81FmkE="
+        result = user.encodePassword(u'סיסמה סודית בהחלט', salt='12345') # Hebrew
+        expected = "{SSHA}YiwfeVWdVW9luqyVn8t2JivlzmUxMjM0NQ=="
         assert result == expected
 
 
@@ -99,49 +99,12 @@
         theUser = user.User(self.request, name=name, password=password)
         assert theUser.valid
 
-    def testOldNonAsciiPassword(self):
-        """ user: login with non-ascii password in pre 1.3 user file
-
-        When trying to login with an old non-ascii password in the user
-        file, utf-8 encoded password will not match. In this case, try
-        all other encoding available on pre 1.3 before failing.
-        """
-        # Create test user
-        # Use iso charset to create user with old enc_password, as if
-        # the user file was migrated from pre 1.3 wiki.
-        name = u'__Jürgen Herman__'
-        password = name
-        self.createUser(name, password, charset='iso-8859-1')
-
-        # Try to "login"
-        theUser = user.User(self.request, name=name, password=password)
-        assert theUser.valid
-
-    def testReplaceOldNonAsciiPassword(self):
-        """ user: login replace old non-ascii password in pre 1.3 user file
-
-        When trying to login with an old non-ascii password in the user
-        file, the password hash should be replaced with new utf-8 hash.
-        """
-        # Create test user
-        # Use iso charset to create user with old enc_password, as if
-        # the user file was migrated from pre 1.3 wiki.
-        name = u'__Jürgen Herman__'
-        password = name
-        self.createUser(name, password, charset='iso-8859-1')
-        # Login - this should replace the old password in the user file
-        theUser = user.User(self.request, name=name, password=password)
-        # Login again - the password should be new unicode password
-        expected = user.encodePassword(password)
-        theUser = user.User(self.request, name=name, password=password)
-        assert theUser.enc_password == expected
-
     def testSubscriptionSubscribedPage(self):
         """ user: tests isSubscribedTo  """
         pagename = u'HelpMiscellaneous'
         name = u'__Jürgen Herman__'
         password = name
-        self.createUser(name, password, charset='iso-8859-1')
+        self.createUser(name, password)
         # Login - this should replace the old password in the user file
         theUser = user.User(self.request, name=name, password=password)
         theUser.subscribe(pagename)
@@ -153,7 +116,7 @@
         testPagename = u'HelpMiscellaneous/FrequentlyAskedQuestions'
         name = u'__Jürgen Herman__'
         password = name
-        self.createUser(name, password, charset='iso-8859-1')
+        self.createUser(name, password)
         # Login - this should replace the old password in the user file
         theUser = user.User(self.request, name=name, password=password)
         theUser.subscribe(pagename)
@@ -164,8 +127,6 @@
         if the old username is removed from the cache name2id
         """
         # Create test user
-        # Use iso charset to create user with old enc_password, as if
-        # the user file was migrated from pre 1.3 wiki.
         name = u'__Some Name__'
         password = name
         self.createUser(name, password)
@@ -178,20 +139,28 @@
 
         assert not theUser.exists()
 
+    def test_upgrade_password_to_salted(self):
+        """
+        Create user with {SHA} password and check that logging in
+        upgrades to {SSHA}.
+        """
+        name = u'/no such user/'
+        password = '{SHA}jLIjfQZ5yojbZGTqxg2pY0VROWQ=' # 12345
+        self.createUser(name, password, True)
+        theuser = user.User(self.request, name=name, password='12345')
+        assert theuser.enc_password[:6] == '{SSHA}'
+
     # Helpers ---------------------------------------------------------
 
-    def createUser(self, name, password, charset='utf-8'):
+    def createUser(self, name, password, pwencoded=False):
         """ helper to create test user
-
-        charset is used to create user with pre 1.3 password hash
         """
-        # Hack self.request form to contain the password
-        self.request.form['password'] = [password]
-
         # Create user
         self.user = user.User(self.request)
         self.user.name = name
-        self.user.enc_password = user.encodePassword(password, charset=charset)
+        if not pwencoded:
+            password = user.encodePassword(password)
+        self.user.enc_password = password
 
         # Validate that we are not modifying existing user data file!
         if self.user.exists():
@@ -209,19 +178,9 @@
 
 class TestGroupName(object):
 
-    def setUp(self):
-        self.config = self.TestConfig(page_group_regex=r'.+Group')
-
-    def tearDown(self):
-        del self.config
-
-    import re
-    group = re.compile(r'.+Group', re.UNICODE)
-
     def testGroupNames(self):
         """ user: isValidName: reject group names """
         test = u'AdminGroup'
-        assert self.group.search(test)
         assert not user.isValidName(self.request, test)
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/_tests/wikiconfig.py	Sat Dec 13 19:27:41 2008 +0100
@@ -0,0 +1,33 @@
+# -*- coding: iso-8859-1 -*-
+"""
+MoinMoin - test wiki configuration
+
+Do not change any values without good reason.
+
+We mostly want to have default values here, except for stuff that doesn't
+work without setting them (like data_dir and underlay_dir).
+
+@copyright: 2000-2004 by Juergen Hermann <jh@web.de>
+@license: GNU GPL, see COPYING for details.
+"""
+
+import os
+
+from MoinMoin.config.multiconfig import DefaultConfig
+
+
+class Config(DefaultConfig):
+    sitename = u'Developer Test Wiki'
+    logo_string = sitename
+
+    _base_dir = os.path.join(os.path.dirname(__file__), '../../tests/wiki')
+    data_dir = os.path.join(_base_dir, "data")
+    data_underlay_dir = os.path.join(_base_dir, "underlay")
+
+    #show_hosts = 1
+
+    #secrets = 'some not secret string just to make tests happy'
+
+    # used to check if it is really a wiki we may modify
+    is_test_wiki = True
+
--- a/MoinMoin/action/AttachFile.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/action/AttachFile.py	Sat Dec 13 19:27:41 2008 +0100
@@ -1107,7 +1107,7 @@
 
         browser = DataBrowserWidget(request)
         browser.setData(data)
-        return browser.toHTML()
+        return browser.render(method="GET")
 
     return ''
 
--- a/MoinMoin/action/Despam.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/action/Despam.py	Sat Dec 13 19:27:41 2008 +0100
@@ -71,7 +71,7 @@
 
     table = DataBrowserWidget(request)
     table.setData(dataset)
-    table.render()
+    return table.render(method="GET")
 
 class tmp:
     pass
@@ -197,7 +197,7 @@
     elif editor:
         show_pages(request, pagename, editor, timestamp)
     else:
-        show_editors(request, pagename, timestamp)
+        request.write(show_editors(request, pagename, timestamp))
 
     # End content and send footer
     request.write(request.formatter.endContent())
--- a/MoinMoin/action/SyncPages.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/action/SyncPages.py	Sat Dec 13 19:27:41 2008 +0100
@@ -46,8 +46,12 @@
         self.status = []
         self.rollback = set()
 
-    def log_status(self, level, message="", substitutions=(), raw_suffix=""):
+    def log_status(self, level, message=u"", substitutions=(), raw_suffix=u""):
         """ Appends the message with a given importance level to the internal log. """
+        if isinstance(message, str):
+            message = message.decode("utf-8")
+        if isinstance(raw_suffix, str):
+            raw_suffix = raw_suffix.decode("utf-8")
         self.status.append((level, message, substitutions, raw_suffix))
 
     def register_rollback(self, func):
@@ -74,17 +78,18 @@
         table = []
 
         for line in self.status:
-            if line[1]:
-                if line[2]:
-                    macro_args = [line[1]] + list(line[2])
+            level, message, substitutions, raw_suffix = line
+            if message:
+                if substitutions:
+                    macro_args = [message] + list(substitutions)
                     message = u"<<GetText2(|%s)>>" % (packLine(macro_args), )
                 else:
-                    message = u"<<GetText(%s)>>" % (line[1], )
+                    message = u"<<GetText(%s)>>" % (message, )
             else:
                 message = u""
-            table.append(table_line % {"smiley": line[0][1],
+            table.append(table_line % {"smiley": level[1],
                                        "message": message,
-                                       "raw_suffix": line[3].replace("\n", "<<BR>>")})
+                                       "raw_suffix": raw_suffix.replace("\n", "<<BR>>")})
 
         return "\n".join(table)
 
--- a/MoinMoin/action/backup.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/action/backup.py	Sat Dec 13 19:27:41 2008 +0100
@@ -1,12 +1,18 @@
 # -*- coding: iso-8859-1 -*-
 """
-    MoinMoin - make or restore a full backup of the wiki
+    MoinMoin - download a backup via http.
 
-    Triggering backup action will check if you are authorized to do
-    a backup and if yes, just send a
-    <siteid>-<date>--<time>.tar.<format> to you.
+    Triggering backup action will check if you are authorized to do a backup
+    and if yes, just send a <siteid>-<date>--<time>.tar.<format> to you.
+    What exactly is contained in your backup depends on your wiki's
+    configuration - please make sure you have everything you need BEFORE you
+    really need it.
 
-    @copyright: 2005 by MoinMoin:ThomasWaldmann
+    Note: there is no restore support, you need somebody having access to your
+          wiki installation via the server's file system, knowing about tar
+          and restoring your data CAREFULLY (AKA "the server admin").
+
+    @copyright: 2005-2008 by MoinMoin:ThomasWaldmann
     @license: GNU GPL, see COPYING for details.
 """
 
@@ -15,81 +21,51 @@
 from MoinMoin import wikiutil
 from MoinMoin.support import tarfile
 
-def addFiles(path, tar, exclude):
+
+def addFiles(path, tar, exclude_func):
     """ Add files in path to tar """
     for root, dirs, files in os.walk(path):
         files.sort() # sorted page revs may compress better
         for name in files:
             path = os.path.join(root, name)
-            if exclude.search(path):
+            if exclude_func(path):
                 continue
             tar.add(path)
 
+
 def sendBackup(request):
     """ Send compressed tar file """
     dateStamp = time.strftime("%Y-%m-%d--%H-%M-%S-UTC", time.gmtime())
     filename = "%s-%s.tar.%s" % (request.cfg.siteid, dateStamp, request.cfg.backup_compression)
     request.emit_http_headers([
-        "Content-Type: application/octet-stream",
-        "Content-Disposition: inline; filename=\"%s\"" % filename, ])
+        'Content-Type: application/octet-stream',
+        'Content-Disposition: inline; filename="%s"' % filename, ])
 
     tar = tarfile.open(fileobj=request, mode="w|%s" % request.cfg.backup_compression)
     # allow GNU tar's longer file/pathnames
     tar.posix = False
-    exclude = re.compile("|".join(request.cfg.backup_exclude))
     for path in request.cfg.backup_include:
-        addFiles(path, tar, exclude)
+        addFiles(path, tar, request.cfg.backup_exclude)
     tar.close()
 
-def restoreBackup(request, pagename):
-    _ = request.getText
-    path = request.cfg.backup_storage_dir
-    filename = "%s.tar.%s" % (request.cfg.siteid, request.cfg.backup_compression)
-    filename = os.path.join(path, filename)
-    targetdir = request.cfg.backup_restore_target_dir
-    try:
-        tar = tarfile.open(fileobj=file(filename), mode="r|%s" % request.cfg.backup_compression)
-        # allow GNU tar's longer file/pathnames
-        tar.posix = False
-        files = []
-        dirs = []
-        for m in tar:
-            if m.isdir():
-                dirs.append("%s %s %s" % (m.name, m.size, m.mtime))
-            else:
-                files.append("%s %s %s" % (m.name, m.size, m.mtime))
-            tar.extract(m, targetdir)
-        tar.close()
-        #files = "<br>".join(files)
-        filecount = len(files)
-        dircount = len(dirs)
-        return sendMsg(request, pagename,
-            msg=_('Restored Backup: %(filename)s to target dir: %(targetdir)s.\nFiles: %(filecount)d, Directories: %(dircount)d') %
-                locals(), msgtype="info")
-    except:
-        return sendMsg(request, pagename, msg=_("Restoring backup: %(filename)s to target dir: %(targetdir)s failed.") % locals(), msgtype="info")
 
 def sendBackupForm(request, pagename):
     _ = request.getText
     request.emit_http_headers()
     request.setContentLanguage(request.lang)
-    title = _('Wiki Backup / Restore')
+    title = _('Wiki Backup')
     request.theme.send_title(title, form=request.form, pagename=pagename)
     request.write(request.formatter.startContent("content"))
 
-    request.write(_("""Some hints:
- * To restore a backup:
-  * Restoring a backup will overwrite existing data, so be careful.
-  * Rename it to <siteid>.tar.<compression> (remove the --date--time--UTC stuff).
-  * Put the backup file into the backup_storage_dir (use scp, ftp, ...).
-  * Hit the <<GetText(Restore)>> button below.
+    request.write(_("""= Downloading a backup =
 
- * To make a backup, just hit the <<GetText(Backup)>> button and save the file
-   you get to a secure place.
+Please note:
+ * Store backups in a safe and secure place - they contain sensitive information.
+ * Make sure your wiki configuration backup_* values are correct and complete.
+ * Make sure the backup file you get contains everything you need in case of problems.
+ * Make sure it is downloaded without problems.
 
-Please make sure your wiki configuration backup_* values are correct and complete.
-
-""", wiki=True))
+To get a backup, just click here:""", wiki=True))
 
     request.write("""
 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
@@ -97,34 +73,30 @@
 <input type="hidden" name="do" value="backup">
 <input type="submit" value="%(backup_button)s">
 </form>
-
-<form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
-<input type="hidden" name="action" value="backup">
-<input type="hidden" name="do" value="restore">
-<input type="submit" value="%(restore_button)s">
-</form>
 """ % {
     'baseurl': request.getScriptname(),
     'pagename': wikiutil.quoteWikinameURL(pagename),
     'backup_button': _('Backup'),
-    'restore_button': _('Restore'),
 })
 
     request.write(request.formatter.endContent())
     request.theme.send_footer(pagename)
     request.theme.send_closing_html()
 
+
 def sendMsg(request, pagename, msg, msgtype):
     from MoinMoin import Page
     request.theme.add_msg(msg, msgtype)
     return Page.Page(request, pagename).send_page()
 
+
 def backupAllowed(request):
     """ Return True if backup is allowed """
     action = __name__.split('.')[-1]
     user = request.user
     return user.valid and user.name in request.cfg.backup_users
 
+
 def execute(pagename, request):
     _ = request.getText
     if not backupAllowed(request):
@@ -134,10 +106,9 @@
     dowhat = request.form.get('do', [None])[0]
     if dowhat == 'backup':
         sendBackup(request)
-    elif dowhat == 'restore':
-        restoreBackup(request, pagename)
     elif dowhat is None:
         sendBackupForm(request, pagename)
     else:
         return sendMsg(request, pagename,
                        msg=_('Unknown backup subaction: %s.') % dowhat, msgtype="error")
+
--- a/MoinMoin/action/cache.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/action/cache.py	Sat Dec 13 19:27:41 2008 +0100
@@ -27,8 +27,6 @@
     @license: GNU GPL, see COPYING for details.
 """
 
-import hmac, sha
-
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
@@ -39,6 +37,7 @@
 from MoinMoin import config, caching
 from MoinMoin.util import filesys
 from MoinMoin.action import AttachFile
+from MoinMoin.support.python_compatibility import hmac_new
 
 action_name = __name__.split('.')[-1]
 
@@ -87,7 +86,7 @@
     @param secret: secret for hMAC calculation (default: use secret from cfg)
     """
     if secret is None:
-        secret = request.cfg.secrets
+        secret = request.cfg.secrets['action/cache']
     if content:
         hmac_data = content
     elif itemname is not None and attachname is not None:
@@ -98,7 +97,7 @@
         raise AssertionError('cache_key called with unsupported parameters')
 
     hmac_data = hmac_data.encode('utf-8')
-    key = hmac.new(secret, hmac_data, sha).hexdigest()
+    key = hmac_new(secret, hmac_data).hexdigest()
     return key
 
 
--- a/MoinMoin/action/info.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/action/info.py	Sat Dec 13 19:27:41 2008 +0100
@@ -32,8 +32,8 @@
                       f.text(_("Page size: %d") % page.size()),
                       f.paragraph(0))
 
-        import sha
-        digest = sha.new(page.get_raw_body().encode(config.charset)).hexdigest().upper()
+        from MoinMoin.support.python_compatibility import hash_new
+        digest = hash_new('sha1', page.get_raw_body().encode(config.charset)).hexdigest().upper()
         request.write(f.paragraph(1),
                       f.rawHTML('%(label)s <tt>%(value)s</tt>' % {
                           'label': _("SHA digest of this page's content is:"),
@@ -176,7 +176,7 @@
 
         div = html.DIV(id="page-history")
         div.append(html.INPUT(type="hidden", name="action", value="diff"))
-        div.append(history_table.toHTML())
+        div.append(history_table.render(method="GET"))
 
         form = html.FORM(method="GET", action="")
         form.append(div)
--- a/MoinMoin/action/newaccount.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/action/newaccount.py	Sat Dec 13 19:27:41 2008 +0100
@@ -56,7 +56,7 @@
 
     pw_checker = request.cfg.password_checker
     if pw_checker:
-        pw_error = pw_checker(theuser.name, password)
+        pw_error = pw_checker(request, theuser.name, password)
         if pw_error:
             return _("Password not acceptable: %s") % pw_error
 
@@ -83,9 +83,6 @@
     # save data
     theuser.save()
 
-    if form.has_key('create_and_mail'):
-        theuser.mailAccountData()
-
     result = _("User account created! You can use this account to login now...")
     if _debug:
         result = result + util.dumpFormData(form)
@@ -148,13 +145,8 @@
     row.append(html.TD())
     td = html.TD()
     row.append(td)
-    td.append(html.INPUT(type="submit", name="create_only",
+    td.append(html.INPUT(type="submit", name="create",
                          value=_('Create Profile')))
-    if request.cfg.mail_enabled:
-        td.append(html.Text(' '))
-        td.append(html.INPUT(type="submit", name="create_and_mail",
-                             value="%s + %s" % (_('Create Profile'),
-                                                _('Email'))))
 
     return unicode(ret)
 
@@ -174,7 +166,7 @@
     _ = request.getText
     form = request.form
 
-    submitted = form.has_key('create_only') or form.has_key('create_and_mail')
+    submitted = form.has_key('create')
 
     if submitted: # user pressed create button
         request.theme.add_msg(_create_user(request), "dialog")
--- a/MoinMoin/action/quickunlink.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/action/quickunlink.py	Sat Dec 13 19:27:41 2008 +0100
@@ -22,5 +22,7 @@
             msg = _('Your quicklink to this page could not be removed.')
     else:
         msg = _('You need to have a quicklink to this page to remove it.')
+    if msg:
+        request.theme.add_msg(msg)
+    Page(request, pagename).send_page()
 
-    Page(request, pagename).send_page(msg=msg)
--- a/MoinMoin/action/recoverpass.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/action/recoverpass.py	Sat Dec 13 19:27:41 2008 +0100
@@ -173,7 +173,7 @@
             pw_checker = request.cfg.password_checker
             pw_error = None
             if pw_checker:
-                pw_error = pw_checker(name, newpass)
+                pw_error = pw_checker(request, name, newpass)
                 if pw_error:
                     msg = _("Password not acceptable: %s") % pw_error
             if not pw_error:
--- a/MoinMoin/action/unsubscribe.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/action/unsubscribe.py	Sat Dec 13 19:27:41 2008 +0100
@@ -28,6 +28,7 @@
     else:
         # The user is not subscribed
         msg = _('You need to be subscribed to unsubscribe.')
+    if msg:
+        request.theme.add_msg(msg)
+    Page(request, pagename).send_page()
 
-    Page(request, pagename).send_page(msg=msg)
-
--- a/MoinMoin/auth/_tests/test_auth.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/auth/_tests/test_auth.py	Sat Dec 13 19:27:41 2008 +0100
@@ -6,13 +6,17 @@
     @license: GNU GPL, see COPYING for details.
 """
 
+import py.test
+py.test.skip("broken due to test Config refactoring, fix later")
+
 import StringIO, urllib
 
 from MoinMoin.server.server_wsgi import WsgiConfig
 from MoinMoin.request import request_wsgi
+from MoinMoin._tests import wikiconfig
 
 
-class TestAuth:
+class AuthTest:
     """ test misc. auth methods """
     PAGES = ['FrontPage', 'MoinMoin', 'HelpContents', 'WikiSandBox', ] # must all exist!
 
@@ -56,6 +60,8 @@
         request.user = save_user
         return request # request.status, request.headers, request.output()
 
+
+class TestNoAuth(AuthTest):
     def testNoAuth(self):
         """ run a simple request, no auth, just check if it succeeds """
         environ = self.setup_env()
@@ -87,9 +93,12 @@
         output = request.output()
         assert '</html>' in output
 
+class TestAnonSession(AuthTest):
+    class Config(wikiconfig.Config):
+        anonymous_session_lifetime = 1
+
     def testAnonSession(self):
         """ run some requests, no auth, check if anon sessions work """
-        self.config = self.TestConfig(anonymous_session_lifetime=1)
         cookie = ''
         trail_expected = []
         first = True
@@ -146,11 +155,14 @@
             trail = request.session['trail']
             assert trail == trail_expected
 
+class TestHttpAuthSession(AuthTest):
+    class Config(wikiconfig.Config):
+        from MoinMoin.auth.http import HTTPAuth
+        auth = [HTTPAuth(autocreate=True)]
+
     def testHttpAuthSession(self):
         """ run some requests with http auth, check whether session works """
-        from MoinMoin.auth.http import HTTPAuth
         username = u'HttpAuthTestUser'
-        self.config = self.TestConfig(auth=[HTTPAuth()], user_autocreate=True)
         cookie = ''
         trail_expected = []
         first = True
@@ -206,13 +218,16 @@
             trail = request.session['trail']
             assert trail == trail_expected
 
+class TestMoinAuthSession(AuthTest):
+    class Config(wikiconfig.Config):
+        from MoinMoin.auth import MoinAuth
+        auth = [MoinAuth()]
+
     def testMoinAuthSession(self):
         """ run some requests with MoinAuth, check whether session works """
-        from MoinMoin.auth import MoinAuth
         from MoinMoin.user import User
-        self.config = self.TestConfig(auth=[MoinAuth()])
         username = u'MoinAuthTestUser'
-        password = u'secret'
+        password = u'ßecretß'
         User(self.request, name=username, password=password).save() # create user
         trail_expected = []
         first = True
--- a/MoinMoin/auth/_tests/test_ldap_login.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/auth/_tests/test_ldap_login.py	Sat Dec 13 19:27:41 2008 +0100
@@ -7,10 +7,11 @@
 """
 
 import py.test
+py.test.skip("Broken due to test Config refactoring")
 
 from MoinMoin._tests.ldap_testbase import LDAPTstBase, LdapEnvironment, check_environ, SLAPD_EXECUTABLE
 from MoinMoin._tests.ldap_testdata import *
-from MoinMoin._tests import nuke_user
+from MoinMoin._tests import nuke_user, wikiconfig
 
 # first check if we have python 2.4, python-ldap and slapd:
 msg = check_environ()
@@ -20,7 +21,7 @@
 
 import ldap
 
-class TestSimpleLdap(LDAPTstBase):
+class TestLDAPServer(LDAPTstBase):
     basedn = BASEDN
     rootdn = ROOTDN
     rootpw = ROOTPW
@@ -39,14 +40,23 @@
         assert 'usera' in uids
         assert 'userb' in uids
 
+class TestMoinLDAPLogin(LDAPTstBase):
+    basedn = BASEDN
+    rootdn = ROOTDN
+    rootpw = ROOTPW
+    slapd_config = SLAPD_CONFIG
+    ldif_content = LDIF_CONTENT
+
+    class Config(wikiconfig.Config):
+        from MoinMoin.auth.ldap_login import LDAPAuth
+        server_uri = self.ldap_env.slapd.url # XXX no self
+        base_dn = self.ldap_env.basedn
+        ldap_auth1 = LDAPAuth(server_uri=server_uri, base_dn=base_dn, autocreate=True)
+        auth = [ldap_auth1, ]
+
     def testMoinLDAPLogin(self):
         """ Just try accessing the LDAP server and see if usera and userb are in LDAP. """
-        server_uri = self.ldap_env.slapd.url
-        base_dn = self.ldap_env.basedn
 
-        from MoinMoin.auth.ldap_login import LDAPAuth
-        ldap_auth1 = LDAPAuth(server_uri=server_uri, base_dn=base_dn)
-        self.config = self.TestConfig(auth=[ldap_auth1, ], user_autocreate=True)
         handle_auth = self.request.handle_auth
 
         # tests that must not authenticate:
@@ -79,6 +89,15 @@
     slapd_config = SLAPD_CONFIG
     ldif_content = LDIF_CONTENT
 
+    class Config(wikiconfig.Config):
+        from MoinMoin.auth.ldap_login import LDAPAuth
+        from MoinMoin.auth import MoinAuth
+        server_uri = self.ldap_env.slapd.url # XXX no self
+        base_dn = self.ldap_env.basedn
+        ldap_auth = LDAPAuth(server_uri=server_uri, base_dn=base_dn, autocreate=True)
+        moin_auth = MoinAuth()
+        auth = [ldap_auth, moin_auth]
+
     def teardown_class(self):
         """ Stop slapd, remove LDAP server environment """
         #self.ldap_env.stop_slapd()  # it is already stopped
@@ -89,14 +108,6 @@
             a default password there), then try logging in via moin login using
             that default password or an empty password.
         """
-        server_uri = self.ldap_env.slapd.url
-        base_dn = self.ldap_env.basedn
-
-        from MoinMoin.auth.ldap_login import LDAPAuth
-        ldap_auth = LDAPAuth(server_uri=server_uri, base_dn=base_dn)
-        from MoinMoin.auth import MoinAuth
-        moin_auth = MoinAuth()
-        self.config = self.TestConfig(auth=[ldap_auth, moin_auth], user_autocreate=True)
 
         nuke_user(self.request, u'usera')
 
@@ -171,6 +182,18 @@
     slapd_config = SLAPD_CONFIG
     ldif_content = LDIF_CONTENT
 
+    class Config(wikiconfig.Config):
+        from MoinMoin.auth.ldap_login import LDAPAuth
+        authlist = []
+        for ldap_env in self.ldap_envs: # XXX no self
+            server_uri = ldap_env.slapd.url
+            base_dn = ldap_env.basedn
+            ldap_auth = LDAPAuth(server_uri=server_uri, base_dn=base_dn,
+                                 autocreate=True,
+                                 timeout=1) # short timeout, faster testing
+            authlist.append(ldap_auth)
+        auth = authlist
+
     def setup_class(self):
         """ Create LDAP servers environment, start slapds """
         self.ldap_envs = []
@@ -195,16 +218,6 @@
 
     def testMoinLDAPFailOver(self):
         """ Try if it does a failover to a secondary LDAP, if the primary fails. """
-        from MoinMoin.auth.ldap_login import LDAPAuth
-        authlist = []
-        for ldap_env in self.ldap_envs:
-            server_uri = ldap_env.slapd.url
-            base_dn = ldap_env.basedn
-            ldap_auth = LDAPAuth(server_uri=server_uri, base_dn=base_dn,
-                                 timeout=1) # short timeout, faster testing
-            authlist.append(ldap_auth)
-
-        self.config = self.TestConfig(auth=authlist, user_autocreate=True)
         handle_auth = self.request.handle_auth
 
         # authenticate user (with primary slapd):
--- a/MoinMoin/auth/http.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/auth/http.py	Sat Dec 13 19:27:41 2008 +0100
@@ -22,6 +22,10 @@
     """ authenticate via http basic/digest/ntlm auth """
     name = 'http'
 
+    def __init__(self, autocreate=False):
+        self.autocreate = autocreate
+        BaseAuth.__init__(self)
+
     def request(self, request, user_obj, **kw):
         u = None
         _ = request.getText
@@ -72,7 +76,7 @@
                 u = user.User(request, auth_username=username,
                               auth_method=self.name, auth_attribs=('name', 'password'))
 
-        if u:
+        if u and self.autocreate:
             u.create_or_update()
         if u and u.valid:
             return u, True # True to get other methods called, too
--- a/MoinMoin/auth/interwiki.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/auth/interwiki.py	Sat Dec 13 19:27:41 2008 +0100
@@ -20,9 +20,10 @@
     logout_possible = True
     login_inputs = ['username', 'password']
 
-    def __init__(self, trusted_wikis):
+    def __init__(self, trusted_wikis, autocreate=False):
         BaseAuth.__init__(self)
         self.trusted_wikis = trusted_wikis
+        self.autocreate = autocreate
 
     def login(self, request, user_obj, **kw):
         username = kw.get('username')
@@ -68,7 +69,8 @@
             if key not in request.cfg.user_transient_fields:
                 setattr(u, key, value)
         u.valid = True
-        u.create_or_update(True)
+        if self.autocreate:
+            u.create_or_update(True)
         logging.debug("successful interwiki auth for %r" % name)
         return ContinueLogin(u)
 
--- a/MoinMoin/auth/ldap_login.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/auth/ldap_login.py	Sat Dec 13 19:27:41 2008 +0100
@@ -81,6 +81,7 @@
         tls_keyfile='',
         tls_require_cert=0, # 0 == ldap.OPT_X_TLS_NEVER (needed for self-signed certs)
         bind_once=False, # set to True to only do one bind - useful if configured to bind as the user on the first attempt
+        autocreate=False, # set to True if you want to autocreate user profiles
         ):
         self.server_uri = server_uri
         self.bind_dn = bind_dn
@@ -107,7 +108,7 @@
         self.tls_require_cert = tls_require_cert
 
         self.bind_once = bind_once
-
+        self.autocreate = autocreate
 
     def login(self, request, user_obj, **kw):
         username = kw.get('username')
@@ -231,7 +232,7 @@
                 logging.debug("invalid credentials (wrong password?) for dn %r (username: %r)" % (dn, username))
                 return CancelLogin(_("Invalid username or password."))
 
-            if u:
+            if u and self.autocreate:
                 u.create_or_update(True)
             return ContinueLogin(u)
 
--- a/MoinMoin/auth/openidrp.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/auth/openidrp.py	Sat Dec 13 19:27:41 2008 +0100
@@ -25,12 +25,14 @@
     def __init__(self, modify_request=None,
                        update_user=None,
                        create_user=None,
-                       forced_service=None):
+                       forced_service=None,
+                       idselector_com=None):
         BaseAuth.__init__(self)
         self._modify_request = modify_request or (lambda x: None)
         self._update_user = update_user or (lambda i, u: None)
         self._create_user = create_user or (lambda i, u: None)
         self._forced_service = forced_service
+        self._idselector_com = idselector_com
         if forced_service:
             self.login_inputs = ['special_no_input']
 
@@ -294,5 +296,9 @@
 
     def login_hint(self, request):
         _ = request.getText
-        return _("If you do not have an account yet, you can still log in "
+        msg = u''
+        if self._idselector_com:
+            msg = self._idselector_com
+        msg += _("If you do not have an account yet, you can still log in "
                  "with your OpenID and create one during login.")
+        return msg
--- a/MoinMoin/auth/php_session.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/auth/php_session.py	Sat Dec 13 19:27:41 2008 +0100
@@ -21,7 +21,7 @@
 
     name = 'php_session'
 
-    def __init__(self, apps=['egw'], s_path="/tmp", s_prefix="sess_"):
+    def __init__(self, apps=['egw'], s_path="/tmp", s_prefix="sess_", autocreate=False):
         """ @param apps: A list of the enabled applications. See above for
             possible keys.
             @param s_path: The path where the PHP sessions are stored.
@@ -31,6 +31,7 @@
         self.s_path = s_path
         self.s_prefix = s_prefix
         self.apps = apps
+        self.autocreate = autocreate
 
     def request(self, request, user_obj, **kw):
         def handle_egroupware(session):
@@ -72,7 +73,7 @@
                 u.email = email
                 changed = True
 
-            if u:
+            if u and self.autocreate:
                 u.create_or_update(changed)
             if u and u.valid:
                 return u, True # True to get other methods called, too
--- a/MoinMoin/auth/sslclientcert.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/auth/sslclientcert.py	Sat Dec 13 19:27:41 2008 +0100
@@ -21,13 +21,15 @@
 
     def __init__(self, authorities=None,
                  email_key=True, name_key=True,
-                 use_email=False, use_name=False):
+                 use_email=False, use_name=False,
+                 autocreate=False):
         self.use_email = use_email
         self.authorities = authorities
         self.email_key = email_key
         self.name_key = name_key
         self.use_email = use_email
         self.use_name = use_name
+        self.autocreate = autocreate
         BaseAuth.__init__(self)
 
     def request(self, request, user_obj, **kw):
@@ -87,7 +89,7 @@
             elif user_obj and user_obj.auth_method == self.name:
                 user_obj.valid = False
                 return user_obj, False
-        if u:
+        if u and self.autocreate:
             u.create_or_update(changed)
         if u and u.valid:
             return u, True
--- a/MoinMoin/caching.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/caching.py	Sat Dec 13 19:27:41 2008 +0100
@@ -25,12 +25,7 @@
 
 
 def get_arena_dir(request, arena, scope):
-    if scope == 'page_or_wiki': # XXX DEPRECATED, remove later
-        if isinstance(arena, str):
-            return os.path.join(request.cfg.cache_dir, request.cfg.siteid, arena)
-        else: # arena is in fact a page object
-            return arena.getPagePath('cache', check_create=1)
-    elif scope == 'item': # arena is a Page instance
+    if scope == 'item': # arena is a Page instance
         # we could move cache out of the page directory and store it to cache_dir
         return arena.getPagePath('cache', check_create=1)
     elif scope == 'wiki':
@@ -49,7 +44,7 @@
 
 
 class CacheEntry:
-    def __init__(self, request, arena, key, scope='page_or_wiki', do_locking=True,
+    def __init__(self, request, arena, key, scope='wiki', do_locking=True,
                  use_pickle=False, use_encode=False):
         """ init a cache entry
             @param request: the request object
--- a/MoinMoin/config/_tests/test_configs.py	Wed Dec 10 11:09:30 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-from MoinMoin.config.multiconfig import DefaultConfig
-
-class NoUnderlay(DefaultConfig):
-    data_underlay_dir = None
-
-_tests = [NoUnderlay, ]
-
-class TestConfigs:
-    def testConfigs(self):
-        for cls in _tests:
-            cls.data_dir = self.request.cfg.data_dir
-            # quite a bad hack to make _importPlugin succeed
-            cls('MoinMoin')
--- a/MoinMoin/config/_tests/test_multiconfig.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/config/_tests/test_multiconfig.py	Sat Dec 13 19:27:41 2008 +0100
@@ -32,7 +32,7 @@
             py.test.skip("password_checker is disabled in the configuration, not testing it")
         else:
             for pw, result in self.tests_builtin:
-                pw_error = pw_checker(self.username, pw)
+                pw_error = pw_checker(self.request, self.username, pw)
                 print "%r: %s" % (pw, pw_error)
                 assert result == (pw_error is None)
 
--- a/MoinMoin/config/multiconfig.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/config/multiconfig.py	Sat Dec 13 19:27:41 2008 +0100
@@ -4,6 +4,7 @@
 
     @copyright: 2000-2004 Juergen Hermann <jh@web.de>,
                 2005-2008 MoinMoin:ThomasWaldmann.
+                2008      MoinMoin:JohannesBerg
     @license: GNU GPL, see COPYING for details.
 """
 
@@ -16,7 +17,7 @@
 logging = log.getLogger(__name__)
 
 from MoinMoin import config, error, util, wikiutil
-import MoinMoin.auth as authmodule
+from MoinMoin.auth import MoinAuth
 import MoinMoin.events as events
 from MoinMoin.events import PageChangedEvent, PageRenamedEvent
 from MoinMoin.events import PageDeletedEvent, PageCopiedEvent
@@ -48,12 +49,12 @@
         raise
     except IndentationError, err:
         logging.exception('Your source code / config file is not correctly indented!')
-        msg = '''IndentationError: %(err)s
+        msg = """IndentationError: %(err)s
 
-The configuration files are python modules. Therefore, whitespace is
+The configuration files are Python modules. Therefore, whitespace is
 important. Make sure that you use only spaces, no tabs are allowed here!
 You have to use four spaces at the beginning of the line mostly.
-''' % {
+""" % {
     'err': err,
 }
         raise error.ConfigurationError(msg)
@@ -68,7 +69,7 @@
     """ Return url matching regular expression
 
     Import wikis list from farmconfig on the first call and compile the
-    regexes. Later then return the cached regex list.
+    regexes. Later just return the cached regex list.
 
     @rtype: list of tuples of (name, compiled re object)
     @return: url to wiki config name matching list
@@ -124,7 +125,7 @@
         logging.info("using wiki config: %s" % os.path.abspath(module.__file__))
     except ImportError, err:
         logging.exception('Could not import.')
-        msg = '''ImportError: %(err)s
+        msg = """ImportError: %(err)s
 
 Check that the file is in the same directory as the server script. If
 it is not, you must add the path of the directory where the file is
@@ -134,13 +135,13 @@
 Check that the configuration file name is either "wikiconfig.py" or the
 module name specified in the wikis list in farmconfig.py. Note that the
 module name does not include the ".py" suffix.
-''' % {
+""" % {
     'err': err,
 }
         raise error.ConfigurationError(msg)
     except AttributeError, err:
         logging.exception('An exception occured.')
-        msg = '''AttributeError: %(err)s
+        msg = """AttributeError: %(err)s
 
 Could not find required "Config" class in "%(name)s.py".
 
@@ -148,36 +149,18 @@
 made a syntax or spelling error.
 
 Another reason for this could be a name clash. It is not possible to have
-config names like e.g. stats.py - because that colides with MoinMoin/stats/ -
+config names like e.g. stats.py - because that collides with MoinMoin/stats/ -
 have a look into your MoinMoin code directory what other names are NOT
 possible.
 
 Please check your configuration file. As an example for correct syntax,
 use the wikiconfig.py file from the distribution.
-''' % {
+""" % {
     'name': name,
     'err': err,
 }
         raise error.ConfigurationError(msg)
 
-    # postprocess configuration
-    # 'setuid' special auth method auth method can log out
-    cfg.auth_can_logout = ['setuid']
-    cfg.auth_login_inputs = []
-    found_names = []
-    for auth in cfg.auth:
-        if not auth.name:
-            raise error.ConfigurationError("Auth methods must have a name.")
-        if auth.name in found_names:
-            raise error.ConfigurationError("Auth method names must be unique.")
-        found_names.append(auth.name)
-        if auth.logout_possible and auth.name:
-            cfg.auth_can_logout.append(auth.name)
-        for input in auth.login_inputs:
-            if not input in cfg.auth_login_inputs:
-                cfg.auth_login_inputs.append(input)
-    cfg.auth_have_login = len(cfg.auth_login_inputs) > 0
-
     return cfg
 
 
@@ -221,511 +204,30 @@
     pass
 
 
-class DefaultConfig(object):
-    """ default config values
+class ConfigFunctionality(object):
+    """ Configuration base class with config class behaviour.
 
-        When adding new config attributes, PLEASE use a name with the TOPIC as prefix,
-        so it will sort naturally. E.g. use "actions_excluded", not "excluded_actions".
-
-        Also, please keep it (roughly) sorted (except if you have good reasons to group otherwise).
+        This class contains the functionality for the DefaultConfig
+        class for the benefit of the WikiConfig macro.
     """
 
-    DesktopEdition = False # True gives all local users special powers - ONLY use for MMDE style usage!
-
-    SecurityPolicy = None
-
-    acl_hierarchic = False # True to use hierarchical ACLs
-    # All acl_rights_* lines must use unicode!
-    acl_rights_default = u"Trusted:read,write,delete,revert Known:read,write,delete,revert All:read,write"
-    acl_rights_before = u""
-    acl_rights_after = u""
-    acl_rights_valid = ['read', 'write', 'delete', 'revert', 'admin']
-
-    actions_excluded = ['xmlrpc',  # we do not want wiki admins unknowingly offering xmlrpc service
-                        'MyPages',  # only works when used with a non-default SecurityPolicy (e.g. autoadmin)
-                        'CopyPage',  # has questionable behaviour regarding subpages a user can't read, but can copy
-                       ]
-    allow_xslt = False
-    antispam_master_url = "http://master.moinmo.in/?action=xmlrpc2"
-
-    auth = [authmodule.MoinAuth()]
-    # default to http and xmlrpc_applytoken to get old semantics
-    # xmlrpc_applytoken shall be removed once that code is changed
-    # to have proper session handling and use request.handle_auth()
-    auth_methods_trusted = ['http', 'xmlrpc_applytoken']
-
-    backup_compression = 'gz'
-    backup_users = []
-    backup_include = []
-    backup_exclude = [
-        r"(.+\.py(c|o)$)",
-        r"%(cache_dir)s",
-        r"%(/)spages%(/)s.+%(/)scache%(/)s[^%(/)s]+$" % {'/': os.sep},
-        r"%(/)s(edit-lock|event-log|\.DS_Store)$" % {'/': os.sep},
-        ]
-    backup_storage_dir = '/tmp'
-    backup_restore_target_dir = '/tmp'
-
-    bang_meta = True
-    caching_formats = ['text_html']
-    changed_time_fmt = '%H:%M'
-
-    # chars_{upper,lower,digits,spaces} see MoinMoin/util/chartypes.py
-
-    # if you have gdchart, add something like
-    # chart_options = {'width = 720, 'height': 540}
-    chart_options = None
-
-    config_check_enabled = False
-
-    cookie_domain = None # use '.domain.tld" for a farm with hosts in that domain
-    cookie_path = None   # use '/wikifarm" for a farm with pathes below that path
-    cookie_lifetime = 12 # 12 hours from now
-    cookie_secure = None # a secure cookie is not transmitted over unsecure connection
-                         # None = auto-enable secure cookie for https
-                         # True = ever use secure cookie
-                         # False = never use secure cookie
-
-    data_dir = './data/'
-    data_underlay_dir = './underlay/'
-
-    date_fmt = '%Y-%m-%d'
-    datetime_fmt = '%Y-%m-%d %H:%M:%S'
-
-    default_markup = 'wiki'
-    docbook_html_dir = r"/usr/share/xml/docbook/stylesheet/nwalsh/html/" # correct for debian sarge
-
-    edit_bar = ['Edit', 'Comments', 'Discussion', 'Info', 'Subscribe', 'Quicklink', 'Attachments', 'ActionsMenu']
-    editor_default = 'text' # which editor is called when nothing is specified
-    editor_force = False # force using the default editor
-    editor_ui = 'freechoice' # which editor links are shown on user interface
-    editor_quickhelp = {
-        # editor markup hints quickhelp
-        # MUST be in wiki markup, even if the help is not for the wiki parser!
-        'wiki': _(u"""\
- Emphasis:: <<Verbatim('')>>''italics''<<Verbatim('')>>; <<Verbatim(''')>>'''bold'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''bold italics'''''<<Verbatim(''''')>>; <<Verbatim('')>>''mixed ''<<Verbatim(''')>>'''''bold'''<<Verbatim(''')>> and italics''<<Verbatim('')>>; <<Verbatim(----)>> horizontal rule.
- Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; ===== Title 5 =====.
- Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1.#n start numbering at n; space alone indents.
- Links:: <<Verbatim(JoinCapitalizedWords)>>; <<Verbatim([[target|linktext]])>>.
- Tables:: || cell text |||| cell text spanning 2 columns ||;    no trailing white space allowed after tables or titles.
-
-(!) For more help, see HelpOnEditing or SyntaxReference.
-"""),
-        'rst': _("""\
-{{{
-Emphasis: *italic* **bold** ``monospace``
-
-Headings: Heading 1  Heading 2  Heading 3
-          =========  ---------  ~~~~~~~~~
-
-Horizontal rule: ----
-
-Links: TrailingUnderscore_ `multi word with backticks`_ external_
-
-.. _external: http://external-site.example.org/foo/
-
-Lists: * bullets; 1., a. numbered items.
-}}}
-(!) For more help, see the
-[[http://docutils.sourceforge.net/docs/user/rst/quickref.html|reStructuredText Quick Reference]].
-"""),
-        'creole': _(u"""\
- Emphasis:: <<Verbatim(//)>>''italics''<<Verbatim(//)>>; <<Verbatim(**)>>'''bold'''<<Verbatim(**)>>; <<Verbatim(**//)>>'''''bold italics'''''<<Verbatim(//**)>>; <<Verbatim(//)>>''mixed ''<<Verbatim(**)>>'''''bold'''<<Verbatim(**)>> and italics''<<Verbatim(//)>>;
- Horizontal Rule:: <<Verbatim(----)>>
- Force Linebreak:: <<Verbatim(\\\\)>>
- Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; ===== Title 5 =====.
- Lists:: * bullets; ** sub-bullets; # numbered items; ## numbered sub items.
- Links:: <<Verbatim([[target]])>>; <<Verbatim([[target|linktext]])>>.
- Tables:: |= header text | cell text | more cell text |;
-
-(!) For more help, see HelpOnEditing or HelpOnCreoleSyntax.
-"""),
-    }
-    edit_locking = 'warn 10' # None, 'warn <timeout mins>', 'lock <timeout mins>'
-    edit_ticketing = True
-    edit_rows = 20
-
-    hacks = {} # { 'feature1': value1, ... }
-               # Configuration for features still in development.
-               # For boolean stuff just use config like this:
-               #   hacks = { 'feature': True, ...}
-               # and in the code use:
-               #   if cfg.hacks.get('feature', False): <doit>
-               # A non-existing hack key should ever mean False, None, "", [] or {}!
-
-    history_count = (100, 200) # (default_revisions_shown, max_revisions_shown)
-
-    hosts_deny = []
-
-    html_head = ''
-    html_head_queries = '''<meta name="robots" content="noindex,nofollow">\n'''
-    html_head_posts   = '''<meta name="robots" content="noindex,nofollow">\n'''
-    html_head_index   = '''<meta name="robots" content="index,follow">\n'''
-    html_head_normal  = '''<meta name="robots" content="index,nofollow">\n'''
-    html_pagetitle = None
-
-    interwikiname = None # our own interwikiname. choose wisely and never change!
-    interwiki_preferred = [] # list of wiki names to show at top of interwiki list
-
-    language_default = 'en'
-    language_ignore_browser = False # ignore browser settings, use language_default
-                                    # or user prefs
-
-    logo_string = None # can be either just some text or a piece of html shown as "logo"
-
-    log_reverse_dns_lookups = True  # if we do reverse dns lookups for logging hostnames
-                                    # instead of just IPs
-    log_timing = False # log infos about timing of actions, good to analyze load conditions
-
-    mail_from = None # u'Juergen Wiki <noreply@jhwiki.org>'
-    mail_login = None # "user pwd" if you need to use SMTP AUTH when using your mail server
-    mail_smarthost = None # your SMTP mail server
-    mail_sendmail = None # "/usr/sbin/sendmail -t -i" to not use SMTP, but sendmail
-
-    mail_import_secret = "" # a shared secret also known to the mail importer xmlrpc script
-    mail_import_subpage_template = u"$from-$date-$subject" # used for mail import
-    mail_import_pagename_search = ['subject', 'to', ] # where to look for target pagename (and in which order)
-    mail_import_pagename_envelope = u"%s" # use u"+ %s/" to add "+ " and "/" automatically
-    mail_import_pagename_regex = r'\[\[([^\]]*)\]\]' # how to find/extract the pagename from the subject
-    mail_import_wiki_addrs = [] # the e-mail addresses for e-mails that should go into the wiki
-
-    # some dangerous mimetypes (we don't use "content-disposition: inline" for them when a user
-    # downloads such attachments, because the browser might execute e.g. Javascript contained
-    # in the HTML and steal your moin session cookie or do other nasty stuff)
-    mimetypes_xss_protect = [
-        'text/html',
-        'application/x-shockwave-flash',
-        'application/xhtml+xml',
-    ]
-
-    mimetypes_embed = [
-        'application/x-dvi',
-        'application/postscript',
-        'application/pdf',
-        'application/ogg',
-        'application/vnd.visio',
-        'image/x-ms-bmp',
-        'image/svg+xml',
-        'image/tiff',
-        'image/x-photoshop',
-        'audio/mpeg',
-        'audio/midi',
-        'audio/x-wav',
-        'video/fli',
-        'video/mpeg',
-        'video/quicktime',
-        'video/x-msvideo',
-        'chemical/x-pdb',
-        'x-world/x-vrml',
-    ]
-
-
-    navi_bar = [u'RecentChanges', u'FindPage', u'HelpContents', ]
-    nonexist_qm = False
-
-    notification_bot_uri = None # uri of the jabber bot
-
-    # OpenID server support
-    openid_server_enabled = False
-    openid_server_restricted_users_group = None
-    openid_server_enable_user = False
-
-    page_credits = [
-        # Feel free to add other credits, but PLEASE do NOT change or remove
-        # the following links - you help us by keeping them "as is":
-        '<a href="http://moinmo.in/" title="This site uses the MoinMoin Wiki software.">MoinMoin Powered</a>',
-        '<a href="http://moinmo.in/Python" title="MoinMoin is written in Python.">Python Powered</a>',
-
-        # Optional credits:
-        # if you think it can be maybe misunderstood as applying to content or topic of your wiki,
-        # feel free to remove this one:
-        '<a href="http://moinmo.in/GPL" title="MoinMoin is GPL licensed.">GPL licensed</a>',
-
-        # if you don't need/want to check the html output, feel free to remove this one:
-        '<a href="http://validator.w3.org/check?uri=referer" title="Click here to validate this page.">Valid HTML 4.01</a>',
-        ]
-
-    # you can put some pieces of html at specific places into the theme output:
-    page_footer1 = ''
-    page_footer2 = ''
-    page_header1 = ''
-    page_header2 = ''
-
-    page_front_page = u'HelpOnLanguages' # this will make people choose a sane config
-    page_local_spelling_words = u'LocalSpellingWords'
-
-    # the following regexes should match the complete name when used in free text
-    # the group 'all' shall match all, while the group 'key' shall match the key only
-    # e.g. CategoryFoo -> group 'all' ==  CategoryFoo, group 'key' == Foo
-    # moin's code will add ^ / $ at beginning / end when needed
-    page_category_regex =  ur'(?P<all>Category(?P<key>(?!Template)\S+))'
-    page_dict_regex = ur'(?P<all>(?P<key>\S+)Dict)'
-    page_group_regex = ur'(?P<all>(?P<key>\S+)Group)'
-    page_template_regex = ur'(?P<all>(?P<key>\S+)Template)'
-
-    page_license_enabled = False
-    page_license_page = u'WikiLicense'
-
-    # These icons will show in this order in the iconbar, unless they
-    # are not relevant, e.g email icon when the wiki is not configured
-    # for email.
-    page_iconbar = ["up", "edit", "view", "diff", "info", "subscribe", "raw", "print", ]
-
-    # Standard buttons in the iconbar
-    page_icons_table = {
-        # key           pagekey, querystr dict, title, icon-key
-        'diff':        ('page', {'action': 'diff'}, _("Diffs"), "diff"),
-        'info':        ('page', {'action': 'info'}, _("Info"), "info"),
-        'edit':        ('page', {'action': 'edit'}, _("Edit"), "edit"),
-        'unsubscribe': ('page', {'action': 'unsubscribe'}, _("UnSubscribe"), "unsubscribe"),
-        'subscribe':   ('page', {'action': 'subscribe'}, _("Subscribe"), "subscribe"),
-        'raw':         ('page', {'action': 'raw'}, _("Raw"), "raw"),
-        'xml':         ('page', {'action': 'show', 'mimetype': 'text/xml'}, _("XML"), "xml"),
-        'print':       ('page', {'action': 'print'}, _("Print"), "print"),
-        'view':        ('page', {}, _("View"), "view"),
-        'up':          ('page_parent_page', {}, _("Up"), "up"),
-        }
-
-
-    def password_checker(username, password):
-        """ Check if a password is secure enough.
-            We use a built-in check to get rid of the worst passwords.
-
-            We do NOT use cracklib / python-crack here any more because it is
-            not thread-safe (we experienced segmentation faults when using it).
-
-            If you don't want to check passwords, use password_checker = None.
-
-            @return: None if there is no problem with the password,
-                     some string with an error msg, if the password is problematic.
-        """
-
-        try:
-            # in any case, do a very simple built-in check to avoid the worst passwords
-            if len(password) < 6:
-                raise ValueError("Password too short.")
-            if len(set(password)) < 4:
-                raise ValueError("Password has not enough different characters.")
-
-            username_lower = username.lower()
-            password_lower = password.lower()
-            if username in password or password in username or \
-               username_lower in password_lower or password_lower in username_lower:
-                raise ValueError("Password too easy (containment).")
-
-            keyboards = (ur"`1234567890-=qwertyuiop[]\asdfghjkl;'zxcvbnm,./", # US kbd
-                         ur"^1234567890ߴqwertzuiop+asdfghjkl#yxcvbnm,.-", # german kbd
-                        ) # add more keyboards!
-            for kbd in keyboards:
-                rev_kbd = kbd[::-1]
-                if password in kbd or password in rev_kbd or \
-                   password_lower in kbd or password_lower in rev_kbd:
-                    raise ValueError("Password too easy (kbd sequence)")
-            return None
-        except ValueError, err:
-            return str(err)
-
-    password_checker = staticmethod(password_checker)
-
-    quicklinks_default = [] # preload user quicklinks with this page list
-
-    refresh = None # (minimum_delay, type), e.g.: (2, 'internal')
-    rss_cache = 60 # suggested caching time for RecentChanges RSS, in seconds
-
-    search_results_per_page = 25
-
-    session_handler = session.DefaultSessionHandler()
-    session_id_handler = session.MoinCookieSessionIDHandler()
-
-    secrets = None  # if wiki admin does not set it, will get calculated from some cfg values
-
-    shared_intermap = None # can be string or list of strings (filenames)
-
-    show_hosts = True # show hostnames on RecentChanges / info/history action
-    show_interwiki = False # show our interwiki name (usually in front of the page name)
-    show_names = True # show editor names on RecentChanges / info/history action
-    show_section_numbers = 0 # enumerate sections (headlines) by default?
-    show_timings = False # show some timing stats (usually in the footer)
-    show_version = False # show moin version info / (C) (depends on theme)
-
-    sistersites = [
-        #('Self', 'http://localhost:8080/?action=sisterpages'),
-        #('EmacsWiki', 'http://www.emacswiki.org/cgi-bin/test?action=sisterpages'),
-        #('JspWiki', 'http://www.jspwiki.org/SisterSites.jsp'),
-    ] # list of (sistersitename, sisterpagelistfetchurl)
-
-    siteid = 'default'
-    sitename = u'Untitled Wiki' # Wiki identity
-
-    stylesheets = [] # list of tuples (media, csshref) to insert after theme css, before user css
-
-    _subscribable_events = None # A list of event types that user can subscribe to
-    subscribed_pages_default = [] # preload user subscribed pages with this page list
-    email_subscribed_events_default = [
-        PageChangedEvent.__name__,
-        PageRenamedEvent.__name__,
-        PageDeletedEvent.__name__,
-        PageCopiedEvent.__name__,
-        PageRevertedEvent.__name__,
-        FileAttachedEvent.__name__,
-    ]
-    jabber_subscribed_events_default = []
-
-    superuser = [] # list of unicode user names that have super powers :)
-
-    supplementation_page = False # use supplementation pages (show a link in the theme)?
-    supplementation_page_name = u'Discussion' # name of suppl. subpage
-    supplementation_page_template = u'DiscussionTemplate' # name of template used to create suppl. pages
-
-    surge_action_limits = {# allow max. <count> <action> requests per <dt> secs
-        # action: (count, dt)
-        'all': (30, 30), # all requests (except cache/AttachFile action) count for this limit
-        'default': (30, 60), # default limit for actions without a specific limit
-        'show': (30, 60),
-        'recall': (10, 120),
-        'raw': (20, 40),  # some people use this for css
-        'diff': (30, 60),
-        'fullsearch': (10, 120),
-        'edit': (30, 300), # can be lowered after making preview different from edit
-        'rss_rc': (1, 60),
-        # The following actions are often used for images - to avoid pages with lots of images
-        # (like photo galleries) triggering surge protection, we assign rather high limits:
-        'AttachFile': (90, 60),
-        'cache': (600, 30), # cache action is very cheap/efficient
-    }
-    surge_lockout_time = 3600 # secs you get locked out when you ignore warnings
-
-    textchas = None # a data structure with site-specific questions/answers, see HelpOnTextChas
-    textchas_disabled_group = None # e.g. u'NoTextChasGroup' if you are a member of this group, you don't get textchas
-
-    theme_default = 'modern'
-    theme_force = False
-
-    traceback_show = True # if True, tracebacks are displayed in the web browser
-    traceback_log_dir = None # if set to a directory path, tracebacks are written to files there
-
-    trail_size = 5 # number of recently visited pagenames shown in the trail display
-    tz_offset = 0.0 # default time zone offset in hours from UTC
-
-    # a regex of HTTP_USER_AGENTS that should be excluded from logging
-    # and receive a FORBIDDEN for anything except viewing a page
-    # list must not contain 'java' because of twikidraw wanting to save drawing uses this useragent
-    ua_spiders = ('archiver|cfetch|charlotte|crawler|curl|gigabot|googlebot|heritrix|holmes|htdig|httrack|httpunit|'
-                  'intelix|jeeves|larbin|leech|libwww-perl|linkbot|linkmap|linkwalk|litefinder|mercator|'
-                  'microsoft.url.control|mirror| mj12bot|msnbot|msrbot|neomo|nutbot|omniexplorer|puf|robot|scooter|seekbot|'
-                  'sherlock|slurp|sitecheck|snoopy|spider|teleport|twiceler|voilabot|voyager|webreaper|wget|yeti')
-
-    unzip_single_file_size = 2.0 * 1000 ** 2
-    unzip_attachments_space = 200.0 * 1000 ** 2
-    unzip_attachments_count = 101 # 1 zip file + 100 files contained in it
-
-    url_mappings = {}
-
-    # url_prefix is DEPRECATED and not used any more by the code.
-    # it confused many people by its name and default value of '/wiki' to the
-    # wrong conclusion that it is the url of the wiki (the dynamic) stuff,
-    # but it was used to address the static stuff (images, css, js).
-    # Thus we use the more clear url_prefix_static ['/moin_staticVVV'] setting now.
-    # For a limited time, we still look at url_prefix - if it is not None, we
-    # copy the value to url_prefix_static to ease transition.
-    url_prefix = None
-
-    # includes the moin version number, so we can have a unlimited cache lifetime
-    # for the static stuff. if stuff changes on version upgrade, url will change
-    # immediately and we have no problem with stale caches.
-    url_prefix_static = config.url_prefix_static
-    url_prefix_local = None # if None, use same value as url_prefix_static.
-                            # must be same site as wiki engine (for e.g. JS permissions)
-
-    # we could prefix actions to be able to exclude them by robots.txt:
-    #url_prefix_action = 'action' # no leading or trailing '/'
-    url_prefix_action = None # compatiblity
-
-    # allow disabling certain userpreferences plugins
-    userprefs_disabled = []
-
-    user_autocreate = False # do we auto-create user profiles
-    user_email_unique = True # do we check whether a user's email is unique?
-    user_jid_unique = True # do we check whether a user's email is unique?
-
-    user_homewiki = 'Self' # interwiki name for where user homepages are located
-
-    user_checkbox_fields = [
-        ('mailto_author', lambda _: _('Publish my email (not my wiki homepage) in author info')),
-        ('edit_on_doubleclick', lambda _: _('Open editor on double click')),
-        ('remember_last_visit', lambda _: _('After login, jump to last visited page')),
-        ('show_comments', lambda _: _('Show comment sections')),
-        ('show_nonexist_qm', lambda _: _('Show question mark for non-existing pagelinks')),
-        ('show_page_trail', lambda _: _('Show page trail')),
-        ('show_toolbar', lambda _: _('Show icon toolbar')),
-        ('show_topbottom', lambda _: _('Show top/bottom links in headings')),
-        ('show_fancy_diff', lambda _: _('Show fancy diffs')),
-        ('wikiname_add_spaces', lambda _: _('Add spaces to displayed wiki names')),
-        ('remember_me', lambda _: _('Remember login information')),
-
-        ('disabled', lambda _: _('Disable this account forever')),
-        # if an account is disabled, it may be used for looking up
-        # id -> username for page info and recent changes, but it
-        # is not usable for the user any more:
-    ]
-
-    user_checkbox_defaults = {'mailto_author':       0,
-                              'edit_on_doubleclick': 0,
-                              'remember_last_visit': 0,
-                              'show_comments':       0,
-                              'show_nonexist_qm':    nonexist_qm,
-                              'show_page_trail':     1,
-                              'show_toolbar':        1,
-                              'show_topbottom':      0,
-                              'show_fancy_diff':     1,
-                              'wikiname_add_spaces': 0,
-                              'remember_me':         1,
-                             }
-
-    # don't let the user change those
-    # user_checkbox_disable = ['disabled']
-    user_checkbox_disable = []
-
-    # remove those checkboxes:
-    #user_checkbox_remove = ['edit_on_doubleclick', 'show_nonexist_qm', 'show_toolbar', 'show_topbottom',
-    #                        'show_fancy_diff', 'wikiname_add_spaces', 'remember_me', 'disabled',]
-    user_checkbox_remove = []
-
-    user_form_fields = [
-        ('name', _('Name'), "text", "36", _("(Use FirstnameLastname)")),
-        ('aliasname', _('Alias-Name'), "text", "36", ''),
-        ('email', _('Email'), "text", "36", ''),
-        ('jid', _('Jabber ID'), "text", "36", ''),
-        ('css_url', _('User CSS URL'), "text", "40", _('(Leave it empty for disabling user CSS)')),
-        ('edit_rows', _('Editor size'), "text", "3", ''),
-    ]
-
-    user_form_defaults = {# key: default - do NOT remove keys from here!
-        'name': '',
-        'aliasname': '',
-        'password': '',
-        'password2': '',
-        'email': '',
-        'jid': '',
-        'css_url': '',
-        'edit_rows': "20",
-    }
-
-    # don't let the user change those, but show them:
-    #user_form_disable = ['name', 'aliasname', 'email',]
-    user_form_disable = []
-
-    # remove those completely:
-    #user_form_remove = ['password', 'password2', 'css_url', 'logout', 'create', 'account_sendmail',]
-    user_form_remove = []
-
-    # attributes we do NOT save to the userpref file
-    user_transient_fields = ['id', 'valid', 'may', 'auth_username', 'password', 'password2', 'auth_method', 'auth_attribs', ]
-
-    xapian_search = False
-    xapian_index_dir = None
-    xapian_stemming = False
-    xapian_index_history = False
+    # attributes of this class that should not be shown
+    # in the WikiConfig() macro.
+    cfg_mtime = None
+    siteid = None
+    cache = None
+    mail_enabled = None
+    jabber_enabled = None
+    auth_can_logout = None
+    auth_have_login = None
+    auth_login_inputs = None
+    _site_plugin_lists = None
+    _iwid = None
+    _iwid_full = None
+    xapian_searchers = None
+    moinmoin_dir = None
+    # will be lazily loaded by interwiki code when needed (?)
+    shared_intermap_files = None
 
     def __init__(self, siteid):
         """ Init Config instance """
@@ -763,7 +265,7 @@
         self.cache.page_group_regexact = re.compile(u'^%s$' % self.page_group_regex, re.UNICODE)
         self.cache.page_template_regexact = re.compile(u'^%s$' % self.page_template_regex, re.UNICODE)
 
-        self.cache.ua_spiders = self.ua_spiders and re.compile(self.ua_spiders, re.I)
+        self.cache.ua_spiders = self.ua_spiders and re.compile(self.ua_spiders, re.IGNORECASE)
 
         self._check_directories()
 
@@ -799,13 +301,29 @@
 
         # post process
 
+        # 'setuid' special auth method auth method can log out
+        self.auth_can_logout = ['setuid']
+        self.auth_login_inputs = []
+        found_names = []
+        for auth in self.auth:
+            if not auth.name:
+                raise error.ConfigurationError("Auth methods must have a name.")
+            if auth.name in found_names:
+                raise error.ConfigurationError("Auth method names must be unique.")
+            found_names.append(auth.name)
+            if auth.logout_possible and auth.name:
+                self.auth_can_logout.append(auth.name)
+            for input in auth.login_inputs:
+                if not input in self.auth_login_inputs:
+                    self.auth_login_inputs.append(input)
+        self.auth_have_login = len(self.auth_login_inputs) > 0
+
         # internal dict for plugin `modules' lists
         self._site_plugin_lists = {}
 
         # we replace any string placeholders with config values
         # e.g u'%(page_front_page)s' % self
         self.navi_bar = [elem % self for elem in self.navi_bar]
-        self.backup_exclude = [elem % self for elem in self.backup_exclude]
 
         # check if python-xapian is installed
         if self.xapian_search:
@@ -820,27 +338,16 @@
 
         # check if mail is possible and set flag:
         self.mail_enabled = (self.mail_smarthost is not None or self.mail_sendmail is not None) and self.mail_from
+        self.mail_enabled = self.mail_enabled and True or False
 
         # check if jabber bot is available and set flag:
         self.jabber_enabled = self.notification_bot_uri is not None
 
         # if we are to use the jabber bot, instantiate a server object for future use
         if self.jabber_enabled:
-
-            errmsg = "You must set a (long) secret string to send notifications!"
-            try:
-                if not self.secret:
-                    raise error.ConfigurationError(errmsg)
-            except AttributeError, err:
-                raise error.ConfigurationError(errmsg)
-
             from xmlrpclib import Server
             self.notification_server = Server(self.notification_bot_uri, )
 
-        if self.secrets is None:  # Note: this is 'secrets' (with s at the end), not 'secret' (as above)
-                                  # This stuff is already cleaned up in 1.8 repo...
-            self.secrets = self.calc_secrets()
-
         # Cache variables for the properties below
         self._iwid = self._iwid_full = self._meta_dict = None
 
@@ -848,9 +355,6 @@
         self.cache.acl_rights_default = AccessControlList(self, [self.acl_rights_default])
         self.cache.acl_rights_after = AccessControlList(self, [self.acl_rights_after])
 
-        if self.url_prefix is not None: # remove this code when url_prefix setting is removed
-            self.url_prefix_static = self.url_prefix
-
         action_prefix = self.url_prefix_action
         if action_prefix is not None and action_prefix.endswith('/'): # make sure there is no trailing '/'
             self.url_prefix_action = action_prefix[:-1]
@@ -858,6 +362,33 @@
         if self.url_prefix_local is None:
             self.url_prefix_local = self.url_prefix_static
 
+        if self.secrets is None:  # admin did not setup a real secret, so make up something
+            self.secrets = self.calc_secrets()
+
+        secret_key_names = ['action/cache', 'wikiutil/tickets', 'xmlrpc/ProcessMail', 'xmlrpc/RemoteScript', ]
+        if self.jabber_enabled:
+            secret_key_names.append('jabberbot')
+
+        secret_min_length = 10
+        if isinstance(self.secrets, str):
+            if len(self.secrets) < secret_min_length:
+                raise error.ConfigurationError("The secrets = '...' wiki config setting is a way too short string (minimum length is %d chars)!" % (
+                    secret_min_length))
+            # for lazy people: set all required secrets to same value
+            secrets = {}
+            for key in secret_key_names:
+                secrets[key] = self.secrets
+            self.secrets = secrets
+
+        # we check if we have all secrets we need and that they have minimum length
+        for secret_key_name in secret_key_names:
+            try:
+                secret = self.secrets[secret_key_name]
+                if len(secret) < secret_min_length:
+                    raise ValueError
+            except (KeyError, ValueError):
+                raise error.ConfigurationError("You must set a (at least %d chars long) secret string for secrets['%s']!" % (
+                    secret_min_length, secret_key_name))
 
     def calc_secrets(self):
         """ make up some 'secret' using some config values """
@@ -872,9 +403,10 @@
                 secret += repr(var)
         return secret
 
+    _meta_dict = None
     def load_meta_dict(self):
         """ The meta_dict contains meta data about the wiki instance. """
-        if getattr(self, "_meta_dict", None) is None:
+        if self._meta_dict is None:
             self._meta_dict = wikiutil.MetaDict(os.path.join(self.data_dir, 'meta'), self.cache_dir)
         return self._meta_dict
     meta_dict = property(load_meta_dict)
@@ -889,25 +421,13 @@
     iwid = make_iwid_property("_iwid")
     iwid_full = make_iwid_property("_iwid_full")
 
-    # lazily load a list of events a user can subscribe to
-    def make_subscribable_events_prop():
-        def getter(self):
-            if getattr(self, "_subscribable_events", None) is None:
-                self._subscribable_events = events.get_subscribable_events()
-            return getattr(self, "_subscribable_events")
-
-        def setter(self, new_events):
-            self._subscribable_events = new_events
-
-        return property(getter, setter)
-    subscribable_events = make_subscribable_events_prop()
-
     # lazily create a list of event handlers
+    _event_handlers = None
     def make_event_handlers_prop():
         def getter(self):
-            if getattr(self, "_event_handlers", None) is None:
+            if self._event_handlers is None:
                 self._event_handlers = events.get_handlers(self)
-            return getattr(self, "_event_handlers")
+            return self._event_handlers
 
         def setter(self, new_handlers):
             self._event_handlers = new_handlers
@@ -972,13 +492,13 @@
         config files.
         """
         charset = 'utf-8'
-        message = u'''
+        message = u"""
 "%(name)s" configuration variable is a string, but should be
 unicode. Use %(name)s = u"value" syntax for unicode variables.
 
 Also check your "-*- coding -*-" line at the top of your configuration
 file. It should match the actual charset of the configuration file.
-'''
+"""
 
         decode_names = (
             'sitename', 'logo_string', 'navi_bar', 'page_front_page',
@@ -1025,7 +545,7 @@
 
             path_pages = os.path.join(path, "pages")
             if not (os.path.isdir(path_pages) and os.access(path_pages, mode)):
-                msg = '''
+                msg = """
 %(attr)s "%(path)s" does not exist, or has incorrect ownership or
 permissions.
 
@@ -1035,50 +555,60 @@
 
 It is recommended to use absolute paths and not relative paths. Check
 also the spelling of the directory name.
-''' % {'attr': attr, 'path': path, }
+""" % {'attr': attr, 'path': path, }
                 raise error.ConfigurationError(msg)
 
     def _loadPluginModule(self):
-        """ import plugin module under configname.plugin
+        """
+        import all plugin modules
 
         To be able to import plugin from arbitrary path, we have to load
         the base package once using imp.load_module. Later, we can use
         standard __import__ call to load plugins in this package.
 
-        Since each wiki has unique plugins, we load the plugin package
-        under the wiki configuration module, named self.siteid.
+        Since each configured plugin path has unique plugins, we load the
+        plugin packages as "moin_plugin_<sha1(path)>.plugin".
         """
         import imp
+        from MoinMoin.support.python_compatibility import hash_new
 
-        name = self.siteid + '.plugin'
+        plugin_dirs = [self.plugin_dir] + self.plugin_dirs
+        self._plugin_modules = []
+
         try:
             # Lock other threads while we check and import
             imp.acquire_lock()
             try:
-                # If the module is not loaded, try to load it
-                if not name in sys.modules:
-                    # Find module on disk and try to load - slow!
-                    plugin_parent_dir = os.path.abspath(os.path.join(self.plugin_dir, '..'))
-                    fp, path, info = imp.find_module('plugin', [plugin_parent_dir])
-                    try:
-                        # Load the module and set in sys.modules
-                        module = imp.load_module(name, fp, path, info)
-                        sys.modules[self.siteid].plugin = module
-                    finally:
-                        # Make sure fp is closed properly
-                        if fp:
-                            fp.close()
+                for pdir in plugin_dirs:
+                    csum = 'p_%s' % hash_new('sha1', pdir).hexdigest()
+                    modname = '%s.%s' % (self.siteid, csum)
+                    # If the module is not loaded, try to load it
+                    if not modname in sys.modules:
+                        # Find module on disk and try to load - slow!
+                        abspath = os.path.abspath(pdir)
+                        parent_dir, pname = os.path.split(abspath)
+                        fp, path, info = imp.find_module(pname, [parent_dir])
+                        try:
+                            # Load the module and set in sys.modules
+                            module = imp.load_module(modname, fp, path, info)
+                            setattr(sys.modules[self.siteid], 'csum', module)
+                        finally:
+                            # Make sure fp is closed properly
+                            if fp:
+                                fp.close()
+                    if modname not in self._plugin_modules:
+                        self._plugin_modules.append(modname)
             finally:
                 imp.release_lock()
         except ImportError, err:
-            msg = '''
-Could not import plugin package "%(path)s/plugin" because of ImportError:
+            msg = """
+Could not import plugin package "%(path)s" because of ImportError:
 %(err)s.
 
 Make sure your data directory path is correct, check permissions, and
 that the data/plugin directory has an __init__.py file.
-''' % {
-    'path': self.data_dir,
+""" % {
+    'path': pdir,
     'err': str(err),
 }
             raise error.ConfigurationError(msg)
@@ -1098,6 +628,598 @@
         """ Make it possible to access a config object like a dict """
         return getattr(self, item)
 
+
+class DefaultConfig(ConfigFunctionality):
+    """ Configuration base class with default config values
+        (added below)
+    """
+    # Do not add anything into this class. Functionality must
+    # be added above to avoid having the methods show up in
+    # the WikiConfig macro. Settings must be added below to
+    # the options dictionary.
+
+
+def _default_password_checker(cfg, request, username, password):
+    """ Check if a password is secure enough.
+        We use a built-in check to get rid of the worst passwords.
+
+        We do NOT use cracklib / python-crack here any more because it is
+        not thread-safe (we experienced segmentation faults when using it).
+
+        If you don't want to check passwords, use password_checker = None.
+
+        @return: None if there is no problem with the password,
+                 some string with an error msg, if the password is problematic.
+    """
+    _ = request.getText
+    try:
+        # in any case, do a very simple built-in check to avoid the worst passwords
+        if len(password) < 6:
+            raise ValueError(_("Password is too short."))
+        if len(set(password)) < 4:
+            raise ValueError(_("Password has not enough different characters."))
+
+        username_lower = username.lower()
+        password_lower = password.lower()
+        if username in password or password in username or \
+           username_lower in password_lower or password_lower in username_lower:
+            raise ValueError(_("Password is too easy (password contains name or name contains password)."))
+
+        keyboards = (ur"`1234567890-=qwertyuiop[]\asdfghjkl;'zxcvbnm,./", # US kbd
+                     ur"^1234567890ߴqwertzuiop+asdfghjkl#yxcvbnm,.-", # german kbd
+                    ) # add more keyboards!
+        for kbd in keyboards:
+            rev_kbd = kbd[::-1]
+            if password in kbd or password in rev_kbd or \
+               password_lower in kbd or password_lower in rev_kbd:
+                raise ValueError(_("Password is too easy (keyboard sequence)."))
+        return None
+    except ValueError, err:
+        return unicode(err)
+
+
+class DefaultExpression(object):
+    def __init__(self, exprstr):
+        self.text = exprstr
+        self.value = eval(exprstr)
+
+
+#
+# Options that are not prefixed automatically with their
+# group name, see below (at the options dict) for more
+# information on the layout of this structure.
+#
+options_no_group_name = {
+  # ==========================================================================
+  'session': ('Session settings', "Session-related settings, see HelpOnSessions.", (
+    ('session_handler', DefaultExpression('session.DefaultSessionHandler()'),
+     "See HelpOnSessions."),
+    ('session_id_handler', DefaultExpression('session.MoinCookieSessionIDHandler()'),
+     "Only used by the DefaultSessionHandler, see HelpOnSessions."),
+    ('cookie_secure', None,
+     'Use secure cookie. (None = auto-enable secure cookie for https, True = ever use secure cookie, False = never use secure cookie).'),
+    ('cookie_domain', None,
+     'Domain used in the session cookie. (None = do not specify domain).'),
+    ('cookie_path', None,
+     'Path used in the session cookie (None = auto-detect).'),
+    ('cookie_lifetime', 12,
+     'Session lifetime [h] of logged-in users (see HelpOnSessions for details).'),
+    ('anonymous_session_lifetime', None,
+     'Session lifetime [h] of users who are not logged in (None = disable anon sessions).'),
+  )),
+  # ==========================================================================
+  'auth': ('Authentication / Authorization / Security settings', None, (
+    ('superuser', [],
+     "List of trusted user names with wiki system administration super powers (not to be confused with ACL admin rights!). Used for e.g. software installation, language installation via SystemPagesSetup and more. See also HelpOnSuperUser."),
+    ('auth', DefaultExpression('[MoinAuth()]'),
+     "list of auth objects, to be called in this order (see HelpOnAuthentication)"),
+    ('auth_methods_trusted', ['http', 'xmlrpc_applytoken'],
+     'authentication methods for which users should be included in the special "Trusted" ACL group.'),
+    ('secrets', None, """Either a long shared secret string used for multiple purposes or a dict {"purpose": "longsecretstring", ...} for setting up different shared secrets for different purposes. If you don't setup own secret(s), a secret string will be auto-generated from other config settings."""),
+    ('DesktopEdition',
+     False,
+     "if True, give all local users special powers - ''only use this for a local desktop wiki!''"),
+    ('SecurityPolicy',
+     None,
+     "Class object hook for implementing security restrictions or relaxations"),
+    ('actions_excluded',
+     ['xmlrpc',  # we do not want wiki admins unknowingly offering xmlrpc service
+      'MyPages',  # only works when used with a non-default SecurityPolicy (e.g. autoadmin)
+      'CopyPage',  # has questionable behaviour regarding subpages a user can't read, but can copy
+     ],
+     "Exclude unwanted actions (list of strings)"),
+
+    ('allow_xslt', False,
+     "if True, enables XSLT processing via 4Suite (note that this enables anyone with enough know-how to insert '''arbitrary HTML''' into your wiki, which is why it defaults to `False`)"),
+
+    ('password_checker', DefaultExpression('_default_password_checker'),
+     'checks whether a password is acceptable (default check is length >= 6, at least 4 different chars, no keyboard sequence, not username used somehow (you can switch this off by using `None`)'),
+
+  )),
+  # ==========================================================================
+  'spam_leech_dos': ('Anti-Spam/Leech/DOS',
+  'These settings help limiting ressource usage and avoiding abuse.',
+  (
+    ('hosts_deny', [], "List of denied IPs; if an IP ends with a dot, it denies a whole subnet (class A, B or C)"),
+    ('surge_action_limits',
+     {# allow max. <count> <action> requests per <dt> secs
+        # action: (count, dt)
+        'all': (30, 30), # all requests (except cache/AttachFile action) count for this limit
+        'default': (30, 60), # default limit for actions without a specific limit
+        'show': (30, 60),
+        'recall': (10, 120),
+        'raw': (20, 40),  # some people use this for css
+        'diff': (30, 60),
+        'fullsearch': (10, 120),
+        'edit': (30, 300), # can be lowered after making preview different from edit
+        'rss_rc': (1, 60),
+        # The following actions are often used for images - to avoid pages with lots of images
+        # (like photo galleries) triggering surge protection, we assign rather high limits:
+        'AttachFile': (90, 60),
+        'cache': (600, 30), # cache action is very cheap/efficient
+     },
+     "Surge protection tries to deny clients causing too much load/traffic, see /SurgeProtection."),
+    ('surge_lockout_time', 3600, "time [s] someone gets locked out when ignoring the warnings"),
+
+    ('textchas', None,
+     "Spam protection setup using site-specific questions/answers, see HelpOnTextChas."),
+    ('textchas_disabled_group', None,
+     "Name of a group of trusted users who do not get asked TextCha questions."),
+
+    ('antispam_master_url', "http://master.moinmo.in/?action=xmlrpc2",
+     "where antispam security policy fetches spam pattern updates (if it is enabled)"),
+
+    # a regex of HTTP_USER_AGENTS that should be excluded from logging
+    # and receive a FORBIDDEN for anything except viewing a page
+    # list must not contain 'java' because of twikidraw wanting to save drawing uses this useragent
+    ('ua_spiders',
+     ('archiver|cfetch|charlotte|crawler|curl|gigabot|googlebot|heritrix|holmes|htdig|httrack|httpunit|'
+      'intelix|jeeves|larbin|leech|libwww-perl|linkbot|linkmap|linkwalk|litefinder|mercator|'
+      'microsoft.url.control|mirror| mj12bot|msnbot|msrbot|neomo|nutbot|omniexplorer|puf|robot|scooter|seekbot|'
+      'sherlock|slurp|sitecheck|snoopy|spider|teleport|twiceler|voilabot|voyager|webreaper|wget|yeti'),
+     "A regex of HTTP_USER_AGENTs that should be excluded from logging and are not allowed to use actions."),
+
+    ('unzip_single_file_size', 2.0 * 1000 ** 2,
+     "max. size of a single file in the archive which will be extracted [bytes]"),
+    ('unzip_attachments_space', 200.0 * 1000 ** 2,
+     "max. total amount of bytes can be used to unzip files [bytes]"),
+    ('unzip_attachments_count', 101,
+     "max. number of files which are extracted from the zip file"),
+  )),
+  # ==========================================================================
+  'style': ('Style / Theme / UI related',
+  'These settings control how the wiki user interface will look like.',
+  (
+    ('sitename', u'Untitled Wiki',
+     "Short description of your wiki site, displayed below the logo on each page, and used in RSS documents as the channel title [Unicode]"),
+    ('interwikiname', None, "unique and stable InterWiki name (prefix, moniker) of the site, or None"),
+    ('logo_string', None, "The wiki logo top of page, HTML is allowed (`<img>` is possible as well) [Unicode]"),
+    ('html_pagetitle', None, "Allows you to set a specific HTML page title (if None, it defaults to the value of `sitename`)"),
+    ('navi_bar', [u'RecentChanges', u'FindPage', u'HelpContents', ],
+     'Most important page names. Users can add more names in their quick links in user preferences. To link to URL, use `u"[url link title]"`, to use a shortened name for long page name, use `u"[LongLongPageName title]"`. To use page names with spaces, use `u"[page_name_with_spaces any title]"` [list of Unicode strings]'),
+
+    ('theme_default', 'modern',
+     "the name of the theme that is used by default (see HelpOnThemes)"),
+    ('theme_force', False,
+     "if True, do not allow to change the theme"),
+
+    ('stylesheets', [],
+     "List of tuples (media, csshref) to insert after theme css, before user css, see HelpOnThemes."),
+
+    ('supplementation_page', False,
+     "if True, show a link to the supplementation page in the theme"),
+    ('supplementation_page_name', u'Discussion',
+     "default name of the supplementation (sub)page [unicode]"),
+    ('supplementation_page_template', u'DiscussionTemplate',
+     "default template used for creation of the supplementation page [unicode]"),
+
+    ('interwiki_preferred', [], "In dialogues, show those wikis at the top of the list."),
+    ('sistersites', [], "list of tuples `('WikiName', 'sisterpagelist_fetch_url')`"),
+
+    ('trail_size', 5,
+     "Number of pages in the trail of visited pages"),
+
+    ('page_footer1', '', "Custom HTML markup sent ''before'' the system footer."),
+    ('page_footer2', '', "Custom HTML markup sent ''after'' the system footer."),
+    ('page_header1', '', "Custom HTML markup sent ''before'' the system header / title area but after the body tag."),
+    ('page_header2', '', "Custom HTML markup sent ''after'' the system header / title area (and body tag)."),
+
+    ('changed_time_fmt', '%H:%M', "Time format used on Recent``Changes for page edits within the last 24 hours"),
+    ('date_fmt', '%Y-%m-%d', "System date format, used mostly in Recent``Changes"),
+    ('datetime_fmt', '%Y-%m-%d %H:%M:%S', 'Default format for dates and times (when the user has no preferences or chose the "default" date format)'),
+    ('chart_options', None, "If you have gdchart, use something like chart_options = {'width': 720, 'height': 540}"),
+
+    ('edit_bar', ['Edit', 'Comments', 'Discussion', 'Info', 'Subscribe', 'Quicklink', 'Attachments', 'ActionsMenu'],
+     'list of edit bar entries'),
+    ('history_count', (100, 200), "number of revisions shown for info/history action (default_count_shown, max_count_shown)"),
+
+    ('show_hosts', True,
+     "if True, show host names and IPs. Set to False to hide them."),
+    ('show_interwiki', False,
+     "if True, let the theme display your interwiki name"),
+    ('show_names', True,
+     "if True, show user names in the revision history and on Recent``Changes. Set to False to hide them."),
+    ('show_section_numbers', False,
+     'show section numbers in headings by default'),
+    ('show_timings', False, "show some timing values at bottom of a page"),
+    ('show_version', False, "show moin's version at the bottom of a page"),
+    ('traceback_show', True,
+     "if True, show debug tracebacks to users when moin crashes"),
+
+    ('page_credits',
+     [
+       '<a href="http://moinmo.in/" title="This site uses the MoinMoin Wiki software.">MoinMoin Powered</a>',
+       '<a href="http://moinmo.in/Python" title="MoinMoin is written in Python.">Python Powered</a>',
+       '<a href="http://moinmo.in/GPL" title="MoinMoin is GPL licensed.">GPL licensed</a>',
+       '<a href="http://validator.w3.org/check?uri=referer" title="Click here to validate this page.">Valid HTML 4.01</a>',
+     ],
+     'list with html fragments with logos or strings for crediting.'),
+
+    # These icons will show in this order in the iconbar, unless they
+    # are not relevant, e.g email icon when the wiki is not configured
+    # for email.
+    ('page_iconbar', ["up", "edit", "view", "diff", "info", "subscribe", "raw", "print", ],
+     'list of icons to show in iconbar, valid values are only those in page_icons_table. Available only in classic theme.'),
+
+    # Standard buttons in the iconbar
+    ('page_icons_table',
+     {
+        # key           pagekey, querystr dict, title, icon-key
+        'diff': ('page', {'action': 'diff'}, _("Diffs"), "diff"),
+        'info': ('page', {'action': 'info'}, _("Info"), "info"),
+        'edit': ('page', {'action': 'edit'}, _("Edit"), "edit"),
+        'unsubscribe': ('page', {'action': 'unsubscribe'}, _("UnSubscribe"), "unsubscribe"),
+        'subscribe': ('page', {'action': 'subscribe'}, _("Subscribe"), "subscribe"),
+        'raw': ('page', {'action': 'raw'}, _("Raw"), "raw"),
+        'xml': ('page', {'action': 'show', 'mimetype': 'text/xml'}, _("XML"), "xml"),
+        'print': ('page', {'action': 'print'}, _("Print"), "print"),
+        'view': ('page', {}, _("View"), "view"),
+        'up': ('page_parent_page', {}, _("Up"), "up"),
+     },
+     "dict of {'iconname': (url, title, icon-img-key), ...}. Available only in classic theme."),
+
+  )),
+  # ==========================================================================
+  'editor': ('Editor related', None, (
+    ('editor_default', 'text', "Editor to use by default, 'text' or 'gui'"),
+    ('editor_force', False, "if True, force using the default editor"),
+    ('editor_ui', 'freechoice', "Editor choice shown on the user interface, 'freechoice' or 'theonepreferred'"),
+    ('page_license_enabled', False, 'if True, show a license hint in page editor.'),
+    ('page_license_page', u'WikiLicense', 'Page linked from the license hint. [Unicode]'),
+    ('edit_locking', 'warn 10', "Editor locking policy: `None`, `'warn <timeout in minutes>'`, or `'lock <timeout in minutes>'`"),
+    ('edit_ticketing', True, None),
+    ('edit_rows', 20, "Default height of the edit box"),
+
+  )),
+  # ==========================================================================
+  'paths': ('Paths', None, (
+    ('data_dir', './data/', "Path to the data directory containing your (locally made) wiki pages."),
+    ('data_underlay_dir', './underlay/', "Path to the underlay directory containing distribution system and help pages."),
+    ('cache_dir', None, "Directory for caching, by default computed from `data_dir`/cache."),
+    ('user_dir', None, "Directory for user storage, by default computed to be `data_dir`/user."),
+    ('plugin_dir', None, "Plugin directory, by default computed to be `data_dir`/plugin."),
+    ('plugin_dirs', [], "Additional plugin directories."),
+
+    ('docbook_html_dir', r"/usr/share/xml/docbook/stylesheet/nwalsh/html/",
+     'Path to the directory with the Docbook to HTML XSLT files (optional, used by the docbook parser). The default value is correct for Debian Etch.'),
+    ('shared_intermap', None,
+     "Path to a file containing global InterWiki definitions (or a list of such filenames)"),
+  )),
+  # ==========================================================================
+  'urls': ('URLs', None, (
+    # includes the moin version number, so we can have a unlimited cache lifetime
+    # for the static stuff. if stuff changes on version upgrade, url will change
+    # immediately and we have no problem with stale caches.
+    ('url_prefix_static', config.url_prefix_static,
+     "used as the base URL for icons, css, etc. - includes the moin version number and changes on every release. This replaces the deprecated and sometimes confusing `url_prefix = '/wiki'` setting."),
+    ('url_prefix_local', None,
+     "used as the base URL for some Javascript - set this to a URL on same server as the wiki if your url_prefix_static points to a different server."),
+
+    ('url_prefix_action', None,
+     "Use 'action' to enable action URL generation to be compatible with robots.txt. It will generate .../action/info/PageName?action=info then. Recommended for internet wikis."),
+
+    ('notification_bot_uri', None, "URI of the Jabber notification bot."),
+
+    ('url_mappings', {},
+     "lookup table to remap URL prefixes (dict of {{{'prefix': 'replacement'}}}); especially useful in intranets, when whole trees of externally hosted documents move around"),
+
+  )),
+  # ==========================================================================
+  'pages': ('Special page names', None, (
+    ('page_front_page', u'HelpOnLanguages',
+     "Name of the front page. We don't expect you to keep the default. Just read HelpOnLanguages in case you're wondering... [Unicode]"),
+
+    # the following regexes should match the complete name when used in free text
+    # the group 'all' shall match all, while the group 'key' shall match the key only
+    # e.g. CategoryFoo -> group 'all' ==  CategoryFoo, group 'key' == Foo
+    # moin's code will add ^ / $ at beginning / end when needed
+    ('page_category_regex', ur'(?P<all>Category(?P<key>(?!Template)\S+))',
+     'Pagenames exactly matching this regex are regarded as Wiki categories [Unicode]'),
+    ('page_dict_regex', ur'(?P<all>(?P<key>\S+)Dict)',
+     'Pagenames exactly matching this regex are regarded as pages containing variable dictionary definitions [Unicode]'),
+    ('page_group_regex', ur'(?P<all>(?P<key>\S+)Group)',
+     'Pagenames exactly matching this regex are regarded as pages containing group definitions [Unicode]'),
+    ('page_template_regex', ur'(?P<all>(?P<key>\S+)Template)',
+     'Pagenames exactly matching this regex are regarded as pages containing templates for new pages [Unicode]'),
+
+    ('page_local_spelling_words', u'LocalSpellingWords',
+     'Name of the page containing user-provided spellchecker words [Unicode]'),
+  )),
+  # ==========================================================================
+  'user': ('User Preferences related', None, (
+    ('quicklinks_default', [],
+     'List of preset quicklinks for a newly created user accounts. Existing accounts are not affected by this option whereas changes in navi_bar do always affect existing accounts. Preset quicklinks can be removed by the user in the user preferences menu, navi_bar settings not.'),
+    ('subscribed_pages_default', [],
+     "List of pagenames used for presetting page subscriptions for newly created user accounts."),
+
+    ('email_subscribed_events_default',
+     [
+        PageChangedEvent.__name__,
+        PageRenamedEvent.__name__,
+        PageDeletedEvent.__name__,
+        PageCopiedEvent.__name__,
+        PageRevertedEvent.__name__,
+        FileAttachedEvent.__name__,
+     ], None),
+    ('jabber_subscribed_events_default', [], None),
+
+    ('tz_offset', 0.0,
+     "default time zone offset in hours from UTC"),
+
+    ('userprefs_disabled', [],
+     "Disable the listed user preferences plugins."),
+  )),
+  # ==========================================================================
+  'various': ('Various', None, (
+    ('bang_meta', True, 'if True, enable {{{!NoWikiName}}} markup'),
+    ('caching_formats', ['text_html'], "output formats that are cached; set to [] to turn off caching (useful for development)"),
+
+    ('config_check_enabled', False, "if True, check configuration for unknown settings."),
+
+    ('default_markup', 'wiki', 'Default page parser / format (name of module in `MoinMoin.parser`)'),
+
+    ('html_head', '', "Additional <HEAD> tags, see HelpOnThemes."),
+    ('html_head_queries', '<meta name="robots" content="noindex,nofollow">\n',
+     "Additional <HEAD> tags for requests with query strings, like actions."),
+    ('html_head_posts', '<meta name="robots" content="noindex,nofollow">\n',
+     "Additional <HEAD> tags for POST requests."),
+    ('html_head_index', '<meta name="robots" content="index,follow">\n',
+     "Additional <HEAD> tags for some few index pages."),
+    ('html_head_normal', '<meta name="robots" content="index,nofollow">\n',
+     "Additional <HEAD> tags for most normal pages."),
+
+    ('language_default', 'en', "Default language for user interface and page content, see HelpOnLanguages."),
+    ('language_ignore_browser', False, "if True, ignore user's browser language settings, see HelpOnLanguages."),
+
+    ('log_reverse_dns_lookups', True,
+     "if True, do a reverse DNS lookup on page SAVE. If your DNS is broken, set this to False to speed up SAVE."),
+    ('log_timing', False,
+     "if True, add timing infos to the log output to analyse load conditions"),
+
+    # some dangerous mimetypes (we don't use "content-disposition: inline" for them when a user
+    # downloads such attachments, because the browser might execute e.g. Javascript contained
+    # in the HTML and steal your moin session cookie or do other nasty stuff)
+    ('mimetypes_xss_protect',
+     [
+       'text/html',
+       'application/x-shockwave-flash',
+       'application/xhtml+xml',
+     ],
+     '"content-disposition: inline" isn\'t used for them when a user downloads such attachments'),
+
+    ('mimetypes_embed',
+     [
+       'application/x-dvi',
+       'application/postscript',
+       'application/pdf',
+       'application/ogg',
+       'application/vnd.visio',
+       'image/x-ms-bmp',
+       'image/svg+xml',
+       'image/tiff',
+       'image/x-photoshop',
+       'audio/mpeg',
+       'audio/midi',
+       'audio/x-wav',
+       'video/fli',
+       'video/mpeg',
+       'video/quicktime',
+       'video/x-msvideo',
+       'chemical/x-pdb',
+       'x-world/x-vrml',
+     ],
+     'mimetypes that can be embedded by the [[HelpOnMacros/EmbedObject|EmbedObject macro]]'),
+
+    ('refresh', None,
+     "refresh = (minimum_delay_s, targets_allowed) enables use of `#refresh 5 PageName` processing instruction, targets_allowed must be either `'internal'` or `'external'`"),
+    ('rss_cache', 60, "suggested caching time for Recent''''''Changes RSS, in second"),
+
+    ('search_results_per_page', 25, "Number of hits shown per page in the search results"),
+
+    ('siteid', 'default', None),
+  )),
+}
+
+#
+# The 'options' dict carries default MoinMoin options. The dict is a
+# group name to tuple mapping.
+# Each group tuple consists of the following items:
+#   group section heading, group help text, option list
+#
+# where each 'option list' is a tuple or list of option tuples
+#
+# each option tuple consists of
+#   option name, default value, help text
+#
+# All the help texts will be displayed by the WikiConfigHelp() macro.
+#
+# Unlike the options_no_group_name dict, option names in this dict
+# are automatically prefixed with "group name '_'" (i.e. the name of
+# the group they are in and an underscore), e.g. the 'hierarchic'
+# below creates an option called "acl_hierarchic".
+#
+# If you need to add a complex default expression that results in an
+# object and should not be shown in the __repr__ form in WikiConfigHelp(),
+# you can use the DefaultExpression class, see 'auth' above for example.
+#
+#
+options = {
+    'acl': ('Access control lists',
+    'ACLs control who may do what, see HelpOnAccessControlLists.',
+    (
+      ('hierarchic', False, 'True to use hierarchical ACLs'),
+      ('rights_default', u"Trusted:read,write,delete,revert Known:read,write,delete,revert All:read,write",
+       "ACL used if no ACL is specified on the page"),
+      ('rights_before', u"",
+       "ACL that is processed before the on-page/default ACL"),
+      ('rights_after', u"",
+       "ACL that is processed after the on-page/default ACL"),
+      ('rights_valid', ['read', 'write', 'delete', 'revert', 'admin'],
+       "Valid tokens for right sides of ACL entries."),
+    )),
+
+    'xapian': ('Xapian search', "Configuration of the Xapian based indexed search, see HelpOnXapian.", (
+      ('search', False,
+       "True to enable the fast, indexed search (based on the Xapian search library)"),
+      ('index_dir', None,
+       "Directory where the Xapian search index is stored (None = auto-configure wiki local storage)"),
+      ('stemming', False,
+       "True to enable Xapian word stemmer usage for indexing / searching."),
+      ('index_history', False,
+       "True to enable indexing of non-current page revisions."),
+    )),
+
+    'user': ('Users / User settings', None, (
+      ('email_unique', True,
+       "if True, check email addresses for uniqueness and don't accept duplicates."),
+      ('jid_unique', True,
+       "if True, check Jabber IDs for uniqueness and don't accept duplicates."),
+
+      ('homewiki', 'Self',
+       "interwiki name of the wiki where the user home pages are located (useful if you have ''many'' users). You could even link to nonwiki \"user pages\" if the wiki username is in the target URL."),
+
+      ('checkbox_fields',
+       [
+        ('mailto_author', lambda _: _('Publish my email (not my wiki homepage) in author info')),
+        ('edit_on_doubleclick', lambda _: _('Open editor on double click')),
+        ('remember_last_visit', lambda _: _('After login, jump to last visited page')),
+        ('show_comments', lambda _: _('Show comment sections')),
+        ('show_nonexist_qm', lambda _: _('Show question mark for non-existing pagelinks')),
+        ('show_page_trail', lambda _: _('Show page trail')),
+        ('show_toolbar', lambda _: _('Show icon toolbar')),
+        ('show_topbottom', lambda _: _('Show top/bottom links in headings')),
+        ('show_fancy_diff', lambda _: _('Show fancy diffs')),
+        ('wikiname_add_spaces', lambda _: _('Add spaces to displayed wiki names')),
+        ('remember_me', lambda _: _('Remember login information')),
+
+        ('disabled', lambda _: _('Disable this account forever')),
+        # if an account is disabled, it may be used for looking up
+        # id -> username for page info and recent changes, but it
+        # is not usable for the user any more:
+       ],
+       "Describes user preferences, see /UserPreferences."),
+
+      ('checkbox_defaults',
+       {
+        'mailto_author': 0,
+        'edit_on_doubleclick': 0,
+        'remember_last_visit': 0,
+        'show_comments': 0,
+        'show_nonexist_qm': False,
+        'show_page_trail': 1,
+        'show_toolbar': 1,
+        'show_topbottom': 0,
+        'show_fancy_diff': 1,
+        'wikiname_add_spaces': 0,
+        'remember_me': 1,
+       },
+       "Defaults for user preferences, see /UserPreferences."),
+
+      ('checkbox_disable', [],
+       "Disable user preferences, see /UserPreferences."),
+
+      ('checkbox_remove', [],
+       "Remove user preferences, see /UserPreferences."),
+
+      ('form_fields',
+       [
+        ('name', _('Name'), "text", "36", _("(Use FirstnameLastname)")),
+        ('aliasname', _('Alias-Name'), "text", "36", ''),
+        ('email', _('Email'), "text", "36", ''),
+        ('jid', _('Jabber ID'), "text", "36", ''),
+        ('css_url', _('User CSS URL'), "text", "40", _('(Leave it empty for disabling user CSS)')),
+        ('edit_rows', _('Editor size'), "text", "3", ''),
+       ],
+       None),
+
+      ('form_defaults',
+       {# key: default - do NOT remove keys from here!
+        'name': '',
+        'aliasname': '',
+        'password': '',
+        'password2': '',
+        'email': '',
+        'jid': '',
+        'css_url': '',
+        'edit_rows': "20",
+       },
+       None),
+
+      ('form_disable', [], "list of field names used to disable user preferences form fields"),
+
+      ('form_remove', [], "list of field names used to remove user preferences form fields"),
+
+      ('transient_fields',
+       ['id', 'valid', 'may', 'auth_username', 'password', 'password2', 'auth_method', 'auth_attribs', ],
+       "User object attributes that are not persisted to permanent storage (internal use)."),
+    )),
+
+    'openid_server': ('OpenID Server',
+        'These settings control the built-in OpenID Identity Provider (server).',
+    (
+      ('enabled', False, "True to enable the built-in OpenID server."),
+      ('restricted_users_group', None, "If set to a group name, the group members are allowed to use the wiki as an OpenID provider. (None = allow for all users)"),
+      ('enable_user', False, "If True, the OpenIDUser processing instruction is allowed."),
+    )),
+
+    'mail': ('Mail settings',
+        'These settings control outgoing and incoming email from and to the wiki.',
+    (
+      ('from', None, "Used as From: address for generated mail."),
+      ('login', None, "'username userpass' for SMTP server authentication (None = don't use auth)."),
+      ('smarthost', None, "Address of SMTP server to use for sending mail (None = don't use SMTP server)."),
+      ('sendmail', None, "sendmail command to use for sending mail (None = don't use sendmail)"),
+
+      ('import_subpage_template', u"$from-$date-$subject", "Create subpages using this template when importing mail."),
+      ('import_pagename_search', ['subject', 'to', ], "Where to look for target pagename specification."),
+      ('import_pagename_envelope', u"%s", "Use this to add some fixed prefix/postfix to the generated target pagename."),
+      ('import_pagename_regex', r'\[\[([^\]]*)\]\]', "Regular expression used to search for target pagename specification."),
+      ('import_wiki_addrs', [], "Target mail addresses to consider when importing mail"),
+    )),
+
+    'backup': ('Backup settings',
+        'These settings control how the backup action works and who is allowed to use it.',
+    (
+      ('compression', 'gz', 'What compression to use for the backup ("gz" or "bz2").'),
+      ('users', [], 'List of trusted user names who are allowed to get a backup.'),
+      ('include', [], 'List of pathes to backup.'),
+      ('exclude', lambda filename: False, 'Function f(filename) that tells whether a file should be excluded from backup. By default, nothing is excluded.'),
+    )),
+}
+
+def _add_options_to_defconfig(opts, addgroup=True):
+    for groupname in opts:
+        group_short, group_doc, group_opts = opts[groupname]
+        for name, default, doc in group_opts:
+            if addgroup:
+                name = groupname + '_' + name
+            if isinstance(default, DefaultExpression):
+                default = default.value
+            setattr(DefaultConfig, name, default)
+
+_add_options_to_defconfig(options)
+_add_options_to_defconfig(options_no_group_name, False)
+
 # remove the gettext pseudo function
 del _
 
--- a/MoinMoin/conftest.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/conftest.py	Sat Dec 13 19:27:41 2008 +0100
@@ -12,34 +12,28 @@
 classes by the framework.
 
 Tests that require a certain configuration, like section_numbers = 1, must
-use a TestConfig to create the required configuration before the test.
-Deleting the TestConfig instance will restore the previous configuration.
+use a Config class to define the required configuration within the test class.
 
-@copyright: 2005 Nir Soffer, 2007 Alexander Schremmer
+@copyright: 2005 MoinMoin:NirSoffer,
+            2007 MoinMoin:AlexanderSchremmer,
+            2008 MoinMoin:ThomasWaldmann
 @license: GNU GPL, see COPYING for details.
 """
 
 import atexit
-from sys import modules
 import sys
 
 import py
 
-
 rootdir = py.magic.autopath().dirpath()
 moindir = rootdir.join("..")
-
 sys.path.insert(0, str(moindir))
-from MoinMoin._tests import maketestwiki, compat
-modules["unittest"] = compat # evil hack
-
-wikiconfig_dir = str(moindir.join("tests"))
 
 from MoinMoin.support.python_compatibility import set
+from MoinMoin._tests import maketestwiki, wikiconfig
 
 coverage_modules = set()
 
-
 try:
     """
     This code adds support for coverage.py (see
@@ -52,7 +46,7 @@
 
     def report_coverage():
         coverage.stop()
-        module_list = [modules[mod] for mod in coverage_modules]
+        module_list = [sys.modules[mod] for mod in coverage_modules]
         module_list.sort()
         coverage.report(module_list)
 
@@ -70,17 +64,14 @@
     coverage = None
 
 
-def init_test_request(static_state=[False]):
+def init_test_request(given_config=None, static_state=[False]):
     from MoinMoin.request import request_cli
     from MoinMoin.user import User
     from MoinMoin.formatter.text_html import Formatter as HtmlFormatter
     if not static_state[0]:
         maketestwiki.run(True)
         static_state[0] = True
-    if sys.path[0] != wikiconfig_dir:
-        sys.path.insert(0, wikiconfig_dir) # this is a race with py.test's collectors
-                                           # because they modify sys.path as well
-    request = request_cli.Request()
+    request = request_cli.Request(given_config=given_config)
     request.form = request.args = request.setup_args()
     request.user = User(request)
     request.html_formatter = HtmlFormatter(request)
@@ -88,84 +79,6 @@
     return request
 
 
-class TestConfig:
-    """ Custom configuration for unit tests
-
-    Some tests assume a specific configuration, and will fail if the wiki admin
-    changed the configuration. For example, DateTime macro test assume
-    the default datetime_fmt.
-
-    When you set custom values in a TestConfig, the previous values are saved,
-    and when the TestConfig is called specifically, they are restored automatically.
-
-    Typical Usage
-    -------------
-    ::
-        class SomeTest:
-            def setUp(self):
-                self.config = self.TestConfig(defaults=key_list, key=value,...)
-            def tearDown(self):
-                self.config.restore()
-            def testSomething(self):
-                # test that needs those defaults and custom values
-    """
-
-    def __init__(self, request):
-        """ Create temporary configuration for a test
-
-        @param request: current request
-        """
-        self.request = request
-        self.old = {}  # Old config values
-        self.new = []  # New added attributes
-
-    def __call__(self, defaults=(), **custom):
-        """ Initialise a temporary configuration for a test
-
-        @param defaults: list of keys that should use the default value
-        @param custom: other keys using non default values, or new keys
-               that request.cfg does not have already
-        """
-        self.setDefaults(defaults)
-        self.setCustom(**custom)
-
-        return self
-
-    def setDefaults(self, defaults=()):
-        """ Set default values for keys in defaults list
-
-        Non existing default will raise an AttributeError.
-        """
-        from MoinMoin.config import multiconfig
-        for key in defaults:
-            self._setattr(key, getattr(multiconfig.DefaultConfig, key))
-
-    def setCustom(self, **custom):
-        """ Set custom values """
-        for key, value in custom.items():
-            self._setattr(key, value)
-
-    def _setattr(self, key, value):
-        """ Set a new value for key saving new added keys """
-        if hasattr(self.request.cfg, key):
-            self.old[key] = getattr(self.request.cfg, key)
-        else:
-            self.new.append(key)
-        setattr(self.request.cfg, key, value)
-
-    def restore(self):
-        """ Restore previous request.cfg
-
-        Set old keys to old values and delete new keys.
-        """
-        for key, value in self.old.items():
-            setattr(self.request.cfg, key, value)
-        for key in self.new:
-            delattr(self.request.cfg, key)
-    __del__ = restore # XXX __del__ semantics are currently broken
-
-
-
 # py.test customization starts here
 
 class MoinTestFunction(py.test.collect.Function):
@@ -183,8 +96,10 @@
 
     def setup(self):
         cls = self.obj
-        cls.request = self.parent.request
-        cls.TestConfig = TestConfig(cls.request)
+        if hasattr(cls, 'Config'):
+            cls.request = init_test_request(given_config=cls.Config)
+        else:
+            cls.request = self.parent.request
         super(MoinClassCollector, self).setup()
 
 
@@ -193,7 +108,7 @@
     Function = MoinTestFunction
 
     def __init__(self, *args, **kwargs):
-        self.request = init_test_request()
+        self.request = init_test_request(given_config=wikiconfig.Config)
         super(Module, self).__init__(*args, **kwargs)
 
     def run(self, *args, **kwargs):
--- a/MoinMoin/converter/_tests/test_text_html_text_moin_wiki.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/converter/_tests/test_text_html_text_moin_wiki.py	Sat Dec 13 19:27:41 2008 +0100
@@ -23,12 +23,6 @@
 
 class TestBase(object):
 
-    def setup_method(self, method):
-        self.cfg = self.TestConfig(bang_meta=True)
-
-    def teardown_method(self, method):
-        del self.cfg
-
     def do_convert_real(self, func_args, successful=True):
         try:
             ret = convert(*func_args)
@@ -788,6 +782,67 @@
 """
         self.do(test, output)
 
+    def testPreSuccess10(self):
+        test = ur"""
+ * {{{{
+{{{
+test
+}}}
+}}}}
+
+"""
+        output = ur"""
+<ul>
+<li>
+<pre>
+{{{
+test
+}}}
+</pre>
+</li>
+</ul>
+"""
+
+    def testPreSuccess11(self):
+        test = ur"""
+ * {{{{
+test
+}}}
+}}}}
+
+"""
+        output = ur"""
+<ul>
+<li>
+<pre>
+test
+}}}
+</pre>
+</li>
+</ul>
+"""
+
+    def testPreSuccess12(self):
+        test = ur"""
+ * {{{{
+{{{
+test
+}}}}
+
+"""
+        output = ur"""
+<ul>
+<li>
+<pre>
+{{{
+test
+</pre>
+</li>
+</ul>
+"""
+
+        self.do(test, output)
+
     def testRule1(self):
         py.test.skip('broken test')
         test = ur"""
--- a/MoinMoin/converter/text_html_text_moin_wiki.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/converter/text_html_text_moin_wiki.py	Sat Dec 13 19:27:41 2008 +0100
@@ -13,6 +13,9 @@
 from MoinMoin import config, wikiutil
 from MoinMoin.error import ConvertError
 
+from MoinMoin.parser.text_moin_wiki import Parser as WikiParser
+interwiki_re = re.compile(WikiParser.interwiki_rule, re.VERBOSE|re.UNICODE)
+
 # Portions (C) International Organization for Standardization 1986
 # Permission to copy in any form is granted for use with
 # conforming SGML systems and applications as defined in
@@ -571,7 +574,7 @@
     def process_heading(self, node):
         text = self.node_list_text_only(node.childNodes).strip()
         if text:
-            depth = int(node.localName[1]) - 1
+            depth = int(node.localName[1])
             hstr = "=" * depth
             self.text.append(self.new_line)
             self.text.append("%s %s %s" % (hstr, text.replace("\n", " "), hstr))
@@ -606,6 +609,11 @@
             style = listitem.getAttribute("style")
             if re.match(ur"list-style-type:\s*none", style, re.I):
                 markup = ". "
+                # set markup with white space when list element containes table
+                for i in listitem.childNodes:
+                    if i.nodeType == Node.ELEMENT_NODE:
+                        if i.localName == 'table':
+                            markup = " "
             else:
                 markup = "* "
         elif name == 'dl':
@@ -661,7 +669,10 @@
             self.text.append(indent)
         for i in nodelist:
             if i.nodeType == Node.ELEMENT_NODE:
-                self.process_inline(i)
+                if i.localName == 'br':
+                    self.text.append('<<BR>>')
+                else:
+                    self.process_inline(i)
             elif i.nodeType == Node.TEXT_NODE:
                 self.text.append(i.data.strip('\n').replace('\n', ' '))
         self.text.append(self.new_line)
@@ -700,6 +711,8 @@
                     self.text.append(indent)
                 self.process_table(i)
                 found = True
+            elif name == 'br':
+                pending.append(i)
             else:
                 pending.append(i)
 
@@ -792,7 +805,8 @@
             command = ",,"
         elif name == 'sup':
             command = "^"
-        elif name in ('font', 'meta', ):
+        elif name in ('area', 'center', 'code', 'embed', 'fieldset', 'font', 'form', 'iframe', 'input', 'label', 'link', 'map',
+                      'meta', 'noscript', 'option', 'script', 'select', 'textarea', 'wbr'):
             command = "" # just throw away unsupported elements
         else:
             raise ConvertError("process_inline: Don't support %s element" % name)
@@ -815,16 +829,48 @@
         self.text.append(command)
 
     def process_span(self, node):
-        # ignore span tags - just descend
+        # process span tag for firefox3
+        node_style = node.getAttribute("style")
+
         is_strike = node.getAttribute("class") == "strike"
+        is_strike = is_strike or "line-through" in node_style
+        is_strong = "bold" in node_style
+        is_italic = "italic" in node_style
+        is_underline = "underline" in node_style
+        is_comment = node.getAttribute("class") == "comment"
+
+        # start tag
+        if is_comment:
+            self.text.append("/* ")
         if is_strike:
             self.text.append("--(")
+        if is_strong:
+            self.text.append("'''")
+        if is_italic:
+            self.text.append("''")
+        if is_underline:
+            self.text.append("__")
+
+        # body
         for i in node.childNodes:
             self.process_inline(i)
+
+        # end tag
+        if is_underline:
+            self.text.append("__")
+        if is_italic:
+            self.text.append("''")
+        if is_strong:
+            self.text.append("'''")
         if is_strike:
             self.text.append(")--")
+        if is_comment:
+            self.text.append(" */")
 
     def process_div(self, node):
+        # process indent
+        self._process_indent(node)
+
         # ignore div tags - just descend
         for i in node.childNodes:
             self.visit(i)
@@ -848,9 +894,21 @@
         self.text.extend([self.new_line, "-" * length, self.new_line])
 
     def process_p(self, node):
+        # process indent
+        self._process_indent(node)
         self.process_paragraph_item(node)
         self.text.append("\n\n") # do not use self.new_line here!
 
+    def _process_indent(self, node):
+        # process indent
+        node_style = node.getAttribute("style")
+        match = re.match(r"margin-left:\s*(\d+)px", node_style)
+        if match:
+            left_margin = int(match.group(1))
+            indent_depth = int(left_margin / 40)
+            if indent_depth > 0:
+                self.text.append(' . ')
+
     def process_paragraph_item(self, node):
         for i in node.childNodes:
             if i.nodeType == Node.ELEMENT_NODE:
@@ -870,25 +928,59 @@
         if class_ == "comment": # we currently use this for stuff like ## or #acl
             for i in node.childNodes:
                 if i.nodeType == Node.TEXT_NODE:
-                    self.text.append(i.data)
-                    #print "'%s'" % i.data
+                    self.text.append(i.data.replace('\n', ''))
                 elif i.localName == 'br':
                     self.text.append(self.new_line)
                 else:
                     pass
-                    #print i.localName
         else:
-            self.text.extend(["{{{", self.new_line])
+            content_buffer = []
+            longest_inner_formater = ''
+            bang_args = ''
+            delimiters = []
+
+            """
+            below code fixed for MoinMoinBugs/GuiEditorCantNest bug
+            this has problem when outer delimiter has two more { than inside one
+            e.g. {{{{{{ {{{ foo }}} }}}}}}  --> {{{{ {{{ foo }}} }}}}
+                   {{{foo {{{ }}} foo}}} --> {{{{ {{{ }}} }}}}
+            """
+
             for i in node.childNodes:
                 if i.nodeType == Node.TEXT_NODE:
-                    self.text.append(i.data)
-                    #print "'%s'" % i.data
+                    # get longest pre tag({{{ or }}}) from content
+                    delimiters.extend(re.compile("((?u){+)").findall(i.data))
+                    delimiters.extend(re.compile("((?u)}+)").findall(i.data))
+                    # when first line is empty, start iteration second line of i.data
+                    data_lines = i.data.rstrip().split('\n')
+                    if data_lines[0].strip() == '':
+                        data_lines = data_lines[1:]
+                    for line in data_lines:
+                        if line.strip().startswith('#!'):
+                            if bang_args == '':
+                                bang_args = line.strip()
+                            else:
+                                content_buffer.extend([line, self.new_line])
+                        else:
+                            content_buffer.extend([line, self.new_line])
                 elif i.localName == 'br':
-                    self.text.append(self.new_line_dont_remove)
+                    content_buffer.append(self.new_line_dont_remove)
                 else:
                     pass
-                    #print i.localName
-            self.text.extend(["}}}", self.new_line])
+
+            if delimiters:
+                longest_inner_formater = max(delimiters)
+
+            if (len(longest_inner_formater) >= 3):
+                self.text.extend([("{" * (len(longest_inner_formater) + 1)) + bang_args, \
+                                      self.new_line])
+                self.text.extend(content_buffer)
+                self.text.extend(["}" * (len(longest_inner_formater) + 1), \
+                                      self.new_line])
+            else:
+                self.text.extend(["{{{"+bang_args, self.new_line])
+                self.text.extend(content_buffer)
+                self.text.extend(["}}}", self.new_line])
 
     _alignment = {"left": "(",
                   "center": ":",
@@ -903,19 +995,26 @@
         except ValueError:
             return value
 
-    def _table_style(self, node):
-        # TODO: attrs = get_attrs(node)
-        result = []
+    def _get_color(self, node, prefix):
         if node.hasAttribute("bgcolor"):
             value = node.getAttribute("bgcolor")
             match = re.match(r"rgb\((\d+),\s*(\d+),\s*(\d+)\)", value)
             if match:
-                result.append('tablebgcolor="#%X%X%X"' %
-                              (int(match.group(1)),
-                               int(match.group(2)),
-                               int(match.group(3))))
+                value = '#%X%X%X' % (int(match.group(1)), int(match.group(2)), int(match.group(3)))
             else:
-                result.append('tablebgcolor="%s"' % value)
+                match = re.match(r"#[0-9A-Fa-f]{6}", value)
+            if not prefix and match:
+                result = value
+            else:
+                result = '%sbgcolor="%s"' % (prefix, value)
+        else:
+            result = ''
+        return result
+
+    def _table_style(self, node):
+        # TODO: attrs = get_attrs(node)
+        result = []
+        result.append(self._get_color(node, 'table'))
         if node.hasAttribute("width"):
             value = node.getAttribute("width")
             result.append('tablewidth="%s"' % self._check_length(value))
@@ -934,16 +1033,7 @@
     def _row_style(self, node):
         # TODO: attrs = get_attrs(node)
         result = []
-        if node.hasAttribute("bgcolor"):
-            value = node.getAttribute("bgcolor")
-            match = re.match(r"rgb\((\d+),\s*(\d+),\s*(\d+)\)", value)
-            if match:
-                result.append('rowbgcolor="#%X%X%X"' %
-                              (int(match.group(1)),
-                               int(match.group(2)),
-                               int(match.group(3))))
-            else:
-                result.append('rowbgcolor="%s"' % value)
+        result.append(self._get_color(node, 'row'))
         if node.hasAttribute("style"):
             result.append('rowstyle="%s"' % node.getAttribute("style"))
         if node.hasAttribute("class"):
@@ -966,15 +1056,7 @@
 
         align = ""
         result = []
-        if  node.hasAttribute("bgcolor"):
-            value = node.getAttribute("bgcolor")
-            match = re.match(r"rgb\((\d+),\s*(\d+),\s*(\d+)\)", value)
-            if match:
-                result.append("#%X%X%X" % (int(match.group(1)),
-                                           int(match.group(2)),
-                                           int(match.group(3))))
-            else:
-                result.append('bgcolor="%s"' % value)
+        result.append(self._get_color(node, ''))
         if node.hasAttribute("align"):
             value = node.getAttribute("align")
             if not spanning or value != "center":
@@ -1007,7 +1089,8 @@
         return " ".join(result).strip()
 
     def process_table(self, node, style=""):
-        self.text.append(self.new_line)
+        if self.depth == 0:
+            self.text.append(self.new_line)
         self.new_table = True
         style += self._table_style(node)
         for i in node.childNodes:
@@ -1055,7 +1138,9 @@
             colspan = 1
         text = self.node_list_text_only(node.childNodes).replace('\n', ' ').strip()
         if text:
-            self.text.extend(["%s'''%s%s'''||" % ('||' * colspan, style, text), self.new_line_dont_remove])
+            if style:
+                style = '<%s>' % style
+            self.text.extend(["%s%s'''%s'''||" % ('||' * colspan, style, text), self.new_line_dont_remove])
 
     def process_table_data(self, node, style=""):
         if node.hasAttribute("colspan"):
@@ -1106,7 +1191,7 @@
         for i in node.childNodes:
             if i.nodeType == Node.ELEMENT_NODE:
                 name = i.localName
-                if name == 'td':
+                if name in ('td', 'th', ):
                     self.process_table_data(i, style=style)
                     style = ""
                 else:
@@ -1147,10 +1232,11 @@
                 pagename = wikiutil.url_unquote(href)
                 interwikiname = "%s:%s" % (title, pagename)
             if interwikiname and pagename == desc:
-                if ' ' in interwikiname:
+                if interwiki_re.match(interwikiname+' '): # the blank is needed by interwiki_re to match
+                    # this is valid as a free interwiki link
+                    self.text.append("%s" % interwikiname)
+                else:
                     self.text.append("[[%s]]" % interwikiname)
-                else:
-                    self.text.append("%s" % interwikiname)
                 return
             elif title == 'Self':
                 self.text.append('[[%s|%s]]' % (href, desc))
@@ -1168,10 +1254,17 @@
             # Attachments
             if title.startswith("attachment:"):
                 attname = wikiutil.url_unquote(title[len("attachment:"):])
+                if 'do=get' in href: # quick&dirty fix for not dropping &do=get param
+                    parms = '|&do=get'
+                else:
+                    parms = ''
                 if attname != desc:
-                    self.text.append('[[attachment:%s|%s]]' % (attname, desc))
+                    desc = '|%s' % desc
+                elif parms:
+                    desc = '|'
                 else:
-                    self.text.append('[[attachment:%s]]' % (attname, ))
+                    desc = ''
+                self.text.append('[[attachment:%s%s%s]]' % (attname, desc, parms))
             # wiki link
             elif href.startswith(scriptname):
                 pagename = href[len(scriptname):]
@@ -1187,6 +1280,9 @@
                 # relative link ../
                 elif desc.startswith('../') and href.endswith(desc[3:]):
                     self.text.append(wikiutil.pagelinkmarkup(desc))
+                # internal link #internal
+                elif '#' in href and pagename.startswith(self.pagename):
+                    self.text.append(wikiutil.pagelinkmarkup(href[href.index('#'):], desc))
                 # labeled link
                 else:
                     self.text.append(wikiutil.pagelinkmarkup(pagename, desc))
@@ -1287,7 +1383,16 @@
     """ get the attributes of <node> into an easy-to-use dict """
     attrs = {}
     for attr_name in node.attributes.keys():
-        attrs[attr_name] = node.attributes.get(attr_name).nodeValue
+        # get attributes of style element
+        if attr_name == "style":
+            for style_element in node.attributes.get(attr_name).nodeValue.split(';'):
+                if style_element.strip() != '':
+                    style_elements = style_element.split(':')
+                    if len(style_elements) == 2:
+                        attrs[style_elements[0].strip()] = style_elements[1].strip()
+        # get attributes without style element
+        else:
+            attrs[attr_name] = node.attributes.get(attr_name).nodeValue
     return attrs
 
 
--- a/MoinMoin/events/_tests/test_events.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/events/_tests/test_events.py	Sat Dec 13 19:27:41 2008 +0100
@@ -59,7 +59,7 @@
 
     event = events.UserCreatedEvent(request, User(request))
     request.cfg.notification_server = server_dummy()
-    request.cfg.secret = "dummy"
+    request.cfg.secrets = "thisisnotsecret"
 
     jabbernotify.handle_user_created(event)
     assert request.cfg.notification_server.sent is True
--- a/MoinMoin/events/jabbernotify.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/events/jabbernotify.py	Sat Dec 13 19:27:41 2008 +0100
@@ -50,11 +50,12 @@
 
     request = event.request
     server = request.cfg.notification_server
+    secret = request.cfg.secrets['jabberbot']
     try:
         if isinstance(event, ev.JabberIDSetEvent):
-            server.addJIDToRoster(request.cfg.secret, event.jid)
+            server.addJIDToRoster(secret, event.jid)
         else:
-            server.removeJIDFromRoster(request.cfg.secret, event.jid)
+            server.removeJIDFromRoster(secret, event.jid)
     except xmlrpclib.Error, err:
         logging.error("XML RPC error: %s" % str(err))
     except Exception, err:
@@ -197,7 +198,7 @@
         raise ValueError("url_list must be of type list!")
 
     try:
-        server.send_notification(request.cfg.secret, jids, notification)
+        server.send_notification(request.cfg.secrets['jabberbot'], jids, notification)
         return True
     except xmlrpclib.Error, err:
         logging.error("XML RPC error: %s" % str(err))
--- a/MoinMoin/events/notification.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/events/notification.py	Sat Dec 13 19:27:41 2008 +0100
@@ -128,12 +128,13 @@
     @return: a dict containing message body and subject
     """
     subject = _("New user account created on %(sitename)s") % {'sitename': sitename or "Wiki"}
-    text = _("""Dear Superuser, a new user has just been created. Details follow:
+    text = _("""Dear Superuser, a new user has just been created on %(sitename)s". Details follow:
 
     User name: %(username)s
     Email address: %(useremail)s""") % {
          'username': username,
          'useremail': email,
+         'sitename': sitename or "Wiki",
          }
 
     return {'subject': subject, 'text': text}
--- a/MoinMoin/failure.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/failure.py	Sat Dec 13 19:27:41 2008 +0100
@@ -7,13 +7,13 @@
     @license: GNU GPL, see COPYING for details.
 """
 import sys, os
+import traceback
 
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
 from MoinMoin.support import cgitb
 from MoinMoin.error import ConfigurationError
-from traceback import extract_tb
 
 
 class View(cgitb.View):
@@ -69,7 +69,7 @@
         text = [self.formatExceptionMessage(self.info)]
 
         if self.info[0] == ConfigurationError:
-            tbt = extract_tb(self.info[1].exceptions()[-1][2])[-1]
+            tbt = traceback.extract_tb(self.info[1].exceptions()[-1][2])[-1]
             text.append(
                 f.paragraph('Error in your configuration file "%s"'
                             ' around line %d.' % tbt[:2]))
@@ -156,33 +156,44 @@
         raise err
 
     savedError = sys.exc_info()
-    logging.exception('An exception occured.')
+    logging.exception('An exception occurred, URI was "%s".' % request.request_uri)
+
     try:
-        debug = 'debug' in getattr(request, 'form', {})
+        display = request.cfg.traceback_show # might fail if we have no cfg yet
+    except:
         # default to True here to allow an admin setting up the wiki
         # to see the errors made in the configuration file
         display = True
-        logdir = None
-        if hasattr(request, 'cfg'):
-            display = request.cfg.traceback_show
-            logdir = request.cfg.traceback_log_dir
-        handler = cgitb.Hook(file=request, display=display, logdir=logdir,
-                             viewClass=View, debug=debug)
-        handler.handle()
+
+    try:
+        debug = 'debug' in request.form
     except:
+        debug = False
+
+    try:
+        # try to output a nice html error page
+        handler = cgitb.Hook(file=request, display=display, viewClass=View, debug=debug)
+        handler.handle(savedError)
+    except:
+        # if that fails, log the cgitb problem ...
+        logging.exception('cgitb raised this exception')
+        # ... and try again with a simpler output method:
         request.write('<pre>\n')
-        printTextException(request, savedError)
+        printTextException(request, savedError, display)
         request.write('\nAdditionally cgitb raised this exception:\n')
-        printTextException(request)
+        printTextException(request, display=display)
         request.write('</pre>\n')
 
 
-def printTextException(request, info=None):
+
+def printTextException(request, info=None, display=True):
     """ Simple text exception that should never fail
 
     Print all exceptions in a composite error.
     """
-    import traceback
+    if not display:
+        request.write("(Traceback display forbidden by configuration)\n")
+        return
     from MoinMoin import wikiutil
     if info is None:
         info = sys.exc_info()
--- a/MoinMoin/formatter/text_gedit.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/formatter/text_gedit.py	Sat Dec 13 19:27:41 2008 +0100
@@ -25,7 +25,7 @@
             self._base_depth = depth
 
         count_depth = max(depth - (self._base_depth - 1), 1)
-        heading_depth = depth + 1
+        heading_depth = depth
 
         # closing tag, with empty line after, to make source more readable
         if not on:
@@ -68,10 +68,15 @@
             return '<span style="background-color:#ffff11">{{attachment:%s|%s}}</span>' % (url, text)
 
     def attachment_link(self, on, url=None, **kw):
+        assert on in (0, 1, False, True) # make sure we get called the new way, not like the 1.5 api was
         _ = self.request.getText
+        querystr = kw.get('querystr', {})
+        assert isinstance(querystr, dict) # new in 1.6, only support dicts
+        if 'do' not in querystr:
+            querystr['do'] = 'view'
         if on:
             pagename = self.page.page_name
-            target = AttachFile.getAttachUrl(pagename, url, self.request)
+            target = AttachFile.getAttachUrl(pagename, url, self.request, do=querystr['do'])
             return self.url(on, target, title="attachment:%s" % wikiutil.quoteWikinameURL(url))
         else:
             return self.url(on)
@@ -234,3 +239,9 @@
     def line_anchorlink(self, on, lineno=0):
         return '' # not needed for gui editor feeding
 
+    def span(self, on, **kw):
+        previous_state = self.request.user.show_comments
+        self.request.user.show_comments = True
+        ret = text_html.Formatter.span(self, on, **kw)
+        self.request.user.show_comments = previous_state
+        return ret
--- a/MoinMoin/formatter/text_html_percent.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/formatter/text_html_percent.py	Sat Dec 13 19:27:41 2008 +0100
@@ -17,7 +17,7 @@
 class Formatter(TextHtmlFormatter):
 
     def _open(self, tag, newline=False, attr=None, allowed_attrs=None, **kw):
-        """ Escape % signs in tags, see also text_html.Formatter._open. """
+        """ Escape % characters in tags, see also text_html.Formatter._open. """
         tagstr = TextHtmlFormatter._open(self, tag, newline, attr, allowed_attrs, **kw)
         return tagstr.replace('%', '%%')
 
--- a/MoinMoin/i18n/MoinMoin.pot	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/i18n/MoinMoin.pot	Sat Dec 13 19:27:41 2008 +0100
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-09-07 23:23+0200\n"
+"POT-Creation-Date: 2008-09-28 20:59+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -697,7 +697,8 @@
 
 #, python-format
 msgid ""
-"Dear Superuser, a new user has just been created. Details follow:\n"
+"Dear Superuser, a new user has just been created on %(sitename)s\". Details "
+"follow:\n"
 "\n"
 "    User name: %(username)s\n"
 "    Email address: %(useremail)s"
@@ -731,6 +732,24 @@
 msgid "Page changed"
 msgstr ""
 
+msgid ""
+" Emphasis:: <<Verbatim('')>>''italics''<<Verbatim('')>>; <<Verbatim(''')"
+">>'''bold'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''bold "
+"italics'''''<<Verbatim(''''')>>; <<Verbatim('')>>''mixed ''<<Verbatim(''')"
+">>'''''bold'''<<Verbatim(''')>> and italics''<<Verbatim('')>>; <<Verbatim"
+"(----)>> horizontal rule.\n"
+" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
+"===== Title 5 =====.\n"
+" Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1."
+"#n start numbering at n; space alone indents.\n"
+" Links:: <<Verbatim(JoinCapitalizedWords)>>; <<Verbatim([[target|linktext]])"
+">>.\n"
+" Tables:: || cell text |||| cell text spanning 2 columns ||;    no trailing "
+"white space allowed after tables or titles.\n"
+"\n"
+"(!) For more help, see HelpOnEditing or SyntaxReference.\n"
+msgstr ""
+
 #, python-format
 msgid "Expected \"%(wanted)s\" after \"%(key)s\", got \"%(token)s\""
 msgstr ""
@@ -761,6 +780,26 @@
 "Rendering of reStructured text is not possible, please install Docutils."
 msgstr ""
 
+msgid ""
+"{{{\n"
+"Emphasis: *italic* **bold** ``monospace``\n"
+"\n"
+"Headings: Heading 1  Heading 2  Heading 3\n"
+"          =========  ---------  ~~~~~~~~~\n"
+"\n"
+"Horizontal rule: ----\n"
+"\n"
+"Links: TrailingUnderscore_ `multi word with backticks`_ external_\n"
+"\n"
+".. _external: http://external-site.example.org/foo/\n"
+"\n"
+"Lists: * bullets; 1., a. numbered items.\n"
+"}}}\n"
+"(!) For more help, see the\n"
+"[[http://docutils.sourceforge.net/docs/user/rst/quickref.html|"
+"reStructuredText Quick Reference]].\n"
+msgstr ""
+
 msgid "**Maximum number of allowed includes exceeded**"
 msgstr ""
 
@@ -772,6 +811,23 @@
 msgid "**Could not find the referenced page: %s**"
 msgstr ""
 
+msgid ""
+" Emphasis:: <<Verbatim(//)>>''italics''<<Verbatim(//)>>; <<Verbatim(**)"
+">>'''bold'''<<Verbatim(**)>>; <<Verbatim(**//)>>'''''bold "
+"italics'''''<<Verbatim(//**)>>; <<Verbatim(//)>>''mixed ''<<Verbatim(**)"
+">>'''''bold'''<<Verbatim(**)>> and italics''<<Verbatim(//)>>;\n"
+" Horizontal Rule:: <<Verbatim(----)>>\n"
+" Force Linebreak:: <<Verbatim(\\\\)>>\n"
+" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
+"===== Title 5 =====.\n"
+" Lists:: * bullets; ** sub-bullets; # numbered items; ## numbered sub "
+"items.\n"
+" Links:: <<Verbatim([[target]])>>; <<Verbatim([[target|linktext]])>>.\n"
+" Tables:: |= header text | cell text | more cell text |;\n"
+"\n"
+"(!) For more help, see HelpOnEditing or HelpOnCreoleSyntax.\n"
+msgstr ""
+
 msgid "Preferences"
 msgstr ""
 
@@ -1162,43 +1218,27 @@
 "username, the recovery token and a new password (twice) below."
 msgstr ""
 
-#, python-format
-msgid ""
-"Restored Backup: %(filename)s to target dir: %(targetdir)s.\n"
-"Files: %(filecount)d, Directories: %(dircount)d"
-msgstr ""
-
-#, python-format
-msgid "Restoring backup: %(filename)s to target dir: %(targetdir)s failed."
-msgstr ""
-
-msgid "Wiki Backup / Restore"
+msgid "Wiki Backup"
 msgstr ""
 
 msgid ""
-"Some hints:\n"
-" * To restore a backup:\n"
-"  * Restoring a backup will overwrite existing data, so be careful.\n"
-"  * Rename it to <siteid>.tar.<compression> (remove the --date--time--UTC "
-"stuff).\n"
-"  * Put the backup file into the backup_storage_dir (use scp, ftp, ...).\n"
-"  * Hit the <<GetText(Restore)>> button below.\n"
+"= Downloading a backup =\n"
 "\n"
-" * To make a backup, just hit the <<GetText(Backup)>> button and save the "
-"file\n"
-"   you get to a secure place.\n"
+"Please note:\n"
+" * Store backups in a safe and secure place - they contain sensitive "
+"information.\n"
+" * Make sure your wiki configuration backup_* values are correct and "
+"complete.\n"
+" * Make sure the backup file you get contains everything you need in case of "
+"problems.\n"
+" * Make sure it is downloaded without problems.\n"
 "\n"
-"Please make sure your wiki configuration backup_* values are correct and "
-"complete.\n"
-"\n"
+"To get a backup, just click here:"
 msgstr ""
 
 msgid "Backup"
 msgstr ""
 
-msgid "Restore"
-msgstr ""
-
 msgid "You are not allowed to do remote backup."
 msgstr ""
 
@@ -2005,59 +2045,17 @@
 msgid "You need to be subscribed to unsubscribe."
 msgstr ""
 
-msgid ""
-" Emphasis:: <<Verbatim('')>>''italics''<<Verbatim('')>>; <<Verbatim(''')"
-">>'''bold'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''bold "
-"italics'''''<<Verbatim(''''')>>; <<Verbatim('')>>''mixed ''<<Verbatim(''')"
-">>'''''bold'''<<Verbatim(''')>> and italics''<<Verbatim('')>>; <<Verbatim"
-"(----)>> horizontal rule.\n"
-" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
-"===== Title 5 =====.\n"
-" Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1."
-"#n start numbering at n; space alone indents.\n"
-" Links:: <<Verbatim(JoinCapitalizedWords)>>; <<Verbatim([[target|linktext]])"
-">>.\n"
-" Tables:: || cell text |||| cell text spanning 2 columns ||;    no trailing "
-"white space allowed after tables or titles.\n"
-"\n"
-"(!) For more help, see HelpOnEditing or SyntaxReference.\n"
+msgid "Password is too short."
+msgstr ""
+
+msgid "Password has not enough different characters."
 msgstr ""
 
 msgid ""
-"{{{\n"
-"Emphasis: *italic* **bold** ``monospace``\n"
-"\n"
-"Headings: Heading 1  Heading 2  Heading 3\n"
-"          =========  ---------  ~~~~~~~~~\n"
-"\n"
-"Horizontal rule: ----\n"
-"\n"
-"Links: TrailingUnderscore_ `multi word with backticks`_ external_\n"
-"\n"
-".. _external: http://external-site.example.org/foo/\n"
-"\n"
-"Lists: * bullets; 1., a. numbered items.\n"
-"}}}\n"
-"(!) For more help, see the\n"
-"[[http://docutils.sourceforge.net/docs/user/rst/quickref.html|"
-"reStructuredText Quick Reference]].\n"
-msgstr ""
-
-msgid ""
-" Emphasis:: <<Verbatim(//)>>''italics''<<Verbatim(//)>>; <<Verbatim(**)"
-">>'''bold'''<<Verbatim(**)>>; <<Verbatim(**//)>>'''''bold "
-"italics'''''<<Verbatim(//**)>>; <<Verbatim(//)>>''mixed ''<<Verbatim(**)"
-">>'''''bold'''<<Verbatim(**)>> and italics''<<Verbatim(//)>>;\n"
-" Horizontal Rule:: <<Verbatim(----)>>\n"
-" Force Linebreak:: <<Verbatim(\\\\)>>\n"
-" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
-"===== Title 5 =====.\n"
-" Lists:: * bullets; ** sub-bullets; # numbered items; ## numbered sub "
-"items.\n"
-" Links:: <<Verbatim([[target]])>>; <<Verbatim([[target|linktext]])>>.\n"
-" Tables:: |= header text | cell text | more cell text |;\n"
-"\n"
-"(!) For more help, see HelpOnEditing or HelpOnCreoleSyntax.\n"
+"Password is too easy (password contains name or name contains password)."
+msgstr ""
+
+msgid "Password is too easy (keyboard sequence)."
 msgstr ""
 
 msgid "Diffs"
@@ -2295,6 +2293,15 @@
 msgid "User"
 msgstr ""
 
+msgid "[ATTACH]"
+msgstr ""
+
+msgid "Variable name"
+msgstr ""
+
+msgid "Description"
+msgstr ""
+
 #, python-format
 msgid "Upload new attachment \"%(filename)s\""
 msgstr ""
@@ -2335,6 +2342,19 @@
 msgid "Display"
 msgstr ""
 
+msgid "Wiki configuration"
+msgstr ""
+
+msgid ""
+"This table shows all settings in this wiki that do not have default values. "
+"Settings that the configuration system doesn't know about are shown in "
+"''italic'', those may be due to third-party extensions needing configuration "
+"or settings that were removed from Moin."
+msgstr ""
+
+msgid "Setting"
+msgstr ""
+
 msgid "Search for items"
 msgstr ""
 
--- a/MoinMoin/i18n/__init__.py	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/i18n/__init__.py	Sat Dec 13 19:27:41 2008 +0100
@@ -290,7 +290,7 @@
             # do not simply return trans with str, but recursively call
             # to get english translation, maybe formatted.
             # if we don't find an english "translation", we just format it
-            # on the fly (this is needed for cfg.editor_quickhelp).
+            # on the fly (this is needed for quickhelp).
             if lang != 'en':
                 logging.debug("falling back to english, requested string not in %r translation: %r" % (lang, original))
                 translated = getText(original, request, 'en', wiki=formatted, percent=percent)
--- a/MoinMoin/i18n/ar.MoinMoin.po	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/i18n/ar.MoinMoin.po	Sat Dec 13 19:27:41 2008 +0100
@@ -13,7 +13,7 @@
 msgstr ""
 "Project-Id-Version: moin 1.6\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-09-07 23:23+0200\n"
+"POT-Creation-Date: 2008-09-28 20:59+0200\n"
 "PO-Revision-Date: 2008-04-12 20:07+0200\n"
 "Last-Translator: Mohamed Yahya <yahya.mohamed@gmail.com>\n"
 "Language-Team: \n"
@@ -726,7 +726,8 @@
 
 #, python-format
 msgid ""
-"Dear Superuser, a new user has just been created. Details follow:\n"
+"Dear Superuser, a new user has just been created on %(sitename)s\". Details "
+"follow:\n"
 "\n"
 "    User name: %(username)s\n"
 "    Email address: %(useremail)s"
@@ -764,6 +765,24 @@
 msgid "Page changed"
 msgstr "إحفظ التغييرات"
 
+msgid ""
+" Emphasis:: <<Verbatim('')>>''italics''<<Verbatim('')>>; <<Verbatim(''')"
+">>'''bold'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''bold "
+"italics'''''<<Verbatim(''''')>>; <<Verbatim('')>>''mixed ''<<Verbatim(''')"
+">>'''''bold'''<<Verbatim(''')>> and italics''<<Verbatim('')>>; <<Verbatim"
+"(----)>> horizontal rule.\n"
+" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
+"===== Title 5 =====.\n"
+" Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1."
+"#n start numbering at n; space alone indents.\n"
+" Links:: <<Verbatim(JoinCapitalizedWords)>>; <<Verbatim([[target|linktext]])"
+">>.\n"
+" Tables:: || cell text |||| cell text spanning 2 columns ||;    no trailing "
+"white space allowed after tables or titles.\n"
+"\n"
+"(!) For more help, see HelpOnEditing or SyntaxReference.\n"
+msgstr ""
+
 #, python-format
 msgid "Expected \"%(wanted)s\" after \"%(key)s\", got \"%(token)s\""
 msgstr ""
@@ -794,6 +813,26 @@
 "Rendering of reStructured text is not possible, please install Docutils."
 msgstr ""
 
+msgid ""
+"{{{\n"
+"Emphasis: *italic* **bold** ``monospace``\n"
+"\n"
+"Headings: Heading 1  Heading 2  Heading 3\n"
+"          =========  ---------  ~~~~~~~~~\n"
+"\n"
+"Horizontal rule: ----\n"
+"\n"
+"Links: TrailingUnderscore_ `multi word with backticks`_ external_\n"
+"\n"
+".. _external: http://external-site.example.org/foo/\n"
+"\n"
+"Lists: * bullets; 1., a. numbered items.\n"
+"}}}\n"
+"(!) For more help, see the\n"
+"[[http://docutils.sourceforge.net/docs/user/rst/quickref.html|"
+"reStructuredText Quick Reference]].\n"
+msgstr ""
+
 msgid "**Maximum number of allowed includes exceeded**"
 msgstr ""
 
@@ -805,6 +844,23 @@
 msgid "**Could not find the referenced page: %s**"
 msgstr ""
 
+msgid ""
+" Emphasis:: <<Verbatim(//)>>''italics''<<Verbatim(//)>>; <<Verbatim(**)"
+">>'''bold'''<<Verbatim(**)>>; <<Verbatim(**//)>>'''''bold "
+"italics'''''<<Verbatim(//**)>>; <<Verbatim(//)>>''mixed ''<<Verbatim(**)"
+">>'''''bold'''<<Verbatim(**)>> and italics''<<Verbatim(//)>>;\n"
+" Horizontal Rule:: <<Verbatim(----)>>\n"
+" Force Linebreak:: <<Verbatim(\\\\)>>\n"
+" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
+"===== Title 5 =====.\n"
+" Lists:: * bullets; ** sub-bullets; # numbered items; ## numbered sub "
+"items.\n"
+" Links:: <<Verbatim([[target]])>>; <<Verbatim([[target|linktext]])>>.\n"
+" Tables:: |= header text | cell text | more cell text |;\n"
+"\n"
+"(!) For more help, see HelpOnEditing or HelpOnCreoleSyntax.\n"
+msgstr ""
+
 msgid "Preferences"
 msgstr "التفضيلات"
 
@@ -1223,43 +1279,28 @@
 "username, the recovery token and a new password (twice) below."
 msgstr ""
 
-#, python-format
-msgid ""
-"Restored Backup: %(filename)s to target dir: %(targetdir)s.\n"
-"Files: %(filecount)d, Directories: %(dircount)d"
-msgstr ""
-
-#, python-format
-msgid "Restoring backup: %(filename)s to target dir: %(targetdir)s failed."
-msgstr ""
-
-msgid "Wiki Backup / Restore"
-msgstr "نسخ إحتياطي / إستعادة ويكي"
+#, fuzzy
+msgid "Wiki Backup"
+msgstr "نسخ احتياطي"
 
 msgid ""
-"Some hints:\n"
-" * To restore a backup:\n"
-"  * Restoring a backup will overwrite existing data, so be careful.\n"
-"  * Rename it to <siteid>.tar.<compression> (remove the --date--time--UTC "
-"stuff).\n"
-"  * Put the backup file into the backup_storage_dir (use scp, ftp, ...).\n"
-"  * Hit the <<GetText(Restore)>> button below.\n"
+"= Downloading a backup =\n"
 "\n"
-" * To make a backup, just hit the <<GetText(Backup)>> button and save the "
-"file\n"
-"   you get to a secure place.\n"
+"Please note:\n"
+" * Store backups in a safe and secure place - they contain sensitive "
+"information.\n"
+" * Make sure your wiki configuration backup_* values are correct and "
+"complete.\n"
+" * Make sure the backup file you get contains everything you need in case of "
+"problems.\n"
+" * Make sure it is downloaded without problems.\n"
 "\n"
-"Please make sure your wiki configuration backup_* values are correct and "
-"complete.\n"
-"\n"
+"To get a backup, just click here:"
 msgstr ""
 
 msgid "Backup"
 msgstr "نسخ احتياطي"
 
-msgid "Restore"
-msgstr "استعادة"
-
 #, fuzzy
 msgid "You are not allowed to do remote backup."
 msgstr "لا يسمح لك القيام بهذا الإجراء."
@@ -2103,59 +2144,19 @@
 msgid "You need to be subscribed to unsubscribe."
 msgstr "لا يسمح لك بتحرير هذه الصفحة"
 
-msgid ""
-" Emphasis:: <<Verbatim('')>>''italics''<<Verbatim('')>>; <<Verbatim(''')"
-">>'''bold'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''bold "
-"italics'''''<<Verbatim(''''')>>; <<Verbatim('')>>''mixed ''<<Verbatim(''')"
-">>'''''bold'''<<Verbatim(''')>> and italics''<<Verbatim('')>>; <<Verbatim"
-"(----)>> horizontal rule.\n"
-" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
-"===== Title 5 =====.\n"
-" Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1."
-"#n start numbering at n; space alone indents.\n"
-" Links:: <<Verbatim(JoinCapitalizedWords)>>; <<Verbatim([[target|linktext]])"
-">>.\n"
-" Tables:: || cell text |||| cell text spanning 2 columns ||;    no trailing "
-"white space allowed after tables or titles.\n"
-"\n"
-"(!) For more help, see HelpOnEditing or SyntaxReference.\n"
-msgstr ""
-
+#, fuzzy
+msgid "Password is too short."
+msgstr "اعادة كلمة السر"
+
+msgid "Password has not enough different characters."
+msgstr ""
+
+#, fuzzy
 msgid ""
-"{{{\n"
-"Emphasis: *italic* **bold** ``monospace``\n"
-"\n"
-"Headings: Heading 1  Heading 2  Heading 3\n"
-"          =========  ---------  ~~~~~~~~~\n"
-"\n"
-"Horizontal rule: ----\n"
-"\n"
-"Links: TrailingUnderscore_ `multi word with backticks`_ external_\n"
-"\n"
-".. _external: http://external-site.example.org/foo/\n"
-"\n"
-"Lists: * bullets; 1., a. numbered items.\n"
-"}}}\n"
-"(!) For more help, see the\n"
-"[[http://docutils.sourceforge.net/docs/user/rst/quickref.html|"
-"reStructuredText Quick Reference]].\n"
-msgstr ""
-
-msgid ""
-" Emphasis:: <<Verbatim(//)>>''italics''<<Verbatim(//)>>; <<Verbatim(**)"
-">>'''bold'''<<Verbatim(**)>>; <<Verbatim(**//)>>'''''bold "
-"italics'''''<<Verbatim(//**)>>; <<Verbatim(//)>>''mixed ''<<Verbatim(**)"
-">>'''''bold'''<<Verbatim(**)>> and italics''<<Verbatim(//)>>;\n"
-" Horizontal Rule:: <<Verbatim(----)>>\n"
-" Force Linebreak:: <<Verbatim(\\\\)>>\n"
-" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
-"===== Title 5 =====.\n"
-" Lists:: * bullets; ** sub-bullets; # numbered items; ## numbered sub "
-"items.\n"
-" Links:: <<Verbatim([[target]])>>; <<Verbatim([[target|linktext]])>>.\n"
-" Tables:: |= header text | cell text | more cell text |;\n"
-"\n"
-"(!) For more help, see HelpOnEditing or HelpOnCreoleSyntax.\n"
+"Password is too easy (password contains name or name contains password)."
+msgstr "لا يوجد كلمة سر. الرجاء إدخال إسم مستخدم و كلمة سر"
+
+msgid "Password is too easy (keyboard sequence)."
 msgstr ""
 
 msgid "Diffs"
@@ -2402,6 +2403,16 @@
 msgid "User"
 msgstr "المستخدم"
 
+msgid "[ATTACH]"
+msgstr ""
+
+#, fuzzy
+msgid "Variable name"
+msgstr "إسم الملف"
+
+msgid "Description"
+msgstr ""
+
 #, python-format
 msgid "Upload new attachment \"%(filename)s\""
 msgstr ""
@@ -2444,6 +2455,20 @@
 msgid "Display"
 msgstr "العرض"
 
+msgid "Wiki configuration"
+msgstr ""
+
+msgid ""
+"This table shows all settings in this wiki that do not have default values. "
+"Settings that the configuration system doesn't know about are shown in "
+"''italic'', those may be due to third-party extensions needing configuration "
+"or settings that were removed from Moin."
+msgstr ""
+
+#, fuzzy
+msgid "Setting"
+msgstr "إعدادات"
+
 msgid "Search for items"
 msgstr ""
 
@@ -2798,6 +2823,12 @@
 msgid "Toggle line numbers"
 msgstr ""
 
+#~ msgid "Wiki Backup / Restore"
+#~ msgstr "نسخ إحتياطي / إستعادة ويكي"
+
+#~ msgid "Restore"
+#~ msgstr "استعادة"
+
 #, fuzzy
 #~ msgid "New Page or New Attachment"
 #~ msgstr "المرفقات"
@@ -2834,10 +2865,6 @@
 #~ "This list does not work, unless you have entered a valid email address!"
 #~ msgstr "هذه القائمة لا تعمل إلا إذا قمت بإدخال عنوان بريد إلكتروني صالح!"
 
-#, fuzzy
-#~ msgid "Filename"
-#~ msgstr "إسم الملف"
-
 #~ msgid ""
 #~ "The remote version of MoinMoin is too old, version 1.6 is required at "
 #~ "least."
--- a/MoinMoin/i18n/bg.MoinMoin.po	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/i18n/bg.MoinMoin.po	Sat Dec 13 19:27:41 2008 +0100
@@ -13,7 +13,7 @@
 msgstr ""
 "Project-Id-Version: MoinMoin 1.6\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-09-07 23:23+0200\n"
+"POT-Creation-Date: 2008-09-28 20:59+0200\n"
 "PO-Revision-Date: 2006-02-11 12:20-0800\n"
 "Last-Translator: Hristo Iliev <hristo@phys.uni-sofia.bg>\n"
 "Language-Team: Bulgarian <moin-devel@lists.sourceforge.net>\n"
@@ -793,7 +793,8 @@
 
 #, python-format
 msgid ""
-"Dear Superuser, a new user has just been created. Details follow:\n"
+"Dear Superuser, a new user has just been created on %(sitename)s\". Details "
+"follow:\n"
 "\n"
 "    User name: %(username)s\n"
 "    Email address: %(useremail)s"
@@ -831,6 +832,42 @@
 msgid "Page changed"
 msgstr "Запис на промените"
 
+#, fuzzy
+msgid ""
+" Emphasis:: <<Verbatim('')>>''italics''<<Verbatim('')>>; <<Verbatim(''')"
+">>'''bold'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''bold "
+"italics'''''<<Verbatim(''''')>>; <<Verbatim('')>>''mixed ''<<Verbatim(''')"
+">>'''''bold'''<<Verbatim(''')>> and italics''<<Verbatim('')>>; <<Verbatim"
+"(----)>> horizontal rule.\n"
+" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
+"===== Title 5 =====.\n"
+" Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1."
+"#n start numbering at n; space alone indents.\n"
+" Links:: <<Verbatim(JoinCapitalizedWords)>>; <<Verbatim([[target|linktext]])"
+">>.\n"
+" Tables:: || cell text |||| cell text spanning 2 columns ||;    no trailing "
+"white space allowed after tables or titles.\n"
+"\n"
+"(!) For more help, see HelpOnEditing or SyntaxReference.\n"
+msgstr ""
+" Наблягане:: <<Verbatim('')>>''наклонен''<<Verbatim('')>>; <<Verbatim(''')"
+">>'''удебелен'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''удебелен и "
+"наклонен'''''<<Verbatim(''''')>>; <<Verbatim('')>>''смесени ''<<Verbatim(''')"
+">>'''''удебелен'''<<Verbatim(''')>> и наклонен''<<Verbatim('')>>; <<Verbatim"
+"(----)>> хоризонтална черта.\n"
+" Заглавия:: <<Verbatim(=)>> Заглавие 1 <<Verbatim(=)>>; <<Verbatim(==)>> "
+"Заглавие 2 <<Verbatim(==)>>; <<Verbatim(===)>> Заглавие 3 <<Verbatim(===)"
+">>;   <<Verbatim(====)>> Заглавие 4 <<Verbatim(====)>>; <<Verbatim(=====)>> "
+"Заглавие 5 <<Verbatim(=====)>>.\n"
+" Списъци:: интервал и едно от: * bullets; 1., a., A., i., I. номерирани "
+"елементи; 1.#n започва номерирането от n; само интервал вмъква навътре.\n"
+" Връзки:: <<Verbatim(СвързаниДумиПървиБуквиГлавни)>>; <<Verbatim"
+"([\"квадратни скоби и кавички\"])>>; url; [url]; [url етикет].\n"
+" Таблици:: || текст на клетка |||| текст на клетка, заемаща 2 колони ||;    "
+"не е позволено оставянето на празно място след таблици или заглавия.\n"
+"\n"
+"(!) За повече помощ вижте ПомощПриРедактиране или СинтактичноУпътване.\n"
+
 #, python-format
 msgid "Expected \"%(wanted)s\" after \"%(key)s\", got \"%(token)s\""
 msgstr "Очаква се \"%(wanted)s\" след \"%(key)s\", а е открит \"%(token)s\""
@@ -863,6 +900,44 @@
 "Изобразяването на реСтруктуриран текст е невъзможно. Моля, инсталирайте "
 "Docutils."
 
+#, fuzzy
+msgid ""
+"{{{\n"
+"Emphasis: *italic* **bold** ``monospace``\n"
+"\n"
+"Headings: Heading 1  Heading 2  Heading 3\n"
+"          =========  ---------  ~~~~~~~~~\n"
+"\n"
+"Horizontal rule: ----\n"
+"\n"
+"Links: TrailingUnderscore_ `multi word with backticks`_ external_\n"
+"\n"
+".. _external: http://external-site.example.org/foo/\n"
+"\n"
+"Lists: * bullets; 1., a. numbered items.\n"
+"}}}\n"
+"(!) For more help, see the\n"
+"[[http://docutils.sourceforge.net/docs/user/rst/quickref.html|"
+"reStructuredText Quick Reference]].\n"
+msgstr ""
+"Наблягане: <i>*наклонен*</i> <b>**удебелен**</b> ``печатен``<br/>\n"
+"<br/><pre>\n"
+"Заглавия: Заглавие 1  Заглавие 2  Заглавие 3\n"
+"          ==========  ----------  ~~~~~~~~~~\n"
+"\n"
+"Хоризонтална черта: ---- \n"
+"Връзки: ПодчертавкаОтзад_ `няколко думи в обратни апострофи`_ external_ \n"
+"\n"
+".. _external: http://външен-сайт.net/foo/\n"
+"\n"
+"Списъци: * bullets; 1., a. номерирани елементи.\n"
+"</pre>\n"
+"<br/>\n"
+"(!) За повече помощ погледнете \n"
+"<a href=\"http://docutils.sourceforge.net/docs/user/rst/quickref.html\">\n"
+"Бързо Ръководство по реСтруктуриранТекст\n"
+"</a>.\n"
+
 msgid "**Maximum number of allowed includes exceeded**"
 msgstr "**Надхвърлен е максималния брой include**"
 
@@ -874,6 +949,41 @@
 msgid "**Could not find the referenced page: %s**"
 msgstr "**Сочената страница не е открита: %s**"
 
+#, fuzzy
+msgid ""
+" Emphasis:: <<Verbatim(//)>>''italics''<<Verbatim(//)>>; <<Verbatim(**)"
+">>'''bold'''<<Verbatim(**)>>; <<Verbatim(**//)>>'''''bold "
+"italics'''''<<Verbatim(//**)>>; <<Verbatim(//)>>''mixed ''<<Verbatim(**)"
+">>'''''bold'''<<Verbatim(**)>> and italics''<<Verbatim(//)>>;\n"
+" Horizontal Rule:: <<Verbatim(----)>>\n"
+" Force Linebreak:: <<Verbatim(\\\\)>>\n"
+" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
+"===== Title 5 =====.\n"
+" Lists:: * bullets; ** sub-bullets; # numbered items; ## numbered sub "
+"items.\n"
+" Links:: <<Verbatim([[target]])>>; <<Verbatim([[target|linktext]])>>.\n"
+" Tables:: |= header text | cell text | more cell text |;\n"
+"\n"
+"(!) For more help, see HelpOnEditing or HelpOnCreoleSyntax.\n"
+msgstr ""
+" Наблягане:: <<Verbatim('')>>''наклонен''<<Verbatim('')>>; <<Verbatim(''')"
+">>'''удебелен'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''удебелен и "
+"наклонен'''''<<Verbatim(''''')>>; <<Verbatim('')>>''смесени ''<<Verbatim(''')"
+">>'''''удебелен'''<<Verbatim(''')>> и наклонен''<<Verbatim('')>>; <<Verbatim"
+"(----)>> хоризонтална черта.\n"
+" Заглавия:: <<Verbatim(=)>> Заглавие 1 <<Verbatim(=)>>; <<Verbatim(==)>> "
+"Заглавие 2 <<Verbatim(==)>>; <<Verbatim(===)>> Заглавие 3 <<Verbatim(===)"
+">>;   <<Verbatim(====)>> Заглавие 4 <<Verbatim(====)>>; <<Verbatim(=====)>> "
+"Заглавие 5 <<Verbatim(=====)>>.\n"
+" Списъци:: интервал и едно от: * bullets; 1., a., A., i., I. номерирани "
+"елементи; 1.#n започва номерирането от n; само интервал вмъква навътре.\n"
+" Връзки:: <<Verbatim(СвързаниДумиПървиБуквиГлавни)>>; <<Verbatim"
+"([\"квадратни скоби и кавички\"])>>; url; [url]; [url етикет].\n"
+" Таблици:: || текст на клетка |||| текст на клетка, заемаща 2 колони ||;    "
+"не е позволено оставянето на празно място след таблици или заглавия.\n"
+"\n"
+"(!) За повече помощ вижте ПомощПриРедактиране или СинтактичноУпътване.\n"
+
 msgid "Preferences"
 msgstr "Предпочитания"
 
@@ -1327,62 +1437,28 @@
 "username, the recovery token and a new password (twice) below."
 msgstr ""
 
-#, python-format
-msgid ""
-"Restored Backup: %(filename)s to target dir: %(targetdir)s.\n"
-"Files: %(filecount)d, Directories: %(dircount)d"
-msgstr ""
-"Възстановен архив: %(filename)s в директория: %(targetdir)s.\n"
-"Файлове: %(filecount)d, Директории: %(dircount)d"
-
-#, python-format
-msgid "Restoring backup: %(filename)s to target dir: %(targetdir)s failed."
-msgstr ""
-"Възстановяването на архив: %(filename)s в директория: %(targetdir)s пропадна."
-
-msgid "Wiki Backup / Restore"
-msgstr "Архивиране / Възстановяване на уикито"
+#, fuzzy
+msgid "Wiki Backup"
+msgstr "Уики маркировка"
 
 msgid ""
-"Some hints:\n"
-" * To restore a backup:\n"
-"  * Restoring a backup will overwrite existing data, so be careful.\n"
-"  * Rename it to <siteid>.tar.<compression> (remove the --date--time--UTC "
-"stuff).\n"
-"  * Put the backup file into the backup_storage_dir (use scp, ftp, ...).\n"
-"  * Hit the <<GetText(Restore)>> button below.\n"
+"= Downloading a backup =\n"
 "\n"
-" * To make a backup, just hit the <<GetText(Backup)>> button and save the "
-"file\n"
-"   you get to a secure place.\n"
+"Please note:\n"
+" * Store backups in a safe and secure place - they contain sensitive "
+"information.\n"
+" * Make sure your wiki configuration backup_* values are correct and "
+"complete.\n"
+" * Make sure the backup file you get contains everything you need in case of "
+"problems.\n"
+" * Make sure it is downloaded without problems.\n"
 "\n"
-"Please make sure your wiki configuration backup_* values are correct and "
-"complete.\n"
-"\n"
+"To get a backup, just click here:"
 msgstr ""
-"Някои напътствия:\n"
-" * За да възстановите от архив:\n"
-"  * Възстановяването ще презапише съществуващите данни, така че бъдете "
-"внимателни.\n"
-"  * Преименувайте го на <сайтидент>.tar.<компресия> (премахнете частта --"
-"дата--час--UTC).\n"
-"  * Поставете архива в backup_storage_dir (използвайте scp, ftp, ...).\n"
-"  * Натиснете бутона <<GetText(Restore)>> по-долу.\n"
-"\n"
-" * За да направите архив, просто натиснете бутона <<GetText(Backup)>> и "
-"запишете файла,\n"
-"   който ще получите, на сигурно място.\n"
-"\n"
-"Моля, уверете се, че конфигурационните стойности backup_* на вашето уики са "
-"верни и пълни.\n"
-"\n"
 
 msgid "Backup"
 msgstr "Архивиране"
 
-msgid "Restore"
-msgstr "Възстановяване"
-
 msgid "You are not allowed to do remote backup."
 msgstr "Не Ви е позволено да правите отдалечено архивиране."
 
@@ -2275,113 +2351,19 @@
 msgstr "Бяхте абонирани за тази страница."
 
 #, fuzzy
-msgid ""
-" Emphasis:: <<Verbatim('')>>''italics''<<Verbatim('')>>; <<Verbatim(''')"
-">>'''bold'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''bold "
-"italics'''''<<Verbatim(''''')>>; <<Verbatim('')>>''mixed ''<<Verbatim(''')"
-">>'''''bold'''<<Verbatim(''')>> and italics''<<Verbatim('')>>; <<Verbatim"
-"(----)>> horizontal rule.\n"
-" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
-"===== Title 5 =====.\n"
-" Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1."
-"#n start numbering at n; space alone indents.\n"
-" Links:: <<Verbatim(JoinCapitalizedWords)>>; <<Verbatim([[target|linktext]])"
-">>.\n"
-" Tables:: || cell text |||| cell text spanning 2 columns ||;    no trailing "
-"white space allowed after tables or titles.\n"
-"\n"
-"(!) For more help, see HelpOnEditing or SyntaxReference.\n"
+msgid "Password is too short."
+msgstr "Повторение на паролата"
+
+msgid "Password has not enough different characters."
 msgstr ""
-" Наблягане:: <<Verbatim('')>>''наклонен''<<Verbatim('')>>; <<Verbatim(''')"
-">>'''удебелен'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''удебелен и "
-"наклонен'''''<<Verbatim(''''')>>; <<Verbatim('')>>''смесени ''<<Verbatim(''')"
-">>'''''удебелен'''<<Verbatim(''')>> и наклонен''<<Verbatim('')>>; <<Verbatim"
-"(----)>> хоризонтална черта.\n"
-" Заглавия:: <<Verbatim(=)>> Заглавие 1 <<Verbatim(=)>>; <<Verbatim(==)>> "
-"Заглавие 2 <<Verbatim(==)>>; <<Verbatim(===)>> Заглавие 3 <<Verbatim(===)"
-">>;   <<Verbatim(====)>> Заглавие 4 <<Verbatim(====)>>; <<Verbatim(=====)>> "
-"Заглавие 5 <<Verbatim(=====)>>.\n"
-" Списъци:: интервал и едно от: * bullets; 1., a., A., i., I. номерирани "
-"елементи; 1.#n започва номерирането от n; само интервал вмъква навътре.\n"
-" Връзки:: <<Verbatim(СвързаниДумиПървиБуквиГлавни)>>; <<Verbatim"
-"([\"квадратни скоби и кавички\"])>>; url; [url]; [url етикет].\n"
-" Таблици:: || текст на клетка |||| текст на клетка, заемаща 2 колони ||;    "
-"не е позволено оставянето на празно място след таблици или заглавия.\n"
-"\n"
-"(!) За повече помощ вижте ПомощПриРедактиране или СинтактичноУпътване.\n"
 
 #, fuzzy
 msgid ""
-"{{{\n"
-"Emphasis: *italic* **bold** ``monospace``\n"
-"\n"
-"Headings: Heading 1  Heading 2  Heading 3\n"
-"          =========  ---------  ~~~~~~~~~\n"
-"\n"
-"Horizontal rule: ----\n"
-"\n"
-"Links: TrailingUnderscore_ `multi word with backticks`_ external_\n"
-"\n"
-".. _external: http://external-site.example.org/foo/\n"
-"\n"
-"Lists: * bullets; 1., a. numbered items.\n"
-"}}}\n"
-"(!) For more help, see the\n"
-"[[http://docutils.sourceforge.net/docs/user/rst/quickref.html|"
-"reStructuredText Quick Reference]].\n"
+"Password is too easy (password contains name or name contains password)."
+msgstr "Липсва парола. Моля, въведете потребителско име и парола."
+
+msgid "Password is too easy (keyboard sequence)."
 msgstr ""
-"Наблягане: <i>*наклонен*</i> <b>**удебелен**</b> ``печатен``<br/>\n"
-"<br/><pre>\n"
-"Заглавия: Заглавие 1  Заглавие 2  Заглавие 3\n"
-"          ==========  ----------  ~~~~~~~~~~\n"
-"\n"
-"Хоризонтална черта: ---- \n"
-"Връзки: ПодчертавкаОтзад_ `няколко думи в обратни апострофи`_ external_ \n"
-"\n"
-".. _external: http://външен-сайт.net/foo/\n"
-"\n"
-"Списъци: * bullets; 1., a. номерирани елементи.\n"
-"</pre>\n"
-"<br/>\n"
-"(!) За повече помощ погледнете \n"
-"<a href=\"http://docutils.sourceforge.net/docs/user/rst/quickref.html\">\n"
-"Бързо Ръководство по реСтруктуриранТекст\n"
-"</a>.\n"
-
-#, fuzzy
-msgid ""
-" Emphasis:: <<Verbatim(//)>>''italics''<<Verbatim(//)>>; <<Verbatim(**)"
-">>'''bold'''<<Verbatim(**)>>; <<Verbatim(**//)>>'''''bold "
-"italics'''''<<Verbatim(//**)>>; <<Verbatim(//)>>''mixed ''<<Verbatim(**)"
-">>'''''bold'''<<Verbatim(**)>> and italics''<<Verbatim(//)>>;\n"
-" Horizontal Rule:: <<Verbatim(----)>>\n"
-" Force Linebreak:: <<Verbatim(\\\\)>>\n"
-" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
-"===== Title 5 =====.\n"
-" Lists:: * bullets; ** sub-bullets; # numbered items; ## numbered sub "
-"items.\n"
-" Links:: <<Verbatim([[target]])>>; <<Verbatim([[target|linktext]])>>.\n"
-" Tables:: |= header text | cell text | more cell text |;\n"
-"\n"
-"(!) For more help, see HelpOnEditing or HelpOnCreoleSyntax.\n"
-msgstr ""
-" Наблягане:: <<Verbatim('')>>''наклонен''<<Verbatim('')>>; <<Verbatim(''')"
-">>'''удебелен'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''удебелен и "
-"наклонен'''''<<Verbatim(''''')>>; <<Verbatim('')>>''смесени ''<<Verbatim(''')"
-">>'''''удебелен'''<<Verbatim(''')>> и наклонен''<<Verbatim('')>>; <<Verbatim"
-"(----)>> хоризонтална черта.\n"
-" Заглавия:: <<Verbatim(=)>> Заглавие 1 <<Verbatim(=)>>; <<Verbatim(==)>> "
-"Заглавие 2 <<Verbatim(==)>>; <<Verbatim(===)>> Заглавие 3 <<Verbatim(===)"
-">>;   <<Verbatim(====)>> Заглавие 4 <<Verbatim(====)>>; <<Verbatim(=====)>> "
-"Заглавие 5 <<Verbatim(=====)>>.\n"
-" Списъци:: интервал и едно от: * bullets; 1., a., A., i., I. номерирани "
-"елементи; 1.#n започва номерирането от n; само интервал вмъква навътре.\n"
-" Връзки:: <<Verbatim(СвързаниДумиПървиБуквиГлавни)>>; <<Verbatim"
-"([\"квадратни скоби и кавички\"])>>; url; [url]; [url етикет].\n"
-" Таблици:: || текст на клетка |||| текст на клетка, заемаща 2 колони ||;    "
-"не е позволено оставянето на празно място след таблици или заглавия.\n"
-"\n"
-"(!) За повече помощ вижте ПомощПриРедактиране или СинтактичноУпътване.\n"
 
 msgid "Diffs"
 msgstr "Разлики"
@@ -2620,6 +2602,16 @@
 msgid "User"
 msgstr "Потребител"
 
+msgid "[ATTACH]"
+msgstr ""
+
+#, fuzzy
+msgid "Variable name"
+msgstr "име на файл"
+
+msgid "Description"
+msgstr ""
+
 #, python-format
 msgid "Upload new attachment \"%(filename)s\""
 msgstr "Качване на ново приложение \"%(filename)s\""
@@ -2660,6 +2652,19 @@
 msgid "Display"
 msgstr "Преглед"
 
+msgid "Wiki configuration"
+msgstr ""
+
+msgid ""
+"This table shows all settings in this wiki that do not have default values. "
+"Settings that the configuration system doesn't know about are shown in "
+"''italic'', those may be due to third-party extensions needing configuration "
+"or settings that were removed from Moin."
+msgstr ""
+
+msgid "Setting"
+msgstr ""
+
 msgid "Search for items"
 msgstr "Търсене за елементи"
 
@@ -3007,6 +3012,58 @@
 msgid "Toggle line numbers"
 msgstr "Превключи показването на номерата на редовете"
 
+#~ msgid ""
+#~ "Restored Backup: %(filename)s to target dir: %(targetdir)s.\n"
+#~ "Files: %(filecount)d, Directories: %(dircount)d"
+#~ msgstr ""
+#~ "Възстановен архив: %(filename)s в директория: %(targetdir)s.\n"
+#~ "Файлове: %(filecount)d, Директории: %(dircount)d"
+
+#~ msgid "Restoring backup: %(filename)s to target dir: %(targetdir)s failed."
+#~ msgstr ""
+#~ "Възстановяването на архив: %(filename)s в директория: %(targetdir)s "
+#~ "пропадна."
+
+#~ msgid "Wiki Backup / Restore"
+#~ msgstr "Архивиране / Възстановяване на уикито"
+
+#~ msgid ""
+#~ "Some hints:\n"
+#~ " * To restore a backup:\n"
+#~ "  * Restoring a backup will overwrite existing data, so be careful.\n"
+#~ "  * Rename it to <siteid>.tar.<compression> (remove the --date--time--UTC "
+#~ "stuff).\n"
+#~ "  * Put the backup file into the backup_storage_dir (use scp, ftp, ...).\n"
+#~ "  * Hit the <<GetText(Restore)>> button below.\n"
+#~ "\n"
+#~ " * To make a backup, just hit the <<GetText(Backup)>> button and save the "
+#~ "file\n"
+#~ "   you get to a secure place.\n"
+#~ "\n"
+#~ "Please make sure your wiki configuration backup_* values are correct and "
+#~ "complete.\n"
+#~ "\n"
+#~ msgstr ""
+#~ "Някои напътствия:\n"
+#~ " * За да възстановите от архив:\n"
+#~ "  * Възстановяването ще презапише съществуващите данни, така че бъдете "
+#~ "внимателни.\n"
+#~ "  * Преименувайте го на <сайтидент>.tar.<компресия> (премахнете частта --"
+#~ "дата--час--UTC).\n"
+#~ "  * Поставете архива в backup_storage_dir (използвайте scp, ftp, ...).\n"
+#~ "  * Натиснете бутона <<GetText(Restore)>> по-долу.\n"
+#~ "\n"
+#~ " * За да направите архив, просто натиснете бутона <<GetText(Backup)>> и "
+#~ "запишете файла,\n"
+#~ "   който ще получите, на сигурно място.\n"
+#~ "\n"
+#~ "Моля, уверете се, че конфигурационните стойности backup_* на вашето уики "
+#~ "са верни и пълни.\n"
+#~ "\n"
+
+#~ msgid "Restore"
+#~ msgstr "Възстановяване"
+
 #~ msgid "Xapian Version"
 #~ msgstr "Версия на Xapian"
 
@@ -3153,10 +3210,6 @@
 #~ msgid "Sorry, login failed."
 #~ msgstr "Съжаляваме, неуспешен вход."
 
-#, fuzzy
-#~ msgid "Filename"
-#~ msgstr "име на файл"
-
 #~ msgid ""
 #~ "The remote version of MoinMoin is too old, version 1.6 is required at "
 #~ "least."
--- a/MoinMoin/i18n/ca.MoinMoin.po	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/i18n/ca.MoinMoin.po	Sat Dec 13 19:27:41 2008 +0100
@@ -13,7 +13,7 @@
 msgstr ""
 "Project-Id-Version: moin 1.7\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-09-07 23:23+0200\n"
+"POT-Creation-Date: 2008-09-28 20:59+0200\n"
 "PO-Revision-Date: 2008-07-30 17:24+0200\n"
 "Last-Translator: Jordi Mallach <jordi@sindominio.net>\n"
 "Language-Team: Catalan <ca@dodds.net>\n"
@@ -780,7 +780,8 @@
 
 #, python-format
 msgid ""
-"Dear Superuser, a new user has just been created. Details follow:\n"
+"Dear Superuser, a new user has just been created on %(sitename)s\". Details "
+"follow:\n"
 "\n"
 "    User name: %(username)s\n"
 "    Email address: %(useremail)s"
@@ -818,6 +819,39 @@
 msgid "Page changed"
 msgstr "Desa els canvis"
 
+msgid ""
+" Emphasis:: <<Verbatim('')>>''italics''<<Verbatim('')>>; <<Verbatim(''')"
+">>'''bold'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''bold "
+"italics'''''<<Verbatim(''''')>>; <<Verbatim('')>>''mixed ''<<Verbatim(''')"
+">>'''''bold'''<<Verbatim(''')>> and italics''<<Verbatim('')>>; <<Verbatim"
+"(----)>> horizontal rule.\n"
+" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
+"===== Title 5 =====.\n"
+" Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1."
+"#n start numbering at n; space alone indents.\n"
+" Links:: <<Verbatim(JoinCapitalizedWords)>>; <<Verbatim([[target|linktext]])"
+">>.\n"
+" Tables:: || cell text |||| cell text spanning 2 columns ||;    no trailing "
+"white space allowed after tables or titles.\n"
+"\n"
+"(!) For more help, see HelpOnEditing or SyntaxReference.\n"
+msgstr ""
+" Èmfasi:: <<Verbatim('')>>''cursiva''<<Verbatim('')>>; <<Verbatim(''')"
+">>'''negreta'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''negreta "
+"cursiva'''''<<Verbatim(''''')>>; <<Verbatim('')>>''combinació ''<<Verbatim"
+"(''')>>'''''negreta'''<<Verbatim(''')>> i cursiva''<<Verbatim('')>>; "
+"<<Verbatim(----)>> regla horitzontal.\n"
+" Encapçalaments:: = Títol 1 =; == Títol 2 ==; === Títol 3 ===; ==== Títol 4 "
+"====; ===== Títol 5 =====.\n"
+" Llistes:: espai i un dels següents: * pics; 1., a., A., i., I. elements "
+"numerats; 1.#n comença a numerar des de n; només espai sagna.\n"
+" Enllaços:: <<Verbatim(JuntaParaulesAmbMajúscules)>>; <<Verbatim"
+"([[destinació|textenllaç]])>>.\n"
+" Taules:: || text de la cel·la |||| text de ce·les que ocupen dos columnes "
+"||;    no s'admet espai en blanc després de taules o títols.\n"
+"\n"
+"(!) Per a obtindre'n més ajuda, vegeu HelpOnEditing o SyntaxReference.\n"
+
 #, python-format
 msgid "Expected \"%(wanted)s\" after \"%(key)s\", got \"%(token)s\""
 msgstr "S'esperava «%(wanted)s» després de «%(key)s», s'ha obtingut «%(token)s»"
@@ -848,6 +882,43 @@
 "Rendering of reStructured text is not possible, please install Docutils."
 msgstr "No és possible renderitzar text reStructurat. Instal·leu Docutils."
 
+msgid ""
+"{{{\n"
+"Emphasis: *italic* **bold** ``monospace``\n"
+"\n"
+"Headings: Heading 1  Heading 2  Heading 3\n"
+"          =========  ---------  ~~~~~~~~~\n"
+"\n"
+"Horizontal rule: ----\n"
+"\n"
+"Links: TrailingUnderscore_ `multi word with backticks`_ external_\n"
+"\n"
+".. _external: http://external-site.example.org/foo/\n"
+"\n"
+"Lists: * bullets; 1., a. numbered items.\n"
+"}}}\n"
+"(!) For more help, see the\n"
+"[[http://docutils.sourceforge.net/docs/user/rst/quickref.html|"
+"reStructuredText Quick Reference]].\n"
+msgstr ""
+"{{{\n"
+"Èmfasi: *cursiva* **bold ``amplada fixa``\n"
+"\n"
+"Capçaleres: Capçalera 1  Capçalera 2  Capçalera 3\n"
+"            ===========  -----------  ~~~~~~~~~~~\n"
+"\n"
+"Regla horitzontal: ----\n"
+"Enllaços: SubratllatFinal_ `múltiples paraules amb cometa invertida`_ "
+"extern_\n"
+"\n"
+".. _extern: http://lloc-extern.exemple.net/mec/\n"
+"\n"
+"Llistes: * pics ; 1., a. elements numerats.\n"
+"}}}\n"
+"(!) Per a obtindre'n més ajuda, vegeu la\n"
+"[[http://docutils.sourceforge.net/docs/user/rst/quickref.html|referència "
+"ràpida de reStructuredText]].\n"
+
 msgid "**Maximum number of allowed includes exceeded**"
 msgstr "**S'ha superat el nombre màxim de includes permès**"
 
@@ -859,6 +930,41 @@
 msgid "**Could not find the referenced page: %s**"
 msgstr "**No s'ha trobat la pàgina referenciada: %s**"
 
+#, fuzzy
+msgid ""
+" Emphasis:: <<Verbatim(//)>>''italics''<<Verbatim(//)>>; <<Verbatim(**)"
+">>'''bold'''<<Verbatim(**)>>; <<Verbatim(**//)>>'''''bold "
+"italics'''''<<Verbatim(//**)>>; <<Verbatim(//)>>''mixed ''<<Verbatim(**)"
+">>'''''bold'''<<Verbatim(**)>> and italics''<<Verbatim(//)>>;\n"
+" Horizontal Rule:: <<Verbatim(----)>>\n"
+" Force Linebreak:: <<Verbatim(\\\\)>>\n"
+" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
+"===== Title 5 =====.\n"
+" Lists:: * bullets; ** sub-bullets; # numbered items; ## numbered sub "
+"items.\n"
+" Links:: <<Verbatim([[target]])>>; <<Verbatim([[target|linktext]])>>.\n"
+" Tables:: |= header text | cell text | more cell text |;\n"
+"\n"
+"(!) For more help, see HelpOnEditing or HelpOnCreoleSyntax.\n"
+msgstr ""
+" Èmfasi:: <<Verbatim('')>>''cursiva''<<Verbatim('')>>; <<Verbatim(''')"
+">>'''negreta'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''negreta "
+"cursiva'''''<<Verbatim(''''')>>; <<Verbatim('')>>''combinació ''<<Verbatim"
+"(''')>>'''''negreta'''<<Verbatim(''')>> i cursiva''<<Verbatim('')>>; "
+"<<Verbatim(----)>> regla horitzontal.\n"
+" Encapçalaments:: <<Verbatim(=)>> Títol 1 <<Verbatim(=)>>; <<Verbatim(==)>> "
+"Títol 2 <<Verbatim(==)>>; <<Verbatim(===)>> Títol 3 <<Verbatim(===)>>;   "
+"<<Verbatim(====)>> Títol 4 <<Verbatim(====)>>; <<Verbatim(=====)>> Títol 5 "
+"<<Verbatim(=====)>>.\n"
+" Llistes:: espai i algun dels següents: pics *; 1., a., A., i., I. elements "
+"numerats; 1.#n comença a numerar des de n; només espai sagna.\n"
+" Enllaços:: <<Verbatim(JuntaParaulesAmbMajúscules)>>; <<Verbatim"
+"([[destinació|textenllaç]])>>.\n"
+" Taules:: || text de la cel·la |||| text de ce·les que ocupen dos columnes "
+"||;    no s'admet espai en blanc després de taules o títols.\n"
+"\n"
+"(!) Per a obtindre'n més ajuda, vegeu HelpOnEditing o SyntaxReference.\n"
+
 msgid "Preferences"
 msgstr "Preferències"
 
@@ -1271,49 +1377,34 @@
 "username, the recovery token and a new password (twice) below."
 msgstr ""
 
-#, python-format
-msgid ""
-"Restored Backup: %(filename)s to target dir: %(targetdir)s.\n"
-"Files: %(filecount)d, Directories: %(dircount)d"
-msgstr ""
-
-#, python-format
-msgid "Restoring backup: %(filename)s to target dir: %(targetdir)s failed."
-msgstr ""
-
-msgid "Wiki Backup / Restore"
-msgstr "Còpia de seguretat / Restauració del wiki"
+#, fuzzy
+msgid "Wiki Backup"
+msgstr "Marcat del Wiki"
 
 msgid ""
-"Some hints:\n"
-" * To restore a backup:\n"
-"  * Restoring a backup will overwrite existing data, so be careful.\n"
-"  * Rename it to <siteid>.tar.<compression> (remove the --date--time--UTC "
-"stuff).\n"
-"  * Put the backup file into the backup_storage_dir (use scp, ftp, ...).\n"
-"  * Hit the <<GetText(Restore)>> button below.\n"
+"= Downloading a backup =\n"
 "\n"
-" * To make a backup, just hit the <<GetText(Backup)>> button and save the "
-"file\n"
-"   you get to a secure place.\n"
+"Please note:\n"
+" * Store backups in a safe and secure place - they contain sensitive "
+"information.\n"
+" * Make sure your wiki configuration backup_* values are correct and "
+"complete.\n"
+" * Make sure the backup file you get contains everything you need in case of "
+"problems.\n"
+" * Make sure it is downloaded without problems.\n"
 "\n"
-"Please make sure your wiki configuration backup_* values are correct and "
-"complete.\n"
-"\n"
+"To get a backup, just click here:"
 msgstr ""
 
 msgid "Backup"
 msgstr "Copia"
 
-msgid "Restore"
-msgstr "Restaura"
-
 msgid "You are not allowed to do remote backup."
 msgstr "No esteu autoritzat a fer una còpia de seguretat remota."
 
-#, python-format
+#, fuzzy, python-format
 msgid "Unknown backup subaction: %s."
-msgstr ""
+msgstr "L'acció %(action_name)s és desconeguda."
 
 msgid "You must login to add a quicklink."
 msgstr "Heu d'entrar per a afegir un enllaç ràpid"
@@ -2153,110 +2244,20 @@
 msgid "You need to be subscribed to unsubscribe."
 msgstr "Vos heu subscrit a aquesta pàgina."
 
-msgid ""
-" Emphasis:: <<Verbatim('')>>''italics''<<Verbatim('')>>; <<Verbatim(''')"
-">>'''bold'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''bold "
-"italics'''''<<Verbatim(''''')>>; <<Verbatim('')>>''mixed ''<<Verbatim(''')"
-">>'''''bold'''<<Verbatim(''')>> and italics''<<Verbatim('')>>; <<Verbatim"
-"(----)>> horizontal rule.\n"
-" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
-"===== Title 5 =====.\n"
-" Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1."
-"#n start numbering at n; space alone indents.\n"
-" Links:: <<Verbatim(JoinCapitalizedWords)>>; <<Verbatim([[target|linktext]])"
-">>.\n"
-" Tables:: || cell text |||| cell text spanning 2 columns ||;    no trailing "
-"white space allowed after tables or titles.\n"
-"\n"
-"(!) For more help, see HelpOnEditing or SyntaxReference.\n"
+#, fuzzy
+msgid "Password is too short."
+msgstr "Contrasenya (comprovació)"
+
+msgid "Password has not enough different characters."
 msgstr ""
-" Èmfasi:: <<Verbatim('')>>''cursiva''<<Verbatim('')>>; <<Verbatim(''')"
-">>'''negreta'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''negreta "
-"cursiva'''''<<Verbatim(''''')>>; <<Verbatim('')>>''combinació ''<<Verbatim"
-"(''')>>'''''negreta'''<<Verbatim(''')>> i cursiva''<<Verbatim('')>>; "
-"<<Verbatim(----)>> regla horitzontal.\n"
-" Encapçalaments:: = Títol 1 =; == Títol 2 ==; === Títol 3 ===; ==== Títol 4 "
-"====; ===== Títol 5 =====.\n"
-" Llistes:: espai i un dels següents: * pics; 1., a., A., i., I. elements "
-"numerats; 1.#n comença a numerar des de n; només espai sagna.\n"
-" Enllaços:: <<Verbatim(JuntaParaulesAmbMajúscules)>>; <<Verbatim"
-"([[destinació|textenllaç]])>>.\n"
-" Taules:: || text de la cel·la |||| text de ce·les que ocupen dos columnes "
-"||;    no s'admet espai en blanc després de taules o títols.\n"
-"\n"
-"(!) Per a obtindre'n més ajuda, vegeu HelpOnEditing o SyntaxReference.\n"
-
-msgid ""
-"{{{\n"
-"Emphasis: *italic* **bold** ``monospace``\n"
-"\n"
-"Headings: Heading 1  Heading 2  Heading 3\n"
-"          =========  ---------  ~~~~~~~~~\n"
-"\n"
-"Horizontal rule: ----\n"
-"\n"
-"Links: TrailingUnderscore_ `multi word with backticks`_ external_\n"
-"\n"
-".. _external: http://external-site.example.org/foo/\n"
-"\n"
-"Lists: * bullets; 1., a. numbered items.\n"
-"}}}\n"
-"(!) For more help, see the\n"
-"[[http://docutils.sourceforge.net/docs/user/rst/quickref.html|"
-"reStructuredText Quick Reference]].\n"
-msgstr ""
-"{{{\n"
-"Èmfasi: *cursiva* **bold ``amplada fixa``\n"
-"\n"
-"Capçaleres: Capçalera 1  Capçalera 2  Capçalera 3\n"
-"            ===========  -----------  ~~~~~~~~~~~\n"
-"\n"
-"Regla horitzontal: ----\n"
-"Enllaços: SubratllatFinal_ `múltiples paraules amb cometa invertida`_ "
-"extern_\n"
-"\n"
-".. _extern: http://lloc-extern.exemple.net/mec/\n"
-"\n"
-"Llistes: * pics ; 1., a. elements numerats.\n"
-"}}}\n"
-"(!) Per a obtindre'n més ajuda, vegeu la\n"
-"[[http://docutils.sourceforge.net/docs/user/rst/quickref.html|referència "
-"ràpida de reStructuredText]].\n"
 
 #, fuzzy
 msgid ""
-" Emphasis:: <<Verbatim(//)>>''italics''<<Verbatim(//)>>; <<Verbatim(**)"
-">>'''bold'''<<Verbatim(**)>>; <<Verbatim(**//)>>'''''bold "
-"italics'''''<<Verbatim(//**)>>; <<Verbatim(//)>>''mixed ''<<Verbatim(**)"
-">>'''''bold'''<<Verbatim(**)>> and italics''<<Verbatim(//)>>;\n"
-" Horizontal Rule:: <<Verbatim(----)>>\n"
-" Force Linebreak:: <<Verbatim(\\\\)>>\n"
-" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
-"===== Title 5 =====.\n"
-" Lists:: * bullets; ** sub-bullets; # numbered items; ## numbered sub "
-"items.\n"
-" Links:: <<Verbatim([[target]])>>; <<Verbatim([[target|linktext]])>>.\n"
-" Tables:: |= header text | cell text | more cell text |;\n"
-"\n"
-"(!) For more help, see HelpOnEditing or HelpOnCreoleSyntax.\n"
+"Password is too easy (password contains name or name contains password)."
+msgstr "Manca la contrasenya. Introduïu el nom d'usuari i contrasenya."
+
+msgid "Password is too easy (keyboard sequence)."
 msgstr ""
-" Èmfasi:: <<Verbatim('')>>''cursiva''<<Verbatim('')>>; <<Verbatim(''')"
-">>'''negreta'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''negreta "
-"cursiva'''''<<Verbatim(''''')>>; <<Verbatim('')>>''combinació ''<<Verbatim"
-"(''')>>'''''negreta'''<<Verbatim(''')>> i cursiva''<<Verbatim('')>>; "
-"<<Verbatim(----)>> regla horitzontal.\n"
-" Encapçalaments:: <<Verbatim(=)>> Títol 1 <<Verbatim(=)>>; <<Verbatim(==)>> "
-"Títol 2 <<Verbatim(==)>>; <<Verbatim(===)>> Títol 3 <<Verbatim(===)>>;   "
-"<<Verbatim(====)>> Títol 4 <<Verbatim(====)>>; <<Verbatim(=====)>> Títol 5 "
-"<<Verbatim(=====)>>.\n"
-" Llistes:: espai i algun dels següents: pics *; 1., a., A., i., I. elements "
-"numerats; 1.#n comença a numerar des de n; només espai sagna.\n"
-" Enllaços:: <<Verbatim(JuntaParaulesAmbMajúscules)>>; <<Verbatim"
-"([[destinació|textenllaç]])>>.\n"
-" Taules:: || text de la cel·la |||| text de ce·les que ocupen dos columnes "
-"||;    no s'admet espai en blanc després de taules o títols.\n"
-"\n"
-"(!) Per a obtindre'n més ajuda, vegeu HelpOnEditing o SyntaxReference.\n"
 
 msgid "Diffs"
 msgstr "Diferències"
@@ -2495,6 +2496,16 @@
 msgid "User"
 msgstr "Usuari"
 
+msgid "[ATTACH]"
+msgstr ""
+
+#, fuzzy
+msgid "Variable name"
+msgstr "Nom del fitxer"
+
+msgid "Description"
+msgstr ""
+
 #, python-format
 msgid "Upload new attachment \"%(filename)s\""
 msgstr "Apuja una nova adjunció «%(filename)s»"
@@ -2535,6 +2546,20 @@
 msgid "Display"
 msgstr "Visualització"
 
+msgid "Wiki configuration"
+msgstr ""
+
+msgid ""
+"This table shows all settings in this wiki that do not have default values. "
+"Settings that the configuration system doesn't know about are shown in "
+"''italic'', those may be due to third-party extensions needing configuration "
+"or settings that were removed from Moin."
+msgstr ""
+
+#, fuzzy
+msgid "Setting"
+msgstr "Paràmetres"
+
 msgid "Search for items"
 msgstr "Cerca elements"
 
@@ -2882,6 +2907,12 @@
 msgid "Toggle line numbers"
 msgstr "Commuta els números de línia"
 
+#~ msgid "Wiki Backup / Restore"
+#~ msgstr "Còpia de seguretat / Restauració del wiki"
+
+#~ msgid "Restore"
+#~ msgstr "Restaura"
+
 #~ msgid "Xapian Version"
 #~ msgstr "Versió del Xapian"
 
@@ -3015,10 +3046,6 @@
 #~ msgid "Sorry, login failed."
 #~ msgstr "Ha fallat l'entrada."
 
-#, fuzzy
-#~ msgid "Filename"
-#~ msgstr "Nom del fitxer"
-
 #~ msgid "belonging to one of the following categories"
 #~ msgstr "que pertanyen a una de les categories següents"
 
--- a/MoinMoin/i18n/cs.MoinMoin.po	Wed Dec 10 11:09:30 2008 +0100
+++ b/MoinMoin/i18n/cs.MoinMoin.po	Sat Dec 13 19:27:41 2008 +0100
@@ -13,7 +13,7 @@
 msgstr ""
 "Project-Id-Version: MoinMoin 1.6\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-09-07 23:23+0200\n"
+"POT-Creation-Date: 2008-09-28 20:59+0200\n"
 "PO-Revision-Date: 2007-11-05 22:11+0100\n"
 "Last-Translator: Václav Haisman <v.haisman@sh.cvut.cz>\n"
 "Language-Team: Czech <moin@lists.sourceforge.net>\n"
@@ -786,7 +786,8 @@
 
 #, python-format
 msgid ""
-"Dear Superuser, a new user has just been created. Details follow:\n"
+"Dear Superuser, a new user has just been created on %(sitename)s\". Details "
+"follow:\n"
 "\n"
 "    User name: %(username)s\n"
 "    Email address: %(useremail)s"
@@ -824,6 +825,42 @@
 msgid "Page changed"
 msgstr "Uložit změny"
 
+#, fuzzy
+msgid ""
+" Emphasis:: <<Verbatim('')>>''italics''<<Verbatim('')>>; <<Verbatim(''')"
+">>'''bold'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''bold "
+"italics'''''<<Verbatim(''''')>>; <<Verbatim('')>>''mixed ''<<Verbatim(''')"
+">>'''''bold'''<<Verbatim(''')>> and italics''<<Verbatim('')>>; <<Verbatim"
+"(----)>> horizontal rule.\n"
+" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
+"===== Title 5 =====.\n"
+" Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1."
+"#n start numbering at n; space alone indents.\n"
+" Links:: <<Verbatim(JoinCapitalizedWords)>>; <<Verbatim([[target|linktext]])"
+">>.\n"
+" Tables:: || cell text |||| cell text spanning 2 columns ||;    no trailing "
+"white space allowed after tables or titles.\n"
+"\n"
+"(!) For more help, see HelpOnEditing or SyntaxReference.\n"
+msgstr ""
+" Zvýraznění:: <<Verbatim('')>>''kurzíva''<<Verbatim('')>>; <<Verbatim(''')"
+">>'''tučně'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''tučně "
+"kurzíva'''''<<Verbatim(''''')>>; <<Verbatim('')>>''smíšené ''<<Verbatim(''')"
+">>'''''tučně'''<<Verbatim(''')>> a kurzíva''<<Verbatim('')>>; <<Verbatim"
+"(----)>> vodorovná čára.\n"
+" Nadpisy:: <<Verbatim(=)>> Nadpis 1 <<Verbatim(=)>>; <<Verbatim(==)>> Nadpis "
+"2 <<Verbatim(==)>>; <<Verbatim(===)>> Nadpis 3 <<Verbatim(===)>>;   "
+"<<Verbatim(====)>> Nadpis 4 <<Verbatim(====)>>; <<Verbatim(=====)>> Nadpis 5 "
+"<<Verbatim(=====)>>.\n"
+" Seznamy:: mezera a jeden z: * odrážky; 1., a., A., i., I. číslované "
+"odrážky; 1.#n začít číslovat u n; sama mezera odsazuje.\n"
+" Odkazy:: <<Verbatim(SpojenaSlovasVelkymiPocatecnimiPismeny)>>; <<Verbatim"
+"([[cíl odkazu|text odkazu]])>>.\n"
+" Tabulky:: || text buněk |||| text dvou spojených buněk ||;    nejsou "
+"dovoleny mezery za nadpisy a tabulkami.\n"
+"\n"
+"(!) Další nápověda viz HelpOnEditing nebo SyntaxReference.\n"
+
 #, python-format
 msgid "Expected \"%(wanted)s\" after \"%(key)s\", got \"%(token)s\""
 msgstr "Očekáváno \"%(wanted)s\" po \"%(key)s\", získáno \"%(token)s\""
@@ -855,6 +892,44 @@
 msgstr ""
 "Zobrazení restrukturovaného textu není možné, prosím nainstalujte Docutils."
 
+#, fuzzy
+msgid ""
+"{{{\n"
+"Emphasis: *italic* **bold** ``monospace``\n"
+"\n"
+"Headings: Heading 1  Heading 2  Heading 3\n"
+"          =========  ---------  ~~~~~~~~~\n"
+"\n"
+"Horizontal rule: ----\n"
+"\n"
+"Links: TrailingUnderscore_ `multi word with backticks`_ external_\n"
+"\n"
+".. _external: http://external-site.example.org/foo/\n"
+"\n"
+"Lists: * bullets; 1., a. numbered items.\n"
+"}}}\n"
+"(!) For more help, see the\n"
+"[[http://docutils.sourceforge.net/docs/user/rst/quickref.html|"
+"reStructuredText Quick Reference]].\n"
+msgstr ""
+"Zvýraznění: <i>*kurzíva*</i> <b>**tučně</b> ``monospace``<br/>\n"
+"<br/><pre>\n"
+"Nadpisy: Nadpis 1  Nadpis 2  Nadpis 3\n"
+"         ========  --------  ~~~~~~~~\n"
+"\n"
+"Vodorovná linka: ---- \n"
+"Odkazy: PřipojenéPodtržítko_ `více slov ve zpětném apostrofu`_ external_ \n"
+"\n"
+".. _external: http://external-site.net/foo/\n"
+"\n"
+"Seznamy: * bodové odrážky; 1., a. číslované seznamy.\n"
+"</pre>\n"
+"<br/>\n"
+"(!) Více informací viz \n"
+"<a href=\"http://docutils.sourceforge.net/docs/user/rst/quickref.html\">\n"
+"reStructuredText Quick Reference\n"
+"</a>.\n"
+
 msgid "**Maximum number of allowed includes exceeded**"
 msgstr "**Překročen maximální počet povolených includes**"
 
@@ -866,6 +941,41 @@
 msgid "**Could not find the referenced page: %s**"
 msgstr "**Nemohu najít odkazovanou stránku: %s**"
 
+#, fuzzy
+msgid ""
+" Emphasis:: <<Verbatim(//)>>''italics''<<Verbatim(//)>>; <<Verbatim(**)"
+">>'''bold'''<<Verbatim(**)>>; <<Verbatim(**//)>>'''''bold "
+"italics'''''<<Verbatim(//**)>>; <<Verbatim(//)>>''mixed ''<<Verbatim(**)"
+">>'''''bold'''<<Verbatim(**)>> and italics''<<Verbatim(//)>>;\n"
+" Horizontal Rule:: <<Verbatim(----)>>\n"
+" Force Linebreak:: <<Verbatim(\\\\)>>\n"
+" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
+"===== Title 5 =====.\n"
+" Lists:: * bullets; ** sub-bullets; # numbered items; ## numbered sub "
+"items.\n"
+" Links:: <<Verbatim([[target]])>>; <<Verbatim([[target|linktext]])>>.\n"
+" Tables:: |= header text | cell text | more cell text |;\n"
+"\n"
+"(!) For more help, see HelpOnEditing or HelpOnCreoleSyntax.\n"
+msgstr ""
+" Zvýraznění:: <<Verbatim('')>>''kurzíva''<<Verbatim('')>>; <<Verbatim(''')"
+">>'''tučně'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''tučně "
+"kurzíva'''''<<Verbatim(''''')>>; <<Verbatim('')>>''smíšené ''<<Verbatim(''')"
+">>'''''tučně'''<<Verbatim(''')>> a kurzíva''<<Verbatim('')>>; <<Verbatim"
+"(----)>> vodorovná čára.\n"
+" Nadpisy:: <<Verbatim(=)>> Nadpis 1 <<Verbatim(=)>>; <<Verbatim(==)>> Nadpis "
+"2 <<Verbatim(==)>>; <<Verbatim(===)>> Nadpis 3 <<Verbatim(===)>>;   "
+"<<Verbatim(====)>> Nadpis 4 <<Verbatim(====)>>; <<Verbatim(=====)>> Nadpis 5 "
+"<<Verbatim(=====)>>.\n"
+" Seznamy:: mezera a jeden z: * odrážky; 1., a., A., i., I. číslované "
+"odrážky; 1.#n začít číslovat u n; sama mezera odsazuje.\n"
+" Odkazy:: <<Verbatim(SpojenaSlovasVelkymiPocatecnimiPismeny)>>; <<Verbatim"
+"([[cíl odkazu|text odkazu]])>>.\n"
+" Tabulky:: || text buněk |||| text dvou spojených buněk ||;    nejsou "
+"dovoleny mezery za nadpisy a tabulkami.\n"
+"\n"
+"(!) Další nápověda viz HelpOnEditing nebo SyntaxReference.\n"
+
 msgid "Preferences"
 msgstr "Nastaveni"
 
@@ -1304,61 +1414,28 @@
 "username, the recovery token and a new password (twice) below."
 msgstr ""
 
-#, python-format
-msgid ""
-"Restored Backup: %(filename)s to target dir: %(targetdir)s.\n"
-"Files: %(filecount)d, Directories: %(dircount)d"
-msgstr ""
-"Obnovena záloha: %(filename)s do adresáře: %(targetdir)s.\n"
-"Souborů: %(filecount)d, Adresářů: %(dircount)d"
-
-#, python-format
-msgid "Restoring backup: %(filename)s to target dir: %(targetdir)s failed."
-msgstr ""
-"Obnovení ze zálohy: %(filename)s do adresáře: %(targetdir)s neproběhlo "
-"úspěšně."
-
-msgid "Wiki Backup / Restore"
-msgstr "Záloha / Obnova Wiki"
+#, fuzzy
+msgid "Wiki Backup"
+msgstr "Značkování Wiki"
 
 msgid ""
-"Some hints:\n"
-" * To restore a backup:\n"
-"  * Restoring a backup will overwrite existing data, so be careful.\n"
-"  * Rename it to <siteid>.tar.<compression> (remove the --date--time--UTC "
-"stuff).\n"
-"  * Put the backup file into the backup_storage_dir (use scp, ftp, ...).\n"
-"  * Hit the <<GetText(Restore)>> button below.\n"
-"\n"
-" * To make a backup, just hit the <<GetText(Backup)>> button and save the "
-"file\n"
-"   you get to a secure place.\n"
-"\n"
-"Please make sure your wiki configuration backup_* values are correct and "
-"complete.\n"
+"= Downloading a backup =\n"
 "\n"
+"Please note:\n"
+" * Store backups in a safe and secure place - they contain sensitive "
+"information.\n"
+" * Make sure your wiki configuration backup_* values are correct and "
+"complete.\n"
+" * Make sure the backup file you get contains everything you need in case of "
+"problems.\n"
+" * Make sure it is downloaded without problems.\n"
+"\n"
+"To get a backup, just click here:"
 msgstr ""
-"Nápověda:\n"
-" * Jak obnovit zálohu:\n"
-"  * Obnovení ze zálohy přepíše současná data. Buďte opatrní.\n"
-"  * Přejmenujte záložní soubor na <siteid>.tar.<compression> (odstraňte --"
-"date--time--UTC).\n"
-"  * Vložte záložní soubor do backup_storage_dir.\n"
-"  * Stiskněte tlačítko <<GetText(Restore)>> níže.\n"
-"\n"
-" * Jak vytvořit zálohu:\n"
-"  * Stačí stisknout tlačítko <<GetText(Backup)>> níže a uložit získaný "
-"soubor na bezpečném místě.\n"
-"\n"
-"Zajistěte prosím správné a kompletní nastavení backup_* hodnot v "
-"konfiguraci.\n"
 
 msgid "Backup"
 msgstr "Záloha"
 
-msgid "Restore"
-msgstr "Obnova"
-
 msgid "You are not allowed to do remote backup."
 msgstr "Nemáte dovoleno provést vzdálenou zálohu."
 
@@ -2232,113 +2309,19 @@
 msgstr "Přihlásili jste se k odběru této stránky."
 
 #, fuzzy
-msgid ""
-" Emphasis:: <<Verbatim('')>>''italics''<<Verbatim('')>>; <<Verbatim(''')"
-">>'''bold'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''bold "
-"italics'''''<<Verbatim(''''')>>; <<Verbatim('')>>''mixed ''<<Verbatim(''')"
-">>'''''bold'''<<Verbatim(''')>> and italics''<<Verbatim('')>>; <<Verbatim"
-"(----)>> horizontal rule.\n"
-" Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; "
-"===== Title 5 =====.\n"
-" Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1."
-"#n start numbering at n; space alone indents.\n"
-" Links:: <<Verbatim(JoinCapitalizedWords)>>; <<Verbatim([[target|linktext]])"
-">>.\n"
-" Tables:: || cell text |||| cell text spanning 2 columns ||;    no trailing "
-"white space allowed after tables or titles.\n"
-"\n"
-"(!) For more help, see HelpOnEditing or SyntaxReference.\n"
+msgid "Password is too short."
+msgstr "Opakovat heslo"
+
+msgid "Password has not enough different characters."
 msgstr ""
-" Zvýraznění:: <<Verbatim('')>>''kurzíva''<<Verbatim('')>>; <<Verbatim(''')"
-">>'''tučně'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''tučně "
-"kurzíva'''''<<Verbatim(''''')>>; <<Verbatim('')>>''smíšené ''<<Verbatim(''')"
-">>'''''tučně'''<<Verbatim(''')>> a kurzíva''<<Verbatim('')>>; <<Verbatim"
-"(----)>> vodorovná čára.\n"
-" Nadpisy:: <<Verbatim(=)>> Nadpis 1 <<Verbatim(=)>>; <<Verbatim(==)>> Nadpis "
-"2 <<Verbatim(==)>>; <<Verbatim(===)>> Nadpis 3 <<Verbatim(===)>>;   "
-"<<Verbatim(====)>> Nadpis 4 <<Verbatim(====)>>; <<Verbatim(=====)>> Nadpis 5 "
-"<<Verbatim(=====)>>.\n"
-" Seznamy:: mezera a jeden z: * odrážky; 1., a., A., i., I. číslované "
-"odrážky; 1.#n začít číslovat u n; sama mezera odsazuje.\n"
-" Odkazy:: <<Verbatim(SpojenaSlovasVelkymiPocatecnimiPismeny)>>; <<Verbatim"
-"([[cíl odkazu|text odkazu]])>>.\n"
-" Tabulky:: || text buněk |||| text dvou spojených buněk ||;    nejsou "
-"dovoleny mezery za nadpisy a tabulkami.\n"
-"\n"
-"(!) Další nápověda viz HelpOnEditing nebo SyntaxReference.\n"
 
 #, fuzzy
 msgid ""
-"{{{\n"
-"Emphasis: *italic* **bold** ``monospace``\n"
-"\n"
-"Headings: Heading 1  Heading 2  Heading 3\n"
-"          =========  ---------  ~~~~~~~~~\n"
-"\n"
-"Horizontal rule: ----\n"
-"\n"
-"Links: TrailingUnderscore_ `multi word with backticks`_ external_\n"
-"\n"
-".. _external: http://external-site.example.org/foo/\n"
-"\n"
-"Lists: * bullets; 1., a. numbered items.\n"
-"}}}\n"
-"(!) For more help, see the\n"
-"[[http://docutils.sourceforge.net/docs/user/rst/quickref.html|"
-"reStructuredText Quick Reference]].\n"
+"Password is too easy (password contains name or name contains password)."
+msgstr "Prázdné heslo. Prosím vložte jméno a heslo."
+
+msgid "Password is too easy (keyboard sequence)."
 msgstr ""
-"Zvýraznění: <i>*kurzíva*</i> <b>**tučně</b> ``monospace``<br/>\n"
-"<br/><pre>\n"
-"Nadpisy: Nadpis 1  Nadpis 2  Nadpis 3\n"
-"         ========  --------  ~~~~~~~~\n"
-"\n"
-"Vodorovná linka: ---- \n"
-"Odkazy: PřipojenéPodtržítko_ `více slov ve zpětném apostrofu`_ external_ \n"
-"\n"
-".. _external: http://external-site.net/foo/\n"
-"\n"
-"Seznamy: * bodové odrážky; 1., a. číslované seznamy.\n"
-"</pre>\n"
-"<br/>\n"
-"(!) Více informací viz \n"
-"<a href=\"http://docutils.sourceforge.net/docs/user/rst/quickref.html\">\n"
-"reStructuredText Quick Reference\n"
-"</a>.\n"
-
-#, fuzzy
-msgid ""
-" Emphasis:: <<Verbatim(//)>>''italics''<<Verbatim(//)>>; <<Verbatim(**)"
-">>'''bold'''<<Verbatim(**)>>; <<Verbatim(**//)>>'''''bold "
-"italics'''''<<Verbatim(//**)>>; <<Verbatim(//)>>''mixed ''<<Verbatim(**)"
-">>'''''bold'''<<Verbatim(**)>> and italics''<<Verbatim(//)>>;\n"
-" Horizontal Rule:: <&