def identify_contacts(self, tp_chan, handles, identifiers=None): """Work out the "best" unique identifier we can for the given handles, in the context of the given channel (which may be None), using only 'fast' connection manager API (that does not involve network round-trips). For the XMPP server case, we proceed as follows: * Find the owners of the given handles, if the channel has channel-specific handles * If the owner (globally-valid JID) is on a trusted server, return 'keyid/' plus the 'key fingerprint' (the user part of their JID, currently implemented as the SHA-1 of the Base64 blob in owner.key.pub) * If the owner (globally-valid JID) cannot be found or is on an untrusted server, return 'xmpp/' plus an escaped form of the JID The idea is that we identify buddies by key-ID (i.e. by key, assuming no collisions) if we can find it without making network round-trips, but if that's not possible we just use their JIDs. :Parameters: `tp_chan` : telepathy.client.Channel or None The channel in which the handles were found, or None if they are known to be channel-specific handles `handles` : iterable over (int or long) The contacts' handles in that channel :Returns: A dict mapping the provided handles to the best available unique identifier, which is a string that could be used as a suffix to an object path """ # we need to be able to index into handles, so force them to # be a sequence if not isinstance(handles, (tuple, list)): handles = tuple(handles) owners = handles if tp_chan is not None and CHANNEL_INTERFACE_GROUP in tp_chan: group = tp_chan[CHANNEL_INTERFACE_GROUP] if (group.GetGroupFlags() & CHANNEL_GROUP_FLAG_CHANNEL_SPECIFIC_HANDLES): identifiers = None owners = group.GetHandleOwners(handles) for i, owner in enumerate(owners): if owner == 0: owners[i] = handles[i] else: group = None if identifiers is None: identifiers = self._conn[CONN_INTERFACE].InspectHandles( HANDLE_TYPE_CONTACT, owners) ret = {} for handle, jid in izip(handles, identifiers): # special-case the Owner - we always know who we are if (handle == self.self_handle or (group is not None and handle == group.GetSelfHandle())): ret[handle] = self._owner.props.objid continue if '/' in jid: # the contact is unidentifiable (in an anonymous MUC) - create # a temporary identity for them, based on their room-JID ret[handle] = 'xmpp/' + psutils.escape_identifier(jid) else: user, host = jid.split('@', 1) if (self._server_is_trusted(host) and len(user) == 40 and user.strip(hexdigits) == ''): # they're on a trusted server and their username looks # like a key-ID ret[handle] = 'keyid/' + user.lower() else: # untrusted server, or not the right format to be a # key-ID - identify the contact by their JID ret[handle] = 'xmpp/' + psutils.escape_identifier(jid) return ret
print "Running test_psutils..." from psutils import escape_identifier, pubkey_to_keyid assert pubkey_to_keyid('abc') == 'a9993e364706816aba3e25717850c26c9cd0d89d' assert escape_identifier('') == '_' assert escape_identifier('_') == '_5f' assert escape_identifier('1') == '_31' assert escape_identifier('a1') == 'a1' assert escape_identifier('1a') == '_31a' assert escape_identifier("0123abc_xyz\x01\xff") == '_30123abc_5fxyz_01_ff'
def identify_contacts(self, tp_chan, handles, identifiers=None): """Work out the "best" unique identifier we can for the given handles, in the context of the given channel (which may be None), using only 'fast' connection manager API (that does not involve network round-trips). For the XMPP server case, we proceed as follows: * Find the owners of the given handles, if the channel has channel-specific handles * If the owner (globally-valid JID) is on a trusted server, return 'keyid/' plus the 'key fingerprint' (the user part of their JID, currently implemented as the SHA-1 of the Base64 blob in owner.key.pub) * If the owner (globally-valid JID) cannot be found or is on an untrusted server, return 'xmpp/' plus an escaped form of the JID The idea is that we identify buddies by key-ID (i.e. by key, assuming no collisions) if we can find it without making network round-trips, but if that's not possible we just use their JIDs. :Parameters: `tp_chan` : telepathy.client.Channel or None The channel in which the handles were found, or None if they are known to be channel-specific handles `handles` : iterable over (int or long) The contacts' handles in that channel :Returns: A dict mapping the provided handles to the best available unique identifier, which is a string that could be used as a suffix to an object path """ # we need to be able to index into handles, so force them to # be a sequence if not isinstance(handles, (tuple, list)): handles = tuple(handles) # we happen to know that Salut has no channel-specific handles if identifiers is None: identifiers = self._conn[CONN_INTERFACE].InspectHandles( HANDLE_TYPE_CONTACT, handles) ret = {} for handle, ident in izip(handles, identifiers): # special-case the Owner - we always know who we are if handle == self.self_handle: ret[handle] = self._owner.props.objid continue # we also happen to know that on Salut, getting properties # is immediate, and the key is (well, will be) trustworthy if CONN_INTERFACE_BUDDY_INFO in self._conn: props = self._conn[CONN_INTERFACE_BUDDY_INFO].GetProperties( handle, byte_arrays=True, utf8_strings=True) key = props.get('key') else: key = None if key is not None: khash = psutils.pubkey_to_keyid(key) ret[handle] = 'keyid/' + khash else: ret[handle] = 'salut/' + psutils.escape_identifier(ident) return ret