From 7a53aaa9a11b761c408d1a03e779d58db97f67e3 Mon Sep 17 00:00:00 2001
From: "Brian S. Stephan" <bss@incorporeal.org>
Date: Fri, 25 Feb 2011 20:59:57 -0600
Subject: [PATCH 1/3] Markov: properly output unicode chains

---
 modules/Markov.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/modules/Markov.py b/modules/Markov.py
index c324a7c..f7c0667 100644
--- a/modules/Markov.py
+++ b/modules/Markov.py
@@ -250,7 +250,7 @@ class Markov(Module):
         if gen_words[-1] == self.stop:
             gen_words = gen_words[:-1]
 
-        return ' '.join(gen_words)
+        return ' '.join(gen_words).encode('utf-8', 'ignore')
 
     def _reply_to_line(self, line, min_size=15, max_size=100):
         """Reply to a line, using some text in the line as a point in the chain."""
@@ -291,7 +291,7 @@ class Markov(Module):
         if gen_words[-1] == self.stop:
             gen_words = gen_words[:-1]
 
-        return ' '.join(gen_words)
+        return ' '.join(gen_words).encode('utf-8', 'ignore')
 
     def _retrieve_chains_for_key(self, k1, k2):
         """Get the value(s) for a given key (a pair of strings)."""

From 67403971dffe312c4c64b185de34382f010854b3 Mon Sep 17 00:00:00 2001
From: "Brian S. Stephan" <bss@incorporeal.org>
Date: Fri, 25 Feb 2011 21:10:54 -0600
Subject: [PATCH 2/3] Twitter: properly reverse the tweets list, remove it from
 the TODO

---
 TODO               | 1 -
 modules/Twitter.py | 6 ++++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/TODO b/TODO
index 3b71a83..efe8199 100644
--- a/TODO
+++ b/TODO
@@ -14,5 +14,4 @@ dr.botzo --- TODO
      note: see commit 3333fe125e8c06a739b4d5e4bbc3ef5c1070fe91
    * periodic reconnects when disconnected/split
    * Alias: convert to use database, since configparser stuff mangles (lowercases) keys
-   * Twitter: print statuses in ascending date order (just reverse the list?)
    * put all bot config in the database?
diff --git a/modules/Twitter.py b/modules/Twitter.py
index bec3abf..cc4919c 100644
--- a/modules/Twitter.py
+++ b/modules/Twitter.py
@@ -243,7 +243,8 @@ class Twitter(Module):
 
             if since_id is not None and output_channel != '':
                 tweets = self.twit.GetFriendsTimeline(since_id=since_id)
-                for tweet in tweets.reverse():
+                tweets.reverse()
+                for tweet in tweets:
                     tweet_text = self._return_tweet_or_retweet_text(tweet=tweet, print_source=True)
                     self.sendmsg(self.connection, output_channel.encode('utf-8', 'ignore'), tweet_text)
 
@@ -251,7 +252,8 @@ class Twitter(Module):
                 new_since_id = self._get_latest_tweet_id(tweets, since_id)
 
                 tweets = self.twit.GetMentions(since_id=since_id)
-                for tweet in tweets.reverse():
+                tweets.reverse()
+                for tweet in tweets:
                     tweet_text = self._return_tweet_or_retweet_text(tweet=tweet, print_source=True)
                     self.sendmsg(self.connection, output_channel.encode('utf-8', 'ignore'), tweet_text)
 

From e020cdb476013dc6bcb54efc3962b359d11e6c7e Mon Sep 17 00:00:00 2001
From: "Brian S. Stephan" <bss@incorporeal.org>
Date: Fri, 25 Feb 2011 21:54:09 -0600
Subject: [PATCH 3/3] Seen: convert to use sqlite database

---
 modules/Seen.py | 62 ++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 49 insertions(+), 13 deletions(-)

diff --git a/modules/Seen.py b/modules/Seen.py
index 386d600..d2d1e8d 100644
--- a/modules/Seen.py
+++ b/modules/Seen.py
@@ -16,7 +16,6 @@ You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
 
-from ConfigParser import NoOptionError
 import re
 
 from datetime import datetime
@@ -29,23 +28,60 @@ class Seen(Module):
 
     """Track when people say things in public channels, and report on it."""
 
-    def do(self, connection, event, nick, userhost, what, admin_unlocked):
-        # whatever it is, store it
-        if not self.config.has_section(self.__class__.__name__):
-            self.config.add_section(self.__class__.__name__)
+    def db_init(self):
+        """Create the table to store seen data."""
 
-        self.config.set(self.__class__.__name__, nick, userhost + '|:|' + datetime.utcnow().isoformat() + '|:|' + what)
+        version = self.db_module_registered(self.__class__.__name__)
+        if version == None:
+            db = self.get_db()
+            try:
+                db.execute('''
+                    CREATE TABLE seen_nicks (
+                        nick TEXT NOT NULL PRIMARY KEY,
+                        host TEXT NOT NULL,
+                        time TEXT DEFAULT CURRENT_TIMESTAMP,
+                        what TEXT NOT NULL
+                    )''')
+                sql = 'INSERT INTO drbotzo_modules VALUES (?,?)'
+                db.execute(sql, (self.__class__.__name__, 1))
+                db.commit()
+                version = 1
+            except sqlite3.Error as e:
+                db.rollback()
+                print("sqlite error: " + str(e))
+                raise
+
+    def do(self, connection, event, nick, userhost, what, admin_unlocked):
+        """Track pubmsg/privmsg events, and if asked, report on someone."""
+
+        # whatever it is, store it
+        try:
+            db = self.get_db()
+            cur = db.cursor()
+            statement = 'REPLACE INTO seen_nicks (nick, host, what) VALUES (?, ?, ?)'
+            cur.execute(statement, (nick, userhost, what))
+            db.commit()
+        except sqlite3.Error as e:
+            db.rollback()
+            print("sqlite error: " + str(e))
+            raise
 
         match = re.search('^!seen\s+(\S+)$', what)
         if match:
-            query = match.group(1)
-            if query != 'debug':
-                try:
-                    seendata = self.config.get(self.__class__.__name__, query).split('|:|')
-                    converted = datetime.strptime(seendata[1], "%Y-%m-%dT%H:%M:%S.%f").replace(tzinfo=tzutc())
-                    replystr = 'last saw ' + query + ' at ' + converted.astimezone(tzlocal()).strftime("%Y/%m/%d %H:%M:%S %Z") + ' saying \'' + seendata[2] + '\''
+            nick = match.group(1)
+            try:
+                db = self.get_db()
+                query = 'SELECT * FROM seen_nicks WHERE nick = ?'
+                cursor = db.execute(query, (nick,))
+                result = cursor.fetchone()
+                if result:
+                    seentime = datetime.strptime(result['time'], '%Y-%m-%d %H:%M:%S').replace(tzinfo=tzutc())
+                    replystr = 'last saw {0:s} at {1:s} saying \'{2:s}\''.format(result['nick'], seentime.astimezone(tzlocal()).strftime('%Y/%m/%d %H:%M:%S %Z'), result['what'])
                     return self.reply(connection, event, replystr)
-                except NoOptionError: pass
+            except sqlite3.Error as e:
+                db.rollback()
+                print("sqlite error: " + str(e))
+                raise
 
 # vi:tabstop=4:expandtab:autoindent
 # kate: indent-mode python;indent-width 4;replace-tabs on;