Index: tracspamfilter/model.py
===================================================================
--- tracspamfilter/model.py	(revision 5329)
+++ tracspamfilter/model.py	(working copy)
@@ -11,10 +11,13 @@
 # individuals. For the exact contribution history, see the revision
 # history and logs, available at http://projects.edgewall.com/trac/.
 
+import binascii
+
 from datetime import datetime, timedelta
 from time import mktime
 
 from trac.db import Column, Index, Table
+from trac.util.text import to_unicode
 
 __all__ = ['LogEntry']
 
@@ -66,6 +69,23 @@
     exists = property(fget=lambda self: self.id is not None,
                       doc='Whether this log entry exists in the database')
 
+    def _encode_content(cls, content):
+        """Take a `basestring` content and return a plain text encoding."""
+        return to_unicode(content).encode('utf-8').encode('base64')
+
+    _encode_content = classmethod(_encode_content)
+
+    def _decode_content(cls, content):
+        """Revert the encoding done by `_encode_content` and return an unicode
+        string"""
+        try:
+            return to_unicode(content.decode('base64'))
+        except (UnicodeEncodeError, binascii.Error):
+            # cope with legacy content (stored before base64 encoding)
+            return to_unicode(content)
+
+    _decode_content = classmethod(_decode_content)
+
     def get_next(self, db=None):
         """Return the next log entry in reverse chronological order (i.e. the
         next older entry.)"""
@@ -79,14 +99,11 @@
         row = cursor.fetchone()
         if not row:
             return None
+        return self.__class__._from_db(self.env, row)
 
-        obj = self.__class__(self.env, *row[1:])
-        obj.id = row[0]
-        return obj
-
     def get_previous(self, db=None):
-        """Return the previous log entry in reverse chronological order (i.e. the
-        next younger entry.)"""
+        """Return the previous log entry in reverse chronological order
+        (i.e. the next younger entry.)"""
         if not db:
             db = self.env.get_db_cnx()
 
@@ -97,11 +114,8 @@
         row = cursor.fetchone()
         if not row:
             return None
+        return self.__class__._from_db(self.env, row)
 
-        obj = self.__class__(self.env, *row[1:])
-        obj.id = row[0]
-        return obj
-
     def insert(self, db=None):
         """Insert a new log entry into the database."""
         if not db:
@@ -112,13 +126,15 @@
 
         assert not self.exists, 'Cannot insert existing log entry'
 
+        content = self._encode_content(self.content)
+
         cursor = db.cursor()
         cursor.execute("INSERT INTO spamfilter_log (time,path,author,"
                        "authenticated,ipnr,headers,content,rejected,"
                        "karma,reasons) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,"
                        "%s)", (int(self.time), self.path, self.author,
                        int(bool(self.authenticated)), self.ipnr, self.headers,
-                       self.content, int(bool(self.rejected)), int(self.karma),
+                       content, int(bool(self.rejected)), int(self.karma),
                        '\n'.join(self.reasons)))
         self.id = db.get_last_id(cursor, 'spamfilter_log')
         if handle_ta:
@@ -138,13 +154,15 @@
             if hasattr(self, name):
                 setattr(self, name, value)
 
+        content = self._encode_content(self.content)
+        
         cursor = db.cursor()
         cursor.execute("UPDATE spamfilter_log SET time=%s,path=%s,author=%s,"
                        "authenticated=%s,ipnr=%s,headers=%s,content=%s,"
                        "rejected=%s,karma=%s,reasons=%s WHERE id=%s", (
                        int(self.time), self.path, self.author,
                        int(bool(self.authenticated)), self.ipnr, self.headers,
-                       self.content, int(bool(self.rejected)), int(self.karma),
+                       content, int(bool(self.rejected)), int(self.karma),
                        '\n'.join(self.reasons), self.id))
         if handle_ta:
             db.commit()
@@ -170,17 +188,14 @@
             db = env.get_db_cnx()
 
         cursor = db.cursor()
-        cursor.execute("SELECT time,path,author,authenticated,ipnr,headers,"
+        cursor.execute("SELECT id,time,path,author,authenticated,ipnr,headers,"
                        "content,rejected,karma,reasons FROM spamfilter_log "
                        "WHERE id=%s", (int(id),))
         row = cursor.fetchone()
         if not row:
             return None
+        return cls._from_db(env, row)
 
-        obj = cls(env, *row)
-        obj.id = id
-        return obj
-
     fetch = classmethod(fetch)
 
     def count(cls, env, db=None):
@@ -247,13 +262,20 @@
                        "content,rejected,karma,reasons FROM spamfilter_log "
                        "%s ORDER BY time DESC %s" % (where, extra), params)
         for row in cursor:
-            obj = cls(env, *row[1:])
-            obj.id = row[0]
-            yield obj
+            yield cls._from_db(env, row)
 
     select = classmethod(select)
 
+    def _from_db(cls, env, row):
+        """Create a new LogEntry from a row from the `spamfilter_log` table."""
+        fields = list(row[1:])
+        fields[6] = cls._decode_content(fields[6])
+        obj = cls(env, *fields)
+        obj.id = row[0]
+        return obj
 
+    _from_db = classmethod(_from_db)
+
 class Bayes(object):
 
     table = Table('spamfilter_bayes', key='word')[
Index: setup.py
===================================================================
--- setup.py	(revision 5329)
+++ setup.py	(working copy)
@@ -15,7 +15,7 @@
 from setuptools import setup, find_packages
 
 PACKAGE = 'TracSpamFilter'
-VERSION = '0.2'
+VERSION = '0.2.1'
 
 setup(
     name = PACKAGE,
