# HG changeset patch # User Goffi # Date 1350426948 -7200 # Node ID 862c0d6ab97475cf5d05948b1a3784925b642e7b # Parent 62f7f24030939a96ae0fe8d9bc2cf3c5fcd6a5b4 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 diff -r 62f7f2403093 -r 862c0d6ab974 frontends/src/quick_frontend/quick_chat.py --- 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): diff -r 62f7f2403093 -r 862c0d6ab974 src/bridge/DBus.py --- 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) diff -r 62f7f2403093 -r 862c0d6ab974 src/bridge/bridge_constructor/bridge_template.ini --- 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 diff -r 62f7f2403093 -r 862c0d6ab974 src/core/sat_main.py --- 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 diff -r 62f7f2403093 -r 862c0d6ab974 src/core/xmpp.py --- 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): diff -r 62f7f2403093 -r 862c0d6ab974 src/memory/memory.py --- 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) diff -r 62f7f2403093 -r 862c0d6ab974 src/memory/sqlite.py --- 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) diff -r 62f7f2403093 -r 862c0d6ab974 src/test/helpers.py --- 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@'):