Index: script/maint/mkpagepacks.py
===================================================================
--- script/maint/mkpagepacks.py	(.../tags/MoinMoin-1.5.6/MoinMoin)	(revision 237)
+++ script/maint/mkpagepacks.py	(.../trunk/MoinMoin)	(revision 237)
@@ -110,7 +110,7 @@
             pagename = pagename.strip()
             page = Page(request, pagename)
             try:
-                underlay, path = page.getPageBasePath(-1)
+                path = page.getPageBasePath()
                 shutil.rmtree(path)
             except:
                 pass
Index: multiconfig.py
===================================================================
--- multiconfig.py	(.../tags/MoinMoin-1.5.6/MoinMoin)	(revision 237)
+++ multiconfig.py	(.../trunk/MoinMoin)	(revision 237)
@@ -612,17 +614,28 @@
         Both data and underlay should exists and allow read, write and
         execute.
         """
+        if not hasattr(self, 'page_data_dirs'):
+           data_dir = getattr(self, 'data_dir')
+           underlay_dir = getattr(self, 'data_underlay_dir')
+           self.page_data_dirs = [ data_dir, ]
+           if underlay_dir:
+               self.page_data_dirs = [ data_dir, underlay_dir, ]
+
         mode = os.F_OK | os.R_OK | os.W_OK | os.X_OK
-        for attr in ('data_dir', 'data_underlay_dir'):
-            path = getattr(self, attr)
+        for attr in ('data_dir', 'data_underlay_dir', 'page_data_dirs'):
+            if attr == 'data_dir' or attr == 'data_underlay_dir':
+                paths_to_check = ( getattr(self, attr), )
+            else:
+                paths_to_check = getattr(self, attr)
             
             # allow an empty underlay path or None
-            if attr == 'data_underlay_dir' and not path:
+            if attr == 'data_underlay_dir' and not paths_to_check:
                 continue
 
-            path_pages = os.path.join(path, "pages")
-            if not (os.path.isdir(path_pages) and os.access(path_pages, mode)):
-                msg = '''
+            for path in paths_to_check:
+                path_pages = os.path.join(path, "pages")
+                if not (os.path.isdir(path_pages) and os.access(path_pages, mode)):
+                    msg = '''
 %(attr)s "%(path)s" does not exists, or has incorrect ownership or
 permissions.
 
Index: PageEditor.py
===================================================================
--- PageEditor.py	(.../tags/MoinMoin-1.5.6/MoinMoin)	(revision 237)
+++ PageEditor.py	(.../trunk/MoinMoin)	(revision 237)
@@ -804,7 +839,10 @@
         llog = editlog.EditLog(self.request, filename=pagelog,
                                uid_override=self.uid_override)
         # Open the global log
-        glog = editlog.EditLog(self.request, uid_override=self.uid_override)
+        root_dir = os.path.dirname( os.path.dirname( pagedir ) )
+        gpagelog = os.path.join( root_dir, 'edit-log')
+        glog = editlog.EditLog(self.request, filename=gpagelog,
+                               uid_override=self.uid_override)
         
         if not os.path.exists(pagedir): # new page, create and init pagedir
             os.mkdir(pagedir)
@@ -894,9 +894,6 @@
                 # set in-memory content
                 self.set_raw_body(text)

-                # reset page object
-                self.reset()
-
                 # write the editlog entry
                 # for now simply make 2 logs, better would be some multilog stuff maybe
                 if self.do_revision_backup:
@@ -910,6 +907,9 @@
             if got_lock:
                 filesys.rename(clfn, cfn)

+        # reset page object
+        self.reset()
+
         # add event log entry
         elog = eventlog.EventLog(self.request)
         elog.add(self.request, 'SAVEPAGE', {'pagename': self.page_name}, 1, mtime_usecs)
@@ -916,7 +955,7 @@
             other = False
             pagelog = self.getPagePath('edit-log', use_underlay=0, isfile=1)
             next_line = None
-            for line in editlog.EditLog(self.request, pagelog).reverse():
+            for line in editlog.EditLog(self.request, filename=pagelog).reverse():
                 if int(line.rev)==int(rev):
                     break
                 if not line.is_from_current_user(self.request):
Index: wikiaction.py
===================================================================
--- wikiaction.py	(.../tags/MoinMoin-1.5.6/MoinMoin)	(revision 237)
+++ wikiaction.py	(.../trunk/MoinMoin)	(revision 237)
@@ -213,6 +215,15 @@
         # show page size
         request.write(("<p>%s</p>" % _("Page size: %d")) % page.size())
 
+        page_location = 'Overlay'
+        page_path = page.getPageBasePath()
+        if request.cfg.data_underlay_dir and \
+           request.cfg.data_underlay_dir ==  os.path.commonprefix( [ request.cfg.data_underlay_dir, page_path ] ):
+            page_location = 'Underlay'
+        elif request.cfg.data_dir ==  os.path.commonprefix( [ request.cfg.data_dir, page_path ] ):
+            page_location = 'Standard'
+        request.write(("<p>%s</p>" % _("Page Location: %s")) % page_location)
+
         # show SHA digest fingerprint
         import sha
         digest = sha.new(page.get_raw_body().encode(config.charset)).hexdigest().upper()
Index: Page.py
===================================================================
--- Page.py	(.../tags/MoinMoin-1.5.6/MoinMoin)	(revision 237)
+++ Page.py	(.../trunk/MoinMoin)	(revision 237)
@@ -24,7 +24,7 @@
     # Header regular expression, used to get header boundaries
     header_re = r'(^#+.*(?:\n\s*)+)+'
 
-    def __init__(self, request, page_name, **keywords):
+    def __init__(self, request, page_name, **kw):
         """
         Create page object.
 
@@ -37,13 +37,12 @@
         @keyword formatter: formatter instance
         @keyword include_self: if 1, include current user (default: 0)
         """
-        self.rev = keywords.get('rev', 0) # revision of this page
-        self.is_rootpage = keywords.get('is_rootpage', 0) # is this __init__ of rootpage?
-        self.include_self = keywords.get('include_self', 0)
         self.request = request
         self.cfg = request.cfg
-
         self.page_name = page_name
+        self.rev = kw.get('rev', 0) # revision of this page
+        self.is_rootpage = kw.get('is_rootpage', 0) # is this __init__ of rootpage?
+        self.include_self = kw.get('include_self', 0)
 
         # XXX uncomment to see how many pages we create....
         #import sys, traceback
@@ -51,8 +50,8 @@
         #traceback.print_stack(limit=4, file=sys.stderr)
 
 
-        if keywords.has_key('formatter'):
-            self.formatter = keywords.get('formatter')
+        if kw.has_key('formatter'):
+            self.formatter = kw.get('formatter')
             self.default_formatter = 0
         else:
             self.default_formatter = 1
@@ -67,39 +66,41 @@
 
     def reset(self):
         """ Reset page state """
-        page_name = self.page_name
         # page_name quoted for file system usage, needs to be reset to
         # None when pagename changes
 
-        qpagename = wikiutil.quoteWikinameFS(page_name)
-        self.page_name_fs = qpagename
+        self.page_name_fs = wikiutil.quoteWikinameFS(self.page_name)
 
         # the normal and the underlay path used for this page
+        self.underlaypath = None
         if not self.cfg.data_underlay_dir is None:
-            underlaypath = os.path.join(self.cfg.data_underlay_dir, "pages", qpagename)
-        else:
-            underlaypath = None
-        if self.is_rootpage: # we have no request.rootpage yet!
-            if not page_name:
-                normalpath = self.cfg.data_dir
-            else:
-                raise NotImplementedError(
-                    "TODO: handle other values of rootpage (not used yet)")
-        else:
-            normalpath = self.request.rootpage.getPagePath("pages", qpagename,
-                                                           check_create=0, use_underlay=0)
+            self.underlaypath = os.path.join(self.cfg.data_underlay_dir, "pages", self.page_name_fs)
 
+        self.default_base_path = os.path.join(self.cfg.data_dir, "pages", self.page_name_fs)
+
+        pos = self.page_name.rfind('/')
+        if pos > 0:
+            parent = Page(self.request, self.page_name[:pos])
+            parent_base = os.path.dirname(parent.getPageBasePath())
+            self.default_base_path = os.path.join(parent_base, self.page_name_fs)
+
+        if self.is_rootpage:
+            self.default_base_path = os.path.dirname( os.path.dirname( self.default_base_path ) )
+
+        # reset the page path
+        self.pagepath = None
+        self.getPageBasePath()
+
         # TUNING - remember some essential values
 
         # does the page come from normal page storage (0) or from
         # underlay dir (1) (can be used as index into following lists)
-        self._underlay = None
+        self._underlay = 0
+        if self.underlaypath == self.pagepath:
+            self._underlay = 1
 
-        # path to normal / underlay page dir
-        self._pagepath = [normalpath, underlaypath]
-
         # path to normal / underlay page file
-        self._pagefile = [normalpath, underlaypath]
+        self._pagefile = [None, None]
 
         # *latest* revision of this page XXX needs to be reset to None
         # when current rev changes
@@ -185,15 +186,19 @@
                   int realrevint,
                   bool exists)
         """
+
         # Figure out if we should use underlay or not, if needed.
-        if use_underlay == -1:
-            if self._underlay is not None and self._pagepath[self._underlay] is not None:
-                underlay = self._underlay
-                pagedir = self._pagepath[underlay]
-            else:
-                underlay, pagedir = self.getPageStatus(check_create=0)
+        if use_underlay == 1:
+            pagedir = self.underlaypath
+            underlay = 1
         else:
-            underlay, pagedir = use_underlay, self._pagepath[use_underlay]
+            pagedir = self.getPageBasePath( )
+            underlay = 0
+            if pagedir == self.underlaypath :
+                underlay = 1
+                if use_underlay == 0:
+                    pagedir = self.default_base_path
+                    underlay = 0
 
         # Find current revision, if automatic selection is requested.
         if rev == 0:
@@ -224,14 +229,21 @@
 
     def current_rev(self):
         """Return number of current revision.
-        
+
         This is the same as get_rev()[1].
-        
+
         @return: int revision
         """
-        pagefile, rev, exists = self.get_rev()
-        return rev
+        if self.rev:
+            return self.rev
 
+        page_path = self.getPageBasePath( )
+        pagefile, realrev, exists = self.get_rev_dir(page_path)
+        #if realrev != 99999999:
+        #    self.rev = realrev
+
+        return realrev
+
     def get_real_rev(self):
         """Returns the real revision number of this page. A rev=0 is
         translated to the current revision.
@@ -243,73 +255,38 @@
             return self.current_rev()
         return self.rev
 
-    def getPageBasePath(self, use_underlay):
+    def _find_page(self, use_underlay=-1):
         """
-        Get full path to a page-specific storage area. `args` can
-        contain additional path components that are added to the base path.
+        Find the full path to a page-specific storage area.
 
-        @param use_underlay: force using a specific pagedir, default '-1'
-                                '-1' = automatically choose page dir
-                                '1' = use underlay page dir
-                                '0' = use standard page dir
+        @param use_underlay: 0 == no underlay, 1 == only underlay, other values default to look everywhere
+
         @rtype: string
-        @return: int underlay,
-                 str the full path to the storage area
+        @return: str the full path to the storage area, '' if no page not found
         """
-        standardpath, underlaypath = self._pagepath
-        if underlaypath is None:
-            use_underlay = 0
 
-        # self is a NORMAL page
-        if not self is self.request.rootpage:
-            if use_underlay == -1: # automatic
-                if self._underlay is None:
-                    underlay, path = 0, standardpath
-                    pagefile, rev, exists = self.get_rev(use_underlay=0)
-                    if not exists:
-                        pagefile, rev, exists = self.get_rev(use_underlay=1)
-                        if exists:
-                            underlay, path = 1, underlaypath
-                    self._underlay = underlay # XXX XXX
-                else:
-                    underlay = self._underlay
-                    path = self._pagepath[underlay]
-            else: # normal or underlay
-                underlay, path = use_underlay, self._pagepath[use_underlay]
+        search_path = self.cfg.page_data_dirs
 
-        # self is rootpage
-        else:
-            # our current rootpage is not a toplevel, but under another page
-            if self.page_name:
-                # this assumes flat storage of pages and sub pages on same level
-                if use_underlay == -1: # automatic
-                    if self._underlay is None:
-                        underlay, path = 0, standardpath
-                        pagefile, rev, exists = self.get_rev(use_underlay=0)
-                        if not exists:
-                            pagefile, rev, exists = self.get_rev(use_underlay=1)
-                            if exists:
-                                underlay, path = 1, underlaypath
-                        self._underlay = underlay # XXX XXX
-                    else:
-                        underlay = self._underlay
-                        path = self._pagepath[underlay]
-                else: # normal or underlay
-                    underlay, path = use_underlay, self._pagepath[use_underlay]
+        if self.request.cfg.data_underlay_dir:
+            if use_underlay == 1: # only look in the underlay dir
+                search_path = [ self.request.cfg.data_underlay_dir ]
+            elif use_underlay == 0: #dont look in underlay dir
+                search_path = []
+                for dir in self.cfg.page_data_dirs:
+                    if not dir == self.request.cfg.data_underlay_dir:
+                        search_path.append( dir )
 
-            # our current rootpage is THE virtual rootpage, really at top of all
+        for dir in search_path:
+            if self.page_name_fs:
+                fullpath = os.path.join( dir, "pages", self.page_name_fs)
+                if os.path.exists(fullpath) :
+                   return fullpath
             else:
-                # 'auto' doesn't make sense here. maybe not even 'underlay':
-                if use_underlay == 1:
-                    underlay, path = 1, self.cfg.data_underlay_dir
-                # no need to check 'standard' case, we just use path in that case!
-                else:
-                    # this is the location of the virtual root page
-                    underlay, path = 0, self.cfg.data_dir
+                return dir
 
-        return underlay, path
+        return ''
 
-    def getPageStatus(self, *args, **kw):
+    def getPagePath(self,  *args, **kw):
         """
         Get full path to a page-specific storage area. `args` can
         contain additional path components that are added to the base path.
@@ -324,28 +301,79 @@
                                (default true)
         @keyword isfile: is the last component in args a filename? (default is false)
         @rtype: string
-        @return: (int underlay (1 if using underlay, 0 otherwise),
-                  str the full path to the storage area )
+        @return: str the full path to the storage area 
         """
+
         check_create = kw.get('check_create', 1)
-        isfile = kw.get('isfile', 0)
         use_underlay = kw.get('use_underlay', -1)
-        underlay, path = self.getPageBasePath(use_underlay)
-        fullpath = os.path.join(*((path,) + args))
+        
+        if use_underlay == 1:
+            page_path = self.underlaypath
+        else:
+            page_path = self.getPageBasePath( )
+            if use_underlay == 0 and page_path == self.underlaypath:
+                page_path = self.default_base_path
+
+        fullpath = os.path.join(*((page_path,) + args))
+
         if check_create:
+            isfile = kw.get('isfile', 0)
             if isfile:
                 dirname, filename = os.path.split(fullpath)
             else:
                 dirname = fullpath
             if not os.path.exists(dirname):
                 filesys.makeDirs(dirname)
-        return underlay, fullpath
+            if hasattr(self.request.cfg, 'uime') and self.request.cfg.uime['enable']:
+                from MoinMoin.action import AttachFile
+                AttachFile.getAttachDir(self, self.page_name, create=1)
+        return fullpath
 
-    def getPagePath(self, *args, **kw):
-        """Return path to the page storage area."""
 
-        return self.getPageStatus(*args, **kw)[1]
+    def getPageBasePath(self):
+        """
+        Get full path to a page-specific storage area.
 
+        @rtype: string
+        @return: str the full path to the storage area
+        """
+
+        if hasattr(self, 'pagepath') and self.pagepath:
+            return self.pagepath
+
+        self.pagepath = self._find_current_page(rev=self.rev)
+        if not self.pagepath:
+            self.pagepath = self.default_base_path
+
+        return self.pagepath
+
+    def _find_current_page(self, rev=0, use_underlay=-1):
+        """
+        Find the current full path to a page-specific storage area.
+
+        @param use_underlay: -1 == auto, 0 == normal, 1 == underlay
+        @param rev: int revision to get (default is 0 and means the current
+                    revision )
+
+        @rtype: string
+        @return: str the full path to the storage area, '' if no page not found
+        """
+
+        if not rev and self.rev:
+            rev = self.rev
+
+        fullpath =  self._find_page(use_underlay)
+        if fullpath :
+            pagefile, realrev, exists = self.get_rev_dir(fullpath, rev)
+            if exists:
+                return fullpath
+            return ''
+
+        return ''
+
+    def getPageUnderlayPath(self):
+        return self.underlaypath
+
     def split_title(self, request, force=0):
         """
         Return a string with the page name split by spaces, if
@@ -397,7 +425,8 @@
     def _last_edited(self, request):
         from MoinMoin.logfile import editlog
         try:
-            logfile = editlog.EditLog(request, self.getPagePath('edit-log', check_create=0, isfile=1))
+            logfile_name = os.path.join( self.getPageBasePath(), 'edit-log')
+            logfile = editlog.EditLog(request, filename=logfile_name)
             logfile.to_end()
             log = logfile.previous()
         except StopIteration:
@@ -486,8 +515,24 @@
         @rtype: bool
         @return: true if page lives in the underlay dir
         """
-        return self.exists(domain='underlay', includeDeleted=includeDeleted)
+        # page cant be an underlay page
+        if not self.request.cfg.data_underlay_dir:
+            return False
 
+        if includeDeleted:
+            page_dir = self._find_page(use_underlay=1)
+        else:
+            page_dir = self._find_current_page(use_underlay=1)
+
+        if page_dir:
+            underlay_dir = self.request.cfg.data_underlay_dir
+
+            # we found the page in a dir that is the underlay dir
+            if underlay_dir == os.path.commonprefix( [ underlay_dir, page_dir ] ):
+                return True
+
+        return False
+
     def isStandardPage(self, includeDeleted=True):
         """ Does this page live in the data dir?
 
@@ -498,9 +543,25 @@
         @rtype: bool
         @return: true if page lives in the data dir
         """
-        return self.exists(domain='standard', includeDeleted=includeDeleted)
+        # page cant be an underlay page
+        if not self.request.cfg.data_underlay_dir:
+            return True
 
-    def exists(self, rev=0, domain=None, includeDeleted=False):
+        if includeDeleted:
+            page_dir = self._find_page()
+        else:
+            page_dir = self._find_current_page()
+
+        if page_dir:
+            underlay_dir = self.request.cfg.data_underlay_dir
+
+            # we found the page in a dir that is not the underlay dir
+            if not underlay_dir == os.path.commonprefix( [ underlay_dir, page_dir ] ):
+                return True
+
+        return False
+
+    def exists(self, rev=0, includeDeleted=False):
         """ Does this page exist?
 
         This is the lower level method for checking page existence. Use
@@ -508,38 +569,19 @@
         cleaner code.
 
         @param rev: revision to look for. Default check current
-        @param domain: where to look for the page. Default look in all,
-            available values: 'underlay', 'standard'
         @param includeDeleted: ignore page state, just check its pagedir
         @rtype: bool
         @return: true, if page exists
         """
-        # Edge cases
-        if domain == 'underlay' and not self.request.cfg.data_underlay_dir:
-            return False
 
         if includeDeleted:
-            # Look for page directory, ignore page state
-            if domain is None:
-                checklist = [0, 1]
-            else:
-                checklist = [domain == 'underlay']
-            for use_underlay in checklist:
-                pagedir = self.getPagePath(use_underlay=use_underlay, check_create=0)
-                if os.path.exists(pagedir):
-                    return True
-            return False
+            page_dir = self._find_page()
         else:
-            # Look for non-deleted pages only, using get_rev
-            if not rev and self.rev:
-                rev = self.rev
+            page_dir = self._find_current_page(rev)
 
-            if domain is None:
-                use_underlay = -1
-            else:
-                use_underlay = domain == 'underlay'
-            d, d, exists = self.get_rev(use_underlay, rev)
-            return exists
+        if page_dir:
+            return True
+        return False
 
     def size(self, rev=0):
         """ Get Page size.
@@ -626,7 +668,8 @@
 
         return count
 
-    def getPageList(self, user=None, exists=1, filter=None):
+    def getPageList(self, user=None, exists=1, filter=None,
+                    return_objects=False):
         """ List user readable pages under current page
 
         Currently only request.rootpage is used to list pages, but if we
@@ -652,6 +695,8 @@
         @param user: the user requesting the pages (MoinMoin.user.User)
         @param filter: filter function
         @param exists: filter existing pages
+        @param return_objects: lets it return a list of Page objects instead of
+            names
         @rtype: list of unicode strings
         @return: user readable wiki page names
         """
@@ -683,15 +728,20 @@
                 if filter and not filter(name):
                     continue
 
+                page = Page(request, name)
+
                 # Filter deleted pages
-                if exists and not Page(request, name).exists():
+                if exists and not page.exists():
                     continue
 
                 # Filter out page user may not read.
                 if user and not user.may.read(name):
                     continue
 
-                pages.append(name)
+                if return_objects:
+                    pages.append(page)
+                else:
+                    pages.append(name)
         else:
             pages = cache.keys()
 
@@ -726,16 +776,12 @@
         @rtype: dict
         @return: dict of page names using file system encoding
         """
-        # Get pages in standard dir
-        path = self.getPagePath('pages')
-        pages = self._listPageInPath(path)
 
-        if self.cfg.data_underlay_dir is not None:
-            # Merge with pages from underlay
-            path = self.getPagePath('pages', use_underlay=1)
-            underlay = self._listPageInPath(path)
-            pages.update(underlay)
-
+        pages = {}
+        for dir in self.cfg.page_data_dirs:
+            path = os.path.join( dir, 'pages' )
+            more_pages = self._listPageInPath(path)
+            pages.update(more_pages)
         return pages
 
     def _listPageInPath(self, path):
@@ -1171,7 +1235,7 @@
                     wikiutil.url_quote_plus(full_text_query))
 
                 title = self.split_title(request)
-                if self.rev:
+                if self.rev and self.rev != 99999999:
                     msg = "<strong>%s</strong><br>%s" % (
                         _('Revision %(rev)d as of %(date)s') % {
                             'rev': self.rev,
@@ -1292,7 +1363,7 @@
         @rtype: string
         @return: formatter name as used in caching
         """
-        if not hasattr(self, 'formatter'):
+        if not hasattr(self, 'formatter') or self.formatter is None:
             return ''
         module = self.formatter.__module__
         return module[module.rfind('.') + 1:]
@@ -1377,10 +1448,10 @@
     def loadCache(self, request):
         """ Return page content cache or raises 'CacheNeedsUpdate' """
         cache = caching.CacheEntry(request, self, self.getFormatterName())
-        attachmentsPath = self.getPagePath('attachments', check_create=0)
+        attachmentsPath = os.path.join( self.getPageBasePath(), 'attachments')
         if cache.needsUpdate(self._text_filename(), attachmentsPath):
             raise Exception('CacheNeedsUpdate')
-        
+
         import marshal
         try:
             return marshal.loads(cache.content())
@@ -1443,7 +1514,7 @@
         import dircache
         revisions = []
         if self.page_name:
-            rev_dir = self.getPagePath('revisions', check_create=0)
+            rev_dir = os.path.join( self.getPageBasePath(), 'revisions')
             if os.path.isdir(rev_dir):
                 for rev in dircache.listdir(rev_dir):
                     try:
