diff -ruN /opt/trac.bak/trac/Anydiff.py trac/Anydiff.py
--- /opt/trac.bak/trac/Anydiff.py	1970-01-01 01:00:00.000000000 +0100
+++ trac/Anydiff.py	2004-11-01 21:13:58.000000000 +0100
@@ -0,0 +1,229 @@
+# -*- coding: iso8859-1 -*-
+#
+# Copyright (C) 2003, 2004 Edgewall Software
+# Copyright (C) 2003, 2004 Jonas Borgström <jonas@edgewall.com>
+#
+# Trac is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# Trac is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# Author: Jonas Borgström <jonas@edgewall.com>
+
+import time
+
+import util
+import Diff
+import perm
+import Module
+from WikiFormatter import wiki_to_html
+
+import svn.delta
+import svn
+
+class HtmlDiffEditor (svn.delta.Editor):
+    """
+    generates a htmlized unified diff of the changes for a given changeset.
+    the output is written to stdout.
+    """
+    def __init__(self, old_root, new_root, rev, req, args, env, authzperm):
+        self.old_root = old_root
+        self.new_root = new_root
+        self.rev = rev
+        self.req = req
+        self.args = args
+        self.env = env
+        self.authzperm = authzperm
+        self.fileno = 0
+
+    def print_diff (self, old_path, new_path, pool):
+        if not old_path or not new_path:
+            return
+
+        old_rev = svn.fs.node_created_rev(self.old_root, old_path, pool)
+        new_rev = svn.fs.node_created_rev(self.new_root, new_path, pool)
+
+        options = Diff.get_options(self.env, self.req, self.args, 1)
+
+        # Make sure we have permission to view this diff
+        if not self.authzperm.has_permission(new_path):
+            return
+
+        # Try to figure out the charset used. We assume that both the old
+        # and the new version uses the same charset, not always the case
+        # but that's all we can do...
+        mime_type = svn.fs.node_prop (self.new_root, new_path,
+                                      svn.util.SVN_PROP_MIME_TYPE,
+                                      pool)
+        # We don't have to guess if the charset is specified in the
+        # svn:mime-type property
+        ctpos = mime_type and mime_type.find('charset=') or -1
+        if ctpos >= 0:
+            charset = mime_type[ctpos + 8:]
+            self.env.log.debug("Charset %s selected" % charset)
+        else:
+            charset = self.env.get_config('trac', 'default_charset', 'iso-8859-15')
+
+        # Start up the diff process
+        differ = svn.fs.FileDiff(self.old_root, old_path, self.new_root,
+                                 new_path, pool, options)
+        differ.get_files()
+        pobj = differ.get_pipe()
+        prefix = 'changeset.diff.files.%d' % (self.fileno)
+        self.req.hdf.setValue(prefix + '.browser_href.old',
+                              self.env.href.file(old_path, old_rev))
+        self.req.hdf.setValue(prefix + '.browser_href.new',
+                              self.env.href.file(new_path, new_rev))
+        tabwidth = int(self.env.get_config('diff', 'tab_width', '8'))
+        builder = Diff.HDFBuilder(self.req.hdf, prefix, tabwidth)
+        self.fileno += 1
+        builder.writeline('header %s %s | %s %s redaeh' % (old_path, old_rev,
+                                                           new_path, new_rev))
+        while 1:
+            line = pobj.readline()
+            if not line:
+                break
+            builder.writeline(util.to_utf8(line, charset))
+        builder.close()
+
+    def add_file(self, path, parent_baton, copyfrom_path,
+                 copyfrom_revision, file_pool):
+        return [None, path, file_pool]
+
+    def open_file(self, path, parent_baton, base_revision, file_pool):
+        return [path, path, file_pool]
+
+    def apply_textdelta(self, file_baton, base_checksum):
+        self.print_diff (*file_baton)
+
+
+class UnifiedDiffEditor(HtmlDiffEditor):
+    """
+    generates a unified diff of the changes for a given changeset.
+    the output is written to stdout.
+    """
+
+    def __init__(self, old_root, new_root, rev, req, args, env, authzperm):
+        HtmlDiffEditor.__init__(self, old_root, new_root, rev, req, args, env, authzperm)
+        self.output = req
+
+    def print_diff (self, old_path, new_path, pool):
+        options = ['-u']
+        options.append('-L')
+        options.append("%s\t(revision %d)" % (old_path, self.rev-1))
+        options.append('-L')
+        options.append("%s\t(revision %d)" % (new_path, self.rev))
+
+        differ = svn.fs.FileDiff(self.old_root, old_path,
+                             self.new_root, new_path, pool, options)
+        differ.get_files()
+        pobj = differ.get_pipe()
+        line = pobj.readline()
+        while line:
+            self.output.write(line)
+            line = pobj.readline()
+
+
+class Anydiff (Module.Module):
+    template_name = 'anydiff.cs'
+    perm = None
+    fs_ptr = None
+    pool = None
+
+    def get_changeset_info (self, rev):
+        cursor = self.db.cursor ()
+        cursor.execute ('SELECT time, author, message FROM revision ' +
+                        'WHERE rev=%d', rev)
+        row = cursor.fetchone()
+        if not row:
+            raise util.TracError('Anydiff %d does not exist.' % rev,
+                            'Invalid Changset')
+        return row
+
+    def get_change_info (self, rev):
+        cursor = self.db.cursor ()
+        cursor.execute ('SELECT name, change FROM node_change ' +
+                        'WHERE rev=%d', rev)
+        info = []
+        while 1:
+            row = cursor.fetchone()
+            if not row:
+                break
+            info.append({'name': row['name'],
+                         'change': row['change'],
+                         'browser_href': self.env.href.browser(row['name'], rev),
+                         'log_href': self.env.href.log(row['name'])})
+        return info
+
+    def render (self):
+        self.perm.assert_permission (perm.CHANGESET_VIEW)
+
+        self.add_link('alternate', '?format=diff', 'Unified Diff',
+            'text/plain', 'diff')
+
+        if self.args.has_key('rev'):
+            self.rev = int(self.args.get('rev'))
+        else:
+            self.rev = svn.fs.youngest_rev(self.fs_ptr, self.pool)
+
+        change_info = self.get_change_info (self.rev)
+        changeset_info = self.get_changeset_info (self.rev)
+
+        self.req.hdf.setValue('changeset.time',
+                              time.asctime (time.localtime(int(changeset_info['time']))))
+        author = changeset_info['author'] or 'anonymous'
+        self.req.hdf.setValue('changeset.author', util.escape(author))
+        self.req.hdf.setValue('changeset.message',
+                              wiki_to_html(util.wiki_escape_newline(changeset_info['message']),
+                                           self.req.hdf, self.env, self.db))
+        self.req.hdf.setValue('changeset.revision', str(self.rev))
+        util.add_dictlist_to_hdf(change_info, self.req.hdf, 'changeset.changes')
+        self.req.hdf.setValue('anydiff.href', 
+				self.env.href.anydiff(self.args.get('path', '/'), self.args.get('a'), self.args.get('b')))
+        self.req.hdf.setValue('title', '[%d] (changeset)' % self.rev)
+
+    def render_diffs(self, editor_class=HtmlDiffEditor):
+        """
+        generates a unified diff of the changes for a given changeset.
+        the output is written to stdout.
+        """
+        try:
+            old_root = svn.fs.revision_root(self.fs_ptr, int(self.args.get('a')), self.pool)
+            new_root = svn.fs.revision_root(self.fs_ptr, int(self.args.get('b')), self.pool)
+        except svn.core.SubversionException:
+            raise util.TracError('Invalid revision number: %d' % int(self.rev))
+
+        editor = editor_class(old_root, new_root, int(self.rev), self.req,
+                              self.args, self.env, self.authzperm)
+        e_ptr, e_baton = svn.delta.make_editor(editor, self.pool)
+
+        def authz_cb(root, path, pool): return 1
+	path = self.args.get('path', '/')[1:]
+
+        svn.repos.svn_repos_dir_delta(old_root, "", path,
+                                      new_root, path, e_ptr, e_baton, authz_cb,
+                                      0, 1, 0, 1, self.pool)
+    def display(self):
+        """Pretty HTML view of the changeset"""
+        self.render_diffs()
+        Module.Module.display(self)
+
+    def display_hdf(self):
+        self.render_diffs()
+        Module.Module.display_hdf(self)
+
+    def display_diff (self):
+        """Raw Unified Diff version"""
+        self.req.send_response(200)
+        self.req.send_header('Content-Type', 'text/plain;charset=utf-8')
+        self.req.end_headers()
+        self.render_diffs(UnifiedDiffEditor)
diff -ruN /opt/trac.bak/trac/core.py trac/core.py
--- /opt/trac.bak/trac/core.py	2004-10-29 02:51:53.000000000 +0200
+++ trac/core.py	2004-11-01 20:54:11.000000000 +0100
@@ -54,6 +54,7 @@
     'browser'     : ('Browser', 'Browser', 1),
     'timeline'    : ('Timeline', 'Timeline', 1),
     'changeset'   : ('Changeset', 'Changeset', 1),
+    'anydiff'        : ('Anydiff', 'Anydiff', 1),
     'newticket'   : ('Ticket', 'NewticketModule', 0),
     'query'       : ('Query', 'QueryModule', 0),
     'attachment'  : ('File', 'Attachment', 0),
@@ -103,7 +104,7 @@
         if match.group(2):
             set_if_missing(args, 'id', match.group(2))
         return args
-    match = re.search('^/(browser|log|file)(?:(/.*))?', path_info)
+    match = re.search('^/(browser|log|file|anydiff)(?:(/.*))?', path_info)
     if match:
         set_if_missing(args, 'mode', match.group(1))
         if match.group(2):
diff -ruN /opt/trac.bak/trac/Href.py trac/Href.py
--- /opt/trac.bak/trac/Href.py	2004-10-29 02:51:53.000000000 +0200
+++ trac/Href.py	2004-11-01 21:24:01.000000000 +0100
@@ -54,6 +54,15 @@
         else:
             return href_join(self.base, 'browser', path)
 
+    def anydiff(self, path=None, revA=None, revB=None):
+	if path and revA and revB:
+        	return href_join(self.base, 'anydiff', path) + "?a=" + str(revA) + "&b=" + str(revB)
+	elif path:
+        	return href_join(self.base, 'anydiff', path)
+	
+	else:	
+	        return href_join(self.base, 'anydiff')
+
     def login(self):
         return href_join(self.base, 'login')
 
diff -ruN /opt/trac.bak/trac/Log.py trac/Log.py
--- /opt/trac.bak/trac/Log.py	2004-10-29 02:51:53.000000000 +0200
+++ trac/Log.py	2004-11-01 21:21:58.000000000 +0100
@@ -115,6 +115,8 @@
             'application/rss+xml', 'rss')
 
         self.path = self.args.get('path', '/')
+	self.req.hdf.setValue('log.href.anydiff', self.env.href.anydiff(self.path))
+	
         if self.args.has_key('rev'):
             try:
                 rev = int(self.args.get('rev'))

