From f386b9ce24c5397b8569e55c65075e59be9f0626 Mon Sep 17 00:00:00 2001 From: "W. Martin Borgert" Date: Thu, 26 Oct 2017 21:54:50 +0200 Subject: [PATCH] Imported upstream master from 2017-10-22 --- gajim/common/connection.py | 31 +---- gajim/common/connection_handlers.py | 16 +-- gajim/common/connection_handlers_events.py | 3 - gajim/common/logger.py | 127 ++++++++++----------- gajim/groupchat_control.py | 6 - gajim/gui_interface.py | 2 +- gajim/profile_window.py | 2 +- win/_base.sh | 1 + 8 files changed, 75 insertions(+), 113 deletions(-) diff --git a/gajim/common/connection.py b/gajim/common/connection.py index 4551535ba..bc4c65183 100644 --- a/gajim/common/connection.py +++ b/gajim/common/connection.py @@ -665,7 +665,6 @@ class Connection(CommonConnection, ConnectionHandlers): self.annotations = {} self.last_io = app.idlequeue.current_time() self.last_sent = [] - self.last_history_time = {} self.password = passwords.get_password(name) self.music_track_info = 0 @@ -2576,20 +2575,11 @@ class Connection(CommonConnection, ConnectionHandlers): # Never join a room when invisible return - # last date/time in history to avoid duplicate - if room_jid not in self.last_history_time: - # Not in memory, get it from DB - last_log = 0 - if app.config.should_log(self.name, room_jid): - # Check time first in the FAST table - last_log = app.logger.get_room_last_message_time( - self.name, room_jid) - if not last_log: - last_log = 0 - - # Create self.last_history_time[room_jid] even if not logging, - # could be used in connection_handlers - self.last_history_time[room_jid] = last_log + # Check time first in the FAST table + last_date = app.logger.get_room_last_message_time( + self.name, room_jid) + if not last_date: + last_date = 0 p = nbxmpp.Presence(to='%s/%s' % (room_jid, nick), show=show, status=self.status) @@ -2608,7 +2598,6 @@ class Connection(CommonConnection, ConnectionHandlers): 'muc_restore_timeout') if timeout is None or timeout == -2: timeout = app.config.get('muc_restore_timeout') - last_date = self.last_history_time[room_jid] if last_date == 0 and timeout >= 0: last_date = time.time() - timeout * 60 elif not rejoin and timeout >= 0: @@ -2736,16 +2725,6 @@ class Connection(CommonConnection, ConnectionHandlers): # disconnect from jabber server self.connection.send(p) - def gc_got_disconnected(self, room_jid): - """ - A groupchat got disconnected. This can be or purpose or not - - Save the time we had last message to avoid duplicate logs AND be faster - than get that date from DB. Save time that we have in mem in a small - table (with fast access) - """ - app.logger.set_room_last_message_time(room_jid, self.last_history_time[room_jid]) - def gc_set_role(self, room_jid, nick, role, reason=''): """ Role is for all the life of the room so it's based on nick diff --git a/gajim/common/connection_handlers.py b/gajim/common/connection_handlers.py index b17d7af09..175905511 100644 --- a/gajim/common/connection_handlers.py +++ b/gajim/common/connection_handlers.py @@ -294,7 +294,8 @@ class ConnectionVcard: # Remove avatar app.log('avatar').info('Remove: %s', obj.jid) app.contacts.set_avatar(self.name, obj.jid, None) - app.logger.set_avatar_sha(self.name, obj.jid, None) + own_jid = self.get_own_jid().getStripped() + app.logger.set_avatar_sha(own_jid, obj.jid, None) app.interface.update_avatar(self.name, obj.jid) else: app.log('avatar').info( @@ -313,6 +314,9 @@ class ConnectionVcard: if server.startswith('irc') or obj.avatar_sha is None: return + if obj.show == 'offline': + return + gc_contact = app.contacts.get_gc_contact( self.name, obj.room_jid, obj.nick) @@ -1014,9 +1018,8 @@ class ConnectionHandlersBase: def _nec_gc_message_received(self, obj): if obj.conn.name != self.name: return - if app.config.should_log(obj.conn.name, obj.jid) and not \ - obj.timestamp < obj.conn.last_history_time[obj.jid] and obj.msgtxt and \ - obj.nick: + if (app.config.should_log(obj.conn.name, obj.jid) and + obj.msgtxt and obj.nick): # if not obj.nick, it means message comes from room itself # usually it hold description and can be send at each connection # so don't store it in logs @@ -1026,10 +1029,7 @@ class ConnectionHandlersBase: message=obj.msgtxt, contact_name=obj.nick, additional_data=obj.additional_data) - # store in memory time of last message logged. - # this will also be saved in rooms_last_message_time table - # when we quit this muc - obj.conn.last_history_time[obj.jid] = obj.timestamp + app.logger.set_room_last_message_time(obj.room_jid, obj.timestamp) # process and dispatch an error message def dispatch_error_message(self, msg, msgtxt, session, frm, tim): diff --git a/gajim/common/connection_handlers_events.py b/gajim/common/connection_handlers_events.py index 3972e9d51..6987cb200 100644 --- a/gajim/common/connection_handlers_events.py +++ b/gajim/common/connection_handlers_events.py @@ -1564,9 +1564,6 @@ class GcMessageReceivedEvent(nec.NetworkIncomingEvent): # Ignore message from room in which we are not self.displaymarking = seclabel.getTag('displaymarking') - if self.jid not in self.conn.last_history_time: - return - self.captcha_form = None captcha_tag = self.stanza.getTag('captcha', namespace=nbxmpp.NS_CAPTCHA) if captcha_tag: diff --git a/gajim/common/logger.py b/gajim/common/logger.py index 3e210982e..81e1e768e 100644 --- a/gajim/common/logger.py +++ b/gajim/common/logger.py @@ -107,7 +107,7 @@ class SubscriptionConstant(IntEnum): class Logger: def __init__(self): - self.jids_already_in = [] # holds jids that we already have in DB + self._jid_ids = {} self.con = None self.commit_timout_id = None @@ -188,7 +188,7 @@ class Logger: def init_vars(self): self.open_db() - self.get_jids_already_in_db() + self.get_jid_ids_from_db() @staticmethod def _get_timeout(): @@ -226,22 +226,17 @@ class Logger: self.cur.execute(sql_to_commit) self._timeout_commit() - def get_jids_already_in_db(self): - try: - self.cur.execute('SELECT jid FROM jids') - rows = self.cur.fetchall() - except sqlite.DatabaseError: - raise exceptions.DatabaseMalformed(LOG_DB_PATH) - self.jids_already_in = [] + def get_jid_ids_from_db(self): + """ + Load all jid/jid_id tuples into a dict for faster access + """ + rows = self.con.execute( + 'SELECT jid_id, jid, type FROM jids').fetchall() for row in rows: - if not row.jid: - # malformed jid, ignore line - pass - else: - self.jids_already_in.append(row.jid) + self._jid_ids[row.jid] = row def get_jids_in_db(self): - return self.jids_already_in + return self._jid_ids.keys() def jid_is_from_pm(self, jid): """ @@ -288,42 +283,41 @@ class Logger: return [user['jid'] for user in family] return [jid] - def get_jid_id(self, jid, typestr=None): - """ - jids table has jid and jid_id logs table has log_id, jid_id, - contact_name, time, kind, show, message so to ask logs we need jid_id - that matches our jid in jids table this method wants jid and returns the - jid_id for later sql-ing on logs typestr can be 'ROOM' or anything else - depending on the type of JID and is only needed to be specified when the - JID is new in DB - """ - if jid.find('/') != -1: # if it has a / - jid_is_from_pm = self.jid_is_from_pm(jid) - if not jid_is_from_pm: # it's normal jid with resource - jid = jid.split('/', 1)[0] # remove the resource - if jid in self.jids_already_in: # we already have jids in DB - self.cur.execute('SELECT jid_id FROM jids WHERE jid=?', [jid]) - row = self.cur.fetchone() - if row: - return row.jid_id - # oh! a new jid :), we add it now - if typestr == 'ROOM': - typ = JIDConstant.ROOM_TYPE - else: - typ = JIDConstant.NORMAL_TYPE - try: - self.cur.execute('INSERT INTO jids (jid, type) VALUES (?, ?)', (jid, - typ)) - self.con.commit() - except sqlite.IntegrityError: - # Jid already in DB, maybe added by another instance. re-read DB - self.get_jids_already_in_db() - return self.get_jid_id(jid, typestr) - except sqlite.OperationalError as e: - raise exceptions.PysqliteOperationalError(str(e)) - jid_id = self.cur.lastrowid - self.jids_already_in.append(jid) - return jid_id + def get_jid_id(self, jid, kind=None, type_=None): + """ + Get the jid id from a jid. + In case the jid id is not found create a new one. + + :param jid: The JID + + :param type_: The JIDConstant type + + return the jid id + """ + + if kind in (KindConstant.GC_MSG, KindConstant.GCSTATUS): + type_ = JIDConstant.ROOM_TYPE + + result = self._jid_ids.get(jid, None) + if result is not None: + return result.jid_id + + sql = 'SELECT jid_id, jid, type FROM jids WHERE jid = ?' + row = self.con.execute(sql, [jid]).fetchone() + if row is not None: + self._jid_ids[jid] = row + return row.jid_id + + if type_ is None: + raise ValueError( + 'Unable to insert new JID because type is missing') + + sql = 'INSERT INTO jids (jid, type) VALUES (?, ?)' + lastrowid = self.con.execute(sql, (jid, type_)).lastrowid + Row = namedtuple('Row', 'jid_id jid type') + self._jid_ids[jid] = Row(lastrowid, jid, type_) + self._timeout_commit() + return lastrowid def convert_kind_values_to_db_api_values(self, kind): """ @@ -758,13 +752,16 @@ class Logger: :param jid: The jid :param timestamp: The timestamp in epoch + """ - self.insert_jid(jid, type_=JIDConstant.ROOM_TYPE) + jid_id = self.get_jid_id(jid, type_=JIDConstant.ROOM_TYPE) sql = '''REPLACE INTO rooms_last_message_time - VALUES ((SELECT jid_id FROM jids WHERE jid = ?), ?)''' + VALUES (:jid_id, COALESCE( + (SELECT time FROM rooms_last_message_time + WHERE jid_id = :jid_id AND time >= :time), :time))''' - self.con.execute(sql, (jid, timestamp)) + self.con.execute(sql, {"jid_id": jid_id, "time": timestamp}) self._timeout_commit() def save_transport_type(self, jid, type_): @@ -961,7 +958,7 @@ class Logger: try: account_jid_id = self.get_jid_id(account_jid) - jid_id = self.get_jid_id(jid) + jid_id = self.get_jid_id(jid, type_=JIDConstant.NORMAL_TYPE) except exceptions.PysqliteOperationalError as e: raise exceptions.PysqliteOperationalError(str(e)) @@ -993,7 +990,7 @@ class Logger: Return the accound_jid roster in NonBlockingRoster format """ data = {} - account_jid_id = self.get_jid_id(account_jid) + account_jid_id = self.get_jid_id(account_jid, type_=JIDConstant.NORMAL_TYPE) # First we fill data with roster_entry informations self.cur.execute(''' @@ -1085,6 +1082,7 @@ class Logger: def insert_jid(self, jid, kind=None, type_=JIDConstant.NORMAL_TYPE): """ Insert a new jid into the `jids` table. + This is an alias of get_jid_id() for better readablility. :param jid: The jid as string @@ -1092,14 +1090,7 @@ class Logger: :param type_: A JIDConstant """ - if jid in self.jids_already_in: - return - if kind in (KindConstant.GC_MSG, KindConstant.GCSTATUS): - type_ = JIDConstant.ROOM_TYPE - sql = 'INSERT OR IGNORE INTO jids (jid, type) VALUES (?, ?)' - self.con.execute(sql, (jid, type_)) - self.jids_already_in.append(jid) - self._timeout_commit() + return self.get_jid_id(jid, kind, type_) def insert_into_logs(self, jid, time_, kind, unread=True, **kwargs): """ @@ -1117,15 +1108,15 @@ class Logger: :param kwargs: Every additional named argument must correspond to a field in the `logs` table """ - self.insert_jid(jid, kind=kind) + jid_id = self.get_jid_id(jid, kind=kind) sql = ''' INSERT INTO logs (jid_id, time, kind, {columns}) - VALUES ((SELECT jid_id FROM jids WHERE jid = ?), ?, ?, {values}) + VALUES (?, ?, ?, {values}) '''.format(columns=', '.join(kwargs.keys()), values=', '.join('?' * len(kwargs))) - lastrowid = self.con.execute(sql, (jid, time_, kind) + tuple(kwargs.values())).lastrowid + lastrowid = self.con.execute(sql, (jid_id, time_, kind) + tuple(kwargs.values())).lastrowid if unread and kind == KindConstant.CHAT_MSG_RECV: sql = '''INSERT INTO unread_messages (message_id, jid_id) @@ -1149,7 +1140,7 @@ class Logger: """ account_jid_id = self.get_jid_id(account_jid) - jid_id = self.get_jid_id(jid) + jid_id = self.get_jid_id(jid, type_=JIDConstant.NORMAL_TYPE) sql = ''' UPDATE roster_entry SET avatar_sha = ? diff --git a/gajim/groupchat_control.py b/gajim/groupchat_control.py index 1ed49a5e6..9c9fd90b1 100644 --- a/gajim/groupchat_control.py +++ b/gajim/groupchat_control.py @@ -1499,8 +1499,6 @@ class GroupchatControl(ChatControlBase): app.contacts.remove_gc_contact(self.account, gc_contact) app.gc_connected[self.account][self.room_jid] = False ChatControlBase.got_disconnected(self) - # Tell connection to note the date we disconnect to avoid duplicate logs - app.connections[self.account].gc_got_disconnected(self.room_jid) # We don't redraw the whole banner here, because only icon change self._update_banner_state_image() if self.parent_win: @@ -2141,10 +2139,6 @@ class GroupchatControl(ChatControlBase): if self.room_jid in app.gc_connected[self.account] and \ app.gc_connected[self.account][self.room_jid]: - # Tell connection to note the date we disconnect to avoid duplicate - # logs. We do it only when connected because if connection was lost - # there may be new messages since disconnection. - app.connections[self.account].gc_got_disconnected(self.room_jid) app.connections[self.account].send_gc_status(self.nick, self.room_jid, show='offline', status=status) nick_list = app.contacts.get_nick_list(self.account, self.room_jid) diff --git a/gajim/gui_interface.py b/gajim/gui_interface.py index cc5257141..cf9274cf0 100644 --- a/gajim/gui_interface.py +++ b/gajim/gui_interface.py @@ -2399,7 +2399,7 @@ class Interface: 'avatar image using pillow', filename) try: avatar = Image.open(path).convert("RGBA") - except NameError: + except (NameError, OSError): app.log('avatar').warning('Pillow convert failed: %s', filename) app.log('avatar').debug('Error', exc_info=True) return diff --git a/gajim/profile_window.py b/gajim/profile_window.py index 6bb4e4a5a..5fb1c1458 100644 --- a/gajim/profile_window.py +++ b/gajim/profile_window.py @@ -253,7 +253,7 @@ class ProfileWindow: else: if i == 'DESC': self.xml.get_object('DESC_textview').get_buffer().set_text( - vcard_[i], len(vcard[i].encode('utf-8'))) + vcard_[i], len(vcard_[i].encode('utf-8'))) else: self.set_value(i + '_entry', vcard_[i]) if self.update_progressbar_timeout_id is not None: diff --git a/win/_base.sh b/win/_base.sh index 03a8bbd1d..4f48bcd49 100644 --- a/win/_base.sh +++ b/win/_base.sh @@ -73,6 +73,7 @@ function install_deps { mingw-w64-"${ARCH}"-"${PYTHON_ID}"-pip \ mingw-w64-"${ARCH}"-gstreamer \ mingw-w64-"${ARCH}"-adwaita-icon-theme \ + mingw-w64-"${ARCH}"-libwebp \ mingw-w64-"${ARCH}"-sqlite3 \ mingw-w64-"${ARCH}"-goocanvas -- 2.20.1