# This file is part of Gajim. # # Gajim is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; version 3 only. # # Gajim is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Gajim. If not, see . # Presence handler import logging import nbxmpp from gajim.common import app from gajim.common.nec import NetworkEvent from gajim.common.modules.user_nickname import parse_nickname log = logging.getLogger('gajim.c.m.presence') class Presence: def __init__(self, con): self._con = con self._account = con.name self.handlers = [ ('presence', self._presence_received), ('presence', self._subscribe_received, 'subscribe'), ('presence', self._subscribed_received, 'subscribed'), ('presence', self._unsubscribe_received, 'unsubscribe'), ('presence', self._unsubscribed_received, 'unsubscribed'), ] # keep the jids we auto added (transports contacts) to not send the # SUBSCRIBED event to GUI self.automatically_added = [] # list of jid to auto-authorize self.jids_for_auto_auth = [] def _presence_received(self, con, stanza): if stanza.getType() in ('subscribe', 'subscribed', 'unsubscribe', 'unsubscribed'): # Dont handle that here return log.info('Received from %s', stanza.getFrom()) app.nec.push_incoming_event( NetworkEvent('raw-pres-received', conn=self._con, stanza=stanza)) def _subscribe_received(self, con, stanza): from_ = stanza.getFrom() jid = from_.getStripped() fjid = str(from_) status = stanza.getStatus() is_transport = app.jid_is_transport(fjid) auto_auth = app.config.get_per('accounts', self._account, 'autoauth') user_nick = parse_nickname(stanza) log.info('Received Subscribe: %s, transport: %s, auto_auth: %s, ' 'user_nick: %s', from_, is_transport, auto_auth, user_nick) if is_transport and fjid in self._con.agent_registrations: self._con.agent_registrations[fjid]['sub_received'] = True if not self.agent_registrations[fjid]['roster_push']: # We'll reply after roster push result raise nbxmpp.NodeProcessed if auto_auth or is_transport or jid in self.jids_for_auto_auth: presence = nbxmpp.Presence(fjid, 'subscribed') presence = self._add_sha(presence) self._con.connection.send(presence) if not status: status = _('I would like to add you to my roster.') app.nec.push_incoming_event(NetworkEvent( 'subscribe-presence-received', conn=self._con, jid=jid, fjid=fjid, status=status, user_nick=user_nick, is_transport=is_transport)) raise nbxmpp.NodeProcessed def _subscribed_received(self, con, stanza): from_ = stanza.getFrom() jid = from_.getStripped() resource = from_.getResource() log.info('Received Subscribed: %s', from_) if jid in self.automatically_added: self.automatically_added.remove(jid) raise nbxmpp.NodeProcessed app.nec.push_incoming_event(NetworkEvent( 'subscribed-presence-received', conn=self._con, jid=jid, resource=resource)) raise nbxmpp.NodeProcessed def _unsubscribe_received(self, con, stanza): log.info('Received Unsubscribe: %s', stanza.getFrom()) raise nbxmpp.NodeProcessed def _unsubscribed_received(self, con, stanza): from_ = stanza.getFrom() jid = from_.getStripped() log.info('Received Unsubscribed: %s', from_) app.nec.push_incoming_event(NetworkEvent( 'unsubscribed-presence-received', conn=self._con, jid=jid)) raise nbxmpp.NodeProcessed def subscribed(self, jid): if not app.account_is_connected(self._account): return log.info('Subscribed: %s', jid) presence = nbxmpp.Presence(jid, 'subscribed') presence = self._add_sha(presence) self._con.connection.send(presence) def unsubscribed(self, jid): if not app.account_is_connected(self._account): return log.info('Unsubscribed: %s', jid) presence = nbxmpp.Presence(jid, 'unsubscribed') presence = self._add_sha(presence) self._con.connection.send(presence) def unsubscribe(self, jid, remove_auth=True): if not app.account_is_connected(self._account): return if remove_auth: self._con.getRoster().delItem(jid) jid_list = app.config.get_per('contacts') for j in jid_list: if j.startswith(jid): app.config.del_per('contacts', j) else: log.info('Unsubscribe from %s', jid) self._con.getRoster().Unsubscribe(jid) self._con.getRoster().setItem(jid) def subscribe(self, jid, msg='', name='', groups=None, auto_auth=False, user_nick=''): if not app.account_is_connected(self._account): return if groups is None: groups = [] log.info('Request Subscription to %s', jid) if auto_auth: self.jids_for_auto_auth.append(jid) infos = {'jid': jid} if name: infos['name'] = name iq = nbxmpp.Iq('set', nbxmpp.NS_ROSTER) query = iq.setQuery() item = query.addChild('item', attrs=infos) for group in groups: item.addChild('group').setData(group) self._con.connection.send(iq) presence = nbxmpp.Presence(jid, 'subscribe') if user_nick: nick = presence.setTag('nick', namespace=nbxmpp.NS_NICK) nick.setData(user_nick) presence = self._add_sha(presence) if msg: presence.setStatus(msg) self._con.connection.send(presence) def _add_sha(self, presence, send_caps=True): vcard = self._con.get_module('VCardAvatars') presence = vcard.add_update_node(presence) if send_caps: return self._add_caps(presence) return presence def _add_caps(self, presence): c = presence.setTag('c', namespace=nbxmpp.NS_CAPS) c.setAttr('hash', 'sha-1') c.setAttr('node', 'http://gajim.org') c.setAttr('ver', app.caps_hash[self._account]) return presence def parse_show(stanza): show = stanza.getShow() type_ = parse_type(stanza) if show is None and type_ is None: return 'online' if type_ == 'unavailable': return 'offline' if show not in (None, 'chat', 'away', 'xa', 'dnd'): log.warning('Invalid show element: %s', stanza) if type_ is None: return 'online' return 'offline' if show is None: return 'online' return show def parse_type(stanza): type_ = stanza.getType() if type_ not in (None, 'unavailable', 'error', 'subscribe', 'subscribed', 'unsubscribe', 'unsubscribed'): log.warning('Invalid type: %s', stanza) return None return type_ def get_instance(*args, **kwargs): return Presence(*args, **kwargs), 'Presence'