Commit f386b9ce authored by Martin's avatar Martin

Imported upstream master from 2017-10-22

parent 1f034751
......@@ -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
......
......@@ -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):
......
......@@ -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:
......
......@@ -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 = ?
......
......@@ -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)
......
......@@ -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
......
......@@ -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:
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment