--- Mailman/Cgi/admin.py
+++ Mailman/Cgi/admin.py
@@ -22,6 +22,7 @@
 
 import sys
 import os
+import string
 import re
 import cgi
 import sha
@@ -215,6 +216,12 @@
     # should have already been set.
     hostname = Utils.get_domain()
     legend = _('%(hostname)s mailing lists - Admin Links')
+
+    if not mm_cfg.LISTINFO_USE_CATEGORIES:
+        columns=2
+    else:
+        columns=3
+ 
     # The html `document'
     doc = Document()
     doc.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
@@ -222,7 +229,7 @@
     # The table that will hold everything
     table = Table(border=0, width="100%")
     table.AddRow([Center(Header(2, legend))])
-    table.AddCellInfo(table.GetCurrentRowIndex(), 0, colspan=2,
+    table.AddCellInfo(table.GetCurrentRowIndex(), 0, colspan=columns,
                       bgcolor=mm_cfg.WEB_HEADER_COLOR)
     # Skip any mailing list that isn't advertised.
     advertised = []
@@ -231,20 +238,20 @@
 
     for name in listnames:
         mlist = MailList.MailList(name, lock=0)
-        if mlist.advertised:
+        # enforce visibility for all lists
+        if mlist.advertised or not mlist.advertised:
+
             if mm_cfg.VIRTUAL_HOST_OVERVIEW and \
                    mlist.web_page_url.find(hostname) == -1:
                 # List is for different identity of this host - skip it.
                 continue
             else:
-                advertised.append((mlist.GetScriptURL('admin'),
-                                   mlist.real_name,
-                                   mlist.description))
+                advertised.append(mlist)
     # Greeting depends on whether there was an error or not
     if msg:
         greeting = FontAttr(msg, color="ff5060", size="+1")
     else:
-        greeting = _("Welcome!")
+        greeting = FontAttr(_('Welcome!'), size='+2')
 
     welcome = []
     mailmanlink = Link(mm_cfg.MAILMAN_URL, _('Mailman')).Format()
@@ -257,49 +264,100 @@
     else:
         welcome.extend([
             greeting,
-            _('''<p>Below is the collection of publicly-advertised
-            %(mailmanlink)s mailing lists on %(hostname)s.  Click on a list
-            name to visit the configuration pages for that list.'''),
+            _('''<p>Below is the collection of all mailing lists
+            on %(hostname)s.  Click on a list name to visit the configuration
+            pages for that list.'''),
             ])
 
     creatorurl = Utils.ScriptURL('create')
-    mailman_owner = Utils.get_site_email()
+    # mailman_owner = Utils.get_site_email()
+    mailman_owner = 'sysadmin@suse.de'
+ 
     extra = msg and _('right ') or ''
     welcome.extend([
-        _('''To visit the administrators configuration page for an
-        unadvertised list, open a URL similar to this one, but with a '/' and
-        the %(extra)slist name appended.  If you have the proper authority,
-        you can also <a href="%(creatorurl)s">create a new mailing list</a>.
-
-        <p>General list information can be found at '''),
+        _(''' <p>General list information can be found at '''),
         Link(Utils.ScriptURL('listinfo'),
              _('the mailing list overview page')),
         '.',
-        _('<p>(Send questions and comments to '),
+        _('<p>Send questions and comments to '),
         Link('mailto:%s' % mailman_owner, mailman_owner),
-        '.)<p>',
+        '.<p>',
         ])
 
     table.AddRow([Container(*welcome)])
-    table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0, colspan=2)
+    table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0, colspan=columns)
 
     if advertised:
-        table.AddRow(['&nbsp;', '&nbsp;'])
-        table.AddRow([Bold(FontAttr(_('List'), size='+2')),
-                      Bold(FontAttr(_('Description'), size='+2'))
-                      ])
-        highlight = 1
-        for url, real_name, description in advertised:
-            table.AddRow(
-                [Link(url, Bold(real_name)),
-                      description or Italic(_('[no description available]'))])
-            if highlight and mm_cfg.WEB_HIGHLIGHT_COLOR:
-                table.AddRowInfo(table.GetCurrentRowIndex(),
-                                 bgcolor=mm_cfg.WEB_HIGHLIGHT_COLOR)
-            highlight = not highlight
+
+        if not mm_cfg.LISTINFO_USE_CATEGORIES:
+            table.AddRow([Bold(FontAttr(_('List'), size='+2')),
+                          Bold(FontAttr(_('Description'), size='+2'))
+                          ])
+            highlight = 1
+            for mlist in advertised:
+                table.AddRow(
+                    [Link(mlist.GetScriptURL('admin'), Bold(mlist.real_name)),
+                     mlist.description or Italic(_('[no description available]'))])
+                if highlight and mm_cfg.WEB_HIGHLIGHT_COLOR:
+                    table.AddRowInfo(table.GetCurrentRowIndex(),
+                                     bgcolor=mm_cfg.WEB_HIGHLIGHT_COLOR)
+                highlight = not highlight
+
+        else:
+            catdict = Utils.category_dictionary_for_display(advertised)
+            list_categories = catdict.keys()
+            list_categories.sort()
+
+            catdesc    = Utils.CategoryDescriptions()
+            policydesc = Utils.SimplifiedPolicyDescriptions()
+
+            table.AddRow([Bold("Lists sorted by category:")])
+            table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0,
+                              colspan=columns, align="center")
+
+            list_links = map(lambda l: '<a href="#'+l+'">'+l+'</a>', list_categories)
+            table.AddRow([string.join(list_links, ", ")])
+            table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0,
+                              colspan=columns, align="center")
+
+            for cat in list_categories:
+                table.AddRow([Anchor(cat), '&nbsp;'])
+                if not catdesc.has_key(cat):
+                    catdesc[cat] = 'yet unclassified mailing lists'
+                table.AddRow([Bold(TextWithLegend(cat))])
+                table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0,
+                                  colspan=columns, align="center")
+                highlight = 1
+                for mlist in catdict[cat]:
+                    policy = mlist.GetSimplifiedPolicy()
+                    table.AddRow(
+                        [Link(mlist.GetScriptURL('admin'), Bold(mlist.real_name)),
+                         mlist.description or Italic('[no description available]'),
+                         TextWithLegend(policy)
+                        ])
+
+                    if highlight and mm_cfg.WEB_HIGHLIGHT_COLOR:
+                        table.AddRowInfo(table.GetCurrentRowIndex(),
+                                         bgcolor=mm_cfg.WEB_HIGHLIGHT_COLOR)
+                    highlight = not highlight
 
     doc.AddItem(table)
     doc.AddItem('<hr>')
+
+    if mm_cfg.LISTINFO_USE_CATEGORIES:
+        table = Table(border=0, width="100%")
+        keys = catdesc.keys()
+        keys.sort()
+        for cat in keys:
+            table.AddRow([Anchor(cat+'desc'), Bold(cat+":"), catdesc[cat]])
+        table.AddRow(['&nbsp;','&nbsp;'])
+        keys = policydesc.keys()
+        keys.sort()
+        for policy in keys:
+            table.AddRow([Anchor(policy+'desc'), Bold(policy+":"), policydesc[policy]])
+        doc.AddItem(table)
+        doc.AddItem('<hr>')
+
     doc.AddItem(MailmanLogo())
     print doc.Format()
 
--- Mailman/Cgi/listinfo.py
+++ Mailman/Cgi/listinfo.py
@@ -21,6 +21,7 @@
 
 import os
 import cgi
+import string
 
 from Mailman import mm_cfg
 from Mailman import Utils
@@ -73,9 +74,14 @@
     legend = _("%(hostname)s Mailing Lists")
     doc.SetTitle(legend)
 
+    if not mm_cfg.LISTINFO_USE_CATEGORIES:
+        columns=2
+    else:
+        columns=3
+
     table = Table(border=0, width="100%")
     table.AddRow([Center(Header(2, legend))])
-    table.AddCellInfo(table.GetCurrentRowIndex(), 0, colspan=2,
+    table.AddCellInfo(table.GetCurrentRowIndex(), 0, colspan=columns,
                       bgcolor=mm_cfg.WEB_HEADER_COLOR)
 
     # Skip any mailing lists that isn't advertised.
@@ -85,15 +91,15 @@
 
     for name in listnames:
         mlist = MailList.MailList(name, lock=0)
-        if mlist.advertised:
+        # enforce visibility for all lists
+        if mlist.advertised  or not mlist.advertised:
             if mm_cfg.VIRTUAL_HOST_OVERVIEW and \
                    mlist.web_page_url.find(hostname) == -1:
                 # List is for different identity of this host - skip it.
                 continue
             else:
-                advertised.append((mlist.GetScriptURL('listinfo'),
-                                   mlist.real_name,
-                                   mlist.description))
+                advertised.append(mlist)
+
     if msg:
         greeting = FontAttr(msg, color="ff5060", size="+1")
     else:
@@ -107,19 +113,18 @@
             %(mailmanlink)s mailing lists on %(hostname)s.'''))
     else:
         welcome.append(
-            _('''<p>Below is a listing of all the public mailing lists on
-            %(hostname)s.  Click on a list name to get more information about
-            the list, or to subscribe, unsubscribe, and change the preferences
+            _('''<p>Below is a listing of all mailing lists on %(hostname)s.
+            Click on a list name to get more information about the list, or
+            to subscribe, unsubscribe, and change the preferences
             on your subscription.'''))
 
     # set up some local variables
     adj = msg and _('right') or ''
-    siteowner = Utils.get_site_email()
+    # siteowner = Utils.get_site_email()
+    siteowner = 'sysadmin@suse.de'
+
     welcome.extend(
-        (_(''' To visit the general information page for an unadvertised list,
-        open a URL similar to this one, but with a '/' and the %(adj)s
-        list name appended.
-        <p>List administrators, you can visit '''),
+        (_(''' <p>List administrators, you can visit '''),
          Link(Utils.ScriptURL('admin'),
               _('the list admin overview page')),
          _(''' to find the management interface for your list.
@@ -128,25 +133,79 @@
          '.<p>'))
 
     table.AddRow([apply(Container, welcome)])
-    table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0, colspan=2)
+    table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0, colspan=columns)
 
     if advertised:
-        table.AddRow(['&nbsp;', '&nbsp;'])
-        table.AddRow([Bold(FontAttr(_('List'), size='+2')),
-                      Bold(FontAttr(_('Description'), size='+2'))
-                      ])
-        highlight = 1
-        for url, real_name, description in advertised:
-            table.AddRow(
-                [Link(url, Bold(real_name)),
-                      description or Italic(_('[no description available]'))])
-            if highlight and mm_cfg.WEB_HIGHLIGHT_COLOR:
-                table.AddRowInfo(table.GetCurrentRowIndex(),
-                                 bgcolor=mm_cfg.WEB_HIGHLIGHT_COLOR)
-            highlight = not highlight
+
+        if not mm_cfg.LISTINFO_USE_CATEGORIES:
+            table.AddRow([Bold(FontAttr(_('List'), size='+2')),
+                          Bold(FontAttr(_('Description'), size='+2'))
+                          ])
+            highlight = 1
+            for mlist in advertised:
+                table.AddRow(
+                    [Link(mlist.GetScriptURL('listinfo'), Bold(mlist.real_name)),
+                     mlist.description or Italic(_('[no description available]'))])
+                if highlight and mm_cfg.WEB_HIGHLIGHT_COLOR:
+                    table.AddRowInfo(table.GetCurrentRowIndex(),
+                                     bgcolor=mm_cfg.WEB_HIGHLIGHT_COLOR)
+                highlight = not highlight
+
+        else:
+            catdict = Utils.category_dictionary_for_display(advertised)
+            list_categories = catdict.keys()
+            list_categories.sort()
+
+            catdesc    = Utils.CategoryDescriptions()
+            policydesc = Utils.SimplifiedPolicyDescriptions() 
+
+            table.AddRow([Bold("Lists sorted by category:")])
+            table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0,
+                              colspan=columns, align="center")
+
+            list_links = map(lambda l: '<a href="#'+l+'">'+l+'</a>', list_categories)
+            table.AddRow([string.join(list_links, ", ")])
+            table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0,
+                              colspan=columns, align="center")
+
+            for cat in list_categories:
+                table.AddRow([Anchor(cat), '&nbsp;'])
+                if not catdesc.has_key(cat):
+                    catdesc[cat] = 'yet unclassified mailing lists'
+                table.AddRow([Bold(TextWithLegend(cat))])
+                table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0,
+                                  colspan=columns, align="center")
+                highlight = 1
+                for mlist in catdict[cat]:
+                    policy = mlist.GetSimplifiedPolicy()
+                    table.AddRow(
+                        [Link(mlist.GetScriptURL('listinfo'), Bold(mlist.real_name)),
+                         mlist.description or Italic('[no description available]'),
+                         TextWithLegend(policy)
+                        ])
+
+                    if highlight and mm_cfg.WEB_HIGHLIGHT_COLOR:
+                        table.AddRowInfo(table.GetCurrentRowIndex(),
+                                         bgcolor=mm_cfg.WEB_HIGHLIGHT_COLOR)
+                    highlight = not highlight
 
     doc.AddItem(table)
     doc.AddItem('<hr>')
+
+    if mm_cfg.LISTINFO_USE_CATEGORIES:
+        table = Table(border=0, width="100%")
+        keys = catdesc.keys()
+        keys.sort()
+        for cat in keys:
+            table.AddRow([Anchor(cat+'desc'), Bold(cat+":"), catdesc[cat]])
+        table.AddRow(['&nbsp;','&nbsp;'])
+        keys = policydesc.keys()
+        keys.sort()
+        for policy in keys:
+            table.AddRow([Anchor(policy+'desc'), Bold(policy+":"), policydesc[policy]])
+        doc.AddItem(table)
+        doc.AddItem('<hr>')
+
     doc.AddItem(MailmanLogo())
     print doc.Format()
 
--- Mailman/Commands/cmd_lists.py
+++ Mailman/Commands/cmd_lists.py
@@ -40,30 +40,6 @@
         res.results.append(_('Usage:'))
         res.results.append(gethelp(mlist))
         return STOP
-    hostname = mlist.host_name
-    res.results.append(_('Public mailing lists at %(hostname)s:'))
-    lists = Utils.list_names()
-    lists.sort()
-    i = 1
-    for listname in lists:
-        if listname == mlist.internal_name():
-            xlist = mlist
-        else:
-            xlist = MailList(listname, lock=0)
-        # We can mention this list if you already know about it
-        if not xlist.advertised and xlist is not mlist:
-            continue
-        # Skip the list if it isn't in the same virtual domain.  BAW: should a
-        # message to the site list include everything regardless of domain?
-        if mm_cfg.VIRTUAL_HOST_OVERVIEW and \
-               xlist.host_name <> mlist.host_name:
-            continue
-        realname = xlist.real_name
-        description = xlist.description or _('n/a')
-        requestaddr = xlist.GetRequestEmail()
-        if i > 1:
-            res.results.append('')
-        res.results.append(_('%(i)3d. List name:   %(realname)s'))
-        res.results.append(_('     Description: %(description)s'))
-        res.results.append(_('     Requests to: %(requestaddr)s'))
-        i += 1
+    res.results.append(_('(The list command has been disabled for this site.)'))
+    res.results.append('')
+
--- Mailman/Handlers/CookHeaders.py
+++ Mailman/Handlers/CookHeaders.py
@@ -140,8 +140,7 @@
         # because some folks think that some MUAs make it easier to delete
         # addresses from the right than from the left.
         if mlist.reply_goes_to_list == 1:
-            i18ndesc = uheader(mlist, mlist.description, 'Reply-To')
-            add((str(i18ndesc), mlist.GetListEmail()))
+            add(mlist.GetListEmail())
         del msg['reply-to']
         # Don't put Reply-To: back if there's nothing to add!
         if new:
--- Mailman/MTA/Utils.py
+++ Mailman/MTA/Utils.py
@@ -57,6 +57,7 @@
                 'request', 'subscribe', 'unsubscribe'):
         aliases.append(('%s-%s' % (listname, ext),
                         '"|%s %s %s"' % (wrapper, ext, safename)))
+    aliases.append(('owner-%s' % listname, '"|%s owner %s"' % (wrapper, safename)))
     return aliases
 
 
--- Mailman/MailList.py
+++ Mailman/MailList.py
@@ -31,6 +31,7 @@
 import socket
 import urllib
 import cPickle
+import string
 
 from cStringIO import StringIO
 from UserDict import UserDict
@@ -347,7 +348,7 @@
         self.header_filter_rules = []
         self.anonymous_list = mm_cfg.DEFAULT_ANONYMOUS_LIST
         internalname = self.internal_name()
-        self.real_name = internalname[0].upper() + internalname[1:]
+        self.real_name = internalname[0] + internalname[1:]
         self.description = ''
         self.info = ''
         self.welcome_msg = ''
@@ -1528,3 +1529,22 @@
         # When testing, it's possible we've disabled a language, so just
         # filter things out so we don't get tracebacks.
         return [lang for lang in langs if mm_cfg.LC_DESCRIPTIONS.has_key(lang)]
+
+    def GetListCategories(self):
+        category_list = []
+        catdesc = Utils.CategoryDescriptions()
+        for category in catdesc.keys():
+            if string.find(self.info, category) >= 0:
+                category_list.append(category)
+        return category_list
+ 
+    def GetSimplifiedPolicy(self):
+        if string.find(self.info, '(autogenerated)') >= 0:
+            return 'essential'
+        if self.default_member_moderation and self.subscribe_policy >= 2:
+            return 'authoritative'
+        if self.subscribe_policy >= 2:
+            return 'closed'
+        return 'public'
+ 
+
--- Mailman/Queue/NewsRunner.py
+++ Mailman/Queue/NewsRunner.py
@@ -135,7 +135,7 @@
     #
     # Our Message-ID format is <mailman.secs.pid.listname@hostname>
     msgid = msg['message-id']
-    hackmsgid = True
+    hackmsgid = False
     if msgid:
         mo = mcre.search(msgid)
         if mo:
--- Mailman/Utils.py
+++ Mailman/Utils.py
@@ -860,6 +860,32 @@
         # Nope, it contains funny characters, so html-ref it
         return uquote(s)
 
+ 
+def category_dictionary_for_display(mlists):
+    """Given a list of MailLists, return a dictionary of
+    all of the list names, keyed by category"""
+    catdict = {}
+    for mlist in mlists:
+        list_categories = mlist.GetListCategories()
+        if not list_categories:
+            list_categories = ["Unclassified"]
+        for cat in list_categories:
+            if not catdict.has_key(cat):
+                catdict[cat] = []
+            catdict[cat].append(mlist)
+    return catdict
+
+def CategoryDescriptions():
+    return {'ORG_ANNOUNCE':  'organizational announcements',\
+            'ORG_UNIT':      'team specific organizational announcements',\
+            'TOPIC_DISCUSS': 'topic related discussion',\
+            'TOPIC_LEISURE': 'off-time topics (leisure)'}
+
+def SimplifiedPolicyDescriptions():
+    return {'essential':     'subscription is inevitable for the audience',\
+            'authoritative': 'subscription needs approval, postings are moderated',\
+            'closed':        'subscription needs approval, postings are not moderated',\
+            'public':        'subscription is free to everybody, postings are not moderated'}
 
 def uquote(s):
     a = []
--- Mailman/htmlformat.py
+++ Mailman/htmlformat.py
@@ -688,3 +688,16 @@
           text = text + spaces + opt + "\n"
 
       return text + spaces + '</Select>'
+
+class Anchor:
+    def __init__(self, name):
+      self.name = name
+
+    def Format(self, indent=0):
+      return '<a name="%s"></a>' % (HTMLFormatObject(self.name, indent))
+
+def TextWithLegend(text):
+    def url(file):
+         return mm_cfg.IMAGE_LOGOS + file
+    return '%s <a href="#%s"><img src="%s"></a>' % (text, text+'desc', url("mm-text.png"))
+
--- bin/sync_members
+++ bin/sync_members
@@ -256,6 +256,7 @@
             try:
                 if not dryrun:
                     mlist.ApprovedAddMember(userdesc, welcome, notifyadmin)
+                enc = sys.getdefaultencoding()
                 s = email.Utils.formataddr((name, addr)).encode(enc, 'replace')
                 print _('Added  : %(s)s')
             except Errors.MMAlreadyAMember:
@@ -276,6 +277,7 @@
                     # reasons is in the database.  Use a lower level remove to
                     # get rid of this member's entry
                     mlist.removeMember(addr)
+            enc = sys.getdefaultencoding()
             s = email.Utils.formataddr((name, addr)).encode(enc, 'replace')
             print _('Removed: %(s)s')
 
