'Check if a JID has a given identity.
The data parameter may provide:
category -- The category of the identity to check.
itype    -- The type of the identity to check.
lang     -- The language of the identity to check.
local    -- If true, then the query is for a JID/node
combination handled by this Sleek instance and
no stanzas need to be sent.
Otherwise, a disco stanza must be sent to the
remove JID to retrieve the info.
cached   -- If true, then look for the disco info data from
the local cache system. If no results are found,
send the query as usual. The self.use_cache
setting must be set to true for this option to
be useful. If set to false, then the cache will
be skipped, even if a result has already been
cached. Defaults to false.'

def has_identity(self, jid, node, ifrom, data):

    identity = (data.get('category', None), data.get('itype', None), data.get('lang', None))
    data = {'local': data.get('local', False), 'cached': data.get('cached', True)}
    trunc = (lambda i: (i[0], i[1], i[2]))
    if (node in (None, '')):
        info = self.caps.get_caps(jid)
        if (info and (identity in map(trunc, info['identities']))):
            return True
    try:
        info = self.disco.get_info(jid=jid, node=node, ifrom=ifrom, **data)
        info = self.disco._wrap(ifrom, jid, info, True)
        return (identity in map(trunc, info['disco_info']['identities']))
    except IqError:
        return False
    except IqTimeout:
        return None
