Index: setup.py
===================================================================
--- setup.py	(revision 429)
+++ setup.py	(working copy)
@@ -1,20 +1,17 @@
 from setuptools import setup
 
 setup(
-    name = 'TracDiscussion',
-    version = '0.1',
-    packages = [ 'tracdiscussion' ],
-    package_data = {
-        'tracdiscussion' : [
-            'templates/*.cs',
-            'htdocs/css/*.css'
-        ]
-    },
-    author = 'Alec Thomas',
-    author_email = 'trac-hacks@swapoff.org',
-    url = 'http://trac-hacks.swapoff.org/wiki/DiscussionPlugin',
-    description = 'Discussion forum plugin for Trac',
-    license = '''
+    name='TracDiscussion',
+    version='0.1',
+    author='Alec Thomas',
+    author_email='trac-hacks@swapoff.org',
+    url='http://trac-hacks.swapoff.org/wiki/DiscussionPlugin',
+    packages=['tracdiscussion'],
+    package_data={'tracdiscussion': ['templates/*.cs', 'htdocs/css/*.css']},
+    entry_points={'trac.plugins': 'tracdiscussion = tracdiscussion.core'},
+    description='Discussion forum plugin for Trac',
+    long_description='''  ''',
+    license='''
 Copyright (c) 2005, Alec Thomas
 All rights reserved.
 
Index: tracdiscussion/core.py
===================================================================
--- tracdiscussion/core.py	(revision 429)
+++ tracdiscussion/core.py	(working copy)
@@ -4,6 +4,7 @@
 from trac.wiki import wiki_to_html, wiki_to_oneliner
 from trac.Timeline import ITimelineEventProvider
 from trac.perm import IPermissionRequestor
+from trac.util import Markup
 import re, os
 
 class DiscussionCore(Component):
@@ -11,7 +12,8 @@
         The discussion module implements a message board, including wiki links to
         discussions, topics and messages.
     """
-    implements(INavigationContributor, IRequestHandler, ITemplateProvider, IPermissionRequestor)
+    implements(INavigationContributor, IRequestHandler, ITemplateProvider,
+      IPermissionRequestor)
 
     # ITimelineEventProvider methods
 #    def get_timeline_events(self, req, start, stop, filters):
@@ -22,19 +24,19 @@
 #    def get_timeline_filters(self, req):
 #        if req.perm.has_permission('DISCUSSION_VIEW'):
 #            yield ('discussion', 'Discussion changes')
-    
+
     # IPermissionRequestor methods
     def get_permission_actions(self):
         return ['DISCUSSION_VIEW', 'DISCUSSION_MODIFY', 'DISCUSSION_MODERATE']
 
     # ITemplateProvider methods
-    def get_htdocs_dir(self):
+    def get_htdocs_dirs(self):
         from pkg_resources import resource_filename
-        return resource_filename(__name__, 'htdocs')
+        return [('discussion', resource_filename(__name__, 'htdocs'))]
 
-    def get_templates_dir(self):
+    def get_templates_dirs(self):
         from pkg_resources import resource_filename
-        return resource_filename(__name__, 'templates')
+        return [resource_filename(__name__, 'templates')]
 
 
     # INavigationContributor methods
@@ -44,11 +46,14 @@
     def get_navigation_items(self, req):
         if not req.perm.has_permission('DISCUSSION_VIEW'):
             return
-        yield 'mainnav', 'discussion', '<a href="%s">%s</a>' % (self.env.href.discussion(), self.env.config.get('discussion', 'title', 'Discussion'))
+        yield 'mainnav', 'discussion', Markup('<a href="%s">%s</a>' % \
+          (self.env.href.discussion(), self.env.config.get('discussion',
+          'title', 'Discussion')))
 
     # IRequestHandler methods
     def match_request(self, req):
-        match = re.match(r'''/discussion(?:/?$|/([a-z]+[-a-z]+)(?:/?$|/(\d+))(?:/?$|/(\d+)))$''', req.path_info)
+        match = re.match(r'''/discussion(?:/?$|/([a-zA-Z]+[-a-zA-Z]+)(?:/?$|/(\d+))(?:/?$|/(\d+)))$''',
+          req.path_info)
         if match:
             req.args['forum'] = match.group(1) or ''
             req.args['topic'] = match.group(2) or ''
@@ -60,8 +65,8 @@
         db = self.env.get_db_cnx()
         cursor = db.cursor()
 
-        add_stylesheet(req, 'css/wiki.css')
-        add_stylesheet(req, 'css/discussion.css')
+        add_stylesheet(req, 'common/css/wiki.css')
+        add_stylesheet(req, 'discussion/css/discussion.css')
         req.hdf['trac.href.discussion'] = self.env.href.discussion()
 
         forum, topic, message = None, None, None
@@ -70,21 +75,24 @@
         # Populate active forum
         if req.args['forum']:
             forum = self.get_forum(cursor, req.args['forum'], req)
-            if not forum: raise TracError('No such forum %s' % req.args['forum'])
+            if not forum:
+                raise TracError('No such forum %s' % req.args['forum'])
             req.hdf['discussion.forum'] = forum
             mode = 'topic-list'
 
         # Populate active topic
         if req.args['topic']:
             topic = self.get_topic(cursor, req.args['topic'], req)
-            if not topic: raise TracError('No such topic %s' % req.args['topic'])
+            if not topic:
+                raise TracError('No such topic %s' % req.args['topic'])
             req.hdf['discussion.topic'] = topic
             mode = 'message-list'
 
         # Populate active topic
         if req.args['message']:
             message = self.get_message(cursor, req.args['message'], req)
-            if not message: raise TracError('No such message %s' % req.args['message'])
+            if not message:
+                raise TracError('No such message %s' % req.args['message'])
             req.hdf['discussion.message'] = message
             mode = 'message-list'
 
@@ -98,46 +106,56 @@
         if mode == 'forum-list':
             req.hdf['discussion.forums'] = self.get_forums(cursor, req)
         elif mode == 'topic-list':
-            req.hdf['discussion.topics'] = self.get_topics(cursor, forum['id'], req)
+            req.hdf['discussion.topics'] = self.get_topics(cursor, forum['id'],
+              req)
         elif mode == 'message-list':
-            req.hdf['discussion.messages'] = self.get_messages(cursor, topic['id'], req)
+            req.hdf['discussion.messages'] = self.get_messages(cursor,
+              topic['id'], req)
 
         return mode + '.cs', None
 
     # Non-extension methods
     def get_message(self, cursor, id, req):
         columns = ('id', 'forum', 'topic', 'replyto', 'time', 'body', 'author')
-        cursor.execute('SELECT id, forum, topic, replyto, time, body, author FROM message WHERE id=%i', id)
-        row = cursor.fetchone()
-        if not row: return None
-        row = dict(zip(columns, row))
-        row['body'] = wiki_to_html(row['body'], self.env, req)
-        return row
+        cursor.execute('SELECT id, forum, topic, replyto, time, body, author'
+          'FROM message WHERE id=%s', [id])
+        for row in cursor:
+            row = dict(zip(columns, row))
+            row['body'] = wiki_to_html(row['body'], self.env, req)
+            return row
+        return None
 
     def get_topic(self, cursor, id, req):
         columns = ('id', 'forum', 'time', 'subject', 'body', 'author')
-        cursor.execute('SELECT id, forum, time, subject, body, author FROM topic WHERE id=%s', id)
-        row = cursor.fetchone()
-        if not row: return None
-        row = dict(zip(columns, row))
-        row['subject'] = wiki_to_oneliner(row['subject'], self.env)
-        return row
+        cursor.execute('SELECT id, forum, time, subject, body, author FROM'
+          ' topic WHERE id=%s', [id])
+        for row in cursor:
+            row = dict(zip(columns, row))
+            row['subject'] = wiki_to_oneliner(row['subject'], self.env)
+            return row
+        return None
 
     def get_forum(self, cursor, id, req):
+        self.log.debug('id=%s', str(id))
         columns = ('name', 'moderators', 'id', 'time', 'subject', 'description')
-        cursor.execute('SELECT name, moderators, id, time, subject, description FROM forum WHERE name=%s', id)
-        row = cursor.fetchone()
-        if not row: return None
-        row = dict(zip(columns, row))
-        row['moderators'] = row['moderators'].split(' ')
-        row['subject'] = wiki_to_oneliner(row['subject'], self.env)
-        return row
+        cursor.execute('SELECT name, moderators, id, time, subject, description'
+          ' FROM forum WHERE name=%s', [id])
+        for row in cursor:
+            row = dict(zip(columns, row))
+            row['moderators'] = row['moderators'].split(' ')
+            row['subject'] = wiki_to_oneliner(row['subject'], self.env)
+            return row
+        return None
 
     def get_forums(self, cursor, req):
-        columns = ('moderators', 'id', 'time', 'subject', 'name', 'description', 'topics', 'replies')
-        cursor.execute('SELECT moderators, id, time, subject, name, description, (SELECT COUNT(id) FROM topic t WHERE t.forum=forum.id), (SELECT COUNT(id) FROM message m WHERE m.forum = forum.id) FROM forum ORDER BY subject')
+        columns = ('moderators', 'id', 'time', 'subject', 'name',
+          'description', 'topics', 'replies')
+        cursor.execute('SELECT moderators, id, time, subject, name,'
+          ' description, (SELECT COUNT(id) FROM topic t WHERE'
+          ' t.forum=forum.id), (SELECT COUNT(id) FROM message m WHERE m.forum'
+          ' = forum.id) FROM forum ORDER BY subject')
         forums = []
-        for row in cursor.fetchall():
+        for row in cursor:
             row = dict(zip(columns, row))
             row['moderators'] = row['moderators'].split(' ')
             row['subject'] = wiki_to_oneliner(row['subject'], self.env)
@@ -146,9 +164,11 @@
 
     def get_topics(self, cursor, forum, req):
         columns = ('id', 'forum', 'time', 'subject', 'body', 'author', 'replies')
-        cursor.execute('SELECT id, forum, time, subject, body, author, (SELECT COUNT(id) FROM message m WHERE m.topic = topic.id) FROM topic WHERE forum = %i ORDER BY time', int(forum))
+        cursor.execute('SELECT id, forum, time, subject, body, author, (SELECT'
+          ' COUNT(id) FROM message m WHERE m.topic = topic.id) FROM topic'
+          ' WHERE forum = %s ORDER BY time', [forum])
         topics = []
-        for row in cursor.fetchall():
+        for row in cursor:
             row = dict(zip(columns, row))
             row['subject'] = wiki_to_oneliner(row['subject'], self.env)
             topics.append(row)
@@ -156,12 +176,13 @@
 
     def get_messages(self, cursor, topic, req):
         columns = ('id', 'replyto', 'time', 'body', 'author')
-        cursor.execute('SELECT id, replyto, time, body, author FROM message WHERE topic=%s ORDER BY time', topic)
+        cursor.execute('SELECT id, replyto, time, body, author FROM message'
+          ' WHERE topic=%s ORDER BY time', [topic])
 
         messagemap = {}
         messages = []
 
-        for message in cursor.fetchall():
+        for message in cursor:
             message = dict(zip(columns, message))
             message['body'] = wiki_to_html(message['body'], self.env, req)
             messagemap[message['id']] = message
Index: tracdiscussion/__init__.py
===================================================================
--- tracdiscussion/__init__.py	(revision 429)
+++ tracdiscussion/__init__.py	(working copy)
@@ -1 +1 @@
-from discussion import init, core, wiki, console
+from tracdiscussion import init, core, wiki
Index: tracdiscussion/init.py
===================================================================
--- tracdiscussion/init.py	(revision 429)
+++ tracdiscussion/init.py	(working copy)
@@ -1,6 +1,7 @@
 from trac.core import *
+from trac.db import *
 from trac.env import IEnvironmentSetupParticipant
-from discussion.db import version as discussion_version, schema
+from tracdiscussion.db import version as discussion_version, schema
 
 class DiscussionInit(Component):
     """ Initialise database and environment for discussion component """
@@ -9,27 +10,28 @@
     # IEnvironmentSetupParticipant
     def environment_created(self):
         pass
-    
+
     def environment_needs_upgrade(self, db):
         cursor = db.cursor()
         # Database is up to date?
         try:
             cursor.execute("SELECT value FROM system WHERE name='discussion_version'")
-            version = int(cursor.fetchone()[0])
-            return version != discussion_version
+            for row in cursor:
+                return int(row[0]) != discussion_version
+            return True
         except:
             return True
         return False
-    
+
     def upgrade_environment(self, db):
         cursor = db.cursor()
         # Initial table creation
-        try:
-            for table in schema:
-                cursor.execute(db.to_sql(table))
-            cursor.execute("INSERT INTO system VALUES ('discussion_version', %i)", discussion_version)
-        except:
-            # Upgrade
-            # TODO Table upgrades...
-            cursor.execute("UPDATE system SET value = %i WHERE name = 'discussion_version'", discussion_version)
-        db.commit()
+        #try:
+        for table in schema:
+            queries = db.to_sql(table)
+            for query in queries:
+                cursor.execute(query)
+        cursor.execute("INSERT INTO system VALUES ('discussion_version', %s)",
+          [discussion_version])
+        #except:
+          #cursor.execute("UPDATE system SET value = %i WHERE name = 'discussion_version'", discussion_version)
Index: tracdiscussion/db.py
===================================================================
--- tracdiscussion/db.py	(revision 429)
+++ tracdiscussion/db.py	(working copy)
@@ -5,21 +5,21 @@
 version = 1
 
 schema = [
-    Table('forum', key=('id', 'name'))[
+    Table('forum', key='id')[
         Column('id', type='int', auto_increment = True),
         Column('name'),
         Column('time', type='int'),
         Column('moderators'),
         Column('subject'),
         Column('description')],
-    Table('topic', key = 'id')[
+    Table('topic', key='id')[
         Column('id', type='int', auto_increment = True),
         Column('forum', type='int'),
         Column('time', type='int'),
         Column('author'),
         Column('subject'),
         Column('body')],
-    Table('message', key = 'id')[
+    Table('message', key='id')[
         Column('id', type='int', auto_increment = True),
         Column('forum', type='int'),
         Column('topic', type='int'),
