def test(q, bus, conn, stream):
    # This sidecar sends a stanza, and waits for a reply, before being
    # created.
    pattern = EventPattern('stream-iq', to='sidecar.example.com',
        query_ns='http://example.com/sidecar')
    call_async(q, conn.Sidecars1, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".IQ")
    e = q.expect_many(pattern)[0]

    # The server said yes, so we should get a sidecar back!
    acknowledge_iq(stream, e.stanza)
    q.expect('dbus-return', method='EnsureSidecar')

    identities = ["test/app-list//Test"]
    features = ["com.example.test1", "com.example.test2"]
    ver = compute_caps_hash(identities, features, {})

    iq = IQ(stream, "get")
    query = iq.addElement((ns.DISCO_INFO, 'query'))
    query['node'] = ns.GABBLE_CAPS + '#' + ver
    stream.send(iq)
    e = q.expect('stream-iq', query_ns='http://jabber.org/protocol/disco#info')

    returned_features = [feature['var']
        for feature in xpath.queryForNodes('/iq/query/feature', e.stanza)]
    assertEquals(features, returned_features)

    returned_identities = [identity['category'] + "/" + identity['type']+"//" + identity['name']
        for identity in xpath.queryForNodes('/iq/query/identity', e.stanza)]
    assertEquals(identities, returned_identities)

    new_ver = compute_caps_hash(returned_identities, returned_features, {})
    assertEquals(new_ver, ver)
    def _cb_disco_iq(self, iq):
        nodes = xpath.queryForNodes("/iq/query", iq)
        query = nodes[0]

        if query.getAttribute('node') is None:
            return

        node = query.attributes['node']
        ver = node.replace("http://telepathy.freedesktop.org/caps#", "")

        if iq.getAttribute('type') == 'result':

            if FileTransferTest.caps_identities is None or \
                    FileTransferTest.caps_features is None:
                identity_nodes = xpath.queryForNodes('/iq/query/identity', iq)
                assertLength(1, identity_nodes)
                identity_node = identity_nodes[0]

                identity_category = identity_node['category']
                identity_type = identity_node['type']
                identity_name = identity_node['name']
                identity = '%s/%s//%s' % (identity_category, identity_type,
                                          identity_name)
                FileTransferTest.caps_identities = [identity]

                FileTransferTest.caps_features = []
                for feature in xpath.queryForNodes('/iq/query/feature', iq):
                    FileTransferTest.caps_features.append(feature['var'])

                # Check if the hash matches the announced capabilities
                assertEquals(compute_caps_hash(FileTransferTest.caps_identities,
                                               FileTransferTest.caps_features,
                                               {}), ver)

            if ver == FileTransferTest.caps_ft:
                caps_share = compute_caps_hash(FileTransferTest.caps_identities,
                                               FileTransferTest.caps_features + \
                                                   [ns.GOOGLE_FEAT_SHARE],
                                               {})
                n = query.attributes['node'].replace(ver, caps_share)
                query.attributes['node'] = n

                for feature in xpath.queryForNodes('/iq/query/feature', iq):
                        query.children.remove(feature)

                for f in FileTransferTest.caps_features + [ns.GOOGLE_FEAT_SHARE]:
                    el = domish.Element((None, 'feature'))
                    el['var'] = f
                    query.addChild(el)

        elif iq.getAttribute('type') == 'get':
            caps_share = compute_caps_hash(FileTransferTest.caps_identities,
                                           FileTransferTest.caps_features + \
                                               [ns.GOOGLE_FEAT_SHARE],
                                           {})

            if ver == caps_share:
                n = query.attributes['node'].replace(ver,
                                                     FileTransferTest.caps_ft)
                query.attributes['node'] = n
def test_caps(q, conn, stream, contact, features, audio, video, google=False):
    caps['ver'] = compute_caps_hash([], features, {})

    h = presence_and_disco(q, conn, stream, contact, True, client, caps,
                           features)

    cflags = 0
    call_expected_media_caps = []

    if audio:
        cflags |= cs.MEDIA_CAP_AUDIO
        call_expected_media_caps.append(cs.CALL_INITIAL_AUDIO)
        call_expected_media_caps.append(cs.CALL_INITIAL_AUDIO_NAME)
    if video:
        cflags |= cs.MEDIA_CAP_VIDEO
        call_expected_media_caps.append(cs.CALL_INITIAL_VIDEO)
        call_expected_media_caps.append(cs.CALL_INITIAL_VIDEO_NAME)

    # If the contact can only do one of audio or video, or uses a Google
    # client, they'll have the ImmutableStreams cap.
    if cflags < (cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO) or google:
        cflags |= cs.MEDIA_CAP_IMMUTABLE_STREAMS
    else:
        call_expected_media_caps.append(cs.CALL_MUTABLE_CONTENTS)

    event, = q.expect_many(
        EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'))

    # Check Contact capabilities
    assertEquals(len(event.args), 1)
    assertEquals(event.args[0], get_contacts_capabilities_sync(conn, [h]))

    check_contact_caps(event.args[0][h], cs.CHANNEL_TYPE_CALL,
                       call_expected_media_caps)
def test(q, bus, conn):
    # last value of the "ver" key we resolved. We use it to be sure that the
    # modified caps has already be announced.
    old_ver = None

    conn.Connect()
    q.expect('dbus-signal', signal='StatusChanged', args=[0, 0])

    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")
    self_handle_name =  conn.Properties.Get(cs.CONN, "SelfID")

    AvahiListener(q).listen_for_service("_presence._tcp")
    e = q.expect('service-added', name = self_handle_name,
        protocol = avahi.PROTO_INET)
    service = e.service
    service.resolve()

    e = q.expect('service-resolved', service = service)
    ver = txt_get_key(e.txt, "ver")
    while ver == old_ver:
        # be sure that the announced caps actually changes
        e = q.expect('service-resolved', service=service)
        ver = txt_get_key(e.txt, "ver")
    old_ver = ver

    caps = compute_caps_hash(['client/pc//%s' % PACKAGE_STRING],
        fixed_features, {})
    assertEquals(caps, ver)

    test_ft_caps_from_contact(q, bus, conn, service, 'yo@momma')

    test_ft_caps_to_contact(q, bus, conn, service)
def test(q, bus, conn):
    # last value of the "ver" key we resolved. We use it to be sure that the
    # modified caps has already be announced.
    old_ver = None

    conn.Connect()
    q.expect('dbus-signal', signal='StatusChanged', args=[0, 0])

    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")
    self_handle_name = conn.Properties.Get(cs.CONN, "SelfID")

    AvahiListener(q).listen_for_service("_presence._tcp")
    e = q.expect('service-added',
                 name=self_handle_name,
                 protocol=avahi.PROTO_INET)
    service = e.service
    service.resolve()

    e = q.expect('service-resolved', service=service)
    ver = txt_get_key(e.txt, "ver")
    while ver == old_ver:
        # be sure that the announced caps actually changes
        e = q.expect('service-resolved', service=service)
        ver = txt_get_key(e.txt, "ver")
    old_ver = ver

    caps = compute_caps_hash(['client/pc//%s' % PACKAGE_STRING],
                             fixed_features, {})
    assertEquals(caps, ver)

    test_ft_caps_from_contact(q, bus, conn, service, 'yo@momma')

    test_ft_caps_to_contact(q, bus, conn, service)
Beispiel #6
0
    def _cb_presence_iq(self, stanza):
        nodes = xpath.queryForNodes("/presence/c", stanza)
        c = nodes[0]
        if 'share-v1' in c.getAttribute('ext'):
            assert FileTransferTest.caps_identities is not None and \
                FileTransferTest.caps_features is not None and \
                FileTransferTest.caps_dataforms is not None

            new_hash = compute_caps_hash(FileTransferTest.caps_identities,
                                         FileTransferTest.caps_features + \
                                             [ns.GOOGLE_FEAT_SHARE],
                                         FileTransferTest.caps_dataforms)
            # Replace ver hash from one with file-transfer ns to one without
            FileTransferTest.caps_ft = c.attributes['ver']
            c.attributes['ver'] = new_hash
        else:
            node = c.attributes['node']
            ver = c.attributes['ver']
            # ask for raw caps
            request = elem_iq(self.stream,
                              'get',
                              from_='[email protected]/resource')(elem(
                                  ns.DISCO_INFO,
                                  'query',
                                  node=(node + '#' + ver)))
            self.stream.send(request)
def receive_caps(q, conn, stream, contact, contact_handle, features,
                 expected_caps, expect_disco=True, expect_ccc=True):

    caps = {'node': client,
            'ver': compute_caps_hash([], features, {}),
            'hash': 'sha-1'}

    presence_and_disco(q, conn, stream, contact, expect_disco,
                       client, caps, features, initial=False)

    if expect_ccc:
        event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
        announced_ccs, = event.args
        assertSameElements(expected_caps, announced_ccs[contact_handle])
    else:
        # Make sure Gabble's got the caps
        sync_stream(q, stream)

    caps = get_contacts_capabilities_sync(conn, [contact_handle])
    assertSameElements(expected_caps, caps[contact_handle])

    # test again, to check GetContactCapabilities does not have side effect
    caps = get_contacts_capabilities_sync(conn, [contact_handle])
    assertSameElements(expected_caps, caps[contact_handle])

    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn.Contacts.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.ATTR_CONTACT_CAPABILITIES]
    assertSameElements(caps[contact_handle], caps_via_contacts_iface)
    def sign_in_a_cat(jid, identities, show=None):
        caps['ver'] = compute_caps_hash(identities, features, {})

        presence_and_disco(q, conn, stream, jid, expect_disco, client, caps, features,
            identities=identities, initial=False, show=show)
        # Make sure Gabble's got the caps
        sync_stream(q, stream)
Beispiel #9
0
def sending_request_to_cappy_contact(q, bus, conn, stream, chan):
    """
    Test that Gabble requests a receipt from a contact whom we know supports
    this extension, but only if asked.
    """

    # Convince Gabble that Guybrush supports this extension
    caps = { 'node': 'http://whatever',
             'ver': caps_helper.compute_caps_hash([], [ns.RECEIPTS], {}),
             'hash': 'sha-1',
           }
    caps_helper.presence_and_disco(q, conn, stream, GUYBRUSH_FULL_JID,
        disco=True,
        client=caps['node'],
        caps=caps,
        features=[ns.RECEIPTS])
    sync_stream(q, stream)

    # Don't ask, don't tell — even if we know Guybrush does support this.
    not_sending_request_to_contact(q, bus, conn, stream, chan)

    # Ask, tell.
    message = [
      { 'message-type': cs.MT_NORMAL,
      },
      { 'content-type': 'text/plain',
        'content': 'Ulysses?',
      }]
    chan.Messages.SendMessage(message, cs.MSG_SENDING_FLAGS_REPORT_DELIVERY)

    e = q.expect('stream-message', to=GUYBRUSH)
    assertLength(1, list(e.stanza.elements(uri=ns.RECEIPTS, name='request')))
Beispiel #10
0
    def sign_in_a_cat(jid, identities, show=None):
        caps['ver'] = compute_caps_hash(identities, features, {})

        presence_and_disco(q, conn, stream, jid, expect_disco, client, caps, features,
            identities=identities, initial=False, show=show)
        # Make sure Gabble's got the caps
        sync_stream(q, stream)
def handle_disco(q, stream, contact_jid, identity):
    # Gabble tries to resolve a caps hash.
    ver = compute_caps_hash([identity], features, {})
    event = q.expect('stream-iq', to=contact_jid, query_ns=ns.DISCO_INFO)
    assertEquals(client + '#' + ver, event.query.attributes['node'])

    # The bare jid replies.
    send_disco_reply(stream, event.stanza, [identity], features)
def handle_disco(q, stream, contact_jid, identity):
    # Gabble tries to resolve a caps hash.
    ver = compute_caps_hash([identity], features, {})
    event = q.expect('stream-iq', to=contact_jid, query_ns=ns.DISCO_INFO)
    assertEquals(client + '#' + ver, event.query.attributes['node'])

    # The bare jid replies.
    send_disco_reply(stream, event.stanza, [identity], features)
Beispiel #13
0
def test(q, bus, conn):
    # last value of the "ver" key we resolved. We use it to be sure that the
    # modified caps has already be announced.
    old_ver = None

    conn.Connect()
    q.expect('dbus-signal', signal='StatusChanged', args=[0L, 0L])

    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")
    self_handle_name = conn.Properties.Get(cs.CONN, "SelfID")

    AvahiListener(q).listen_for_service("_presence._tcp")
    e = q.expect('service-added',
                 name=self_handle_name,
                 protocol=avahi.PROTO_INET)
    service = e.service
    service.resolve()

    e = q.expect('service-resolved', service=service)

    ver = txt_get_key(e.txt, "ver")
    while ver == old_ver:
        # be sure that the announced caps actually changes
        e = q.expect('service-resolved', service=service)
        ver = txt_get_key(e.txt, "ver")
    old_ver = ver

    # We support OOB file transfer
    caps = compute_caps_hash(['client/pc//%s' % PACKAGE_STRING],
                             fixed_features, {})
    check_caps_txt(e.txt, caps)

    conn_caps_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACT_CAPS)

    # Advertise nothing
    conn_caps_iface.UpdateCapabilities([])

    service.resolve()
    e = q.expect('service-resolved', service=service)

    # Announced capa didn't change
    caps = compute_caps_hash(['client/pc//%s' % PACKAGE_STRING],
                             fixed_features, {})

    check_caps_txt(e.txt, caps)
def test(q, bus, conn):
    # last value of the "ver" key we resolved. We use it to be sure that the
    # modified caps has already be announced.
    old_ver = None

    conn.Connect()
    q.expect('dbus-signal', signal='StatusChanged', args=[0L, 0L])

    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")
    self_handle_name =  conn.Properties.Get(cs.CONN, "SelfID")

    AvahiListener(q).listen_for_service("_presence._tcp")
    e = q.expect('service-added', name = self_handle_name,
        protocol = avahi.PROTO_INET)
    service = e.service
    service.resolve()

    e = q.expect('service-resolved', service = service)

    ver = txt_get_key(e.txt, "ver")
    while ver == old_ver:
        # be sure that the announced caps actually changes
        e = q.expect('service-resolved', service=service)
        ver = txt_get_key(e.txt, "ver")
    old_ver = ver

    # We support OOB file transfer
    caps = compute_caps_hash(['client/pc//%s' % PACKAGE_STRING],
        fixed_features, {})
    check_caps_txt(e.txt, caps)

    conn_caps_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACT_CAPS)

    # Advertise nothing
    conn_caps_iface.UpdateCapabilities([])

    service.resolve()
    e = q.expect('service-resolved', service = service)

    # Announced capa didn't change
    caps = compute_caps_hash(['client/pc//%s' % PACKAGE_STRING],
        fixed_features, {})

    check_caps_txt(e.txt, caps)
def receive_caps(q, bus, conn, service, contact, contact_handle, features,
                 expected_caps, expect_disco=True, expect_ccc=True):

    ver = compute_caps_hash([], features, {})
    txt_record = { "txtvers": "1", "status": "avail",
                   "node": client, "ver": ver, "hash": "sha-1"}

    listener, port = setup_stream_listener(q, contact)
    AvahiAnnouncer(contact, "_presence._tcp", port, txt_record)

    if expect_disco:
        # Salut looks up our capabilities
        e = q.expect('incoming-connection', listener=listener)
        stream = e.connection

        event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO,
                         connection=stream)
        query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
        assert query_node.attributes['node'] == \
            client + '#' + ver

        # send good reply
        result = make_result_iq(event.stanza)
        query = result.firstChildElement()
        query['node'] = client + '#' + ver

        for f in features:
            feature = query.addElement('feature')
            feature['var'] = f

        stream.send(result)

    if expect_ccc:
        event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
        announced_ccs, = event.args
        assertSameElements(expected_caps, announced_ccs[contact_handle])
    else:
        if expect_disco:
            # Make sure Salut's got the caps
            sync_stream(q, stream)

    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn.Contacts.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.ATTR_CONTACT_CAPABILITIES]
    assertSameElements(expected_caps, caps_via_contacts_iface)

    # close the connection and expect a new one to be opened by Salut
    # the next time we need some discoing doing
    if expect_disco:
        stream.send('</stream:stream>')
        stream.transport.loseConnection()
        # pass some time so Salut knows the connection is lost and
        # won't try and send stuff down a closed connection on the
        # next test.
        sync_dbus(bus, q, conn)
def send_presence(q, stream, contact_jid, identity):
    ver = compute_caps_hash([identity], features, {})
    stream.send(
        make_presence(contact_jid,
                      status='Hello',
                      caps={
                          'node': client,
                          'hash': 'sha-1',
                          'ver': ver
                      }))
Beispiel #17
0
def receive_caps(q,
                 conn,
                 stream,
                 contact,
                 contact_handle,
                 features,
                 expected_caps,
                 expect_disco=True,
                 expect_ccc=True):
    presence = make_presence(contact, status='hello')
    c = presence.addElement((ns.CAPS, 'c'))
    c['node'] = client
    c['ver'] = compute_caps_hash([], features if features is not None else [],
                                 {})
    c['hash'] = 'sha-1'
    stream.send(presence)

    if expect_disco:
        # Gabble looks up our capabilities
        event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO)
        query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
        assert query_node.attributes['node'] == \
            client + '#' + c['ver']

        # send good reply
        result = make_result_iq(stream, event.stanza)
        query = result.firstChildElement()
        query['node'] = client + '#' + c['ver']

        for f in features:
            feature = query.addElement('feature')
            feature['var'] = f

        stream.send(result)

    if expect_ccc:
        event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
        announced_ccs, = event.args
        assertSameElements(expected_caps, announced_ccs)
    else:
        # Make sure Gabble's got the caps
        sync_stream(q, stream)

    caps = get_contacts_capabilities_sync(conn, [contact_handle])
    assertSameElements(expected_caps, caps)

    # test again, to check GetContactCapabilities does not have side effect
    caps = get_contacts_capabilities_sync(conn, [contact_handle])
    assertSameElements(expected_caps, caps)

    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn.Contacts.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.ATTR_CONTACT_CAPABILITIES]
    assertSameElements(caps[contact_handle], caps_via_contacts_iface)
def test_caps(q, conn, stream, contact, features, audio, video, google=False):
    caps['ver'] = compute_caps_hash ([], features, {})

    h = presence_and_disco(q, conn, stream, contact, True,
        client, caps, features)

    cflags = 0
    stream_expected_media_caps = []
    call_expected_media_caps = []

    if audio:
      cflags |= cs.MEDIA_CAP_AUDIO
      stream_expected_media_caps.append (cs.INITIAL_AUDIO)
      call_expected_media_caps.append (cs.CALL_INITIAL_AUDIO)
      call_expected_media_caps.append (cs.CALL_INITIAL_AUDIO_NAME)
    if video:
      cflags |= cs.MEDIA_CAP_VIDEO
      stream_expected_media_caps.append (cs.INITIAL_VIDEO)
      call_expected_media_caps.append (cs.CALL_INITIAL_VIDEO)
      call_expected_media_caps.append (cs.CALL_INITIAL_VIDEO_NAME)

    # If the contact can only do one of audio or video, or uses a Google
    # client, they'll have the ImmutableStreams cap.
    if cflags < (cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO) or google:
        cflags |= cs.MEDIA_CAP_IMMUTABLE_STREAMS
        stream_expected_media_caps.append(cs.IMMUTABLE_STREAMS)
    else:
        call_expected_media_caps.append(cs.CALL_MUTABLE_CONTENTS)

    _, event = q.expect_many(
            EventPattern('dbus-signal', signal='CapabilitiesChanged',
                    args = [[ ( h,
                        cs.CHANNEL_TYPE_STREAMED_MEDIA,
                        0, # old generic
                        3, # new generic (can create and receive these)
                        0, # old specific
                        cflags ) ]] # new specific
                ),
            EventPattern('dbus-signal', signal='ContactCapabilitiesChanged')
        )

    assertContains((h, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, cflags),
        conn.Capabilities.GetCapabilities([h]))

    # Check Contact capabilities for streamed media
    assertEquals(len(event.args), 1)
    assertEquals (event.args[0],
        conn.ContactCapabilities.GetContactCapabilities([h]))

    check_contact_caps (event.args[0][h],
        cs.CHANNEL_TYPE_STREAMED_MEDIA, stream_expected_media_caps)

    check_contact_caps (event.args[0][h],
        cs.CHANNEL_TYPE_CALL, call_expected_media_caps)
    def announce_contact(self, name=CONTACT_NAME, metadata=True):
        client = 'http://telepathy.freedesktop.org/fake-client'
        features = [ns.IQ_OOB]

        if metadata:
            features += [ns.TP_FT_METADATA]

        ver = compute_caps_hash([], features, {})
        txt_record = {
            "txtvers": "1",
            "status": "avail",
            "node": client,
            "ver": ver,
            "hash": "sha-1"
        }

        suffix = '@%s' % get_host_name()
        name += ('-' + os.path.splitext(os.path.basename(sys.argv[0]))[0])

        self.contact_name = name + suffix
        if len(self.contact_name) > 63:
            allowed = 63 - len(suffix)
            self.contact_name = name[:allowed] + suffix

        self.listener, port = setup_stream_listener(self.q, self.contact_name)

        self.contact_service = AvahiAnnouncer(self.contact_name,
                                              "_presence._tcp", port,
                                              txt_record)

        self.handle = wait_for_contact_in_publish(self.q, self.bus, self.conn,
                                                  self.contact_name)

        # expect salut to disco our caps
        e = self.q.expect('incoming-connection', listener=self.listener)
        stream = e.connection

        e = self.q.expect('stream-iq',
                          to=self.contact_name,
                          query_ns=ns.DISCO_INFO,
                          connection=stream)
        assertEquals(client + '#' + ver, e.query['node'])
        send_disco_reply(stream, e.stanza, [], features)

        # lose the connection here to ensure connections are created
        # where necessary; I just wanted salut to know my caps.
        stream.send('</stream:stream>')
        # spend a bit of time in the main loop to ensure the last two
        # stanzas are actually received by salut before closing the
        # connection.
        sync_dbus(self.bus, self.q, self.conn)
        stream.transport.loseConnection()
Beispiel #20
0
def receive_caps(q, conn, stream, contact, contact_handle, features,
                 expected_caps, expect_disco=True, expect_ccc=True):
    presence = make_presence(contact, status='hello')
    c = presence.addElement((ns.CAPS, 'c'))
    c['node'] = client
    c['ver'] = compute_caps_hash([],
        features if features is not None else [],
        {})
    c['hash'] = 'sha-1'
    stream.send(presence)

    if expect_disco:
        # Gabble looks up our capabilities
        event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO)
        query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
        assert query_node.attributes['node'] == \
            client + '#' + c['ver']

        # send good reply
        result = make_result_iq(stream, event.stanza)
        query = result.firstChildElement()
        query['node'] = client + '#' + c['ver']

        for f in features:
            feature = query.addElement('feature')
            feature['var'] = f

        stream.send(result)

    if expect_ccc:
        event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
        announced_ccs, = event.args
        assertSameElements(expected_caps, announced_ccs)
    else:
        # Make sure Gabble's got the caps
        sync_stream(q, stream)

    caps = conn.ContactCapabilities.GetContactCapabilities([contact_handle])
    assertSameElements(expected_caps, caps)

    # test again, to check GetContactCapabilities does not have side effect
    caps = conn.ContactCapabilities.GetContactCapabilities([contact_handle])
    assertSameElements(expected_caps, caps)

    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn.Contacts.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.ATTR_CONTACT_CAPABILITIES]
    assertSameElements(caps[contact_handle], caps_via_contacts_iface)
def receive_caps(q,
                 conn,
                 stream,
                 contact,
                 contact_handle,
                 features,
                 expected_caps,
                 expect_disco=True,
                 expect_ccc=True):

    caps = {
        'node': client,
        'ver': compute_caps_hash([], features, {}),
        'hash': 'sha-1'
    }

    presence_and_disco(q,
                       conn,
                       stream,
                       contact,
                       expect_disco,
                       client,
                       caps,
                       features,
                       initial=False)

    if expect_ccc:
        event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
        announced_ccs, = event.args
        assertSameElements(expected_caps, announced_ccs[contact_handle])
    else:
        # Make sure Gabble's got the caps
        sync_stream(q, stream)

    caps = get_contacts_capabilities_sync(conn, [contact_handle])
    assertSameElements(expected_caps, caps[contact_handle])

    # test again, to check GetContactCapabilities does not have side effect
    caps = get_contacts_capabilities_sync(conn, [contact_handle])
    assertSameElements(expected_caps, caps[contact_handle])

    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn.Contacts.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.ATTR_CONTACT_CAPABILITIES]
    assertSameElements(caps[contact_handle], caps_via_contacts_iface)
Beispiel #22
0
def receive_presence_and_ask_caps(q, stream, service, contact_name):
    global old_ver

    event_avahi = q.expect('service-resolved', service=service)

    ver = txt_get_key(event_avahi.txt, "ver")
    while ver == old_ver:
        # be sure that the announced caps actually changes
        event_avahi = q.expect('service-resolved', service=service)
        ver = txt_get_key(event_avahi.txt, "ver")
    old_ver = ver

    hash = txt_get_key(event_avahi.txt, "hash")
    node = txt_get_key(event_avahi.txt, "node")
    assert hash == 'sha-1'

    # ask caps
    # FIXME: this only works because Salut ignores @to
    request = """
<iq from='""" + contact_name + """'
    id='receive-presence-and-ask-caps'
    to='[email protected]/resource'
    type='get'>
  <query xmlns='http://jabber.org/protocol/disco#info'
         node='""" + node + '#' + ver + """'/>
</iq>
"""
    stream.send(request)

    # receive caps
    event = q.expect('stream-iq',
                     iq_type='result',
                     to=contact_name,
                     iq_id='receive-presence-and-ask-caps',
                     query_ns='http://jabber.org/protocol/disco#info')
    caps_str = str(xpath.queryForNodes('/iq/query/feature', event.stanza))

    features = []
    for feature in xpath.queryForNodes('/iq/query/feature', event.stanza):
        features.append(feature['var'])

    # Check if the hash matches the announced capabilities
    assert ver == compute_caps_hash(['client/pc//%s' % PACKAGE_STRING],
                                    features, {})
    assert ns.X_OOB in features
    assert ns.IQ_OOB in features
    def announce_contact(self, name=CONTACT_NAME, metadata=True):
        client = 'http://telepathy.freedesktop.org/fake-client'
        features = [ns.IQ_OOB]

        if metadata:
            features += [ns.TP_FT_METADATA]

        ver = compute_caps_hash([], features, {})
        txt_record = { "txtvers": "1", "status": "avail",
                       "node": client, "ver": ver, "hash": "sha-1"}

        suffix = '@%s' % get_host_name()
        name += ('-' + os.path.splitext(os.path.basename(sys.argv[0]))[0])

        self.contact_name = name + suffix
        if len(self.contact_name) > 63:
            allowed = 63 - len(suffix)
            self.contact_name = name[:allowed] + suffix

        self.listener, port = setup_stream_listener(self.q, self.contact_name)

        self.contact_service = AvahiAnnouncer(self.contact_name, "_presence._tcp",
                port, txt_record)

        self.handle = wait_for_contact_in_publish(self.q, self.bus, self.conn,
                self.contact_name)

        # expect salut to disco our caps
        e = self.q.expect('incoming-connection', listener=self.listener)
        stream = e.connection

        e = self.q.expect('stream-iq', to=self.contact_name, query_ns=ns.DISCO_INFO,
                     connection=stream)
        assertEquals(client + '#' + ver, e.query['node'])
        send_disco_reply(stream, e.stanza, [], features)

        # lose the connection here to ensure connections are created
        # where necessary; I just wanted salut to know my caps.
        stream.send('</stream:stream>')
        # spend a bit of time in the main loop to ensure the last two
        # stanzas are actually received by salut before closing the
        # connection.
        sync_dbus(self.bus, self.q, self.conn)
        stream.transport.loseConnection()
def receive_presence_and_ask_caps(q, stream, service, contact_name):
    global old_ver

    event_avahi = q.expect('service-resolved', service=service)

    ver = txt_get_key(event_avahi.txt, "ver")
    while ver == old_ver:
        # be sure that the announced caps actually changes
        event_avahi = q.expect('service-resolved', service=service)
        ver = txt_get_key(event_avahi.txt, "ver")
    old_ver = ver

    hash = txt_get_key(event_avahi.txt, "hash")
    node = txt_get_key(event_avahi.txt, "node")
    assert hash == 'sha-1'

    # ask caps
    # FIXME: this only works because Salut ignores @to
    request = """
<iq from='""" + contact_name + """'
    id='receive-presence-and-ask-caps'
    to='[email protected]/resource'
    type='get'>
  <query xmlns='http://jabber.org/protocol/disco#info'
         node='""" + node + '#' + ver + """'/>
</iq>
"""
    stream.send(request)

    # receive caps
    event = q.expect('stream-iq', iq_type='result',
            to=contact_name, iq_id='receive-presence-and-ask-caps',
            query_ns='http://jabber.org/protocol/disco#info')
    caps_str = str(xpath.queryForNodes('/iq/query/feature', event.stanza))

    features = []
    for feature in xpath.queryForNodes('/iq/query/feature', event.stanza):
        features.append(feature['var'])

    # Check if the hash matches the announced capabilities
    assert ver == compute_caps_hash(['client/pc//%s' % PACKAGE_STRING], features, {})
    assert ns.X_OOB in features
    assert ns.IQ_OOB in features
    def _cb_presence_iq(self, stanza):
        nodes = xpath.queryForNodes("/presence/c", stanza)
        c = nodes[0]
        if 'share-v1' in c.getAttribute('ext'):
            assert FileTransferTest.caps_identities is not None and \
                FileTransferTest.caps_features is not None

            new_hash = compute_caps_hash(FileTransferTest.caps_identities,
                                         FileTransferTest.caps_features + \
                                             [ns.GOOGLE_FEAT_SHARE],
                                         {})
            # Replace ver hash from one with file-transfer ns to one without
            FileTransferTest.caps_ft = c.attributes['ver']
            c.attributes['ver'] = new_hash
        else:
            node = c.attributes['node']
            ver = c.attributes['ver']
            # ask for raw caps
            request = elem_iq(self.stream, 'get',
                              from_='[email protected]/resource')(
                elem(ns.DISCO_INFO, 'query', node=(node + '#' + ver)))
            self.stream.send(request)
def two_contacts_with_the_same_hash(q, bus, conn, stream, bare_jids):
    contact1 = '*****@*****.**'
    contact2 = '*****@*****.**'

    if not bare_jids:
        contact1 += '/lol'
        contact2 += '/whut'

    h1, h2 = conn.get_contact_handles_sync([contact1, contact2])
    ver = compute_caps_hash(BANANAPHONE, features, {})
    caps = {
        # Uniquify slightly with a stringified boolean ;-)
        'node': '%s%s' % (client_base, bare_jids),
        'ver': ver,
        'hash': 'sha-1',
    }

    send_presence(q, conn, stream, contact1, caps)
    stanza = expect_disco(q, contact1, caps['node'], caps)

    send_presence(q, conn, stream, contact2, caps)
    q.forbid_events([
        EventPattern('stream-iq', to=contact2, query_ns=ns.DISCO_INFO),
    ])
    sync_stream(q, stream)

    send_disco_reply(stream, stanza, BANANAPHONE, features, {})
    q.expect_many(
        EventPattern('dbus-signal',
                     signal='ClientTypesUpdated',
                     args=[h1, ['phone']]),
        # Gabble previously did not emit ClientTypesUpdated for anyone beside
        # the contact we sent the disco request to; so this second event would
        # never arrive.
        EventPattern('dbus-signal',
                     signal='ClientTypesUpdated',
                     args=[h2, ['phone']]),
    )
def two_contacts_with_the_same_hash(q, bus, conn, stream, bare_jids):
    contact1 = '*****@*****.**'
    contact2 = '*****@*****.**'

    if not bare_jids:
        contact1 += '/lol'
        contact2 += '/whut'

    h1, h2 = conn.get_contact_handles_sync([contact1, contact2])
    ver = compute_caps_hash(BANANAPHONE, features, {})
    caps = {
        # Uniquify slightly with a stringified boolean ;-)
        'node': '%s%s' % (client_base, bare_jids),
        'ver':  ver,
        'hash': 'sha-1',
        }

    send_presence(q, conn, stream, contact1, caps)
    stanza = expect_disco(q, contact1, caps['node'], caps)

    send_presence(q, conn, stream, contact2, caps)
    q.forbid_events([
        EventPattern('stream-iq', to=contact2, query_ns=ns.DISCO_INFO),
        ])
    sync_stream(q, stream)

    send_disco_reply(stream, stanza, BANANAPHONE, features, {})
    q.expect_many(
        EventPattern('dbus-signal', signal='ClientTypesUpdated',
            args=[h1, ['phone']]),
        # Gabble previously did not emit ClientTypesUpdated for anyone beside
        # the contact we sent the disco request to; so this second event would
        # never arrive.
        EventPattern('dbus-signal', signal='ClientTypesUpdated',
            args=[h2, ['phone']]),
        )
Beispiel #28
0
def test_caps(q, conn, stream, contact, features, audio, video, google=False):
    caps['ver'] = compute_caps_hash ([], features, {})

    h = presence_and_disco(q, conn, stream, contact, True,
        client, caps, features)

    cflags = 0
    call_expected_media_caps = []

    if audio:
      cflags |= cs.MEDIA_CAP_AUDIO
      call_expected_media_caps.append (cs.CALL_INITIAL_AUDIO)
      call_expected_media_caps.append (cs.CALL_INITIAL_AUDIO_NAME)
    if video:
      cflags |= cs.MEDIA_CAP_VIDEO
      call_expected_media_caps.append (cs.CALL_INITIAL_VIDEO)
      call_expected_media_caps.append (cs.CALL_INITIAL_VIDEO_NAME)

    # If the contact can only do one of audio or video, or uses a Google
    # client, they'll have the ImmutableStreams cap.
    if cflags < (cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO) or google:
        cflags |= cs.MEDIA_CAP_IMMUTABLE_STREAMS
    else:
        call_expected_media_caps.append(cs.CALL_MUTABLE_CONTENTS)

    event, = q.expect_many(
            EventPattern('dbus-signal', signal='ContactCapabilitiesChanged')
        )

    # Check Contact capabilities
    assertEquals(len(event.args), 1)
    assertEquals (event.args[0],
        get_contacts_capabilities_sync(conn, [h]))

    check_contact_caps (event.args[0][h],
        cs.CHANNEL_TYPE_CALL, call_expected_media_caps)
def test_ft_caps_from_contact(q, bus, conn, client):

    conn_caps_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACT_CAPS)
    conn_contacts_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACTS)

    # send presence with FT capa
    ver = compute_caps_hash([], [ns.IQ_OOB], {})
    txt_record = { "txtvers": "1", "status": "avail",
        "node": client, "ver": ver, "hash": "sha-1"}
    contact_name = "test-caps-ft@" + get_host_name()
    listener, port = setup_stream_listener(q, contact_name)
    announcer = AvahiAnnouncer(contact_name, "_presence._tcp", port,
            txt_record)

    # this is the first presence, Salut connects to the contact
    e = q.expect('incoming-connection', listener = listener)
    incoming = e.connection

    # Salut looks up our capabilities
    event = q.expect('stream-iq', connection = incoming,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + ver, (query_node.attributes['node'], client, ver)

    contact_handle = conn_contacts_iface.GetContactByID(contact_name, [])[0]

    # send good reply
    result = make_result_iq(event.stanza)
    query = result.firstChildElement()
    query['node'] = client + '#' + ver

    feature = query.addElement('feature')
    feature['var'] = ns.IQ_OOB
    incoming.send(result)

    # FT capa is announced
    e = q.expect('dbus-signal', signal='ContactCapabilitiesChanged',
            predicate=lambda e: contact_handle in e.args[0])
    caps = e.args[0][contact_handle]
    assertContains(ft_caps, caps)

    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.CONN_IFACE_CONTACT_CAPS + '/capabilities']
    assert caps_via_contacts_iface == caps, caps_via_contacts_iface

    # check if Salut announces the OOB capa
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")
    self_handle_name =  conn.Properties.Get(cs.CONN, "SelfID")

    AvahiListener(q).listen_for_service("_presence._tcp")
    e = q.expect('service-added', name = self_handle_name,
            protocol = avahi.PROTO_INET)
    service = e.service
    service.resolve()

    receive_presence_and_ask_caps(q, incoming, service, contact_name)

    # capa announced without FT
    ver = compute_caps_hash([], ["http://telepathy.freedesktop.org/xmpp/pony"], {})
    txt_record = { "txtvers": "1", "status": "avail",
        "node": client, "ver": ver, "hash": "sha-1"}
    contact_name = "test-caps-ft2@" + get_host_name()
    listener, port = setup_stream_listener(q, contact_name)
    announcer = AvahiAnnouncer(contact_name, "_presence._tcp", port,
            txt_record)

    # this is the first presence, Salut connects to the contact
    e = q.expect('incoming-connection', listener = listener)
    incoming = e.connection

    # Salut looks up our capabilities
    event = q.expect('stream-iq', connection = incoming,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + ver, (query_node.attributes['node'], client, ver)

    contact_handle = conn_contacts_iface.GetContactByID(contact_name, [])[0]

    # send good reply
    result = make_result_iq(event.stanza)
    query = result.firstChildElement()
    query['node'] = client + '#' + ver

    feature = query.addElement('feature')
    feature['var'] = "http://telepathy.freedesktop.org/xmpp/pony"
    incoming.send(result)

    # the FT capability is not announced
    e = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
    caps = e.args[0][contact_handle]
    assertDoesNotContain(ft_caps, caps)

    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.CONN_IFACE_CONTACT_CAPS + '/capabilities']
    assert caps_via_contacts_iface == caps, caps_via_contacts_iface

    # no capabilites announced (assume FT is supported to insure interop)
    txt_record = { "txtvers": "1", "status": "avail"}
    contact_name = "test-caps-ft-no-capa2@" + get_host_name()
    contact_handle = conn_contacts_iface.GetContactByID(contact_name, [])[0]
    listener, port = setup_stream_listener(q, contact_name)
    announcer = AvahiAnnouncer(contact_name, "_presence._tcp", port,
            txt_record)

    # FT capa is announced
    e = q.expect('dbus-signal', signal='ContactCapabilitiesChanged',
            predicate=lambda e: contact_handle in e.args[0].keys())

    caps = e.args[0][contact_handle]
    assertContains(ft_caps, caps)

    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.CONN_IFACE_CONTACT_CAPS + '/capabilities']
    assert caps_via_contacts_iface == caps, caps_via_contacts_iface
def test_ft_caps_from_contact(q, bus, conn, stream, contact, contact_handle,
                              client):

    conn_caps_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACT_CAPS)
    conn_contacts_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACTS)

    # send presence with no FT cap
    presence = make_presence(contact, status='hello')
    c = presence.addElement((ns.CAPS, 'c'))
    c['node'] = client
    c['ver'] = compute_caps_hash([], [], {})
    c['hash'] = 'sha-1'
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO)
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + c['ver']

    # send good reply
    result = make_result_iq(stream, event.stanza)
    query = result.firstChildElement()
    query['node'] = client + '#' + c['ver']
    stream.send(result)

    # no change in ContactCapabilities, so no signal ContactCapabilitiesChanged
    sync_stream(q, stream)

    # no special capabilities
    basic_caps = dbus.Dictionary(
        {contact_handle: [(text_fixed_properties, text_allowed_properties)]})
    caps = get_contacts_capabilities_sync(conn, [contact_handle])
    assert caps == basic_caps, caps
    # test again, to check GetContactCapabilities does not have side effect
    caps = get_contacts_capabilities_sync(conn, [contact_handle])
    assert caps == basic_caps, caps
    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.ATTR_CONTACT_CAPABILITIES]
    assert caps_via_contacts_iface == caps[contact_handle], \
                                    caps_via_contacts_iface

    # send presence with ft capa
    presence = make_presence(contact, status='hello')
    c = presence.addElement((ns.CAPS, 'c'))
    c['node'] = client
    c['ver'] = compute_caps_hash([], [ns.FILE_TRANSFER], {})
    c['hash'] = 'sha-1'
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO)
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + c['ver']

    # send good reply
    result = make_result_iq(stream, event.stanza)
    query = result.firstChildElement()
    query['node'] = client + '#' + c['ver']
    feature = query.addElement('feature')
    feature['var'] = ns.FILE_TRANSFER
    stream.send(result)

    generic_tubes_caps = dbus.Dictionary({
        contact_handle: [(text_fixed_properties, text_allowed_properties),
                         (ft_fixed_properties, ft_allowed_properties)]
    })

    event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
    assert len(event.args) == 1
    assert event.args[0] == generic_tubes_caps

    caps = get_contacts_capabilities_sync(conn, [contact_handle])
    assert caps == generic_tubes_caps, caps
    # test again, to check GetContactCapabilities does not have side effect
    caps = get_contacts_capabilities_sync(conn, [contact_handle])
    assert caps == generic_tubes_caps, caps
    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.ATTR_CONTACT_CAPABILITIES]
    assert caps_via_contacts_iface == caps[contact_handle], \
                                    caps_via_contacts_iface
Beispiel #31
0
def test(q, bus, conn, stream):
    caps = {
        'node': client,
        'ver':  '0.1',
        }

    update_contact_caps(q, conn, stream, '[email protected]/Foo', caps)
    update_contact_caps(q, conn, stream, '[email protected]/Foo', caps)

    # Meredith signs in from one resource.
    update_contact_caps(q, conn, stream, '[email protected]/One', caps)
    # Meredith signs in from another resource with the same client. We don't
    # need to disco her, even though we don't trust this caps node in general
    # yet, because she's already told us what it means.
    meredith_two = '[email protected]/Two'
    q.forbid_events([
        EventPattern('stream-iq', to=meredith_two, query_ns=ns.DISCO_INFO)
        ])
    stream.send(make_presence(meredith_two, 'hello', caps=caps))
    sync_stream(q, stream)

    # Jens signs in from one resource, which is slow to answer the disco query.
    jens_one = '[email protected]/One'
    j = send_presence(q, conn, stream, jens_one, caps)
    j_stanza = expect_disco(q, jens_one, client, caps)

    # Jens now signs in elsewhere with the same client; we disco it (maybe
    # it'll reply sooner? Maybe his first client's network connection went away
    # and the server hasn't noticed yet?) and it replies immediately.
    update_contact_caps (q, conn, stream, '[email protected]/Two', caps,
        initial=False)

    # Jens' first client replies. We don't expect any caps changes here, and
    # this shouldn't count as a second point towards the five we need to trust
    # this caps node.
    send_disco_reply(stream, j_stanza, [], features)
    check_caps (conn, j)

    update_contact_caps (q, conn, stream, '[email protected]/Foo', caps)

    # Now five distinct contacts have told us what this caps node means, we
    # trust it.
    update_contact_caps (q, conn, stream, '[email protected]/Foo', caps,
        disco = False)
    update_contact_caps (q, conn, stream, '[email protected]/Foo', caps,
        disco = False)

    caps = {
        'node': client,
        'ver':  compute_caps_hash([], features, fake_client_dataforms),
        'hash': 'sha-1',
        }

    update_contact_caps(q, conn, stream, '[email protected]/Foo',
       caps,  dataforms = fake_client_dataforms)
    # We can verify the reply for these caps against the hash, and thus never
    # need to disco it again.
    update_contact_caps(q, conn, stream, '[email protected]/Foo', caps,
        disco = False, dataforms = fake_client_dataforms)
    update_contact_caps(q, conn, stream, '[email protected]/Foo', caps,
        disco = False, dataforms = fake_client_dataforms)
def test(q, bus, conn, stream):
    client = 'http://example.com/perverse-client'
    contact_bare_jid = '*****@*****.**'
    contact_with_resource = '[email protected]/hi'
    contact_handle = conn.get_contact_handle_sync(contact_bare_jid)

    # Gabble gets a presence stanza from a bare JID, which is a tad surprising.
    features = [
        ns.JINGLE_015,
        ns.JINGLE_015_AUDIO,
        ns.JINGLE_015_VIDEO,
        ns.GOOGLE_P2P,
    ]
    caps = {
        'node': client,
        'hash': 'sha-1',
        'ver': compute_caps_hash([], features, {}),
    }
    p = make_presence(contact_bare_jid, status='Hello', caps=caps)
    stream.send(p)

    # Gabble looks up the hash
    event = q.expect('stream-iq',
                     to=contact_bare_jid,
                     query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assertEquals(client + '#' + caps['ver'], query_node.attributes['node'])

    # The bare jid replies
    send_disco_reply(stream, event.stanza, [], features)

    # Gabble lets us know their caps have changed. (Gabble used to ignore the
    # reply.)
    cc, = q.expect_many(
        EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), )
    assert_rccs_callable(cc.args[0][contact_handle])

    # Gabble gets another presence stanza from the bare JID, with different
    # caps.
    features.append(ns.TUBES)
    caps = {
        'node': client,
        'hash': 'sha-1',
        'ver': compute_caps_hash([], features, {}),
    }
    p = make_presence(contact_bare_jid, status='Get out the abacus', caps=caps)
    stream.send(p)

    # Gabble looks up the new hash
    disco2 = q.expect('stream-iq',
                      to=contact_bare_jid,
                      query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', disco2.stanza)[0]
    assertEquals(client + '#' + caps['ver'], query_node.attributes['node'])

    # This time, before the bare JID replies, Gabble gets a presence from the
    # resourceful jid.
    features_ = features + [ns.CHAT_STATES]
    caps = {
        'node': client,
        'hash': 'sha-1',
        'ver': compute_caps_hash([], features_, {}),
    }
    p = make_presence(contact_with_resource, status='Count this', caps=caps)
    stream.send(p)

    # Gabble throws away presence from the bare JID when it gets presence from
    # a resource (and vice versa), so it should now say the contact is
    # incapable.  Gabble also looks up the resourceful JID's hash.
    cc, disco3 = q.expect_many(
        EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'),
        EventPattern('stream-iq',
                     to=contact_with_resource,
                     query_ns='http://jabber.org/protocol/disco#info'),
    )

    assert_rccs_not_callable(cc.args[0][contact_handle])

    query_node = xpath.queryForNodes('/iq/query', disco3.stanza)[0]
    assertEquals(client + '#' + caps['ver'], query_node.attributes['node'])

    # The bare jid replies! Getting a disco reply from a bare JID when we've
    # got presence from resources used to crash Gabble, but now it just ignores
    # it.
    send_disco_reply(stream, disco2.stanza, [], features)

    # Now the resourceful JID replies:
    send_disco_reply(stream, disco3.stanza, [], features_)

    # Gabble should announce that the contact has acquired some caps.
    cc, = q.expect_many(
        EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), )
    assert_rccs_callable(cc.args[0][contact_handle])
def test_hash(q, bus, conn, stream, contact, contact_handle, client):
    global caps_changed_flag

    presence = make_presence(contact, status='hello')
    stream.send(presence)

    q.expect_many(
        EventPattern('dbus-signal', signal='PresenceUpdate',
            args=[{contact_handle:
                (0L, {u'available': {'message': 'hello'}})}]),
        EventPattern('dbus-signal', signal='PresencesChanged',
            args=[{contact_handle:
                (2, u'available', 'hello')}]))

    # no special capabilities
    basic_caps = [(contact_handle, cs.CHANNEL_TYPE_TEXT, 3, 0)]
    assert conn.Capabilities.GetCapabilities([contact_handle]) == basic_caps

    # send updated presence with Jingle caps info
    presence = make_presence(contact, status='hello',
        caps={'node': client,
              'ver':  '0.1',
             })
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + '0.1'

    # send good reply
    stream.send(make_caps_disco_reply(stream, event.stanza,
        jingle_av_features))

    # we can now do audio calls
    event = q.expect('dbus-signal', signal='CapabilitiesChanged')
    caps_changed_flag = False

    # send bogus presence
    caps = {
        'node': client,
        'ver':  'ceci=nest=pas=un=hash',
        'hash': 'sha-1',
        }
    presence = make_presence(contact, status='hello', caps=caps)
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + caps['ver']

    # send bogus reply
    stream.send(make_caps_disco_reply(stream, event.stanza,
        ['http://jabber.org/protocol/bogus-feature']))

    # don't receive any D-Bus signal
    sync_dbus(bus, q, conn)
    sync_stream(q, stream)
    assert caps_changed_flag == False


    # send presence with empty caps
    presence = make_presence(contact, status='hello',
        caps={'node': client,
              'ver':  '0.0',
             })
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + '0.0'

    # still don't receive any D-Bus signal
    sync_dbus(bus, q, conn)
    assert caps_changed_flag == False

    # send good reply
    result = make_result_iq(stream, event.stanza)
    query = result.firstChildElement()
    stream.send(result)

    # we can now do nothing
    event = q.expect('dbus-signal', signal='CapabilitiesChanged')
    assert caps_changed_flag == True
    caps_changed_flag = False


    # send correct presence
    ver = compute_caps_hash([], jingle_av_features, fake_client_dataforms)
    caps = {
        'node': client,
        'ver':  ver,
        'hash': 'sha-1',
        }
    presence = make_presence(contact, status='hello', caps=caps)
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + caps['ver']

    # don't receive any D-Bus signal
    sync_dbus(bus, q, conn)
    assert caps_changed_flag == False

    # send good reply
    result = make_caps_disco_reply(stream, event.stanza, jingle_av_features,
        fake_client_dataforms)
    stream.send(result)

    # we can now do audio calls
    event = q.expect('dbus-signal', signal='CapabilitiesChanged',
    )
    assert caps_changed_flag == True
    caps_changed_flag = False
Beispiel #34
0
def test_hash(q, bus, conn, stream, contact, contact_handle, client):
    presence = make_presence(contact, status='hello')
    stream.send(presence)

    q.expect('dbus-signal', signal='PresencesChanged',
            args=[{contact_handle:
                (2, u'available', 'hello')}])

    # no special capabilities
    for rcc in get_contacts_capabilities_sync(conn, [contact_handle])[contact_handle]:
        assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE))

    # send updated presence with Jingle caps info
    presence = make_presence(contact, status='hello',
        caps={'node': client,
              'ver':  '0.1',
             })
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + '0.1'

    # send good reply
    send_disco_reply(stream, event.stanza, [], jingle_av_features)

    # we can now do audio calls
    cc, = q.expect_many(
        EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'),
        )

    assert_rccs_callable(cc.args[0][contact_handle])
    assertEquals(cc.args[0],
            get_contacts_capabilities_sync(conn, [contact_handle]))

    # Send presence without any capabilities. XEP-0115 §8.4 Caps Optimization
    # says “receivers of presence notifications MUST NOT expect an annotation
    # on every presence notification they receive”, so the contact should still
    # be media-capable afterwards.
    stream.send(make_presence(contact, status='very capable'))
    q.expect('dbus-signal', signal='PresencesChanged',
        args=[{contact_handle: (2, u'available', 'very capable')}])
    # still exactly the same capabilities
    assertEquals(cc.args[0],
            get_contacts_capabilities_sync(conn, [contact_handle]))

    # send bogus presence
    caps = {
        'node': client,
        'ver':  'ceci=nest=pas=un=hash',
        'hash': 'sha-1',
        }
    presence = make_presence(contact, status='hello', caps=caps)
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + caps['ver']

    # send bogus reply
    send_disco_reply(stream, event.stanza, [],
        ['http://jabber.org/protocol/bogus-feature'])

    # don't receive any D-Bus signal
    forbidden = [
        EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'),
        ]
    q.forbid_events(forbidden)
    sync_dbus(bus, q, conn)
    sync_stream(q, stream)

    # send presence with empty caps
    presence = make_presence(contact, status='hello',
        caps={'node': client,
              'ver':  '0.0',
             })
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + '0.0'

    # still don't receive any D-Bus signal
    sync_dbus(bus, q, conn)

    # send good reply
    q.unforbid_events(forbidden)
    result = make_result_iq(stream, event.stanza)
    query = result.firstChildElement()
    stream.send(result)

    # we can now do nothing
    cc, = q.expect_many(
        EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'),
        )
    for rcc in cc.args[0][contact_handle]:
        assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE))
    assert_rccs_not_callable(cc.args[0][contact_handle])
    assertEquals(cc.args[0],
            get_contacts_capabilities_sync(conn, [contact_handle]))

    # send correct presence
    ver = compute_caps_hash(some_identities, jingle_av_features, fake_client_dataforms)
    caps = {
        'node': client,
        'ver':  ver,
        'hash': 'sha-1',
        }
    presence = make_presence(contact, status='hello', caps=caps)
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + caps['ver']

    # don't receive any D-Bus signal
    q.forbid_events(forbidden)
    sync_dbus(bus, q, conn)
    q.unforbid_events(forbidden)

    # send good reply
    send_disco_reply(
        stream, event.stanza, some_identities, jingle_av_features, fake_client_dataforms)

    # we can now do audio calls
    cc, = q.expect_many(
        EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'),
        )
    assert_rccs_callable(cc.args[0][contact_handle])
    assertEquals(cc.args[0],
            get_contacts_capabilities_sync(conn, [contact_handle]))
Beispiel #35
0
def test_two_clients(q, bus, conn, stream, contact1, contact2,
        contact_handle1, contact_handle2, client, broken_hash):

    presence = make_presence(contact1, status='hello')
    stream.send(presence)

    q.expect('dbus-signal', signal='PresencesChanged',
            args=[{contact_handle1:
                (2, u'available', 'hello')}])

    presence = make_presence(contact2, status='hello')
    stream.send(presence)

    q.expect('dbus-signal', signal='PresencesChanged',
            args=[{contact_handle2:
                (2, u'available', 'hello')}])

    # no special capabilities
    for h in (contact_handle1, contact_handle2):
        for rcc in get_contacts_capabilities_sync(conn, [h])[h]:
            assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE))

    # send updated presence with Jingle caps info
    ver = compute_caps_hash(some_identities, jingle_av_features, {})
    caps = {
        'node': client,
        'ver': ver,
        'hash': 'sha-1',
        }
    presence = make_presence(contact1, status='hello', caps=caps)
    stream.send(presence)
    presence = make_presence(contact2, status='hello', caps=caps)
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact1,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + ver

    # don't receive any D-Bus signal
    forbidden = [
        EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'),
        ]
    q.forbid_events(forbidden)
    sync_dbus(bus, q, conn)
    q.unforbid_events(forbidden)

    result = make_caps_disco_reply(
        stream, event.stanza, some_identities, jingle_av_features)

    if broken_hash:
        # make the hash break!
        query = result.firstChildElement()
        query.addElement('feature')['var'] = 'http://example.com/another-feature'

    stream.send(result)

    if broken_hash:
        # Gabble looks up our capabilities again because the first contact
        # failed to provide a valid hash
        event = q.expect('stream-iq', to=contact2,
            query_ns='http://jabber.org/protocol/disco#info')
        query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
        assert query_node.attributes['node'] == \
            client + '#' + ver

        # don't receive any D-Bus signal
        q.forbid_events(forbidden)
        sync_dbus(bus, q, conn)
        q.unforbid_events(forbidden)

        # send good reply
        send_disco_reply(stream, event.stanza, some_identities, jingle_av_features)

    # we can now do audio calls
    cc, = q.expect_many(
        EventPattern('dbus-signal', signal='ContactCapabilitiesChanged',
            predicate=lambda e: contact_handle2 in e.args[0]),
        )
    assert_rccs_callable(cc.args[0][contact_handle2])

    if not broken_hash:
        # if the first contact failed to provide a good hash, it does not
        # deserve its capabilities to be understood by Gabble!
        cc, = q.expect_many(
            EventPattern('dbus-signal', signal='ContactCapabilitiesChanged',
                predicate=lambda e: contact_handle1 in e.args[0]),
            )
        assert_rccs_callable(cc.args[0][contact_handle1])

    # don't receive any further signals
    q.forbid_events(forbidden)
    sync_dbus(bus, q, conn)
    q.unforbid_events(forbidden)
Beispiel #36
0
def test(q, bus, conn, stream):
    caps = {
        'node': client,
        'ver':  '0.1',
        }

    update_contact_caps(q, conn, stream, '[email protected]/Foo', caps)
    update_contact_caps(q, conn, stream, '[email protected]/Foo', caps)

    # Meredith signs in from one resource.
    update_contact_caps(q, conn, stream, '[email protected]/One', caps)
    # Meredith signs in from another resource with the same client. We don't
    # need to disco her, even though we don't trust this caps node in general
    # yet, because she's already told us what it means.
    meredith_two = '[email protected]/Two'
    q.forbid_events([
        EventPattern('stream-iq', to=meredith_two, query_ns=ns.DISCO_INFO)
        ])
    stream.send(make_presence(meredith_two, 'hello', caps=caps))
    sync_stream(q, stream)

    # Jens signs in from one resource, which is slow to answer the disco query.
    jens_one = '[email protected]/One'
    j = send_presence(q, conn, stream, jens_one, caps)
    j_stanza = expect_disco(q, jens_one, client, caps)

    # Jens now signs in elsewhere with the same client; we disco it (maybe
    # it'll reply sooner? Maybe his first client's network connection went away
    # and the server hasn't noticed yet?) and it replies immediately.
    update_contact_caps (q, conn, stream, '[email protected]/Two', caps,
        initial=False)

    # Jens' first client replies. We don't expect any caps changes here, and
    # this shouldn't count as a second point towards the five we need to trust
    # this caps node.
    send_disco_reply(stream, j_stanza, [], features)
    check_caps (conn, j)

    update_contact_caps (q, conn, stream, '[email protected]/Foo', caps)

    # Now five distinct contacts have told us what this caps node means, we
    # trust it.
    update_contact_caps (q, conn, stream, '[email protected]/Foo', caps,
        disco = False)
    update_contact_caps (q, conn, stream, '[email protected]/Foo', caps,
        disco = False)

    caps = {
        'node': client,
        'ver':  compute_caps_hash([], features, fake_client_dataforms),
        'hash': 'sha-1',
        }

    update_contact_caps(q, conn, stream, '[email protected]/Foo',
       caps,  dataforms = fake_client_dataforms)
    # We can verify the reply for these caps against the hash, and thus never
    # need to disco it again.
    update_contact_caps(q, conn, stream, '[email protected]/Foo', caps,
        disco = False, dataforms = fake_client_dataforms)
    update_contact_caps(q, conn, stream, '[email protected]/Foo', caps,
        disco = False, dataforms = fake_client_dataforms)
def receive_caps(q,
                 bus,
                 conn,
                 service,
                 contact,
                 contact_handle,
                 features,
                 expected_caps,
                 expect_disco=True,
                 expect_ccc=True):

    ver = compute_caps_hash([], features, {})
    txt_record = {
        "txtvers": "1",
        "status": "avail",
        "node": client,
        "ver": ver,
        "hash": "sha-1"
    }

    listener, port = setup_stream_listener(q, contact)
    AvahiAnnouncer(contact, "_presence._tcp", port, txt_record)

    if expect_disco:
        # Salut looks up our capabilities
        e = q.expect('incoming-connection', listener=listener)
        stream = e.connection

        event = q.expect('stream-iq',
                         to=contact,
                         query_ns=ns.DISCO_INFO,
                         connection=stream)
        query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
        assert query_node.attributes['node'] == \
            client + '#' + ver

        # send good reply
        result = make_result_iq(event.stanza)
        query = result.firstChildElement()
        query['node'] = client + '#' + ver

        for f in features:
            feature = query.addElement('feature')
            feature['var'] = f

        stream.send(result)

    if expect_ccc:
        event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
        announced_ccs, = event.args
        assertSameElements(expected_caps, announced_ccs[contact_handle])
    else:
        if expect_disco:
            # Make sure Salut's got the caps
            sync_stream(q, stream)

    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn.Contacts.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.ATTR_CONTACT_CAPABILITIES]
    assertSameElements(expected_caps, caps_via_contacts_iface)

    # close the connection and expect a new one to be opened by Salut
    # the next time we need some discoing doing
    if expect_disco:
        stream.send('</stream:stream>')
        stream.transport.loseConnection()
        # pass some time so Salut knows the connection is lost and
        # won't try and send stuff down a closed connection on the
        # next test.
        sync_dbus(bus, q, conn)
def test_ft_caps_from_contact(q, bus, conn, stream, contact, contact_handle, client):
    global run
    run += 1

    conn_caps_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACT_CAPS)
    conn_contacts_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACTS)

    # send presence with no FT cap
    presence = make_presence(contact, status='hello')
    c = presence.addElement((ns.CAPS, 'c'))
    c['node'] = client
    c['ver'] = compute_caps_hash(['client/pc//jingleshareutils-%d' % run], [], {})
    c['ext'] = ""
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO)
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + c['ver']

    # send good reply
    result = make_result_iq(stream, event.stanza)
    query = result.firstChildElement()
    query['node'] = client + '#' + c['ver']
    stream.send(result)

    # no change in ContactCapabilities, so no signal ContactCapabilitiesChanged
    sync_stream(q, stream)

    # no special capabilities
    basic_caps = dbus.Dictionary({contact_handle:
            [(text_fixed_properties, text_allowed_properties)]})
    caps = conn_caps_iface.GetContactCapabilities([contact_handle])
    assert caps == basic_caps, caps
    # test again, to check GetContactCapabilities does not have side effect
    caps = conn_caps_iface.GetContactCapabilities([contact_handle])
    assert caps == basic_caps, caps
    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.ATTR_CONTACT_CAPABILITIES]
    assert caps_via_contacts_iface == caps[contact_handle], \
                                    caps_via_contacts_iface

    # send presence with ft capa
    presence = make_presence(contact, status='hello')
    c = presence.addElement((ns.CAPS, 'c'))
    c['node'] = client
    c['ext'] = "share-v1"
    c['ver'] = compute_caps_hash([], [], {})
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO)
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + c['ext']

    # send good reply
    result = make_result_iq(stream, event.stanza)
    query = result.firstChildElement()
    query['node'] = client + '#' + c['ext']
    feature = query.addElement('feature')
    feature['var'] = ns.GOOGLE_FEAT_SHARE
    stream.send(result)


    generic_ft_caps = dbus.Dictionary({contact_handle:
            [(text_fixed_properties, text_allowed_properties),
             (ft_fixed_properties, ft_allowed_properties)]})

    event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
    assert len(event.args) == 1
    assert event.args[0] == generic_ft_caps

    caps = conn_caps_iface.GetContactCapabilities([contact_handle])
    assert caps == generic_ft_caps, caps
    # test again, to check GetContactCapabilities does not have side effect
    caps = conn_caps_iface.GetContactCapabilities([contact_handle])
    assert caps == generic_ft_caps, caps
    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.ATTR_CONTACT_CAPABILITIES]
    assert caps_via_contacts_iface == caps[contact_handle], \
                                    caps_via_contacts_iface
def send_presence(q, stream, contact_jid, identity):
    ver = compute_caps_hash([identity], features, {})
    stream.send(make_presence(contact_jid, status='Hello',
        caps={'node': client, 'hash': 'sha-1', 'ver': ver}))
Beispiel #40
0
def test_ft_caps_from_contact(q, bus, conn, client):

    conn_caps_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACT_CAPS)
    conn_contacts_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACTS)

    # send presence with FT capa
    ver = compute_caps_hash([], [ns.IQ_OOB], {})
    txt_record = {
        "txtvers": "1",
        "status": "avail",
        "node": client,
        "ver": ver,
        "hash": "sha-1"
    }
    contact_name = "test-caps-ft@" + get_host_name()
    listener, port = setup_stream_listener(q, contact_name)
    announcer = AvahiAnnouncer(contact_name, "_presence._tcp", port,
                               txt_record)

    # this is the first presence, Salut connects to the contact
    e = q.expect('incoming-connection', listener=listener)
    incoming = e.connection

    # Salut looks up our capabilities
    event = q.expect('stream-iq',
                     connection=incoming,
                     query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + ver, (query_node.attributes['node'], client, ver)

    contact_handle = conn_contacts_iface.GetContactByID(contact_name, [])[0]

    # send good reply
    result = make_result_iq(event.stanza)
    query = result.firstChildElement()
    query['node'] = client + '#' + ver

    feature = query.addElement('feature')
    feature['var'] = ns.IQ_OOB
    incoming.send(result)

    # FT capa is announced
    e = q.expect('dbus-signal',
                 signal='ContactCapabilitiesChanged',
                 predicate=lambda e: contact_handle in e.args[0])
    caps = e.args[0][contact_handle]
    assertContains(ft_caps, caps)

    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.CONN_IFACE_CONTACT_CAPS + '/capabilities']
    assert caps_via_contacts_iface == caps, caps_via_contacts_iface

    # check if Salut announces the OOB capa
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")
    self_handle_name = conn.Properties.Get(cs.CONN, "SelfID")

    AvahiListener(q).listen_for_service("_presence._tcp")
    e = q.expect('service-added',
                 name=self_handle_name,
                 protocol=avahi.PROTO_INET)
    service = e.service
    service.resolve()

    receive_presence_and_ask_caps(q, incoming, service, contact_name)

    # capa announced without FT
    ver = compute_caps_hash([], ["http://telepathy.freedesktop.org/xmpp/pony"],
                            {})
    txt_record = {
        "txtvers": "1",
        "status": "avail",
        "node": client,
        "ver": ver,
        "hash": "sha-1"
    }
    contact_name = "test-caps-ft2@" + get_host_name()
    listener, port = setup_stream_listener(q, contact_name)
    announcer = AvahiAnnouncer(contact_name, "_presence._tcp", port,
                               txt_record)

    # this is the first presence, Salut connects to the contact
    e = q.expect('incoming-connection', listener=listener)
    incoming = e.connection

    # Salut looks up our capabilities
    event = q.expect('stream-iq',
                     connection=incoming,
                     query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + ver, (query_node.attributes['node'], client, ver)

    contact_handle = conn_contacts_iface.GetContactByID(contact_name, [])[0]

    # send good reply
    result = make_result_iq(event.stanza)
    query = result.firstChildElement()
    query['node'] = client + '#' + ver

    feature = query.addElement('feature')
    feature['var'] = "http://telepathy.freedesktop.org/xmpp/pony"
    incoming.send(result)

    # the FT capability is not announced
    e = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
    caps = e.args[0][contact_handle]
    assertDoesNotContain(ft_caps, caps)

    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.CONN_IFACE_CONTACT_CAPS + '/capabilities']
    assert caps_via_contacts_iface == caps, caps_via_contacts_iface

    # no capabilites announced (assume FT is supported to insure interop)
    txt_record = {"txtvers": "1", "status": "avail"}
    contact_name = "test-caps-ft-no-capa2@" + get_host_name()
    contact_handle = conn_contacts_iface.GetContactByID(contact_name, [])[0]
    listener, port = setup_stream_listener(q, contact_name)
    announcer = AvahiAnnouncer(contact_name, "_presence._tcp", port,
                               txt_record)

    # FT capa is announced
    e = q.expect('dbus-signal',
                 signal='ContactCapabilitiesChanged',
                 predicate=lambda e: contact_handle in e.args[0].keys())

    caps = e.args[0][contact_handle]
    assertContains(ft_caps, caps)

    # check the Contacts interface give the same caps
    caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
            [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
            [contact_handle][cs.CONN_IFACE_CONTACT_CAPS + '/capabilities']
    assert caps_via_contacts_iface == caps, caps_via_contacts_iface
Beispiel #41
0
    def _cb_disco_iq(self, iq):
        nodes = xpath.queryForNodes("/iq/query", iq)
        query = nodes[0]

        if query.getAttribute('node') is None:
            return

        node = query.attributes['node']
        ver = node.replace("http://telepathy.freedesktop.org/caps#", "")

        if iq.getAttribute('type') == 'result':

            if FileTransferTest.caps_identities is None or \
                    FileTransferTest.caps_features is None or \
                    FileTransferTest.caps_dataforms is None:
                # create our own identity
                identity_nodes = xpath.queryForNodes('/iq/query/identity', iq)
                assertLength(1, identity_nodes)
                identity_node = identity_nodes[0]

                identity_category = identity_node['category']
                identity_type = identity_node['type']
                identity_name = identity_node['name']
                identity = '%s/%s//%s' % (identity_category, identity_type,
                                          identity_name)

                _, features, dataforms = extract_disco_parts(iq)

                FileTransferTest.caps_identities = [identity]
                FileTransferTest.caps_features = features
                FileTransferTest.caps_dataforms = dataforms

                # Check if the hash matches the announced capabilities
                assertEquals(compute_caps_hash(FileTransferTest.caps_identities,
                                               FileTransferTest.caps_features,
                                               FileTransferTest.caps_dataforms), ver)

            if ver == FileTransferTest.caps_ft:
                caps_share = compute_caps_hash(FileTransferTest.caps_identities,
                                               FileTransferTest.caps_features + \
                                                   [ns.GOOGLE_FEAT_SHARE],
                                               FileTransferTest.caps_dataforms)
                n = query.attributes['node'].replace(ver, caps_share)
                query.attributes['node'] = n

                for feature in xpath.queryForNodes('/iq/query/feature', iq):
                        query.children.remove(feature)

                for f in FileTransferTest.caps_features + [ns.GOOGLE_FEAT_SHARE]:
                    el = domish.Element((None, 'feature'))
                    el['var'] = f
                    query.addChild(el)

        elif iq.getAttribute('type') == 'get':
            caps_share = compute_caps_hash(FileTransferTest.caps_identities,
                                           FileTransferTest.caps_features + \
                                               [ns.GOOGLE_FEAT_SHARE],
                                           FileTransferTest.caps_dataforms)

            if ver == caps_share:
                n = query.attributes['node'].replace(ver,
                                                     FileTransferTest.caps_ft)
                query.attributes['node'] = n
def test_two_clients(q, bus, conn, stream, contact1, contact2,
        contact_handle1, contact_handle2, client, broken_hash):
    global caps_changed_flag

    presence = make_presence(contact1, status='hello')
    stream.send(presence)

    event = q.expect_many(
        EventPattern('dbus-signal', signal='PresenceUpdate',
            args=[{contact_handle1:
                (0L, {u'available': {'message': 'hello'}})}]),
        EventPattern('dbus-signal', signal='PresencesChanged',
            args=[{contact_handle1:
                (2, u'available', 'hello')}]))

    presence = make_presence(contact2, status='hello')
    stream.send(presence)

    event = q.expect_many(
        EventPattern('dbus-signal', signal='PresenceUpdate',
            args=[{contact_handle2:
                (0L, {u'available': {'message': 'hello'}})}]),
        EventPattern('dbus-signal', signal='PresencesChanged',
            args=[{contact_handle2:
                (2, u'available', 'hello')}]))

    # no special capabilities
    basic_caps = [(contact_handle1, cs.CHANNEL_TYPE_TEXT, 3, 0)]
    assert conn.Capabilities.GetCapabilities([contact_handle1]) == basic_caps
    basic_caps = [(contact_handle2, cs.CHANNEL_TYPE_TEXT, 3, 0)]
    assert conn.Capabilities.GetCapabilities([contact_handle2]) == basic_caps

    # send updated presence with Jingle caps info
    ver = compute_caps_hash([], jingle_av_features, {})
    caps = {
        'node': client,
        'ver': ver,
        'hash': 'sha-1',
        }
    presence = make_presence(contact1, status='hello', caps=caps)
    stream.send(presence)
    presence = make_presence(contact2, status='hello', caps=caps)
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact1,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + ver

    # don't receive any D-Bus signal
    sync_dbus(bus, q, conn)
    assert caps_changed_flag == False

    result = make_caps_disco_reply(stream, event.stanza, jingle_av_features)

    if broken_hash:
        # make the hash break!
        query = result.firstChildElement()
        query.addElement('feature')['var'] = 'http://example.com/another-feature'

    stream.send(result)

    if broken_hash:
        # Gabble looks up our capabilities again because the first contact
        # failed to provide a valid hash
        event = q.expect('stream-iq', to=contact2,
            query_ns='http://jabber.org/protocol/disco#info')
        query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
        assert query_node.attributes['node'] == \
            client + '#' + ver

        # don't receive any D-Bus signal
        sync_dbus(bus, q, conn)
        assert caps_changed_flag == False

        # send good reply
        result = make_caps_disco_reply(stream, event.stanza, jingle_av_features)
        stream.send(result)

    # we can now do audio calls with both contacts
    event = q.expect('dbus-signal', signal='CapabilitiesChanged',
        args=[[(contact_handle2, cs.CHANNEL_TYPE_STREAMED_MEDIA, 0, 3, 0,
            cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO)]])
    if not broken_hash:
        # if the first contact failed to provide a good hash, it does not
        # deserve its capabilities to be understood by Gabble!
        event = q.expect('dbus-signal', signal='CapabilitiesChanged',
            args=[[(contact_handle1, cs.CHANNEL_TYPE_STREAMED_MEDIA, 0, 3, 0,
                cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO)]])

    caps_changed_flag = False

    # don't receive any D-Bus signal
    sync_dbus(bus, q, conn)
    assert caps_changed_flag == False
def test(q, bus, conn, stream):
    client = 'http://example.com/perverse-client'
    contact_bare_jid = '*****@*****.**'
    contact_with_resource = '[email protected]/hi'
    contact_handle = conn.RequestHandles(cs.HT_CONTACT, [contact_bare_jid])[0]

    # Gabble gets a presence stanza from a bare JID, which is a tad surprising.
    features = [
        ns.JINGLE_015,
        ns.JINGLE_015_AUDIO,
        ns.JINGLE_015_VIDEO,
        ns.GOOGLE_P2P,
        ]
    caps = {'node': client,
            'hash': 'sha-1',
            'ver': compute_caps_hash([], features, {}),
           }
    p = make_presence(contact_bare_jid, status='Hello', caps=caps)
    stream.send(p)

    # Gabble looks up the hash
    event = q.expect('stream-iq', to=contact_bare_jid,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assertEquals(client + '#' + caps['ver'], query_node.attributes['node'])

    # The bare jid replies
    send_disco_reply(stream, event.stanza, [], features)

    # Gabble lets us know their caps have changed. (Gabble used to ignore the
    # reply.)
    streamed_media_caps = (contact_handle, cs.CHANNEL_TYPE_STREAMED_MEDIA,
        0, 3, 0, cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO)
    e = q.expect('dbus-signal', signal='CapabilitiesChanged')
    assertContains(streamed_media_caps, e.args[0])

    # Gabble gets another presence stanza from the bare JID, with different
    # caps.
    features.append(ns.TUBES)
    caps = {'node': client,
            'hash': 'sha-1',
            'ver': compute_caps_hash([], features, {}),
           }
    p = make_presence(contact_bare_jid, status='Get out the abacus', caps=caps)
    stream.send(p)

    # Gabble looks up the new hash
    disco2 = q.expect('stream-iq', to=contact_bare_jid,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', disco2.stanza)[0]
    assertEquals(client + '#' + caps['ver'], query_node.attributes['node'])

    # This time, before the bare JID replies, Gabble gets a presence from the
    # resourceful jid.
    features_ = features + [ns.CHAT_STATES]
    caps = {'node': client,
            'hash': 'sha-1',
            'ver': compute_caps_hash([], features_, {}),
           }
    p = make_presence(contact_with_resource, status='Count this', caps=caps)
    stream.send(p)

    # Gabble throws away presence from the bare JID when it gets presence from
    # a resource (and vice versa), so it should now say the contact is
    # incapable.  Gabble also looks up the resourceful JID's hash.
    cc, disco3 = q.expect_many(
        EventPattern('dbus-signal', signal='CapabilitiesChanged'),
        EventPattern('stream-iq', to=contact_with_resource,
            query_ns='http://jabber.org/protocol/disco#info'),
        )

    assertDoesNotContain(streamed_media_caps, cc.args[0])

    query_node = xpath.queryForNodes('/iq/query', disco3.stanza)[0]
    assertEquals(client + '#' + caps['ver'], query_node.attributes['node'])

    # The bare jid replies! Getting a disco reply from a bare JID when we've
    # got presence from resources used to crash Gabble, but now it just ignores
    # it.
    send_disco_reply(stream, disco2.stanza, [], features)

    # Now the resourceful JID replies:
    send_disco_reply(stream, disco3.stanza, [], features_)

    # Gabble should announce that the contact has acquired some caps.
    e = q.expect('dbus-signal', signal='CapabilitiesChanged')
    assertContains(streamed_media_caps, e.args[0])
Beispiel #44
0
def test_hash(q, bus, conn, stream, contact, contact_handle, client):
    global caps_changed_flag

    presence = make_presence(contact, status='hello')
    stream.send(presence)

    q.expect('dbus-signal', signal='PresencesChanged',
            args=[{contact_handle:
                (2, u'available', 'hello')}])

    # no special capabilities
    basic_caps = [(contact_handle, cs.CHANNEL_TYPE_TEXT, 3, 0)]
    assert conn.Capabilities.GetCapabilities([contact_handle]) == basic_caps

    # send updated presence with Jingle caps info
    presence = make_presence(contact, status='hello',
        caps={'node': client,
              'ver':  '0.1',
             })
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + '0.1'

    # send good reply
    send_disco_reply(stream, event.stanza, [], jingle_av_features)

    # we can now do audio calls
    event = q.expect('dbus-signal', signal='CapabilitiesChanged')
    caps_diff = event.args[0]
    media_diff = [c for c in caps_diff
                    if c[1] == cs.CHANNEL_TYPE_STREAMED_MEDIA][0]
    assert media_diff[5] & cs.MEDIA_CAP_AUDIO, media_diff[5]
    caps_changed_flag = False

    # Send presence without any capabilities. XEP-0115 §8.4 Caps Optimization
    # says “receivers of presence notifications MUST NOT expect an annotation
    # on every presence notification they receive”, so the contact should still
    # be media-capable afterwards.
    stream.send(make_presence(contact, status='very capable'))
    q.expect('dbus-signal', signal='PresencesChanged',
        args=[{contact_handle: (2, u'available', 'very capable')}])
    ye_olde_caps = conn.Capabilities.GetCapabilities([contact_handle])
    assertLength(1, [c for c in ye_olde_caps
                       if c[1] == cs.CHANNEL_TYPE_STREAMED_MEDIA and
                          c[3] & cs.MEDIA_CAP_AUDIO])

    # send bogus presence
    caps = {
        'node': client,
        'ver':  'ceci=nest=pas=un=hash',
        'hash': 'sha-1',
        }
    presence = make_presence(contact, status='hello', caps=caps)
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + caps['ver']

    # send bogus reply
    send_disco_reply(stream, event.stanza, [],
        ['http://jabber.org/protocol/bogus-feature'])

    # don't receive any D-Bus signal
    sync_dbus(bus, q, conn)
    sync_stream(q, stream)
    assert caps_changed_flag == False


    # send presence with empty caps
    presence = make_presence(contact, status='hello',
        caps={'node': client,
              'ver':  '0.0',
             })
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + '0.0'

    # still don't receive any D-Bus signal
    sync_dbus(bus, q, conn)
    assert caps_changed_flag == False

    # send good reply
    result = make_result_iq(stream, event.stanza)
    query = result.firstChildElement()
    stream.send(result)

    # we can now do nothing
    event = q.expect('dbus-signal', signal='CapabilitiesChanged')
    assert caps_changed_flag == True
    caps_changed_flag = False


    # send correct presence
    ver = compute_caps_hash(some_identities, jingle_av_features, fake_client_dataforms)
    caps = {
        'node': client,
        'ver':  ver,
        'hash': 'sha-1',
        }
    presence = make_presence(contact, status='hello', caps=caps)
    stream.send(presence)

    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + caps['ver']

    # don't receive any D-Bus signal
    sync_dbus(bus, q, conn)
    assert caps_changed_flag == False

    # send good reply
    send_disco_reply(
        stream, event.stanza, some_identities, jingle_av_features, fake_client_dataforms)

    # we can now do audio calls
    event = q.expect('dbus-signal', signal='CapabilitiesChanged',
    )
    assert caps_changed_flag == True
    caps_changed_flag = False