changeset 512:862c0d6ab974

core, bridge, quick_frontend: MUC private messages history management: - history now store message type - sqlite3 storage: fixed resource management in getHistory - bridge: added message type in getHistory return value - quick_chats: (ugly) hacks to manage private history filtering/nickname printing
author Goffi <goffi@goffi.org>
date Wed, 17 Oct 2012 00:35:48 +0200
parents 62f7f2403093
children 8ee9113d307b
files frontends/src/quick_frontend/quick_chat.py src/bridge/DBus.py src/bridge/bridge_constructor/bridge_template.ini src/core/sat_main.py src/core/xmpp.py src/memory/memory.py src/memory/sqlite.py src/test/helpers.py
diffstat 8 files changed, 52 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/src/quick_frontend/quick_chat.py	Tue Oct 16 01:22:40 2012 +0200
+++ b/frontends/src/quick_frontend/quick_chat.py	Wed Oct 17 00:35:48 2012 +0200
@@ -100,18 +100,28 @@
         debug (_("now we print history"))
         def onHistory(history):
             for line in history: 
-                timestamp, from_jid, to_jid, message = line
+                timestamp, from_jid, to_jid, message, _type = line
+                if ((self.type == 'group' and _type != 'groupchat') or
+                   (self.type == 'one2one' and _type == 'groupchat')):
+                    continue
                 self.printMessage(JID(from_jid), message, profile, timestamp)
                     
         def onHistoryError(err):
             error (_("Can't get history"))
 
-        self.host.bridge.getHistory(self.host.profiles[profile]['whoami'].short, self.target.short, 20, callback=onHistory, errback=onHistoryError)
+        if self.target.startswith(const_PRIVATE_PREFIX):
+            target = unescapePrivate(self.target)
+        else:
+            target = self.target.short
+
+        self.host.bridge.getHistory(self.host.profiles[profile]['whoami'].short, target, 20, callback=onHistory, errback=onHistoryError)
 
     def _get_nick(self, jid):
         """Return nick of this jid when possible"""
-        if jid.startswith(const_PRIVATE_PREFIX):
-            return unescapePrivate(jid).resource
+        if self.target.startswith(const_PRIVATE_PREFIX):
+            unescaped = unescapePrivate(self.target)
+            if jid.startswith(const_PRIVATE_PREFIX) or unescaped.short == jid.short:
+                return unescaped.resource
         return jid.resource if self.type == "group" else (self.host.contact_list.getCache(jid,'nick') or self.host.contact_list.getCache(jid,'name') or jid.node)
     
     def printMessage(self, from_jid, msg, profile, timestamp):
--- a/src/bridge/DBus.py	Tue Oct 16 01:22:40 2012 +0200
+++ b/src/bridge/DBus.py	Wed Oct 17 00:35:48 2012 +0200
@@ -268,7 +268,7 @@
         return self._callback("getEntityData", unicode(jid), keys, unicode(profile))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
-                         in_signature='ssib', out_signature='a(dsss)',
+                         in_signature='ssib', out_signature='a(dssss)',
                          async_callbacks=('callback', 'errback'))
     def getHistory(self, from_jid, to_jid, limit, between=True, callback=None, errback=None):
         return self._callback("getHistory", unicode(from_jid), unicode(to_jid), limit, between, callback=callback, errback=errback)
--- a/src/bridge/bridge_constructor/bridge_template.ini	Tue Oct 16 01:22:40 2012 +0200
+++ b/src/bridge/bridge_constructor/bridge_template.ini	Wed Oct 17 00:35:48 2012 +0200
@@ -462,14 +462,14 @@
 type=method
 category=core
 sig_in=ssib
-sig_out=a(dsss)
+sig_out=a(dssss)
 param_3_default=True
 doc=Get history of a communication between two entities
 doc_param_0=from_jid: source JID (bare jid for catch all, full jid else)
 doc_param_1=to_jid: dest JID (bare jid for catch all, full jid else)
 doc_param_2=limit: max number of history elements to get (0 for the whole history)
 doc_param_3=between: True if we want history between the two jids (in both direction), False if we only want messages from from_jid to to_jid
-doc_return=Ordered list (by timestamp) of tuples (timestamp, full from_jid, full to_jid, message)
+doc_return=Ordered list (by timestamp) of tuples (timestamp, full from_jid, full to_jid, message, type)
 
 [addContact]
 type=method
--- a/src/core/sat_main.py	Tue Oct 16 01:22:40 2012 +0200
+++ b/src/core/sat_main.py	Wed Oct 17 00:35:48 2012 +0200
@@ -499,7 +499,7 @@
         message.addElement("body", "jabber:client", mess_data["message"])
         client.xmlstream.send(message)
         if mess_data["type"]!="groupchat":
-            self.memory.addToHistory(current_jid, jid.JID(to), unicode(mess_data["message"]), profile=profile) #we don't add groupchat message to history, as we get them back
+            self.memory.addToHistory(current_jid, jid.JID(to), unicode(mess_data["message"]), unicode(mess_data["type"]), profile=profile) #we don't add groupchat message to history, as we get them back
                                                                                               #and they will be added then
             self.bridge.newMessage(message['from'], unicode(mess_data["message"]), mess_type=mess_data["type"], to_jid=message['to'], profile=profile) #We send back the message, so all clients are aware of it
 
--- a/src/core/xmpp.py	Tue Oct 16 01:22:40 2012 +0200
+++ b/src/core/xmpp.py	Wed Oct 17 00:35:48 2012 +0200
@@ -113,7 +113,7 @@
               mess_body = e.children[0] if e.children else ""
               self.host.bridge.newMessage(message["from"], mess_body, mess_type, message['to'], profile=self.parent.profile)
               if not u"delay" in [elem.name for elem in message.elements()]: #we don't save delayed messages in history
-                  self.host.memory.addToHistory(jid.JID(message["from"]), jid.JID(message["to"]), mess_body, profile=self.parent.profile)
+                  self.host.memory.addToHistory(jid.JID(message["from"]), jid.JID(message["to"]), mess_body, mess_type, profile=self.parent.profile)
               break
     
 class SatRosterProtocol(xmppim.RosterClientProtocol):
--- a/src/memory/memory.py	Tue Oct 16 01:22:40 2012 +0200
+++ b/src/memory/memory.py	Wed Oct 17 00:35:48 2012 +0200
@@ -610,9 +610,9 @@
         @param name: Name of the profile"""
         return self.params.deleteProfile(name)
 
-    def addToHistory(self, from_jid, to_jid, message, timestamp=None, profile="@NONE@"):
+    def addToHistory(self, from_jid, to_jid, message, _type='chat', timestamp=None, profile="@NONE@"):
         assert(profile!="@NONE@")
-        return self.storage.addToHistory(from_jid, to_jid, message, timestamp, profile)
+        return self.storage.addToHistory(from_jid, to_jid, message, _type, timestamp, profile)
 
     def getHistory(self, from_jid, to_jid, limit=0, between=True):
         return self.storage.getHistory(jid.JID(from_jid), jid.JID(to_jid), limit, between)
--- a/src/memory/sqlite.py	Tue Oct 16 01:22:40 2012 +0200
+++ b/src/memory/sqlite.py	Wed Oct 17 00:35:48 2012 +0200
@@ -46,7 +46,13 @@
             info(_("The database is new, creating the tables"))
             database_creation = [
             "CREATE TABLE profiles (id INTEGER PRIMARY KEY ASC, name TEXT, UNIQUE (name))",
-            "CREATE TABLE history (id INTEGER PRIMARY KEY ASC, profile_id INTEGER, source TEXT, dest TEXT, source_res TEXT, dest_res TEXT, timestamp DATETIME, message TEXT, FOREIGN KEY(profile_id) REFERENCES profiles(id))",
+            "CREATE TABLE message_types (type TEXT PRIMARY KEY)",
+            "INSERT INTO message_types VALUES ('chat')",
+            "INSERT INTO message_types VALUES ('error')",
+            "INSERT INTO message_types VALUES ('groupchat')",
+            "INSERT INTO message_types VALUES ('headline')",
+            "INSERT INTO message_types VALUES ('normal')",
+            "CREATE TABLE history (id INTEGER PRIMARY KEY ASC, profile_id INTEGER, source TEXT, dest TEXT, source_res TEXT, dest_res TEXT, timestamp DATETIME, message TEXT, type TEXT, FOREIGN KEY(profile_id) REFERENCES profiles(id), FOREIGN KEY(type) REFERENCES message_types(type))",
             "CREATE TABLE param_gen (category TEXT, name TEXT, value TEXT, PRIMARY KEY (category,name))",
             "CREATE TABLE param_ind (category TEXT, name TEXT, profile_id INTEGER, value TEXT, PRIMARY KEY (category,name,profile_id), FOREIGN KEY(profile_id) REFERENCES profiles(id))",
             "CREATE TABLE private_gen (namespace TEXT, key TEXT, value TEXT, PRIMARY KEY (namespace, key))",
@@ -169,17 +175,18 @@
         return d
 
     #History
-    def addToHistory(self, from_jid, to_jid, message, timestamp=None, profile=None):
+    def addToHistory(self, from_jid, to_jid, message, _type='chat', timestamp=None, profile=None):
         """Store a new message in history
         @param from_jid: full source JID
         @param to_jid: full dest JID
         @param message: message
+        @param _type: message type (see RFC 6121 ยง5.2.2)
         @param timestamp: timestamp in seconds since epoch, or None to use current time
         """
         assert(profile!=None)
-        d = self.dbpool.runQuery("INSERT INTO history(source, source_res, dest, dest_res, timestamp, message, profile_id) VALUES (?,?,?,?,?,?,?)",
+        d = self.dbpool.runQuery("INSERT INTO history(source, source_res, dest, dest_res, timestamp, message, type, profile_id) VALUES (?,?,?,?,?,?,?,?)",
                                 (from_jid.userhost(), from_jid.resource, to_jid.userhost(), to_jid.resource, timestamp or time.time(),
-                                message, self.profiles[profile]))
+                                message, _type, self.profiles[profile]))
         d.addErrback(lambda ignore: error(_("Can't save following message in history: from [%(from_jid)s] to [%(to_jid)s] ==> [%(message)s]" %
                                          {"from_jid":from_jid.full(), "to_jid":to_jid.full(), "message":message})))
         return d
@@ -194,33 +201,38 @@
             query_result.reverse()
             result = []
             for row in query_result:
-                timestamp, source, source_res, dest, dest_res, message = row
+                timestamp, source, source_res, dest, dest_res, message, _type= row
                 result.append((timestamp, "%s/%s" % (source, source_res) if source_res else source,
                                           "%s/%s" % (dest, dest_res) if dest_res else dest,
-                                          message))
+                                          message, _type))
             return result
-        
-        query_parts = ["SELECT timestamp, source, source_res, dest, dest_res, message FROM history WHERE"]
+
+
+        query_parts = ["SELECT timestamp, source, source_res, dest, dest_res, message, type FROM history WHERE"]
         values = []
 
+        def test_jid(_type,_jid):
+            values.append(_jid.userhost())
+            if _jid.resource:
+                values.append(_jid.resource)
+                return '(%s=? AND %s_res=?)' % (_type, _type)
+            return '%s=?' % (_type,)
+        
         if between:
-            query_parts.append("(source=? OR source=?) AND (dest=? or dest=?)")
-            values.extend([from_jid.userhost(), to_jid.userhost(), to_jid.userhost(), from_jid.userhost()])
+            query_parts.append("(%s OR %s) AND (%s or %s)" % (test_jid('source', from_jid),
+                                                               test_jid('source', to_jid),
+                                                               test_jid('dest', to_jid),
+                                                               test_jid('dest', from_jid)))
         else:
-            query_parts.append("source=? AND dest=?")
-            values.extend([from_jid.userhost(), to_jid.userhost()])
-        if from_jid.resource:
-            query_parts.append("AND source_res=?")
-            values.append(from_jid.resource)
-        if to_jid.resource:
-            query_parts.append("AND dest_res=?")
-            values.append(to_jid.resource)
+            query_parts.append("%s AND %s") % (test_jid('source', from_jid),
+                                               test_jid('dest', to_jid))
 
         query_parts.append("ORDER BY timestamp DESC")
 
         if limit:
             query_parts.append("LIMIT ?")
             values.append(limit)
+        
         d = self.dbpool.runQuery(" ".join(query_parts), values)
         return d.addCallback(sqliteToDict)
 
--- a/src/test/helpers.py	Tue Oct 16 01:22:40 2012 +0200
+++ b/src/test/helpers.py	Wed Oct 17 00:35:48 2012 +0200
@@ -60,7 +60,7 @@
     def getProfileName(self, profile_key):
         return profile_key
 
-    def addToHistory(self, from_jid, to_jid, message, timestamp=None, profile=None):
+    def addToHistory(self, from_jid, to_jid, message, _type='chat', timestamp=None, profile=None):
         pass
     
     def addContact(self, contact_jid, attributes, groups, profile_key='@DEFAULT@'):