Commit a289ad5f authored by Philipp Hörist's avatar Philipp Hörist

Refactor Presence

- Remove option to hide self contacts for now. This makes the code less
complicated.
- Move as much code as possible into the presence module
- Use nbxmpp properties
parent 608607b7
......@@ -268,7 +268,6 @@ class Config:
'check_idle_every_foo_seconds': [opt_int, 2, _('Choose interval between 2 checks of idleness.')],
'uri_schemes': [opt_str, 'aaa:// aaas:// acap:// cap:// cid: crid:// data: dav: dict:// dns: fax: file:/ ftp:// geo: go: gopher:// h323: http:// https:// iax: icap:// im: imap:// info: ipp:// iris: iris.beep: iris.xpc: iris.xpcs: iris.lwz: ldap:// mid: modem: msrp:// msrps:// mtqp:// mupdate:// news: nfs:// nntp:// opaquelocktoken: pop:// pres: prospero:// rtsp:// service: shttp:// sip: sips: sms: snmp:// soap.beep:// soap.beeps:// tag: tel: telnet:// tftp:// thismessage:/ tip:// tv: urn:// vemmi:// xmlrpc.beep:// xmlrpc.beeps:// z39.50r:// z39.50s:// about: apt: cvs:// daap:// ed2k:// feed: fish:// git:// iax2: irc:// ircs:// ldaps:// magnet: mms:// rsync:// ssh:// svn:// sftp:// smb:// webcal:// aesgcm://', _('Valid uri schemes. Only schemes in this list will be accepted as "real" uri. (mailto and xmpp are handled separately)'), True],
'shell_like_completion': [opt_bool, False, _('If true, completion in groupchats will be like a shell auto-completion')],
'show_self_contact': [opt_str, 'when_other_resource', _('When is self contact row displayed. Can be "always", "when_other_resource" or "never"'), True],
'audio_input_device': [opt_str, 'autoaudiosrc ! volume name=gajim_vol'],
'audio_output_device': [opt_str, 'autoaudiosink'],
'video_input_device': [opt_str, 'autovideosrc'],
......
......@@ -67,136 +67,13 @@ class ConnectionHandlersBase:
# We decrypt GPG messages one after the other. Keep queue in mem
self.gpg_messages_to_decrypt = []
app.ged.register_event_handler('presence-received', ged.CORE,
self._nec_presence_received)
app.ged.register_event_handler('gc-message-received', ged.CORE,
self._nec_gc_message_received)
def cleanup(self):
app.ged.remove_event_handler('presence-received', ged.CORE,
self._nec_presence_received)
app.ged.remove_event_handler('gc-message-received', ged.CORE,
self._nec_gc_message_received)
def _nec_presence_received(self, obj):
account = obj.conn.name
if account != self.name:
return
jid = obj.jid
resource = obj.resource or ''
statuss = ['offline', 'error', 'online', 'chat', 'away', 'xa', 'dnd',
'invisible']
obj.old_show = 0
obj.new_show = statuss.index(obj.show)
obj.contact_list = []
highest = app.contacts.get_contact_with_highest_priority(account, jid)
obj.was_highest = (highest and highest.resource == resource)
# Update contact
obj.contact_list = app.contacts.get_contacts(account, jid)
obj.contact = None
resources = []
for c in obj.contact_list:
resources.append(c.resource)
if c.resource == resource:
obj.contact = c
break
if obj.contact:
if obj.contact.show in statuss:
obj.old_show = statuss.index(obj.contact.show)
# nick changed
if obj.contact_nickname is not None and \
obj.contact.contact_name != obj.contact_nickname:
obj.contact.contact_name = obj.contact_nickname
obj.need_redraw = True
elif obj.old_show != obj.new_show or obj.contact.status != \
obj.status:
obj.need_redraw = True
else:
obj.contact = app.contacts.get_first_contact_from_jid(account,
jid)
if not obj.contact:
# Presence of another resource of our jid
# Create self contact and add to roster
if resource == obj.conn.server_resource:
return
# Ignore offline presence of unknown self resource
if obj.new_show < 2:
return
obj.contact = app.contacts.create_self_contact(jid=jid,
account=account, show=obj.show, status=obj.status,
priority=obj.prio, keyID=obj.keyID,
resource=obj.resource)
app.contacts.add_contact(account, obj.contact)
obj.contact_list.append(obj.contact)
elif obj.contact.show in statuss:
obj.old_show = statuss.index(obj.contact.show)
if (resources != [''] and (len(obj.contact_list) != 1 or \
obj.contact_list[0].show not in ('not in roster', 'offline'))) and \
not app.jid_is_transport(jid):
# Another resource of an existing contact connected
obj.old_show = 0
obj.contact = app.contacts.copy_contact(obj.contact)
obj.contact_list.append(obj.contact)
obj.contact.resource = resource
obj.need_redraw = True
obj.need_add_in_roster = True
if not app.jid_is_transport(jid) and len(obj.contact_list) == 1:
# It's not an agent
if obj.old_show == 0 and obj.new_show > 1:
if not jid in app.newly_added[account]:
app.newly_added[account].append(jid)
if jid in app.to_be_removed[account]:
app.to_be_removed[account].remove(jid)
elif obj.old_show > 1 and obj.new_show == 0 and \
obj.conn.connected > 1:
if not jid in app.to_be_removed[account]:
app.to_be_removed[account].append(jid)
if jid in app.newly_added[account]:
app.newly_added[account].remove(jid)
obj.need_redraw = True
obj.contact.show = obj.show
obj.contact.status = obj.status
obj.contact.priority = obj.prio
attached_keys = app.config.get_per('accounts', account,
'attached_gpg_keys').split()
if jid in attached_keys:
obj.contact.keyID = attached_keys[attached_keys.index(jid) + 1]
else:
# Do not override assigned key
obj.contact.keyID = obj.keyID
obj.contact.contact_nickname = obj.contact_nickname
obj.contact.idle_time = obj.idle_time
if app.jid_is_transport(jid):
return
# It isn't an agent
# (when contact signs out or has errors)
if obj.show in ('offline', 'error'):
# TODO: This causes problems when another
# resource signs off!
self.stop_all_active_file_transfers(obj.contact)
if app.config.get('log_contact_status_changes') and \
app.config.should_log(self.name, obj.jid):
show = app.logger.convert_show_values_to_db_api_values(obj.show)
if show is not None:
app.logger.insert_into_logs(self.name,
nbxmpp.JID(obj.jid).getStripped(),
time.time(),
KindConstant.STATUS,
message=obj.status,
show=show)
def _check_for_mam_compliance(self, room_jid, stanza_id):
namespace = muc_caps_cache.get_mam_namespace(room_jid)
if stanza_id is None and namespace == nbxmpp.NS_MAM_2:
......
......@@ -144,105 +144,8 @@ class StreamConflictReceivedEvent(nec.NetworkIncomingEvent):
self.conn = self.base_event.conn
return True
class PresenceHelperEvent:
def _generate_show(self):
self.show = self.stanza.getShow()
if self.show not in ('chat', 'away', 'xa', 'dnd'):
self.show = '' # We ignore unknown show
if not self.ptype and not self.show:
self.show = 'online'
elif self.ptype == 'unavailable':
self.show = 'offline'
def _generate_ptype(self):
self.ptype = self.stanza.getType()
if self.ptype == 'available':
self.ptype = None
rfc_types = ('unavailable', 'error', 'subscribe', 'subscribed',
'unsubscribe', 'unsubscribed')
if self.ptype and not self.ptype in rfc_types:
self.ptype = None
class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent,
PresenceHelperEvent):
class PresenceReceivedEvent(nec.NetworkIncomingEvent):
name = 'presence-received'
base_network_events = ['raw-pres-received']
def _generate_keyID(self, sig_tag):
self.keyID = ''
if sig_tag and self.conn.USE_GPG and self.ptype != 'error':
# error presences contain our own signature
# verify
sig_msg = sig_tag.getData()
self.keyID = self.conn.gpg.verify(self.status, sig_msg)
self.keyID = helpers.prepare_and_validate_gpg_keyID(self.conn.name,
self.jid,
self.keyID)
def _generate_prio(self):
self.prio = self.stanza.getPriority()
try:
self.prio = int(self.prio)
except Exception:
self.prio = 0
def generate(self):
self.conn = self.base_event.conn
self.stanza = self.base_event.stanza
self.need_add_in_roster = False
self.need_redraw = False
self.popup = False # Do we want to open chat window ?
if not self.conn or self.conn.connected < 2:
log.debug('account is no more connected')
return
self._generate_ptype()
try:
self.get_jid_resource()
except Exception:
log.warning('Invalid JID: %s, ignoring it', self.stanza.getFrom())
return
jid_list = app.contacts.get_jid_list(self.conn.name)
self.timestamp = None
self.get_id()
self.avatar_sha = None
# XEP-0172 User Nickname
self.user_nick = self.stanza.getTagData('nick') or ''
self.contact_nickname = None
self.transport_auto_auth = False
# XEP-0203
self.timestamp = parse_delay(self.stanza)
if self.timestamp is None:
self.timestamp = time_time()
# XEP-0319
self.idle_time = parse_idle(self.stanza)
sig_tag = self.stanza.getTag('x', namespace=nbxmpp.NS_SIGNED)
self.status = self.stanza.getStatus() or ''
self._generate_show()
self._generate_prio()
self._generate_keyID(sig_tag)
self.errcode = self.stanza.getErrorCode()
self.errmsg = self.stanza.getErrorMsg()
if self.ptype == 'error':
return
if not self.ptype or self.ptype == 'unavailable':
our_jid = app.get_jid_from_account(self.conn.name)
if self.jid == our_jid and self.resource == self.conn.server_resource:
# We got our own presence
app.nec.push_incoming_event(OurShowEvent(None, conn=self.conn,
show=self.show))
elif self.jid in jid_list or self.jid == our_jid:
return True
class ZeroconfPresenceReceivedEvent(nec.NetworkIncomingEvent):
name = 'presence-received'
......@@ -254,16 +157,13 @@ class ZeroconfPresenceReceivedEvent(nec.NetworkIncomingEvent):
self.keyID = None
self.idle_time = None
self.timestamp = 0
self.contact_nickname = None
self.avatar_sha = None
self.need_add_in_roster = False
self.need_redraw = False
if self.show == 'offline':
self.ptype = 'unavailable'
else:
self.ptype = None
self.user_nick = ''
self.transport_auto_auth = False
self.errcode = None
self.errmsg = ''
self.popup = False # Do we want to open chat window ?
......
......@@ -368,6 +368,9 @@ class LegacyContactsAPI:
def get_contact(self, account, jid, resource=None):
return self._accounts[account].contacts.get_contact(jid, resource=resource)
def get_contact_strict(self, account, jid, resource):
return self._accounts[account].contacts.get_contact_strict(jid, resource)
def get_avatar(self, account, *args, **kwargs):
return self._accounts[account].contacts.get_avatar(*args, **kwargs)
......@@ -553,7 +556,7 @@ class Contacts():
"""
Return the list of contact instances for this jid
"""
return self._contacts.get(jid, [])
return list(self._contacts.get(jid, []))
def get_contact(self, jid, resource=None):
### WARNING ###
......
This diff is collapsed.
......@@ -152,7 +152,7 @@ class ConnectionZeroconf(CommonConnection, ConnectionHandlersZeroconf):
def _on_remove_service(self, jid):
self.roster.delItem(jid)
# 'NOTIFY' (account, (jid, status, status message, resource, priority,
# keyID, timestamp, contact_nickname))
# keyID, timestamp))
app.nec.push_incoming_event(ZeroconfPresenceReceivedEvent(
None, conn=self, fjid=jid, show='offline', status=''))
......
......@@ -331,7 +331,7 @@ class Interface:
def handle_event_presence(self, obj):
# 'NOTIFY' (account, (jid, status, status message, resource,
# priority, # keyID, timestamp, contact_nickname))
# priority, # keyID, timestamp))
#
# Contact changed show
account = obj.conn.name
......
......@@ -366,8 +366,7 @@ class GajimRemote(Server):
else:
return
self.raise_signal(event, (obj.conn.name, [obj.jid, obj.show,
obj.status, obj.resource, obj.prio, obj.keyID, obj.timestamp,
obj.contact_nickname]))
obj.status, obj.resource, obj.prio, obj.keyID, obj.timestamp]))
def on_subscribe_presence_received(self, obj):
self.raise_signal('Subscribe', (obj.conn.name, [obj.jid, obj.status,
......
......@@ -720,14 +720,7 @@ class RosterWindow:
return
if jid == app.get_jid_from_account(account):
show_self_contact = app.config.get('show_self_contact')
if show_self_contact == 'never':
return
if (contact.resource != app.connections[account].server_resource \
and show_self_contact == 'when_other_resource') or \
show_self_contact == 'always':
return self._add_self_contact(account)
return
return self._add_self_contact(account)
is_observer = contact.is_observer()
if is_observer:
......@@ -1871,13 +1864,13 @@ class RosterWindow:
'contacts': {}}
if account not in app.groups:
app.groups[account] = {}
if app.config.get('show_self_contact') == 'always':
self_jid = app.get_jid_from_account(account)
if app.connections[account].server_resource:
self_jid += '/' + app.connections[account].server_resource
array[self_jid] = {'name': app.nicks[account],
'groups': ['self_contact'], 'subscription': 'both',
'ask': 'none'}
self_jid = app.get_jid_from_account(account)
if app.connections[account].server_resource:
self_jid += '/' + app.connections[account].server_resource
array[self_jid] = {'name': app.nicks[account],
'groups': ['self_contact'], 'subscription': 'both',
'ask': 'none'}
# .keys() is needed
for jid in list(array.keys()):
......@@ -2212,10 +2205,7 @@ class RosterWindow:
elif contact.jid == app.get_jid_from_account(account) and \
show in ('offline', 'error'):
if app.config.get('show_self_contact') != 'never':
# SelfContact went offline. Remove him when last pending
# message was read
self.remove_contact(contact.jid, account, backend=True)
self.remove_contact(contact.jid, account, backend=True)
uf_show = helpers.get_uf_show(show)
......@@ -2249,13 +2239,12 @@ class RosterWindow:
if account not in app.contacts.get_accounts():
return
child_iterA = self._get_account_iter(account, self.model)
if app.config.get('show_self_contact') == 'always':
self_resource = app.connections[account].server_resource
self_contact = app.contacts.get_contact(account,
app.get_jid_from_account(account), resource=self_resource)
if self_contact:
status = app.connections[account].status
self.chg_contact_status(self_contact, show, status, account)
self_resource = app.connections[account].server_resource
self_contact = app.contacts.get_contact(account,
app.get_jid_from_account(account), resource=self_resource)
if self_contact:
status = app.connections[account].status
self.chg_contact_status(self_contact, show, status, account)
self.set_account_status_icon(account)
if show == 'offline':
if self.quit_on_next_offline > -1:
......@@ -2570,8 +2559,7 @@ class RosterWindow:
GLib.timeout_add_seconds(5, self.remove_to_be_removed,
jid, account)
if obj.need_redraw:
self.draw_contact(jid, account)
self.draw_contact(jid, account)
if app.jid_is_transport(jid) and jid in jid_list:
# It must be an agent
......@@ -2579,7 +2567,7 @@ class RosterWindow:
self.draw_contact(jid, account)
self.draw_group(_('Transports'), account)
if obj.contact and obj.need_redraw:
if obj.contact:
self.chg_contact_status(obj.contact, obj.show, obj.status, account)
if obj.popup:
......@@ -2598,20 +2586,20 @@ class RosterWindow:
self.fire_up_unread_messages_events(obj.conn.name)
else:
# add self contact
if app.config.get('show_self_contact') == 'always':
account = obj.conn.name
self_jid = app.get_jid_from_account(account)
if self_jid not in app.contacts.get_jid_list(account):
resource = ''
if app.connections[account].server_resource:
resource = app.connections[account].server_resource
sha = app.config.get_per('accounts', account, 'avatar_sha')
contact = app.contacts.create_contact(
jid=self_jid, account=account, name=app.nicks[account],
groups=['self_contact'], show='offline', sub='both',
ask='none', resource=resource, avatar_sha=sha)
app.contacts.add_contact(account, contact)
self.add_contact(self_jid, account)
account = obj.conn.name
self_jid = app.get_jid_from_account(account)
if self_jid not in app.contacts.get_jid_list(account):
resource = ''
if app.connections[account].server_resource:
resource = app.connections[account].server_resource
sha = app.config.get_per('accounts', account, 'avatar_sha')
contact = app.contacts.create_contact(
jid=self_jid, account=account, name=app.nicks[account],
groups=['self_contact'], show='offline', sub='both',
ask='none', resource=resource, avatar_sha=sha)
app.contacts.add_contact(account, contact)
self.add_contact(self_jid, account)
if app.config.get('remember_opened_chat_controls'):
account = obj.conn.name
controls = app.config.get_per(
......
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