def join_muc(q, bus, conn, stream, muc, request=None):
    """
    Joins 'muc', returning the muc's handle, a proxy object for the channel,
    its path and its immutable properties just after the CreateChannel event
    has fired. The room contains one other member.
    """
    if request is None:
        request = {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: muc,
        }

    muc_handle = request_muc_handle(q, conn, stream, muc)

    requests = dbus.Interface(conn, cs.CONN_IFACE_REQUESTS)
    call_async(q, requests, 'CreateChannel',
        dbus.Dictionary(request, signature='sv'))

    q.expect('stream-presence', to='%s/test' % muc)

    # Send presence for other member of room.
    stream.send(make_muc_presence('owner', 'moderator', muc, 'bob'))

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', muc, 'test'))

    event = q.expect('dbus-return', method='CreateChannel')
    path, props = event.value
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['Messages'])

    return (muc_handle, chan, path, props)
def test_ensure_ensure(q, conn, bus, stream, room_jid):
    # Call Ensure twice for the same channel.
    call_async(q, conn.Requests, 'EnsureChannel',
           { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
             cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
             cs.TARGET_ID: room_jid,
           })
    call_async(q, conn.Requests, 'EnsureChannel',
           { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
             cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
             cs.TARGET_ID: room_jid,
           })

    mc, _ = q.expect_many(
        EventPattern('dbus-signal', signal='MembersChangedDetailed'),
        EventPattern('stream-presence', to=('%s/test' % room_jid)))
    added, removed, local_pending, remote_pending, details = mc.args

    assert added == [], mc.args
    assert removed == [], mc.args
    assert local_pending == [], mc.args
    assert len(remote_pending) == 1, mc.args

    # Send presence for other member of room.
    stream.send(make_muc_presence('owner', 'moderator', room_jid, 'bob'))

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', room_jid, 'test'))

    mc = q.expect('dbus-signal', signal='MembersChangedDetailed')
    added, removed, local_pending, remote_pending, details = mc.args

    assert len(added) == 2, mc.args
    assert removed == [], mc.args
    assert local_pending == [], mc.args
    assert remote_pending == [], mc.args

    members = conn.inspect_contacts_sync(added)
    members.sort()
    assert members == ['%s/bob' % room_jid, '%s/test' % room_jid], members

    # We should get two EnsureChannel returns
    es = []
    while len(es) < 2:
        e = q.expect('dbus-return', method='EnsureChannel')
        es.append(e)

    e1, e2 = es

    assert len(e1.value) == 3
    yours1, path1, props1 = e1.value

    assert len(e2.value) == 3
    yours2, path2, props2 = e2.value

    # Exactly one Ensure should get Yours=True.
    assert (yours1 == (not yours2))

    assert path1 == path2, (path1, path2)
    assert props1 == props2, (props1, props2)
def join_muc(q,
             bus,
             conn,
             stream,
             muc,
             request=None,
             also_capture=[],
             role='participant',
             affiliation='none'):
    """
    Joins 'muc', returning a proxy object for the channel,
    its path and its immutable properties just after the CreateChannel event
    has fired. The room contains one other member.
    """
    try_to_join_muc(q, bus, conn, stream, muc, request=request)

    # Send presence for other member of room.
    stream.send(make_muc_presence('owner', 'moderator', muc, 'bob'))

    # Send presence for own membership of room.
    stream.send(make_muc_presence(affiliation, role, muc, 'test'))

    captured = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'), *also_capture)
    path, props = captured[0].value
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
                        ['Subject.DRAFT'])

    return (chan, path, props) + tuple(captured[1:])
Example #4
0
def test(q, bus, conn, stream):
    iq_event = q.expect('stream-iq',
                        to=None,
                        query_ns='vcard-temp',
                        query_name='vCard')

    acknowledge_iq(stream, iq_event.stanza)
    t.check_conn_properties(q, conn)

    # Create new style tube channel and make sure that is indeed
    # returned.
    muc = '*****@*****.**'

    call_async(
        q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_DBUS_TUBE,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: muc,
            cs.DBUS_TUBE_SERVICE_NAME: 'com.example.LolDongs'
        })

    q.expect('stream-presence', to='%s/test' % muc)
    stream.send(make_muc_presence('owner', 'moderator', muc, 'bob'))
    stream.send(make_muc_presence('none', 'participant', muc, 'test'))

    ret, _ = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('dbus-signal', signal='NewChannels'),
    )

    _, props = ret.value

    assertEquals(props[cs.CHANNEL_TYPE], cs.CHANNEL_TYPE_DBUS_TUBE)
    assertEquals(props[cs.TARGET_HANDLE_TYPE], cs.HT_ROOM)
    assertEquals(props[cs.TARGET_ID], muc)

    # Now try joining the text muc before asking for the tube channel.
    muc = '*****@*****.**'

    join_muc(q, bus, conn, stream, muc)

    call_async(
        q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_DBUS_TUBE,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: muc,
            cs.DBUS_TUBE_SERVICE_NAME: 'com.example.LolDongs'
        })

    ret, _ = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('dbus-signal', signal='NewChannels'),
    )

    _, props = ret.value

    assertEquals(props[cs.CHANNEL_TYPE], cs.CHANNEL_TYPE_DBUS_TUBE)
    assertEquals(props[cs.TARGET_HANDLE_TYPE], cs.HT_ROOM)
    assertEquals(props[cs.TARGET_ID], muc)
Example #5
0
def test(q, bus, conn, stream):
    expect_and_handle_get_vcard(q, stream)

    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")
    conn.Aliasing.SetAliases({self_handle: 'lala'})

    expect_and_handle_set_vcard(q, stream)

    event = q.expect('dbus-signal',
                     signal='AliasesChanged',
                     args=[[(self_handle, u'lala')]])

    room_jid = '*****@*****.**'

    # muc stream tube
    call_async(
        q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: room_jid
        })

    gfc, _, _ = q.expect_many(
        EventPattern('dbus-signal', signal='GroupFlagsChanged'),
        EventPattern(
            'dbus-signal',
            signal='MembersChangedDetailed',
            predicate=lambda e: e.args[0] == [] and  # added
            e.args[1] == [] and  # removed
            e.args[2] == [] and  # local pending
            len(e.args[3]) == 1 and  # remote pending
            e.args[4].get('actor', 0) == 0 and e.args[4].get(
                'change-reason', 0) == 0 and e.args[4]['contact-ids'][e.args[
                    3][0]] == '[email protected]/lala'),
        EventPattern('stream-presence', to='%s/lala' % room_jid))
    assert gfc.args[1] == 0

    # Send presence for other member of room.
    stream.send(make_muc_presence('owner', 'moderator', room_jid, 'bob'))

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', room_jid, 'lala'))

    event = q.expect(
        'dbus-signal',
        signal='MembersChangedDetailed',
        predicate=lambda e: len(e.args[0]) == 2 and  # added
        e.args[1] == [] and  # removed
        e.args[2] == [] and  # local pending
        e.args[3] == [] and  # remote pending
        e.args[4].get('actor', 0) == 0 and e.args[4].get('change-reason', 0) ==
        0 and set([e.args[4]['contact-ids'][h] for h in e.args[0]]) == set(
            ['[email protected]/lala', '[email protected]/bob']))

    event = q.expect('dbus-return', method='CreateChannel')
def test_create_ensure(q, conn, bus, stream, room_jid, room_handle):
    # Call both Create and Ensure for the same channel.
    call_async(q, conn.Requests, 'CreateChannel',
           { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
             cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
             cs.TARGET_HANDLE: room_handle,
           })
    call_async(q, conn.Requests, 'EnsureChannel',
           { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
             cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
             cs.TARGET_HANDLE: room_handle,
           })

    mc, _ = q.expect_many(
        EventPattern('dbus-signal', signal='MembersChanged'),
        EventPattern('stream-presence', to=('%s/test' % room_jid)))
    msg, added, removed, local_pending, remote_pending, actor, reason = mc.args

    assert added == [], mc.args
    assert removed == [], mc.args
    assert local_pending == [], mc.args
    assert len(remote_pending) == 1, mc.args

    # Send presence for other member of room.
    stream.send(make_muc_presence('owner', 'moderator', room_jid, 'bob'))

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', room_jid, 'test'))

    mc = q.expect('dbus-signal', signal='MembersChanged')
    msg, added, removed, local_pending, remote_pending, actor, reason = mc.args

    assert len(added) == 2, mc.args
    assert removed == [], mc.args
    assert local_pending == [], mc.args
    assert remote_pending == [], mc.args

    members = conn.InspectHandles(1, added)
    members.sort()
    assert members == ['%s/bob' % room_jid, '%s/test' % room_jid], members

    create_event, ensure_event = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('dbus-return', method='EnsureChannel'))

    assert len(create_event.value) == 2
    c_path, c_props = create_event.value

    assert len(ensure_event.value) == 3
    yours, e_path, e_props = ensure_event.value

    assert c_path == e_path, (c_path, e_path)
    assert c_props == e_props, (c_props, e_props)

    assert not yours
def test(q, bus, conn, stream):
    expect_and_handle_get_vcard(q, stream)

    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")
    conn.Aliasing.SetAliases({self_handle: 'lala'})

    expect_and_handle_set_vcard(q, stream)

    event = q.expect('dbus-signal', signal='AliasesChanged',
        args=[[(self_handle, u'lala')]])

    room_jid = '*****@*****.**'

    # muc stream tube
    call_async(q, conn.Requests, 'CreateChannel', {
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
        cs.TARGET_ID: room_jid})

    gfc, _, _ = q.expect_many(
        EventPattern('dbus-signal', signal='GroupFlagsChanged'),
        EventPattern('dbus-signal', signal='MembersChangedDetailed',
            predicate=lambda e:
                e.args[0] == [] and         # added
                e.args[1] == [] and         # removed
                e.args[2] == [] and         # local pending
                len(e.args[3]) == 1 and     # remote pending
                e.args[4].get('actor', 0) == 0 and
                e.args[4].get('change-reason', 0) == 0 and
                e.args[4]['contact-ids'][e.args[3][0]] == '[email protected]/lala'),
        EventPattern('stream-presence', to='%s/lala' % room_jid))
    assert gfc.args[1] == 0

    # Send presence for other member of room.
    stream.send(make_muc_presence('owner', 'moderator', room_jid, 'bob'))

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', room_jid, 'lala'))

    event = q.expect('dbus-signal', signal='MembersChangedDetailed',
            predicate=lambda e:
                len(e.args[0]) == 2 and     # added
                e.args[1] == [] and         # removed
                e.args[2] == [] and         # local pending
                e.args[3] == [] and         # remote pending
                e.args[4].get('actor', 0) == 0 and
                e.args[4].get('change-reason', 0) == 0 and
                set([e.args[4]['contact-ids'][h] for h in e.args[0]]) ==
                set(['[email protected]/lala', '[email protected]/bob']))

    event = q.expect('dbus-return', method='CreateChannel')
def test(q, bus, conn, stream):
    muc_handle = request_muc_handle(q, conn, stream, '*****@*****.**')

    call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM,
        muc_handle, True)

    q.expect('stream-presence', to='[email protected]/test')

    # Send presence for own membership of room.
    stream.send(
        make_muc_presence('owner', 'moderator', '*****@*****.**', 'test'))

    iq, ret = q.expect_many(
        EventPattern('stream-iq', to='*****@*****.**', iq_type='get',
            query_ns=ns.MUC_OWNER),
        EventPattern('dbus-return', method='RequestChannel'))
    handle_muc_get_iq(stream, iq.stanza)

    text_chan = wrap_channel(
        bus.get_object(conn.bus_name, ret.value[0]), 'Text')

    props = dict([(name, id)
        for id, name, sig, flags in text_chan.TpProperties.ListProperties()])
    call_async(q, text_chan.TpProperties, 'SetProperties',
        [(props['password'], 'foo'), (props['password-required'], True)])

    event = q.expect('stream-iq', to='*****@*****.**', iq_type='get',
        query_ns=ns.MUC_OWNER)
    handle_muc_get_iq(stream, event.stanza)

    event = q.expect('stream-iq', to='*****@*****.**', iq_type='set',
        query_ns=ns.MUC_OWNER)
    fields = xpath.queryForNodes('/iq/query/x/field', event.stanza)
    form = {}
    for field in fields:
        values = xpath.queryForNodes('/field/value', field)
        form[field['var']] = [str(v) for v in values]
    assert form == {'password': ['foo'], 'password_protected': ['1'],
            'muc#roomconfig_presencebroadcast' :
            ['moderator', 'participant', 'visitor']}
    acknowledge_iq(stream, event.stanza)

    event = q.expect('dbus-signal', signal='PropertiesChanged')
    assert event.args == [[(props['password'], 'foo'),
        (props['password-required'], True)]]

    q.expect('dbus-return', method='SetProperties', value=())

    call_async(q, text_chan.TpProperties, 'SetProperties',
        [(31337, 'foo'), (props['password-required'], True)])
    q.expect('dbus-error', name=cs.INVALID_ARGUMENT)

    call_async(q, text_chan.TpProperties, 'SetProperties',
        [(props['password'], True), (props['password-required'], 'foo')])
    q.expect('dbus-error', name=cs.NOT_AVAILABLE)

    call_async(q, text_chan.TpProperties, 'SetProperties',
        [(props['subject-contact'], 42)])
    q.expect('dbus-error', name=cs.PERMISSION_DENIED)
def create_muc(q, conn, stream, props):
    call_async(q, conn.Requests, 'CreateChannel', props)

    r = q.expect('stream-presence')
    muc_name = r.to.split('/', 2)[0]

    stream.send(make_muc_presence('owner', 'moderator', muc_name, 'test'))

    r = q.expect('dbus-return', method='CreateChannel')

    assertEquals(2, len(r.value))
    return r.value[1]
Example #10
0
def create_muc(q, conn, stream, props):
    call_async(q, conn.Requests, 'CreateChannel', props)

    r = q.expect('stream-presence')
    muc_name = r.to.split('/', 2)[0]

    stream.send(make_muc_presence('owner', 'moderator', muc_name, 'test'))

    r = q.expect('dbus-return', method='CreateChannel')

    assertEquals(2, len(r.value))
    return r.value[1]
def test(q, bus, conn, stream):
    conn.Connect()

    expect_and_handle_get_vcard(q, stream)

    self_handle = conn.GetSelfHandle()
    conn.Aliasing.SetAliases({self_handle: 'lala'})

    expect_and_handle_set_vcard(q, stream)

    event = q.expect('dbus-signal', signal='AliasesChanged',
        args=[[(self_handle, u'lala')]])

    room_jid = '*****@*****.**'
    room_handle = request_muc_handle(q, conn, stream, room_jid)

    call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM,
        room_handle, True)

    gfc, _, _ = q.expect_many(
        EventPattern('dbus-signal', signal='GroupFlagsChanged'),
        EventPattern('dbus-signal', signal='MembersChanged',
            args=[u'', [], [], [], [2], 0, 0]),
        EventPattern('stream-presence', to='%s/lala' % room_jid))
    assert gfc.args[1] == 0

    # Send presence for other member of room.
    stream.send(make_muc_presence('owner', 'moderator', room_jid, 'bob'))

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', room_jid, 'lala'))

    event = q.expect('dbus-signal', signal='MembersChanged',
        args=[u'', [2, 3], [], [], [], 0, 0])
    assert conn.InspectHandles(1, [2]) == ['[email protected]/lala']
    assert conn.InspectHandles(1, [3]) == ['[email protected]/bob']

    event = q.expect('dbus-return', method='RequestChannel')
Example #12
0
def join_muc(q, bus, conn, stream, muc, request=None,
        also_capture=[], role='participant', affiliation='none'):
    """
    Joins 'muc', returning a proxy object for the channel,
    its path and its immutable properties just after the CreateChannel event
    has fired. The room contains one other member.
    """
    try_to_join_muc(q, bus, conn, stream, muc, request=request)

    # Send presence for other member of room.
    stream.send(make_muc_presence('owner', 'moderator', muc, 'bob'))

    # Send presence for own membership of room.
    stream.send(make_muc_presence(affiliation, role, muc, 'test'))

    captured = q.expect_many(
            EventPattern('dbus-return', method='CreateChannel'),
            *also_capture)
    path, props = captured[0].value
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['Subject.DRAFT'])


    return (chan, path, props) + tuple(captured[1:])
Example #13
0
def create_pmuc(q, conn, stream, extra_props=None):
    """
    Request a PMUC just for ourselves.
    """

    props = {
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_NONE,
        cs.CONFERENCE_INITIAL_CHANNELS: dbus.Array([], signature='o'),
    }

    if extra_props: props.update(extra_props)

    call_async(q, conn.Requests, 'CreateChannel', props)

    # wait for the MUC name, so we can inject a reply
    r = q.expect('stream-presence')
    pmuc_name = r.to.split('/', 2)[0]

    assert re.match(
        r'^private-chat-\w{8}-\w{4}-\w{4}-\w{4}-\w{12}@conf.localhost$',
        pmuc_name), pmuc_name

    stream.send(make_muc_presence('owner', 'moderator', pmuc_name, 'test'))

    # wait for the method return
    r = q.expect('dbus-return', method='CreateChannel')

    assert len(r.value) == 2
    path, out_props = r.value

    assert out_props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT
    assert out_props[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM
    assert out_props[cs.TARGET_ID] == pmuc_name

    assertContains(cs.CHANNEL_IFACE_CONFERENCE, out_props[cs.INTERFACES])
    assertEquals(props[cs.CONFERENCE_INITIAL_CHANNELS],
            out_props[cs.CONFERENCE_INITIAL_CHANNELS])

    return pmuc_name, path, out_props
def create_pmuc(q, conn, stream, extra_props=None):
    """
    Request a PMUC just for ourselves.
    """

    props = {
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_NONE,
        cs.CONFERENCE_INITIAL_CHANNELS: dbus.Array([], signature='o'),
    }

    if extra_props: props.update(extra_props)

    call_async(q, conn.Requests, 'CreateChannel', props)

    # wait for the MUC name, so we can inject a reply
    r = q.expect('stream-presence')
    pmuc_name = r.to.split('/', 2)[0]

    assert re.match(
        r'^private-chat-\w{8}-\w{4}-\w{4}-\w{4}-\w{12}@conf.localhost$',
        pmuc_name), pmuc_name

    stream.send(make_muc_presence('owner', 'moderator', pmuc_name, 'test'))

    # wait for the method return
    r = q.expect('dbus-return', method='CreateChannel')

    assert len(r.value) == 2
    path, out_props = r.value

    assert out_props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT
    assert out_props[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM
    assert out_props[cs.TARGET_ID] == pmuc_name

    assertContains(cs.CHANNEL_IFACE_CONFERENCE, out_props[cs.INTERFACES])
    assertEquals(props[cs.CONFERENCE_INITIAL_CHANNELS],
                 out_props[cs.CONFERENCE_INITIAL_CHANNELS])

    return pmuc_name, path, out_props
def join_channel(name, q, conn, stream):
    call_async(q, conn, 'RequestHandles', cs.HT_ROOM, [name])

    # announce conference service
    event = q.expect('stream-iq', to='conference.localhost', query_ns=ns.DISCO_INFO)
    reply = make_result_iq(stream, event.stanza)
    feature = reply.firstChildElement().addElement('feature')
    feature['var'] = ns.MUC
    stream.send(reply)

    event = q.expect('dbus-return', method='RequestHandles')
    handles = event.value[0]

    call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM,
        handles[0], True)

    event = q.expect('stream-presence', to='[email protected]/test')
    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', '*****@*****.**', 'test'))

    event = q.expect('dbus-return', method='RequestChannel')
    return handles[0], event.value[0]
def test(q, bus, conn, stream):
    iq_event = q.expect('stream-iq',
                        to=None,
                        query_ns='vcard-temp',
                        query_name='vCard')

    acknowledge_iq(stream, iq_event.stanza)

    # muc stream tube
    call_async(
        q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: '*****@*****.**',
            cs.STREAM_TUBE_SERVICE: 'test'
        })

    q.expect('stream-presence', to='[email protected]/test')

    # Send presence for other member of room.
    stream.send(
        make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob'))

    # Send presence for own membership of room.
    stream.send(
        make_muc_presence('owner', 'moderator', '*****@*****.**', 'test'))

    _, event = q.expect_many(
        EventPattern(
            'dbus-signal',
            signal='MembersChangedDetailed',
            predicate=lambda e: len(e.args[0]) == 2 and  # added
            e.args[1] == [] and  # removed
            e.args[2] == [] and  # local pending
            e.args[3] == [] and  # remote pending
            e.args[4].get('actor', 0) == 0 and e.args[4].get(
                'change-reason', 0) == 0 and
            set([e.args[4]['contact-ids'][h] for h in e.args[0]]) == set(
                ['[email protected]/test', '[email protected]/bob'])),
        EventPattern('dbus-return', method='CreateChannel'))

    path = event.value[0]
    props = event.value[1]

    tube = bus.get_object(conn.bus_name, path)
    stream_tubes_types = tube.Get(cs.CHANNEL_TYPE_STREAM_TUBE,
                                  'SupportedSocketTypes',
                                  dbus_interface=cs.PROPERTIES_IFACE)

    if os.name == 'posix':
        assert cs.SOCKET_ACCESS_CONTROL_LOCALHOST in \
            stream_tubes_types[cs.SOCKET_ADDRESS_TYPE_UNIX], \
            stream_tubes_types[cs.SOCKET_ADDRESS_TYPE_UNIX]
        # so far we only guarantee to support credentials-passing on Linux
        if sys.platform == 'linux2':
            assert cs.SOCKET_ACCESS_CONTROL_CREDENTIALS in \
                stream_tubes_types[cs.SOCKET_ADDRESS_TYPE_UNIX], \
                stream_tubes_types[cs.SOCKET_ADDRESS_TYPE_UNIX]

    assertEquals(
        [cs.SOCKET_ACCESS_CONTROL_LOCALHOST, cs.SOCKET_ACCESS_CONTROL_PORT],
        stream_tubes_types[cs.SOCKET_ADDRESS_TYPE_IPV4])
    assertEquals(
        [cs.SOCKET_ACCESS_CONTROL_LOCALHOST, cs.SOCKET_ACCESS_CONTROL_PORT],
        stream_tubes_types[cs.SOCKET_ADDRESS_TYPE_IPV6])
Example #17
0
def run_incoming_test(q, bus, conn, stream, bob_leaves_room = False):
    jp = JingleProtocol031 ()
    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', muc + "/bob")
    jt.prepare()
    forbidden = [ no_muji_presences (muc) ]

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

    _, _, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, muc)

    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    muji =  ('muji', ns.MUJI, {},
        [('content', ns.MUJI, { "name": "Voice" },
            [( 'description', ns.JINGLE_RTP, {"media": "audio"},
            jt.generate_payloads(jt.audio_codecs))])])
    presence.addChild(jp._simple_xml(muji))

    stream.send(presence)

    e = q.expect ('dbus-signal',
        signal='NewChannels',
        predicate=lambda e: \
            e.args[0][0][1][cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_CALL )

    (path, props) = e.args[0][0]

    assertContains((cs.CHANNEL_TYPE_CALL + '.InitialAudio', True),
        props.items())
    assertContains((cs.CHANNEL_TYPE_CALL + '.InitialVideo', False),
        props.items())

    general_tests (jp, q, bus, conn, stream, path, props)

    channel = bus.get_object (conn.bus_name, path)
    props = channel.GetAll (cs.CHANNEL_TYPE_CALL,
        dbus_interface = dbus.PROPERTIES_IFACE)

    content = bus.get_object (conn.bus_name, props['Contents'][0])

    check_state (q, channel, cs.CALL_STATE_PENDING_RECEIVER)

    md = jt.get_call_audio_md_dbus()
    check_and_accept_offer (q, bus, conn, self_handle,
            content, md)
    channel.Accept (dbus_interface=cs.CHANNEL_TYPE_CALL)

    # Preparing stanza
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Codecs stanza
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Gabble shouldn't send new presences for a while
    q.forbid_events(forbidden)

    e = q.expect ('dbus-signal', signal = 'StreamsAdded')
    cstream = bus.get_object (conn.bus_name, e.args[0][0])

    cstream.SetCredentials(jt.ufrag, jt.pwd,
        dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

    candidates = jt.get_call_remote_transports_dbus ()
    cstream.AddCandidates (candidates,
        dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

    e = q.expect('stream-iq',
        predicate=jp.action_predicate('session-initiate'))
    jt.parse_session_initiate (e.query)

    jt.accept()

   # Bob adds a Video content
    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    presence.addElement ((ns.MUJI, 'muji')).addElement('preparing')
    stream.send(presence)

    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    muji =  ('muji', ns.MUJI, {},
        [('content', ns.MUJI, { "name": "Voice" },
            [( 'description', ns.JINGLE_RTP, {"media": "audio"},
            jt.generate_payloads(jt.audio_codecs))]),
         ('content', ns.MUJI, { "name": "Camera" },
            [( 'description', ns.JINGLE_RTP, {"media": "video"},
            jt.generate_payloads(jt.video_codecs))]),
        ])
    presence.addChild(jp._simple_xml(muji))
    stream.send(presence)

    # Gabble noticed bob added a content
    e = q.expect('dbus-signal', signal = 'ContentAdded')

    q.unforbid_events (forbidden)
    content = bus.get_object (conn.bus_name, e.args[0])
    check_and_accept_offer (q, bus, conn, self_handle,
            content, jt.get_call_video_codecs_dbus(),
            check_codecs_changed = False)

    # Gabble sends a presence to prepare
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Gabble sends a presence with the video codecs
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Gabble adds a content to the jingle session and thus a stream is added
    e = q.expect ('dbus-signal', signal = 'StreamsAdded')
    cstream = bus.get_object (conn.bus_name, e.args[0][0])

    candidates = jt.get_call_remote_transports_dbus ()
    cstream.AddCandidates (candidates,
        dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

    # And now the content-add on the jingle streams
    e = q.expect('stream-iq', to = muc + "/bob",
        predicate = lambda x: \
        xpath.queryForNodes("/iq/jingle[@action='content-add']", x.stanza))

    # Bob leaves the call, bye bob
    if bob_leaves_room:
        presence = make_muc_presence('owner', 'moderator', muc, 'bob')
        presence['type'] = 'unavailable'
    else:
        presence = make_muc_presence('owner', 'moderator', muc, 'bob')

    stream.send(presence)
    (cmembers, _, _) = q.expect_many(
        EventPattern ('dbus-signal', signal = 'CallMembersChanged'),
        # Audio and video stream
        EventPattern ('dbus-signal', signal = 'StreamsRemoved'),
        EventPattern ('dbus-signal', signal = 'StreamsRemoved'))


    # Just bob left
    assertLength (1, cmembers.args[1])
def test(q, bus, conn, stream, access_control):
    iq_event = q.expect('stream-iq',
                        to=None,
                        query_ns='vcard-temp',
                        query_name='vCard')

    acknowledge_iq(stream, iq_event.stanza)

    muc = '*****@*****.**'
    _, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, muc)

    # Bob offers a stream tube
    bob_bus_name = ':2.Ym9i'
    presence = make_muc_presence('owner', 'moderator', '*****@*****.**',
                                 'bob')
    tubes = presence.addElement((ns.TUBES, 'tubes'))
    tube = tubes.addElement((None, 'tube'))
    tube['type'] = 'dbus'
    tube['initiator'] = '[email protected]/bob'
    tube['stream-id'] = '10'
    tube['id'] = '1'
    tube['service'] = 'com.example.Test'
    tube['dbus-name'] = bob_bus_name
    parameters = tube.addElement((None, 'parameters'))
    parameter = parameters.addElement((None, 'parameter'))
    parameter['type'] = 'str'
    parameter['name'] = 'foo'
    parameter.addContent('bar')
    stream.send(presence)

    # tube channel is created
    def new_chan_predicate(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE

    event = q.expect('dbus-signal',
                     signal='NewChannels',
                     predicate=new_chan_predicate)
    channels = event.args[0]
    path, props = channels[0]

    assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE])
    assertEquals('[email protected]/bob', props[cs.INITIATOR_ID])
    bob_handle = props[cs.INITIATOR_HANDLE]
    assertSameSets([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE],
                   props[cs.INTERFACES])
    assertEquals(False, props[cs.REQUESTED])
    assertEquals('*****@*****.**', props[cs.TARGET_ID])
    assertEquals('com.example.Test', props[cs.DBUS_TUBE_SERVICE_NAME])
    assertEquals({'foo': 'bar'}, props[cs.TUBE_PARAMETERS])
    assertEquals([
        cs.SOCKET_ACCESS_CONTROL_CREDENTIALS,
        cs.SOCKET_ACCESS_CONTROL_LOCALHOST
    ], props[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS])

    tube_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'DBusTube')

    # only Bob is in DBusNames
    dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE,
                               'DBusNames',
                               dbus_interface=cs.PROPERTIES_IFACE)
    assertEquals({bob_handle: bob_bus_name}, dbus_names)

    call_async(q, tube_chan.DBusTube, 'Accept', access_control)

    return_event, names_changed1, names_changed2, presence_event = q.expect_many(
        EventPattern('dbus-return', method='Accept'),
        EventPattern('dbus-signal',
                     signal='DBusNamesChanged',
                     interface=cs.CHANNEL_TYPE_DBUS_TUBE),
        EventPattern('dbus-signal',
                     signal='DBusNamesChanged',
                     interface=cs.CHANNEL_TYPE_DBUS_TUBE),
        EventPattern('stream-presence',
                     to='[email protected]/test',
                     predicate=lambda e: t.presence_contains_tube(e)))

    tube_addr = return_event.value[0]
    assert len(tube_addr) > 0

    # check presence stanza
    tube_node = xpath.queryForNodes('/presence/tubes/tube',
                                    presence_event.stanza)[0]
    assertEquals('[email protected]/bob', tube_node['initiator'])
    assertEquals('com.example.Test', tube_node['service'])
    assertEquals('10', tube_node['stream-id'])
    assertEquals('dbus', tube_node['type'])
    assertEquals('1', tube_node['id'])
    self_bus_name = tube_node['dbus-name']

    tubes_self_handle = tube_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP,
                                                 'SelfHandle')
    assertNotEquals(0, tubes_self_handle)

    # both of us are in DBusNames now
    dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE,
                               'DBusNames',
                               dbus_interface=cs.PROPERTIES_IFACE)
    assertEquals({
        bob_handle: bob_bus_name,
        tubes_self_handle: self_bus_name
    }, dbus_names)

    added, removed = names_changed1.args
    assertEquals({bob_handle: bob_bus_name}, added)
    assertEquals([], removed)

    added, removed = names_changed2.args
    assertEquals({tubes_self_handle: self_bus_name}, added)
    assertEquals([], removed)

    tube_chan.Channel.Close()
    q.expect_many(EventPattern('dbus-signal', signal='Closed'),
                  EventPattern('dbus-signal', signal='ChannelClosed'))
Example #19
0
def test(q, bus, conn, stream):
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    # When Gabble initially requests its avatar from the server, it discovers
    # it has none.
    expect_and_handle_get_vcard(q, stream)
    handle, signalled_token = q.expect('dbus-signal',
                                       signal='AvatarUpdated').args

    assertEquals(self_handle, handle)
    assertEquals('', signalled_token)

    # The user sets an avatar.
    call_async(q, conn.Avatars, 'SetAvatar', AVATAR_1_DATA, AVATAR_1_MIME_TYPE)
    expect_and_handle_get_vcard(q, stream)
    expect_and_handle_set_vcard(q, stream)

    # It's signalled on D-Bus …
    set_ret, avatar_updated = q.expect_many(
        EventPattern('dbus-return', method='SetAvatar'),
        EventPattern('dbus-signal', signal='AvatarUpdated'),
    )

    returned_token, = set_ret.value
    handle, signalled_token = avatar_updated.args

    assertEquals(self_handle, handle)
    assertEquals(returned_token, signalled_token)

    # … and also on XMPP.
    broadcast = q.expect('stream-presence', to=None)
    broadcast_hash = extract_hash_from_presence(broadcast.stanza)
    assertEquals(AVATAR_1_SHA1, broadcast_hash)

    # If applications ask Gabble for information about the user's own avatar,
    # it should be able to answer. (Strictly speaking, expecting Gabble to know
    # the avatar data is risky because Gabble discards cached vCards after a
    # while, but we happen to know it takes 20 seconds or so for that to
    # happen.)
    known = conn.Avatars.GetKnownAvatarTokens([self_handle])
    assertEquals({self_handle: signalled_token}, known)

    conn.Avatars.RequestAvatars([self_handle])
    retrieved = q.expect('dbus-signal', signal='AvatarRetrieved')
    handle, token, data, mime_type = retrieved.args
    assertEquals(self_handle, handle)
    assertEquals(signalled_token, token)
    assertEquals(AVATAR_1_DATA, data)
    assertEquals(AVATAR_1_MIME_TYPE, mime_type)

    # Well, that was quite easy. How about we join a MUC? XEP-0153 §4.1 says:
    #     If a client supports the protocol defined herein, it […] SHOULD
    #     also include the update child in directed presence stanzas (e.g.,
    #     directed presence sent when joining Multi-User Chat [5] rooms).
    #         — http://xmpp.org/extensions/xep-0153.html#bizrules-presence
    join_event = try_to_join_muc(q, bus, conn, stream, MUC)
    directed_hash = extract_hash_from_presence(join_event.stanza)
    assertEquals(AVATAR_1_SHA1, directed_hash)

    # There are two others in the MUC: fredrik has no avatar, wendy has an
    # avatar. We, of course, have our own avatar.
    stream.send(make_muc_presence('none', 'participant', MUC, 'fredrik'))
    stream.send(
        make_muc_presence('none',
                          'participant',
                          MUC,
                          'wendy',
                          photo=AVATAR_2_SHA1))
    stream.send(
        make_muc_presence('owner',
                          'moderator',
                          MUC,
                          'test',
                          photo=AVATAR_1_SHA1))

    path, _ = q.expect('dbus-return', method='CreateChannel').value
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    members = chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'Members')
    assertLength(3, members)

    fredrik, wendy, muc_self_handle = conn.get_contact_handles_sync(
        ['%s/%s' % (MUC, x) for x in ["fredrik", "wendy", "test"]])

    known = conn.Avatars.GetKnownAvatarTokens(members)
    # <https://bugs.freedesktop.org/show_bug.cgi?id=32017>: this assertion
    # failed, the MUC self handle's token was the empty string.
    assertEquals(AVATAR_1_SHA1, known[muc_self_handle])
    assertEquals(AVATAR_2_SHA1, known[wendy])
    assertEquals('', known[fredrik])

    # 'k, cool. Wendy loves our avatar and switches to it.
    stream.send(
        make_muc_presence('none',
                          'participant',
                          MUC,
                          'wendy',
                          photo=AVATAR_1_SHA1))
    # Okay this is technically assuming that we just expose the SHA1 sums
    # directly which is not guaranteed … but we do.
    q.expect('dbus-signal',
             signal='AvatarUpdated',
             args=[wendy, AVATAR_1_SHA1])

    # Fredrik switches too.
    stream.send(
        make_muc_presence('none',
                          'participant',
                          MUC,
                          'fredrik',
                          photo=AVATAR_1_SHA1))
    q.expect('dbus-signal',
             signal='AvatarUpdated',
             args=[fredrik, AVATAR_1_SHA1])

    # And we switch to some other avatar. Gabble should update its vCard, and
    # then update its MUC presence (which the test, acting as the MUC server,
    # must echo).
    call_async(q, conn.Avatars, 'SetAvatar', AVATAR_2_DATA, AVATAR_2_MIME_TYPE)
    expect_and_handle_get_vcard(q, stream)
    expect_and_handle_set_vcard(q, stream)

    muc_presence = q.expect('stream-presence', to=('%s/test' % MUC))
    directed_hash = extract_hash_from_presence(muc_presence.stanza)
    stream.send(
        make_muc_presence('owner',
                          'moderator',
                          MUC,
                          'test',
                          photo=directed_hash))

    # Gabble should signal an avatar update for both our global self-handle and
    # our MUC self-handle. (The first of these of course does not need to wait
    # for the MUC server to echo our presence.)
    q.expect_many(
        EventPattern('dbus-signal',
                     signal='AvatarUpdated',
                     args=[self_handle, AVATAR_2_SHA1]),
        EventPattern('dbus-signal',
                     signal='AvatarUpdated',
                     args=[muc_self_handle, AVATAR_2_SHA1]),
    )
Example #20
0
def test_role_changes(q, bus, conn, stream):
    # The test user joins a room. Bob is an owner (and moderator); the test
    # user starts out with no affiliation and the rôle of participant.
    MUC = 'aoeu@snth'
    chan, _, immutable_props, disco = join_muc(q,
                                               bus,
                                               conn,
                                               stream,
                                               MUC,
                                               role='participant',
                                               also_capture=[
                                                   EventPattern(
                                                       'stream-iq',
                                                       to=MUC,
                                                       iq_type='get',
                                                       query_ns=ns.DISCO_INFO),
                                               ])
    assertContains(cs.CHANNEL_IFACE_ROOM_CONFIG,
                   immutable_props[cs.INTERFACES])

    handle_disco_info_iq(stream, disco.stanza)
    q.expect('dbus-signal',
             signal='PropertiesChanged',
             args=[
                 cs.CHANNEL_IFACE_ROOM_CONFIG, {
                     'ConfigurationRetrieved': True
                 }, []
             ])

    # If we try to change the configuration, Gabble should say no: it knows
    # we're not allowed to do that.
    call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {})
    q.expect('dbus-error', name=cs.PERMISSION_DENIED)

    config = chan.Properties.GetAll(cs.CHANNEL_IFACE_ROOM_CONFIG)
    assert not config['CanUpdateConfiguration'], config

    # If we acquire affiliation='owner', this should be signalled as our
    # becoming able to modify the channel configuration.
    stream.send(make_muc_presence('owner', 'moderator', MUC, 'test'))
    q.expect('dbus-signal',
             signal='PropertiesChanged',
             args=[
                 cs.CHANNEL_IFACE_ROOM_CONFIG, {
                     'CanUpdateConfiguration': True
                 }, []
             ])

    # Due to silliness, Gabble has to grab the owner configuration form to see
    # whether it's possible to change the room description.
    owner_iq = q.expect('stream-iq',
                        to=MUC,
                        iq_type='get',
                        query_ns=ns.MUC_OWNER)
    handle_muc_owner_get_iq(stream, owner_iq.stanza)

    # Bob's ownership rights being taken away should have no effect.
    stream.send(make_muc_presence('none', 'participant', MUC, 'bob'))

    # So now we're an owner, and CanUpdateConfiguration is True, we should be
    # able to change some configuration.
    props = dbus.Dictionary({
        'Persistent': True,
    }, signature='sv')
    call_async(q, chan.RoomConfig1, 'UpdateConfiguration', props)

    owner_iq = q.expect('stream-iq',
                        to=MUC,
                        iq_type='get',
                        query_ns=ns.MUC_OWNER)
    handle_muc_owner_get_iq(stream, owner_iq.stanza)

    event = q.expect('stream-iq', to=MUC, iq_type='set', query_ns=ns.MUC_OWNER)
    handle_muc_owner_set_iq(stream, event.stanza,
                            {'muc#roomconfig_persistentroom': ['1']})

    q.expect_many(
        EventPattern('dbus-return', method='UpdateConfiguration'),
        EventPattern(
            'dbus-signal',
            signal='PropertiesChanged',
            args=[cs.CHANNEL_IFACE_ROOM_CONFIG, {
                'Persistent': True
            }, []]))

    # If we lose our affiliation, that should be signalled too.
    stream.send(make_muc_presence('none', 'participant', MUC, 'test'))
    q.expect('dbus-signal',
             signal='PropertiesChanged',
             args=[
                 cs.CHANNEL_IFACE_ROOM_CONFIG, {
                     'CanUpdateConfiguration': False
                 }, []
             ])

    # Gabble should once again reject attempts to change the configuration
    call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {})
    q.expect('dbus-error', name=cs.PERMISSION_DENIED)
def test(q, bus, conn, stream):
    conn.Connect()

    q.expect('dbus-signal', signal='StatusChanged',
            args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])

    # Need to call this asynchronously as it involves Gabble sending us a
    # query
    call_async(q, conn, 'RequestHandles', 2, ['*****@*****.**'])

    event = q.expect('stream-iq', to='conf.localhost',
        query_ns='http://jabber.org/protocol/disco#info')
    result = make_result_iq(stream, event.stanza)
    feature = result.firstChildElement().addElement('feature')
    feature['var'] = 'http://jabber.org/protocol/muc'
    stream.send(result)

    event = q.expect('dbus-return', method='RequestHandles')
    room_handle = event.value[0][0]

    call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM,
        room_handle, True)

    gfc, _, _ = q.expect_many(
        EventPattern('dbus-signal', signal='GroupFlagsChanged'),
        EventPattern('dbus-signal', signal='MembersChanged',
            args=[u'', [], [], [], [2], 0, 0]),
        EventPattern('stream-presence', to='[email protected]/test'))
    assert gfc.args[1] == 0

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

    # Send presence for anonymous other member of room.
    stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob'))

    # Send presence for anonymous other member of room (2)
    stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'brian'))

    # Send presence for nonymous other member of room.
    stream.send(make_muc_presence('none', 'participant', '*****@*****.**',
        'che', '*****@*****.**'))

    # Send presence for nonymous other member of room (2)
    stream.send(make_muc_presence('none', 'participant', '*****@*****.**',
        'chris', '*****@*****.**'))

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', '*****@*****.**', 'test'))

    event = q.expect('dbus-signal', signal='GroupFlagsChanged')
    # Since we received MUC presence that contains an owner JID, the
    # OWNERS_NOT_AVAILABLE flag should be removed.
    assert event.args == [0, 1024]

    event = q.expect('dbus-signal', signal='HandleOwnersChanged',
        args=[{2: 1, 3: 0, 4: 0, 5: 6, 7: 8}, []])

    event = q.expect('dbus-signal', signal='MembersChanged',
        args=[u'', [2, 3, 4, 5, 7], [], [], [], 0, 0])
    assert conn.InspectHandles(1, [2]) == ['[email protected]/test']
    assert conn.InspectHandles(1, [3]) == ['[email protected]/bob']
    assert conn.InspectHandles(1, [4]) == ['[email protected]/brian']
    assert conn.InspectHandles(1, [5]) == ['[email protected]/che']
    assert conn.InspectHandles(1, [6]) == ['*****@*****.**']
    assert conn.InspectHandles(1, [7]) == ['[email protected]/chris']
    assert conn.InspectHandles(1, [8]) == ['*****@*****.**']

    event = q.expect('dbus-return', method='RequestChannel')

    bus = dbus.SessionBus()
    chan = bus.get_object(conn.bus_name, event.value[0])
    group = dbus.Interface(chan, cs.CHANNEL_IFACE_GROUP)
    props = dbus.Interface(chan, dbus.PROPERTIES_IFACE)

    # Exercise GetHandleOwners
    assert group.GetHandleOwners([5, 7]) == [6, 8]

    # Exercise D-Bus properties
    all = props.GetAll(cs.CHANNEL_IFACE_GROUP)

    assert all[u'LocalPendingMembers'] == [], all
    assert all[u'Members'] == [2, 3, 4, 5, 7], all
    assert all[u'RemotePendingMembers'] == [], all
    assert all[u'SelfHandle'] == 2, all
    assert all[u'HandleOwners'] == { 2: 1, 3: 0, 4: 0, 5: 6, 7: 8 }, all
    assert (all[u'GroupFlags'] & 2048) == 2048, all.get('GroupFlags')
def test_join(q, bus, conn, stream, room_jid, transient_conflict):
    """
    Tells Gabble to join a MUC, but make the first nick it tries conflict with
    an existing member of the MUC.  If transient_conflict is True, then when
    Gabble successfully joins with a different nick the originally conflicting
    user turns out not actually to be in the room (they left while we were
    retrying).
    """
    # Implementation detail: Gabble uses the first part of your jid (if you
    # don't have an alias) as your room nickname, and appends an underscore a
    # few times before giving up.
    member, member_ = [room_jid + '/' + x for x in ['test', 'test_']]

    call_async(
        q, conn.Requests, 'CreateChannel',
        dbus.Dictionary(
            {
                cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
                cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
                cs.TARGET_ID: room_jid,
            },
            signature='sv'))

    # Gabble first tries to join as test
    q.expect('stream-presence', to=member)

    # MUC says no: there's already someone called test in room_jid
    presence = elem('presence', from_=member,
                    type='error')(elem(ns.MUC, 'x'),
                                  elem('error', type='cancel')(elem(
                                      ns.STANZA, 'conflict'), ))
    stream.send(presence)

    # Gabble tries again as test_
    q.expect('stream-presence', to=member_)

    # MUC says yes!

    if not transient_conflict:
        # Send the other member of the room's presence. This is the nick we
        # originally wanted.
        stream.send(make_muc_presence('owner', 'moderator', room_jid, 'test'))

    # If gabble erroneously thinks the other user's presence is our own, it'll
    # think that it's got the whole userlist now. If so, syncing here will make
    # CreateChannel incorrectly return here.
    sync_stream(q, stream)
    sync_dbus(bus, q, conn)

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', room_jid, 'test_'))

    # Only now should we have finished joining the room.
    event = q.expect('dbus-return', method='CreateChannel')
    path, props = event.value
    text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')
    group_props = unwrap(text_chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP))

    t, t_ = conn.get_contact_handles_sync([member, member_])

    # Check that Gabble think our nickname in the room is test_, not test
    muc_self_handle = group_props['SelfHandle']
    assert muc_self_handle == t_, (muc_self_handle, t_, t)

    members = group_props['Members']

    if transient_conflict:
        # The user we originally conflicted with isn't actually here; check
        # there's exactly one member (test_).
        assert members == [t_], (members, t_, t)
    else:
        # Check there are exactly two members (test and test_)
        assertSameSets([t, t_], members)

    # In either case, there should be no pending members.
    assert len(group_props['LocalPendingMembers']) == 0, group_props
    assert len(group_props['RemotePendingMembers']) == 0, group_props

    # Check that test_'s handle owner is us, and that test (if it's there) has
    # no owner.
    handle_owners = group_props['HandleOwners']
    assertEquals(conn.Properties.Get(cs.CONN, "SelfHandle"), handle_owners[t_])
    if not transient_conflict:
        assertEquals(0, handle_owners[t])

    # test that closing the channel results in an unavailable message to the
    # right jid
    text_chan.Close()

    event = q.expect('stream-presence', to=member_)
    assertEquals('unavailable', event.stanza['type'])
def test(q, bus, conn, stream, access_control):
    conn.Connect()

    _, iq_event = q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged',
            args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]),
        EventPattern('stream-iq', to=None, query_ns='vcard-temp',
            query_name='vCard'))

    acknowledge_iq(stream, iq_event.stanza)

    muc = '*****@*****.**'
    _, _, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, muc)

    # Bob offers a stream tube
    bob_bus_name = ':2.Ym9i'
    presence = make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob')
    tubes = presence.addElement((ns.TUBES, 'tubes'))
    tube = tubes.addElement((None, 'tube'))
    tube['type'] = 'dbus'
    tube['initiator'] = '[email protected]/bob'
    tube['stream-id'] = '10'
    tube['id'] = '1'
    tube['service'] = 'com.example.Test'
    tube['dbus-name'] = bob_bus_name
    parameters = tube.addElement((None, 'parameters'))
    parameter = parameters.addElement((None, 'parameter'))
    parameter['type'] = 'str'
    parameter['name'] = 'foo'
    parameter.addContent('bar')
    stream.send(presence)

    # tubes channel is created
    event = q.expect('dbus-signal', signal='NewChannels')
    channels = event.args[0]
    path, props = channels[0]

    # tube channel is created
    event = q.expect('dbus-signal', signal='NewChannels')
    channels = event.args[0]
    path, props = channels[0]

    assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE])
    assertEquals('[email protected]/bob', props[cs.INITIATOR_ID])
    bob_handle = props[cs.INITIATOR_HANDLE]
    assertEquals([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE],
        props[cs.INTERFACES])
    assertEquals(False, props[cs.REQUESTED])
    assertEquals('*****@*****.**', props[cs.TARGET_ID])
    assertEquals('com.example.Test', props[cs.DBUS_TUBE_SERVICE_NAME])
    assertEquals({'foo': 'bar'}, props[cs.TUBE_PARAMETERS])
    assertEquals([cs.SOCKET_ACCESS_CONTROL_CREDENTIALS,
                    cs.SOCKET_ACCESS_CONTROL_LOCALHOST],
        props[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS])

    tube_chan = bus.get_object(conn.bus_name, path)
    tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_IFACE_TUBE)
    dbus_tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_DBUS_TUBE)
    tube_chan_iface = dbus.Interface(tube_chan, cs.CHANNEL)

    # only Bob is in DBusNames
    dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', dbus_interface=cs.PROPERTIES_IFACE)
    assertEquals({bob_handle: bob_bus_name}, dbus_names)

    call_async(q, dbus_tube_iface, 'Accept', access_control)

    return_event, names_changed1, names_changed2, presence_event = q.expect_many(
        EventPattern('dbus-return', method='Accept'),
        EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE),
        EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE),
        EventPattern('stream-presence', to='[email protected]/test'))

    tube_addr = return_event.value[0]
    assert len(tube_addr) > 0

    # check presence stanza
    tube_node = xpath.queryForNodes('/presence/tubes/tube', presence_event.stanza)[0]
    assertEquals('[email protected]/bob', tube_node['initiator'])
    assertEquals('com.example.Test', tube_node['service'])
    assertEquals('10', tube_node['stream-id'])
    assertEquals('dbus', tube_node['type'])
    assertEquals('1', tube_node['id'])
    self_bus_name = tube_node['dbus-name']

    tubes_self_handle = tube_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP)
    assertNotEquals(0, tubes_self_handle)

    # both of us are in DBusNames now
    dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', dbus_interface=cs.PROPERTIES_IFACE)
    assertEquals({bob_handle: bob_bus_name, tubes_self_handle: self_bus_name}, dbus_names)

    added, removed = names_changed1.args
    assertEquals({bob_handle: bob_bus_name}, added)
    assertEquals([], removed)

    added, removed = names_changed2.args
    assertEquals({tubes_self_handle: self_bus_name}, added)
    assertEquals([], removed)

    tube_chan_iface.Close()
    q.expect_many(
        EventPattern('dbus-signal', signal='Closed'),
        EventPattern('dbus-signal', signal='ChannelClosed'))
def test(q, bus, conn, stream):
    handles = {}
    handles['bob'] = conn.get_contact_handle_sync('bob@localhost')

    buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo')
    act_prop_iface = dbus.Interface(conn,
                                    'org.laptop.Telepathy.ActivityProperties')
    call_async(q, buddy_iface, 'GetActivities', handles['bob'])

    event = q.expect('stream-iq', iq_type='get', to='bob@localhost')
    # Bob has no activities
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'bob@localhost'
    stream.send(event.stanza)

    event = q.expect('dbus-return', method='GetActivities')
    # initially, Bob has no activities
    assert event.value == ([], )

    # Bob sends an activity properties message
    message = domish.Element(('jabber:client', 'message'))
    message['from'] = 'bob@localhost'
    message['to'] = 'test@localhost'
    properties = message.addElement((ns.OLPC_ACTIVITY_PROPS, 'properties'))
    properties['room'] = '*****@*****.**'
    properties['activity'] = 'foo_id'
    property = properties.addElement((None, 'property'))
    property['type'] = 'str'
    property['name'] = 'color'
    property.addContent('#ffff00,#00ffff')
    property = properties.addElement((None, 'property'))
    property['type'] = 'bool'
    property['name'] = 'private'
    property.addContent('1')

    stream.send(message)

    event = q.expect('dbus-signal', signal='ActivityPropertiesChanged')
    handles['chat'], props = event.args
    assert props == {'color': '#ffff00,#00ffff', 'private': True}

    event = q.expect('dbus-signal', signal='ActivitiesChanged')
    assert event.args[0] == handles['bob']
    acts = event.args[1]
    assert len(acts) == 1
    assert acts[0] == ('foo_id', handles['chat'])

    props = act_prop_iface.GetProperties(handles['chat'])
    assert props == {'color': '#ffff00,#00ffff', 'private': True}

    # Bobs invites us to the activity
    message = domish.Element((None, 'message'))
    message['from'] = '*****@*****.**'
    message['to'] = 'test@localhost'
    x = message.addElement((ns.MUC_USER, 'x'))
    invite = x.addElement((None, 'invite'))
    invite['from'] = 'bob@localhost'
    reason = invite.addElement((None, 'reason'))
    reason.addContent('No good reason')

    stream.send(message)

    event = q.expect('dbus-signal', signal='NewChannel')
    assert event.args[1] == cs.CHANNEL_TYPE_TEXT

    assert event.args[2] == 2  # handle type
    assert event.args[3] == handles['chat']  # handle

    text_chan = wrap_channel(bus.get_object(conn.bus_name, event.args[0]),
                             'Text')
    group_iface = text_chan.Group

    members = group_iface.GetAllMembers()[0]
    local_pending = group_iface.GetAllMembers()[1]
    remote_pending = group_iface.GetAllMembers()[2]

    assert len(members) == 1
    assert conn.inspect_contact_sync(members[0]) == 'bob@localhost'
    assert len(local_pending) == 1
    # FIXME: the username-part-is-nickname assumption
    assert conn.inspect_contact_sync(local_pending[0]) == \
            '[email protected]/test'
    assert len(remote_pending) == 0

    handles['chat_self'] = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP,
                                                    "SelfHandle")
    assert handles['chat_self'] == local_pending[0]

    # by now, we should have picked up the extra activity properties
    call_async(q, buddy_iface, 'GetActivities', handles['bob'])

    event = q.expect('stream-iq', iq_type='get', to='bob@localhost')
    # Bob still has no (public) activities
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'bob@localhost'
    stream.send(event.stanza)

    event = q.expect('dbus-return', method='GetActivities')

    assert event.value == ([('foo_id', handles['chat'])], )

    # OK, now accept the invitation
    call_async(q, group_iface, 'AddMembers', [handles['chat_self']],
               'Oh, OK then')

    _, event, _ = q.expect_many(
        EventPattern('stream-presence', to='[email protected]/test'),
        EventPattern('dbus-signal', signal='MembersChanged'),
        EventPattern('dbus-return', method='AddMembers'))

    assert event.args == [
        '', [], [handles['bob']], [], [handles['chat_self']], 0,
        cs.GC_REASON_INVITED
    ]

    # Send presence for own membership of room.
    stream.send(
        make_muc_presence('owner', 'moderator', '*****@*****.**', 'test'))

    event = q.expect('dbus-signal', signal='MembersChanged')
    assert event.args == ['', [handles['chat_self']], [], [], [], 0, 0]

    call_async(q, buddy_iface, 'SetActivities', [('foo_id', handles['chat'])])

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    q.expect('dbus-return', method='SetActivities')
    call_async(q, act_prop_iface, 'SetProperties', handles['chat'], {
        'color': '#ffff00,#00ffff',
        'private': True
    })

    event = q.expect('dbus-signal', signal='ActivityPropertiesChanged')
    chat_handle, props = event.args
    assert chat_handle == handles['chat']
    assert props == {'color': '#ffff00,#00ffff', 'private': True}

    q.expect('dbus-return', method='SetProperties')
    # Test sending an invitation
    handles['alice'] = conn.get_contact_handle_sync('alice@localhost')
    call_async(q, group_iface, 'AddMembers', [handles['alice']],
               'I want to test invitations')

    event = q.expect('stream-message', to='alice@localhost')
    message = event.stanza

    properties = xpath.queryForNodes('/message/properties', message)
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'color':
            assert p['type'] == 'str'
            assert str(p) == '#ffff00,#00ffff'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '1'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'color' in seen, seen
    assert 'private' in seen, seen

    event = q.expect('stream-message', to='*****@*****.**')
    message = event.stanza

    x = xpath.queryForNodes('/message/x', message)
    assert (x is not None and len(x) == 1), repr(x)
    assert x[0].uri == ns.MUC_USER

    invites = xpath.queryForNodes('/x/invite', x[0])
    assert (invites is not None and len(invites) == 1), repr(invites)
    assert invites[0]['to'] == 'alice@localhost'

    reasons = xpath.queryForNodes('/invite/reason', invites[0])
    assert (reasons is not None and len(reasons) == 1), repr(reasons)
    assert str(reasons[0]) == 'I want to test invitations'

    call_async(q, act_prop_iface, 'SetProperties', handles['chat'], {
        'color': '#f00baa,#f00baa',
        'private': True
    })

    event, apc_event, _ = q.expect_many(
        EventPattern('stream-message', to='alice@localhost'),
        EventPattern('dbus-signal', signal='ActivityPropertiesChanged'),
        EventPattern('dbus-return', method='SetProperties'),
    )
    message = event.stanza

    properties = xpath.queryForNodes('/message/properties', message)
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'color':
            assert p['type'] == 'str'
            assert str(p) == '#f00baa,#f00baa'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '1'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'color' in seen, seen
    assert 'private' in seen, seen

    chat_handle, props = apc_event.args
    assert chat_handle == handles['chat']
    assert props == {'color': '#f00baa,#f00baa', 'private': True}
def send_muc_presence(q, stream, jid):
    q.expect('stream-presence', to='%s/test' % jid)

    stream.send(make_muc_presence('owner', 'moderator', jid, 'bob'))
    stream.send(make_muc_presence('none', 'participant', jid, 'test'))
def test(q, bus, conn, stream):
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    requests = dbus.Interface(conn, CONN_IFACE_REQUESTS)

    room_jid = '*****@*****.**'

    call_async(
        q, requests, 'CreateChannel',
        dbus.Dictionary(
            {
                CHANNEL_TYPE: CHANNEL_TYPE_TEXT,
                TARGET_HANDLE_TYPE: HT_ROOM,
                TARGET_ID: room_jid,
            },
            signature='sv'))

    expected_jid = '%s/%s' % (room_jid, 'test')

    q.expect('stream-presence', to=expected_jid)

    # Send presence for another member of the MUC
    stream.send(make_muc_presence('owner', 'moderator', room_jid, 'liz'))

    # This is a themed discussion, so the MUC server forces you to have an
    # appropriate name.
    self_presence = make_muc_presence('none', 'participant', room_jid,
                                      'toofer')
    x = [elt for elt in self_presence.elements() if elt.name == 'x'][0]
    status = x.addElement('status')
    status['code'] = '110'  # "This is you"
    status = x.addElement('status')
    status['code'] = '210'  # "I renamed you. Muahaha."
    stream.send(self_presence)

    # Gabble should figure out from 110 that it's in the room, and from 210
    # that we've been renamed.
    event = q.expect('dbus-return', method='CreateChannel')
    path, props = event.value
    text_chan = bus.get_object(conn.bus_name, path)
    group_props = unwrap(
        text_chan.GetAll(CHANNEL_IFACE_GROUP,
                         dbus_interface=dbus.PROPERTIES_IFACE))

    liz, toofer, expected_handle = conn.get_contact_handles_sync(
        ["%s/%s" % (room_jid, m) for m in ['liz', 'toofer', 'test']])

    # Check that Gabble think our nickname in the room is toofer not test
    muc_self_handle = group_props['SelfHandle']
    assert muc_self_handle == toofer, (muc_self_handle, toofer,
                                       expected_handle)

    members = group_props['Members']

    # Check there are exactly two members (liz and toofer)
    expected_members = [liz, toofer]
    assert sorted(members) == sorted(expected_members), \
        (members, expected_members)

    # There should be no pending members.
    assert len(group_props['LocalPendingMembers']) == 0, group_props
    assert len(group_props['RemotePendingMembers']) == 0, group_props

    # Check that toofer's handle owner is us, and that liz has
    # no owner.
    handle_owners = group_props['HandleOwners']
    assert handle_owners[toofer] == self_handle, \
        (handle_owners, toofer, handle_owners[toofer], self_handle)
    assert handle_owners[liz] == 0, (handle_owners, liz)
def test(q, bus, conn, stream):
    # Bob has invited us to an activity.
    message = domish.Element((None, 'message'))
    message['from'] = '*****@*****.**'
    message['to'] = 'test@localhost'
    x = message.addElement(('http://jabber.org/protocol/muc#user', 'x'))
    invite = x.addElement((None, 'invite'))
    invite['from'] = 'bob@localhost'
    reason = invite.addElement((None, 'reason'))
    reason.addContent('No good reason')

    stream.send(message)

    event = q.expect('dbus-signal', signal='NewChannels')
    path, props = event.args[0][0]
    assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE])
    assertEquals(cs.HT_ROOM, props[cs.TARGET_HANDLE_TYPE])
    assertEquals(1, props[cs.TARGET_HANDLE])

    text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    members = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'Members')
    local_pending = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'LocalPendingMembers')
    remote_pending = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'RemotePendingMembers')

    assert len(members) == 1
    assert conn.inspect_contact_sync(members[0]) == 'bob@localhost'
    bob_handle = members[0]
    assert len(local_pending) == 1
    # FIXME: the username-part-is-nickname assumption
    assert conn.inspect_contact_sync(local_pending[0][0]) == \
            '[email protected]/test'
    assert len(remote_pending) == 0

    room_self_handle = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP,
            "SelfHandle")
    assert room_self_handle == local_pending[0][0]

    channel_props = text_chan.Properties.GetAll(cs.CHANNEL)
    assert channel_props['TargetID'] == '*****@*****.**', channel_props
    assert channel_props['Requested'] == False
    assert channel_props['InitiatorID'] == 'bob@localhost'
    assert channel_props['InitiatorHandle'] == bob_handle

    # set ourselves to away and back again, to check that we don't send any
    # presence to the MUC before the invite has been accepted
    conn.SimplePresence.SetPresence('away', 'failure')
    conn.SimplePresence.SetPresence('available', 'success')

    # accept the invitation
    call_async(q, text_chan.Group, 'AddMembers', [room_self_handle], 'Oh, OK then')

    event, event2, _ = q.expect_many(
            EventPattern('stream-presence', to='[email protected]/test'),
            EventPattern('dbus-signal', signal='MembersChangedDetailed'),
            EventPattern('dbus-return', method='AddMembers')
            )

    # check that the status we joined with was available / success
    elem = event.stanza
    show = [e for e in elem.elements() if e.name == 'show']
    assert not show
    status = [e for e in elem.elements() if e.name == 'status'][0]
    assert status
    assert status.children[0] == u'success'

    # We are added as remote pending while joining the room. The inviter (Bob)
    # is removed for now. It will be re-added with his channel specific handle
    # once we have joined.
    added, removed, local_pending, remote_pending, details = event2.args
    assertEquals([], added)
    assertEquals([bob_handle], removed)
    assertEquals([], local_pending)
    assertEquals([room_self_handle], remote_pending)
    assertEquals(cs.GC_REASON_INVITED, details['change-reason'])

    # Send presence for Bob's membership of room.
    stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob'))

    # Send presence for own membership of room.
    stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'test'))

    event = q.expect('dbus-signal', signal='MembersChangedDetailed')

    room_bob_handle = conn.get_contact_handle_sync('[email protected]/bob')

    added, removed, local_pending, remote_pending, details = event.args
    assertEquals([room_self_handle, room_bob_handle], added)
    assertEquals([], removed)
    assertEquals([], local_pending)
    assertEquals([], remote_pending)

    # Test sending an invitation
    alice_handle = conn.get_contact_handle_sync('alice@localhost')
    call_async(q, text_chan.Group, 'AddMembers', [alice_handle],
            'I want to test invitations')

    event = q.expect('stream-message', to='*****@*****.**')
    message = event.stanza

    x = xpath.queryForNodes('/message/x', message)
    assert (x is not None and len(x) == 1), repr(x)
    assert x[0].uri == 'http://jabber.org/protocol/muc#user'

    invites = xpath.queryForNodes('/x/invite', x[0])
    assert (invites is not None and len(invites) == 1), repr(invites)
    assert invites[0]['to'] == 'alice@localhost'

    reasons = xpath.queryForNodes('/invite/reason', invites[0])
    assert (reasons is not None and len(reasons) == 1), repr(reasons)
    assert str(reasons[0]) == 'I want to test invitations'
Example #28
0
def run_outgoing_test(q, bus, conn, stream, close_channel=False):
    jp = JingleProtocol031 ()
    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', muc + '/bob')
    jt.prepare()

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

    # Not allowed to have muji related presences before we accept the channel
    forbidden = [ no_muji_presences (muc) ]

    (path, props) = create_muji_channel (q, conn, stream, muc)

    q.forbid_events(forbidden)
    general_tests (jp, q, bus, conn, stream, path, props)

    channel = bus.get_object (conn.bus_name, path)

    props = channel.GetAll (cs.CHANNEL_TYPE_CALL,
        dbus_interface = dbus.PROPERTIES_IFACE)

    content = bus.get_object (conn.bus_name, props['Contents'][0])


    md = jt.get_call_audio_md_dbus()
    check_and_accept_offer (q, bus, conn, content, md)

    # Accept the channel, which means we can get muji presences
    q.unforbid_events (forbidden)
    channel.Accept()

    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')
    mujinode = xpath.queryForNodes("/presence/muji", e.stanza)
    assertLength (1, mujinode)

    # The one with the codecs
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Gabble shouldn't send new presences for a while
    q.forbid_events(forbidden)

    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    presence.addElement ((ns.MUJI, 'muji')).addElement('preparing')
    stream.send(presence)

    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    muji =  ('muji', ns.MUJI, {},
        [('content', ns.MUJI, { "name": "Audio" },
            [( 'description', ns.JINGLE_RTP, {"media": "audio"},
            jt.generate_payloads(jt.audio_codecs))])])
    presence.addChild(jp._simple_xml(muji))
    stream.send(presence)

    q.expect('dbus-signal', signal = 'CallStateChanged')

    # Bob appears and starts a session right afterwards
    q.expect('dbus-signal', signal = 'CallMembersChanged')

    q.unforbid_events(forbidden)

    e = q.expect('dbus-signal', signal = 'NewMediaDescriptionOffer')
    offer = bus.get_object (conn.bus_name, e.args[0])
    offer.Accept(md, dbus_interface=cs.CALL_CONTENT_MEDIA_DESCRIPTION)

    jt.incoming_call(audio = "Audio")

    e = q.expect ('dbus-signal', signal = 'StreamsAdded')
    cstream = bus.get_object (conn.bus_name, e.args[0][0])

    candidates = jt.get_call_remote_transports_dbus ()
    cstream.AddCandidates (candidates,
        dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

    # Fake our endpoint being connected
    endpoints = cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
        "Endpoints", dbus_interface=dbus.PROPERTIES_IFACE)
    assertLength (1, endpoints)

    endpoint = bus.get_object (conn.bus_name, endpoints[0])

    endpoint.SetEndpointState (1, cs.MEDIA_STREAM_STATE_CONNECTED,
                               dbus_interface=cs.CALL_STREAM_ENDPOINT)
    endpoint.SetEndpointState (2, cs.MEDIA_STREAM_STATE_CONNECTED,
                               dbus_interface=cs.CALL_STREAM_ENDPOINT)

    e = q.expect ('stream-iq',
        predicate = jp.action_predicate ('session-accept'))
    stream.send(jp.xml(jp.ResultIq(jt.peer, e.stanza, [])))

    # But we want video as well !
    c = channel.AddContent ("Camera!", cs.MEDIA_STREAM_TYPE_VIDEO,
        dbus_interface=cs.CHANNEL_TYPE_CALL)

    q.expect('dbus-signal', signal = 'ContentAdded')

    content = bus.get_object (conn.bus_name, c)

    # wait for the CodecOffer and Accept it
    q.expect('dbus-signal', signal = 'NewMediaDescriptionOffer')

    md = jt.get_call_video_md_dbus()
    check_and_accept_offer (q, bus, conn, content, md)
    
    # preparing
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    #codecs
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Bob would like to join our video party
    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    muji =  ('muji', ns.MUJI, {},
        [('content', ns.MUJI, { "name": "Audio" },
            [( 'description', ns.JINGLE_RTP, {"media": "audio"},
            jt.generate_payloads(jt.audio_codecs))]),
         ('content', ns.MUJI, { "name": "Camera!" },
            [( 'description', ns.JINGLE_RTP, {"media": "video"},
            jt.generate_payloads(jt.video_codecs))]),
        ])
    presence.addChild(jp._simple_xml(muji))
    stream.send(presence)

    # new codec offer as bob threw in some codecs
    q.expect('dbus-signal', signal='NewMediaDescriptionOffer')
    check_and_accept_offer (q, bus, conn, self_handle,
            content, codecs, check_codecs_changed = False)

    # Bob sends a content
    node = jp.SetIq(jt.peer, jt.jid, [
        jp.Jingle(jt.sid, jt.peer, 'content-add', [
            jp.Content('videostream', 'initiator', 'both',
                jp.Description('video', [
                    jp.PayloadType(name, str(rate), str(id), parameters) for
                        (name, id, rate, parameters) in jt.video_codecs ]),
            jp.TransportGoogleP2P()) ]) ])
    stream.send(jp.xml(node))

    # We get a new stream
    q.expect('dbus-signal', signal = 'StreamsAdded')

    # Sync up the stream to ensure we sent out all the xmpp traffic that was
    # the result of a stream being added
    sync_stream (q, stream)

    # happiness.. Now let's hang up
    if close_channel:
        channel.Close()
        hangup_event = EventPattern ('dbus-signal', signal = "Closed",
            path = path)
    else:
        channel.Hangup (0, "", "", dbus_interface=cs.CHANNEL_TYPE_CALL)
        hangup_event = EventPattern ('dbus-signal', signal='CallStateChanged')

    # Should change the call state to ended, send a session-terminate to our
    # only peer and send a muc presence without any mention of muji
    q.forbid_events(forbidden)
    q.expect_many (EventPattern ('stream-presence', to = muc + "/test"),
        EventPattern ('stream-iq',
                predicate=jp.action_predicate ('session-terminate')),
        hangup_event)

    if not close_channel:
        channel.Close()
        q.expect ('dbus-signal', signal="Closed", path = path)

    try:
        channel.Close()
        raise AssertionError ("Channel didn't actually close")
    except DBusException:
        pass
Example #29
0
def test(q, bus, conn, stream):
    room = '*****@*****.**'

    call_async(q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: room })

    expected_muc_jid = '%s/%s' % (room, 'test')
    q.expect('stream-presence', to=expected_muc_jid)

    # tell gabble the room needs a password
    denied = \
        elem('jabber:client', 'presence', from_=expected_muc_jid,
            type='error')(
          elem(ns.MUC, 'x'),
          elem('error', type='auth')(
            elem(ns.STANZA, 'not-authorized'),
          ),
        )
    stream.send(denied)

    cc, _, _ = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('dbus-signal', signal='NewChannels'),
        EventPattern('dbus-signal', signal='PasswordFlagsChanged',
            args=[cs.PASSWORD_FLAG_PROVIDE, 0]))

    chan = wrap_channel(bus.get_object(conn.bus_name, cc.value[0]), 'Text')

    flags = chan.Password.GetPasswordFlags()
    assertEquals(cs.PASSWORD_FLAG_PROVIDE, flags)

    call_async(q, chan.Password, 'ProvidePassword', 'brand new benz')
    expect_attempt(q, expected_muc_jid, 'brand new benz')

    # Try again while the first attempt is outstanding. Gabble should say no.
    call_async(q, chan.Password, 'ProvidePassword', 'faster faster')
    q.expect('dbus-error', method='ProvidePassword')

    # Sorry, wrong password.
    stream.send(denied)
    ret = q.expect('dbus-return', method='ProvidePassword')
    assert not ret.value[0]

    call_async(q, chan.Password, 'ProvidePassword', 'bougie friends')
    expect_attempt(q, expected_muc_jid, 'bougie friends')

    # Well, this may be the right password, but actually that nick is in use.
    presence = elem('presence', from_=expected_muc_jid, type='error')(
        elem(ns.MUC, 'x'),
        elem('error', type='cancel')(
          elem(ns.STANZA, 'conflict'),
        ))
    stream.send(presence)

    # Okay, so Gabble tries again, with a new JID *and the same password*.
    expected_muc_jid = expected_muc_jid + '_'
    expect_attempt(q, expected_muc_jid, 'bougie friends')

    # Hey this worked.
    stream.send(make_muc_presence('none', 'participant', room, 'test_'))
    ret, _ = q.expect_many(
        EventPattern('dbus-return', method='ProvidePassword'),
        EventPattern('dbus-signal', signal='PasswordFlagsChanged',
            args=[0, cs.PASSWORD_FLAG_PROVIDE]))
    assert ret.value[0]
def test_gtalk_weirdness(q, bus, conn, stream, room_jid):
    """
    There's a strange bug in the Google Talk MUC server where it sends the
    <conflict/> stanza twice. This has been reported to their server team; but
    in any case it triggered a crazy bug in Gabble, so here's a regression test.
    """

    # Implementation detail: Gabble uses the first part of your jid (if you
    # don't have an alias) as your room nickname, and appends an underscore a
    # few times before giving up.
    jids = ['%s/test%s' % (room_jid, x) for x in ['', '_', '__']]
    member, member_, member__ = jids

    # Gabble should never get as far as trying to join as 'test__' since
    # joining as 'test_' will succeed.
    q.forbid_events([EventPattern('stream-presence', to=member__)])

    call_async(
        q, conn.Requests, 'CreateChannel',
        dbus.Dictionary(
            {
                cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
                cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
                cs.TARGET_ID: room_jid,
            },
            signature='sv'))

    # Gabble first tries to join as test
    q.expect('stream-presence', to=member)

    # Google Talk says no from 'test', twice.
    presence = elem('presence', from_=member,
                    type='error')(elem(ns.MUC, 'x'),
                                  elem('error', type='cancel')(elem(
                                      ns.STANZA, 'conflict'), ))
    stream.send(presence)
    stream.send(presence)

    # Gabble should try to join again as test_
    q.expect('stream-presence', to=member_)

    # Since 'test_' is not in use in the MUC, joining should succeed. According
    # to XEP-0045 §7.1.3 <http://xmpp.org/extensions/xep-0045.html#enter-pres>:
    #  The service MUST first send the complete list of the existing occupants
    #  to the new occupant and only then send the new occupant's own presence
    #  to the new occupant
    # but groupchat.google.com cheerfully violates this.
    stream.send(make_muc_presence('none', 'participant', room_jid, 'test_'))

    # Here's some other random person, who owns the MUC.
    stream.send(
        make_muc_presence('owner', 'moderator', room_jid, 'foobar_gmail.com'))
    # And here's our hypothetical other self.
    stream.send(make_muc_presence('none', 'participant', room_jid, 'test'))

    # The Gabble bug makes this time out: because Gabble thinks it's joining as
    # test__ it ignores the presence for test_, since it's not flagged with
    # code='210' to say “this is you”. (This is acceptable behaviour by the
    # server: it only needs to include code='210' if it's assigned the client a
    # name other than the one it asked for.
    #
    # The forbidden stream-presence event above doesn't blow up here because
    # servicetest doesn't process events on the 'stream-*' queue at all when
    # we're not waiting for one. But during disconnection in the test clean-up,
    # the forbidden event is encountered and correctly flagged up.
    event = q.expect('dbus-return', method='CreateChannel')
    path, _ = event.value
    text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    # As far as Gabble's concerned, the two other participants joined
    # immediately after we did.  We can't request handles for them before we
    # try to join the MUC, because until we do so, Gabble doesn't know that
    # room_jid is a MUC, and so considers these three JIDs to be different
    # resources of the same contact. There is no race between this method
    # returning and MembersChangedDetailed firing, because libdbus reorders
    # messages when you make blocking calls.
    handle, handle_, handle__, foobar_handle = conn.get_contact_handles_sync(
        jids + ['%s/foobar_gmail.com' % room_jid])

    q.expect('dbus-signal',
             signal='MembersChangedDetailed',
             predicate=lambda e: e.args[0:4] == [[foobar_handle], [], [], []])
    q.expect('dbus-signal',
             signal='MembersChangedDetailed',
             predicate=lambda e: e.args[0:4] == [[handle], [], [], []])

    group_props = text_chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP)
    assertEquals(handle_, group_props['SelfHandle'])
    assertSameSets([handle, handle_, foobar_handle], group_props['Members'])
def test(q, bus, conn, stream):
    conn.Connect()

    _, iq_event = q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged',
            args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]),
        EventPattern('stream-iq', to=None, query_ns='vcard-temp',
            query_name='vCard'))

    acknowledge_iq(stream, iq_event.stanza)

    buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo')
    act_prop_iface = dbus.Interface(conn, 'org.laptop.Telepathy.ActivityProperties')
    bob_handle = conn.RequestHandles(1, ['bob@localhost'])[0]

    # Bob invites us to a chatroom, pre-seeding properties
    message = domish.Element(('jabber:client', 'message'))
    message['from'] = 'bob@localhost'
    message['to'] = 'test@localhost'
    properties = message.addElement(
        (ns.OLPC_ACTIVITY_PROPS, 'properties'))
    properties['room'] = '*****@*****.**'
    properties['activity'] = 'foo_id'
    property = properties.addElement((None, 'property'))
    property['type'] = 'str'
    property['name'] = 'title'
    property.addContent('From the invitation')
    property = properties.addElement((None, 'property'))
    property['type'] = 'bool'
    property['name'] = 'private'
    property.addContent('1')

    stream.send(message)

    message = domish.Element((None, 'message'))
    message['from'] = '*****@*****.**'
    message['to'] = 'test@localhost'
    x = message.addElement((ns.MUC_USER, 'x'))
    invite = x.addElement((None, 'invite'))
    invite['from'] = 'bob@localhost'
    reason = invite.addElement((None, 'reason'))
    reason.addContent('No good reason')

    stream.send(message)

    event = q.expect('dbus-signal', signal='NewChannel')

    assert event.args[1] == cs.CHANNEL_TYPE_TEXT

    assert event.args[2] == 2   # handle type
    assert event.args[3] == 1   # handle
    room_handle = 1

    text_chan = bus.get_object(conn.bus_name, event.args[0])
    chan_iface = dbus.Interface(text_chan, cs.CHANNEL)
    group_iface = dbus.Interface(text_chan, cs.CHANNEL_IFACE_GROUP)

    members = group_iface.GetAllMembers()[0]
    local_pending = group_iface.GetAllMembers()[1]
    remote_pending = group_iface.GetAllMembers()[2]

    assert len(members) == 1
    assert conn.InspectHandles(1, members)[0] == 'bob@localhost'
    bob_handle = members[0]
    assert len(local_pending) == 1
    # FIXME: the username-part-is-nickname assumption
    assert conn.InspectHandles(1, local_pending)[0] == \
            '[email protected]/test'
    assert len(remote_pending) == 0

    room_self_handle = group_iface.GetSelfHandle()
    assert room_self_handle == local_pending[0]

    # by now, we should have picked up the extra activity properties
    buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo')
    call_async(q, buddy_iface, 'GetActivities', bob_handle)

    event = q.expect('stream-iq', iq_type='get', to='bob@localhost')
    # Bob still has no (public) activities
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'bob@localhost'
    stream.send(event.stanza)

    event = q.expect('dbus-return', method='GetActivities')

    assert event.value == ([('foo_id', room_handle)],)

    props = act_prop_iface.GetProperties(room_handle)
    assert len(props) == 2
    assert props['title'] == 'From the invitation'
    assert props['private'] == True

    # Now Bob changes the properties
    message = domish.Element(('jabber:client', 'message'))
    message['from'] = 'bob@localhost'
    message['to'] = 'test@localhost'
    properties = message.addElement(
        (ns.OLPC_ACTIVITY_PROPS, 'properties'))
    properties['room'] = '*****@*****.**'
    properties['activity'] = 'foo_id'
    property = properties.addElement((None, 'property'))
    property['type'] = 'str'
    property['name'] = 'title'
    property.addContent('Mushroom, mushroom')
    property = properties.addElement((None, 'property'))
    property['type'] = 'bool'
    property['name'] = 'private'
    property.addContent('0')

    stream.send(message)

    event = q.expect('dbus-signal', signal='ActivityPropertiesChanged')

    assert event.args == [room_handle, {'title': 'Mushroom, mushroom',
        'private': False }]
    assert act_prop_iface.GetProperties(room_handle) == \
            event.args[1]

    # OK, now accept the invitation
    call_async(q, group_iface, 'AddMembers', [room_self_handle], 'Oh, OK then')

    q.expect_many(
        EventPattern('stream-presence', to='[email protected]/test'),
        EventPattern('dbus-signal', signal='MembersChanged',
            args=['', [], [bob_handle], [], [room_self_handle],
                0, cs.GC_REASON_INVITED])
            )

    # Send presence for own membership of room.
    stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'test'))

    q.expect('dbus-return', method='AddMembers')

    event = q.expect('dbus-signal', signal='MembersChanged')
    assert event.args == ['', [room_self_handle], [], [], [], 0, 0]

    call_async(q, buddy_iface, 'SetActivities', [('foo_id', room_handle)])

    event = q.expect('stream-iq', iq_type='set')
    # Now that it's not private, it'll go in my PEP
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    q.expect('dbus-return', method='SetActivities')

    # Bob changes the properties and tells the room he's done so
    message = domish.Element(('jabber:client', 'message'))
    message['from'] = '[email protected]/bob'
    message['to'] = '*****@*****.**'
    properties = message.addElement(
        (ns.OLPC_ACTIVITY_PROPS, 'properties'))
    properties['activity'] = 'foo_id'
    property = properties.addElement((None, 'property'))
    property['type'] = 'str'
    property['name'] = 'title'
    property.addContent('Badger badger badger')
    property = properties.addElement((None, 'property'))
    property['type'] = 'bool'
    property['name'] = 'private'
    property.addContent('0')

    stream.send(message)

    event = q.expect('stream-iq', iq_type='set')
    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
            message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'Badger badger badger'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '0'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen

    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    act_prop_iface = dbus.Interface(conn, 'org.laptop.Telepathy.ActivityProperties')

    # test sets the title and sets private back to True
    call_async(q, act_prop_iface, 'SetProperties',
            room_handle, {'title': 'I can set the properties too', 'private': True})

    event = q.expect('stream-message', to='*****@*****.**')
    message = event.stanza

    properties = xpath.queryForNodes('/message/properties', message)
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'I can set the properties too'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '1'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen


    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
            message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert properties is None, repr(properties)

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
            message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITIES

    activity = xpath.queryForNodes('/activities/activity', activities[0])
    assert activity is None, repr(activity)

    q.expect('dbus-return', method='SetProperties')

    # test sets the title and sets private back to True
    call_async(q, act_prop_iface, 'SetProperties',
        room_handle, {'title': 'I can set the properties too',
                              'private': False})

    event = q.expect('stream-message', to='*****@*****.**')
    message = event.stanza

    properties = xpath.queryForNodes('/message/properties', message)
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'I can set the properties too'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '0'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
            message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'I can set the properties too'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '0'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
            message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITIES

    activity = xpath.queryForNodes('/activities/activity', activities[0])
    assert (activity is not None and len(activity) == 1), repr(activity)
    assert activity[0]['room'] == '*****@*****.**'
    assert activity[0]['type'] == 'foo_id'                  # sic

    q.expect('dbus-return', method='SetProperties')

    chan_iface.Close()

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
            message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITIES

    activity = xpath.queryForNodes('/activities/activity', activities[0])
    assert activity is None, repr(activity)

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
            message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert properties is None, repr(properties)
Example #32
0
def test(q, bus, conn, stream, access_control):
    iq_event = q.expect('stream-iq',
                        to=None,
                        query_ns='vcard-temp',
                        query_name='vCard')

    acknowledge_iq(stream, iq_event.stanza)

    # check if we can request muc D-Bus tube
    t.check_conn_properties(q, conn)

    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")
    self_name = conn.inspect_contact_sync(self_handle)

    # offer a D-Bus tube to another room using new API
    muc = '*****@*****.**'
    request = {
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_DBUS_TUBE,
        cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
        cs.TARGET_ID: '*****@*****.**',
        cs.DBUS_TUBE_SERVICE_NAME: 'com.example.TestCase',
    }
    join_muc(q, bus, conn, stream, muc, request=request)

    exv = q.expect('dbus-signal', signal='NewChannels')

    channels = exv.args[0]
    assert len(channels) == 1
    path, prop = channels[0]
    assert prop[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE
    assert prop[cs.INITIATOR_ID] == '[email protected]/test'
    assert prop[cs.REQUESTED] == True
    assert prop[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM
    assert prop[cs.TARGET_ID] == '*****@*****.**'
    assert prop[cs.DBUS_TUBE_SERVICE_NAME] == 'com.example.TestCase'
    assert prop[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS] == [
        cs.SOCKET_ACCESS_CONTROL_CREDENTIALS,
        cs.SOCKET_ACCESS_CONTROL_LOCALHOST
    ]

    # check that the tube channel is in the channels list
    all_channels = conn.Get(cs.CONN_IFACE_REQUESTS,
                            'Channels',
                            dbus_interface=cs.PROPERTIES_IFACE,
                            byte_arrays=True)
    assertContains((path, prop), all_channels)

    tube_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'DBusTube')
    tube_props = tube_chan.Properties.GetAll(cs.CHANNEL_IFACE_TUBE,
                                             byte_arrays=True)

    assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_NOT_OFFERED

    # try to offer using a wrong access control
    try:
        tube_chan.DBusTube.Offer(sample_parameters,
                                 cs.SOCKET_ACCESS_CONTROL_PORT)
    except dbus.DBusException as e:
        assertEquals(e.get_dbus_name(), cs.INVALID_ARGUMENT)
    else:
        assert False

    # offer the tube
    call_async(q, tube_chan.DBusTube, 'Offer', sample_parameters,
               access_control)

    presence_event, return_event, status_event, dbus_changed_event = q.expect_many(
        EventPattern('stream-presence',
                     to='[email protected]/test',
                     predicate=lambda e: t.presence_contains_tube(e)),
        EventPattern('dbus-return', method='Offer'),
        EventPattern('dbus-signal',
                     signal='TubeChannelStateChanged',
                     args=[cs.TUBE_CHANNEL_STATE_OPEN]),
        EventPattern('dbus-signal',
                     signal='DBusNamesChanged',
                     interface=cs.CHANNEL_TYPE_DBUS_TUBE))

    tube_self_handle = tube_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP,
                                                'SelfHandle')
    assert tube_self_handle != 0

    # handle presence_event
    # We announce our newly created tube in our muc presence
    presence = presence_event.stanza
    dbus_stream_id, my_bus_name, dbus_tube_id = check_tube_in_presence(
        presence, '[email protected]/test')

    # handle dbus_changed_event
    added, removed = dbus_changed_event.args
    assert added == {tube_self_handle: my_bus_name}
    assert removed == []

    dbus_tube_adr = return_event.value[0]

    bob_bus_name = ':2.Ym9i'
    bob_handle = conn.get_contact_handle_sync('[email protected]/bob')

    def bob_in_tube():
        presence = elem('presence',
                        from_='[email protected]/bob',
                        to='*****@*****.**')(
                            elem('x', xmlns=ns.MUC_USER),
                            elem('tubes', xmlns=ns.TUBES)(
                                elem('tube',
                                     type='dbus',
                                     initiator='[email protected]/test',
                                     service='com.example.TestCase',
                                     id=str(dbus_tube_id))(elem('parameters')(
                                         elem('parameter',
                                              name='ay',
                                              type='bytes')(u'aGVsbG8='),
                                         elem('parameter',
                                              name='s',
                                              type='str')(u'hello'),
                                         elem('parameter',
                                              name='i',
                                              type='int')(u'-123'),
                                         elem('parameter',
                                              name='u',
                                              type='uint')(u'123')))))

        # have to add stream-id and dbus-name attributes manually as we can't use
        # keyword with '-'...
        tube_node = xpath.queryForNodes('/presence/tubes/tube', presence)[0]
        tube_node['stream-id'] = dbus_stream_id
        tube_node['dbus-name'] = bob_bus_name
        stream.send(presence)

    # Bob joins the tube
    bob_in_tube()

    dbus_changed_event = q.expect('dbus-signal',
                                  signal='DBusNamesChanged',
                                  interface=cs.CHANNEL_TYPE_DBUS_TUBE)

    added, removed = dbus_changed_event.args
    assert added == {bob_handle: bob_bus_name}
    assert removed == []

    tube = Connection(dbus_tube_adr)
    fire_signal_on_tube(q, tube, '*****@*****.**', dbus_stream_id,
                        my_bus_name)

    names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE,
                          'DBusNames',
                          dbus_interface=cs.PROPERTIES_IFACE)
    assert names == {tube_self_handle: my_bus_name, bob_handle: bob_bus_name}

    # Bob leave the tube
    presence = elem('presence',
                    from_='[email protected]/bob',
                    to='*****@*****.**')(elem('x', xmlns=ns.MUC_USER),
                                               elem('tubes', xmlns=ns.TUBES))
    stream.send(presence)

    dbus_changed_event = q.expect('dbus-signal',
                                  signal='DBusNamesChanged',
                                  interface=cs.CHANNEL_TYPE_DBUS_TUBE)

    added, removed = dbus_changed_event.args
    assert added == {}
    assert removed == [bob_handle]

    names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE,
                          'DBusNames',
                          dbus_interface=cs.PROPERTIES_IFACE)
    assert names == {tube_self_handle: my_bus_name}

    tube_chan.Channel.Close()
    _, _, event = q.expect_many(
        EventPattern('dbus-signal', signal='Closed'),
        EventPattern('dbus-signal', signal='ChannelClosed'),
        EventPattern('stream-presence',
                     to='[email protected]/test',
                     presence_type='unavailable'))

    # we must echo the MUC presence so the room will actually close
    # and we should wait to make sure gabble has actually parsed our
    # echo before trying to rejoin
    echo_muc_presence(q, stream, event.stanza, 'none', 'participant')
    sync_stream(q, stream)

    # rejoin the room
    call_async(
        q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: '*****@*****.**'
        })

    q.expect('stream-presence', to='[email protected]/test')

    # Bob is in the room and in the tube
    bob_in_tube()

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', muc, 'test'))

    def new_tube(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE

    def new_text(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT

    # tube and text is created
    text_event, tube_event = q.expect_many(
        EventPattern('dbus-signal', signal='NewChannels', predicate=new_text),
        EventPattern('dbus-signal', signal='NewChannels', predicate=new_tube))

    channels = exv.args[0]
    tube_path, props = tube_event.args[0][0]
    assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE])
    assertEquals('[email protected]/test', props[cs.INITIATOR_ID])
    assertEquals(False, props[cs.REQUESTED])
    assertEquals(cs.HT_ROOM, props[cs.TARGET_HANDLE_TYPE])
    assertEquals('com.example.TestCase', props[cs.DBUS_TUBE_SERVICE_NAME])

    _, props = text_event.args[0][0]
    assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE])
    assertEquals(True, props[cs.REQUESTED])

    # tube is local-pending
    tube_chan = bus.get_object(conn.bus_name, tube_path)
    state = tube_chan.Get(cs.CHANNEL_IFACE_TUBE,
                          'State',
                          dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(cs.TUBE_STATE_LOCAL_PENDING, state)
Example #33
0
def get_muc_tubes_channel(q, bus, conn, stream, muc_jid, anonymous=True):
    """
    Returns a singleton list containing the MUC's handle, a proxy for the Tubes
    channel, and a proxy for the Tubes iface on that channel.
    """
    muc_server = muc_jid.split('@')[1]
    test_jid = muc_jid + "/test"
    bob_jid = muc_jid + "/bob"

    self_handle = conn.GetSelfHandle()
    self_name = conn.InspectHandles(cs.HT_CONTACT, [self_handle])[0]

    call_async(q, conn, 'RequestHandles', cs.HT_ROOM, [muc_jid])

    event = q.expect('dbus-return', method='RequestHandles')
    handles = event.value[0]
    room_handle = handles[0]

    # request tubes channel
    call_async(q, conn, 'RequestChannel',
        tp_name_prefix + '.Channel.Type.Tubes', cs.HT_ROOM, room_handle, True)

    _, stream_event = q.expect_many(
        EventPattern('dbus-signal', signal='MembersChanged',
            args=[u'', [], [], [], [2], 0, 0]),
        EventPattern('stream-presence', to=test_jid))

    # Send presence for other member of room.
    if not anonymous:
        real_jid = 'bob@localhost'
    else:
        real_jid = None

    stream.send(make_muc_presence('owner', 'moderator', muc_jid, 'bob', real_jid))

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', muc_jid, 'test'))

    q.expect('dbus-signal', signal='MembersChanged',
            args=[u'', [2, 3], [], [], [], 0, 0])

    assert conn.InspectHandles(cs.HT_CONTACT, [2]) == [test_jid]
    assert conn.InspectHandles(cs.HT_CONTACT, [3]) == [bob_jid]

    # text and tubes channels are created
    # FIXME: We can't check NewChannel signals (old API) because two of them
    # would be fired and we can't catch twice the same signals without specifying
    # all their arguments.
    new_sig, returned = q.expect_many(
        EventPattern('dbus-signal', signal='NewChannels'),
        EventPattern('dbus-return', method='RequestChannel'))

    channels = new_sig.args[0]
    assert len(channels) == 2

    for channel in channels:
        path, props = channel
        type = props[cs.CHANNEL_TYPE]

        if type == cs.CHANNEL_TYPE_TEXT:
            # check text channel properties
            assert props[cs.TARGET_HANDLE] == room_handle
            assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM
            assert props[cs.TARGET_ID] == '*****@*****.**'
            assert props[cs.REQUESTED] == False
            assert props[cs.INITIATOR_HANDLE] == self_handle
            assert props[cs.INITIATOR_ID] == self_name
        elif type == cs.CHANNEL_TYPE_TUBES:
            # check tubes channel properties
            assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM
            assert props[cs.TARGET_HANDLE] == room_handle
            assert props[cs.TARGET_ID] == '*****@*****.**'
            assert props[cs.REQUESTED] == True
            assert props[cs.INITIATOR_HANDLE] == self_handle
            assert props[cs.INITIATOR_ID] == self_name
        else:
            assert True

    tubes_chan = bus.get_object(conn.bus_name, returned.value[0])
    tubes_iface = dbus.Interface(tubes_chan,
            tp_name_prefix + '.Channel.Type.Tubes')

    return (room_handle, tubes_chan, tubes_iface)
def test(q, bus, conn, stream):
    iq_event = q.expect('stream-iq',
                        to=None,
                        query_ns='vcard-temp',
                        query_name='vCard')

    acknowledge_iq(stream, iq_event.stanza)

    # join the muc
    call_async(
        q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: '*****@*****.**'
        })

    q.expect_many(
        EventPattern(
            'dbus-signal',
            signal='MembersChangedDetailed',
            predicate=lambda e: e.args[0] == [] and  # added
            e.args[1] == [] and  # removed
            e.args[2] == [] and  # local pending
            len(e.args[3]) == 1 and  # remote pending
            e.args[4].get('actor', 0) == 0 and e.args[4].get(
                'change-reason', 0) == 0 and e.args[4]['contact-ids'][e.args[
                    3][0]] == '[email protected]/test'),
        EventPattern('stream-presence', to='[email protected]/test'))

    # Send presence for other member of room.
    stream.send(
        make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob'))

    # Send presence for own membership of room.
    stream.send(
        make_muc_presence('none', 'participant', '*****@*****.**',
                          'test'))

    event = q.expect(
        'dbus-signal',
        signal='MembersChangedDetailed',
        predicate=lambda e: len(e.args[0]) == 2 and  # added
        e.args[1] == [] and  # removed
        e.args[2] == [] and  # local pending
        e.args[3] == [] and  # remote pending
        e.args[4].get('actor', 0) == 0 and e.args[4].get('change-reason', 0) ==
        0 and set([e.args[4]['contact-ids'][h] for h in e.args[0]]) == set(
            ['[email protected]/test', '[email protected]/bob']))

    for h in event.args[0]:
        if event.args[4]['contact-ids'][h] == '[email protected]/bob':
            bob_handle = h

    event = q.expect('dbus-return', method='CreateChannel')
    text_chan = bus.get_object(conn.bus_name, event.value[0])

    # Bob offers a muc tube
    tube_id = 666
    stream_id = 1234
    presence = make_muc_presence('owner', 'moderator', '*****@*****.**',
                                 'bob')
    tubes = presence.addElement((ns.TUBES, 'tubes'))
    tube = tubes.addElement((None, 'tube'))
    tube['type'] = 'dbus'
    tube['service'] = 'org.telepathy.freedesktop.test'
    tube['id'] = str(tube_id)
    tube['stream-id'] = str(stream_id)
    tube['dbus-name'] = ':2.Y2Fzc2lkeS10ZXN0MgAA'
    tube['initiator'] = '[email protected]/bob'
    parameters = tube.addElement((None, 'parameters'))
    parameter = parameters.addElement((None, 'parameter'))
    parameter['name'] = 's'
    parameter['type'] = 'str'
    parameter.addContent('hello')
    parameter = parameters.addElement((None, 'parameter'))
    parameter['name'] = 'ay'
    parameter['type'] = 'bytes'
    parameter.addContent('aGVsbG8=')
    parameter = parameters.addElement((None, 'parameter'))
    parameter['name'] = 'u'
    parameter['type'] = 'uint'
    parameter.addContent('123')
    parameter = parameters.addElement((None, 'parameter'))
    parameter['name'] = 'i'
    parameter['type'] = 'int'
    parameter.addContent('-123')

    stream.send(presence)

    def new_chan_predicate(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE

    # tube channel is automatically created
    event = q.expect('dbus-signal',
                     signal='NewChannels',
                     predicate=new_chan_predicate)

    path, props = event.args[0][0]

    assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE])
    assertEquals(cs.HT_ROOM, props[cs.TARGET_HANDLE_TYPE])
    assertEquals('*****@*****.**', props[cs.TARGET_ID])
    assertEquals(False, props[cs.REQUESTED])

    tube_chan = bus.get_object(conn.bus_name, path)
    tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_DBUS_TUBE)

    # reject the tube
    tube_iface.Close(dbus_interface=cs.CHANNEL)
    q.expect('dbus-signal', signal='ChannelClosed')

    # close the text channel
    text_chan.Close()
Example #35
0
def test_role_changes(q, bus, conn, stream):
    # The test user joins a room. Bob is an owner (and moderator); the test
    # user starts out with no affiliation and the rôle of participant.
    MUC = 'aoeu@snth'
    chan, _, immutable_props, disco = join_muc(q, bus, conn, stream,
        MUC, role='participant',
        also_capture=[
            EventPattern('stream-iq', to=MUC, iq_type='get',
                query_ns=ns.DISCO_INFO),
        ])
    assertContains(cs.CHANNEL_IFACE_ROOM_CONFIG, immutable_props[cs.INTERFACES])

    handle_disco_info_iq(stream, disco.stanza)
    q.expect('dbus-signal', signal='PropertiesChanged',
        args=[cs.CHANNEL_IFACE_ROOM_CONFIG,
              {'ConfigurationRetrieved': True},
              []
             ])

    # If we try to change the configuration, Gabble should say no: it knows
    # we're not allowed to do that.
    call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {})
    q.expect('dbus-error', name=cs.PERMISSION_DENIED)

    config = chan.Properties.GetAll(cs.CHANNEL_IFACE_ROOM_CONFIG)
    assert not config['CanUpdateConfiguration'], config

    # If we acquire affiliation='owner', this should be signalled as our
    # becoming able to modify the channel configuration.
    stream.send(make_muc_presence('owner', 'moderator', MUC, 'test'))
    q.expect('dbus-signal', signal='PropertiesChanged',
        args=[cs.CHANNEL_IFACE_ROOM_CONFIG,
              {'CanUpdateConfiguration': True},
              []
             ])

    # Due to silliness, Gabble has to grab the owner configuration form to see
    # whether it's possible to change the room description.
    owner_iq = q.expect('stream-iq', to=MUC, iq_type='get', query_ns=ns.MUC_OWNER)
    handle_muc_owner_get_iq(stream, owner_iq.stanza)

    # Bob's ownership rights being taken away should have no effect.
    stream.send(make_muc_presence('none', 'participant', MUC, 'bob'))

    # So now we're an owner, and CanUpdateConfiguration is True, we should be
    # able to change some configuration.
    props = dbus.Dictionary(
        { 'Persistent': True,
        }, signature='sv')
    call_async(q, chan.RoomConfig1, 'UpdateConfiguration', props)

    owner_iq = q.expect('stream-iq', to=MUC, iq_type='get', query_ns=ns.MUC_OWNER)
    handle_muc_owner_get_iq(stream, owner_iq.stanza)

    event = q.expect('stream-iq', to=MUC, iq_type='set', query_ns=ns.MUC_OWNER)
    handle_muc_owner_set_iq(stream, event.stanza,
        {'muc#roomconfig_persistentroom': ['1']})

    q.expect_many(
        EventPattern('dbus-return', method='UpdateConfiguration'),
        EventPattern('dbus-signal', signal='PropertiesChanged',
            args=[cs.CHANNEL_IFACE_ROOM_CONFIG,
                  {'Persistent': True},
                  []
                 ]))

    # If we lose our affiliation, that should be signalled too.
    stream.send(make_muc_presence('none', 'participant', MUC, 'test'))
    q.expect('dbus-signal', signal='PropertiesChanged',
        args=[cs.CHANNEL_IFACE_ROOM_CONFIG,
              {'CanUpdateConfiguration': False},
              []
             ])

    # Gabble should once again reject attempts to change the configuration
    call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {})
    q.expect('dbus-error', name=cs.PERMISSION_DENIED)
def test(q, bus, conn, stream):
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    call_async(
        q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: '*****@*****.**'
        })

    gfc, _, _, _ = q.expect_many(
        # Initial group flags
        EventPattern('dbus-signal',
                     signal='GroupFlagsChanged',
                     predicate=lambda e: e.args[0] != 0),
        EventPattern('dbus-signal',
                     signal='MembersChangedDetailed',
                     predicate=lambda e: e.args[3] == [2]),
        # Removing CAN_ADD
        EventPattern('dbus-signal',
                     signal='GroupFlagsChanged',
                     args=[0, cs.GF_CAN_ADD],
                     predicate=lambda e: e.args[0] == 0),
        EventPattern('stream-presence', to='[email protected]/test'))
    assert gfc.args[1] == 0

    # Send presence for anonymous other member of room.
    stream.send(
        make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob'))

    # Send presence for anonymous other member of room (2)
    stream.send(
        make_muc_presence('owner', 'moderator', '*****@*****.**',
                          'brian'))

    # Send presence for nonymous other member of room.
    stream.send(
        make_muc_presence('none', 'participant', '*****@*****.**', 'che',
                          '*****@*****.**'))

    # Send presence for nonymous other member of room (2)
    stream.send(
        make_muc_presence('none', 'participant', '*****@*****.**',
                          'chris', '*****@*****.**'))

    # Send presence for own membership of room.
    stream.send(
        make_muc_presence('none', 'participant', '*****@*****.**',
                          'test'))

    # Since we received MUC presence that contains an owner JID, the
    # OWNERS_NOT_AVAILABLE flag should be removed.
    event = q.expect('dbus-signal',
                     signal='GroupFlagsChanged',
                     args=[0, cs.GF_HANDLE_OWNERS_NOT_AVAILABLE])

    event = q.expect('dbus-signal', signal='HandleOwnersChanged')
    owners = event.args[0]

    event = q.expect('dbus-signal', signal='MembersChangedDetailed')
    added = event.args[0]

    [test, bob, brian, che, che_owner, chris, chris_owner] = \
        conn.get_contact_handles_sync(
            [ '[email protected]/test', '[email protected]/bob',
              '[email protected]/brian', '[email protected]/che',
              '*****@*****.**', '[email protected]/chris', '*****@*****.**',
            ])
    expected_members = sorted([test, bob, brian, che, chris])
    expected_owners = {
        test: self_handle,
        bob: 0,
        brian: 0,
        che: che_owner,
        chris: chris_owner
    }
    assertEquals(expected_members, sorted(added))
    assertEquals(expected_owners, owners)

    event = q.expect('dbus-return', method='CreateChannel')

    chan = wrap_channel(bus.get_object(conn.bus_name, event.value[0]), 'Text')

    # Exercise HandleOwners
    owners = chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'HandleOwners')
    assertEquals(che_owner, owners[che])
    assertEquals(chris_owner, owners[chris])

    # Exercise D-Bus properties
    all = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP)

    assert all[u'LocalPendingMembers'] == [], all
    assert sorted(all[u'Members']) == expected_members, all
    assert all[u'RemotePendingMembers'] == [], all
    assert all[u'SelfHandle'] == test, all
    assert all[u'HandleOwners'] == expected_owners, all

    flags = all[u'GroupFlags']
    assertFlagsSet(cs.GF_CHANNEL_SPECIFIC_HANDLES, flags)
    assertFlagsUnset(cs.GF_HANDLE_OWNERS_NOT_AVAILABLE, flags)
def send_muc_presence(q, stream, jid):
    q.expect('stream-presence', to='%s/test' % jid)

    stream.send(make_muc_presence('owner', 'moderator', jid, 'bob'))
    stream.send(make_muc_presence('none', 'participant', jid, 'test'))
Example #38
0
def test_gtalk_weirdness(q, bus, conn, stream, room_jid):
    """
    There's a strange bug in the Google Talk MUC server where it sends the
    <conflict/> stanza twice. This has been reported to their server team; but
    in any case it triggered a crazy bug in Gabble, so here's a regression test.
    """

    # Implementation detail: Gabble uses the first part of your jid (if you
    # don't have an alias) as your room nickname, and appends an underscore a
    # few times before giving up.
    jids = ['%s/test%s' % (room_jid, x) for x in ['', '_', '__']]
    member, member_, member__ = jids

    # Gabble should never get as far as trying to join as 'test__' since
    # joining as 'test_' will succeed.
    q.forbid_events([ EventPattern('stream-presence', to=member__) ])

    call_async(q, conn.Requests, 'CreateChannel',
        dbus.Dictionary({ cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
                          cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
                          cs.TARGET_ID: room_jid,
                        }, signature='sv'))

    # Gabble first tries to join as test
    q.expect('stream-presence', to=member)

    # Google Talk says no from 'test', twice.
    presence = elem('presence', from_=member, type='error')(
        elem(ns.MUC, 'x'),
        elem('error', type='cancel')(
          elem(ns.STANZA, 'conflict'),
        ))
    stream.send(presence)
    stream.send(presence)

    # Gabble should try to join again as test_
    q.expect('stream-presence', to=member_)

    # Since 'test_' is not in use in the MUC, joining should succeed. According
    # to XEP-0045 §7.1.3 <http://xmpp.org/extensions/xep-0045.html#enter-pres>:
    #  The service MUST first send the complete list of the existing occupants
    #  to the new occupant and only then send the new occupant's own presence
    #  to the new occupant
    # but groupchat.google.com cheerfully violates this.
    stream.send(make_muc_presence('none', 'participant', room_jid, 'test_'))

    # Here's some other random person, who owns the MUC.
    stream.send(make_muc_presence('owner', 'moderator', room_jid, 'foobar_gmail.com'))
    # And here's our hypothetical other self.
    stream.send(make_muc_presence('none', 'participant', room_jid, 'test'))

    # The Gabble bug makes this time out: because Gabble thinks it's joining as
    # test__ it ignores the presence for test_, since it's not flagged with
    # code='210' to say “this is you”. (This is acceptable behaviour by the
    # server: it only needs to include code='210' if it's assigned the client a
    # name other than the one it asked for.
    #
    # The forbidden stream-presence event above doesn't blow up here because
    # servicetest doesn't process events on the 'stream-*' queue at all when
    # we're not waiting for one. But during disconnection in the test clean-up,
    # the forbidden event is encountered and correctly flagged up.
    event = q.expect('dbus-return', method='CreateChannel')
    path, _ = event.value
    text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    # As far as Gabble's concerned, the two other participants joined
    # immediately after we did.  We can't request handles for them before we
    # try to join the MUC, because until we do so, Gabble doesn't know that
    # room_jid is a MUC, and so considers these three JIDs to be different
    # resources of the same contact. There is no race between this method
    # returning and MembersChangedDetailed firing, because libdbus reorders
    # messages when you make blocking calls.
    handle, handle_, handle__, foobar_handle = conn.RequestHandles(
        cs.HT_CONTACT, jids + ['%s/foobar_gmail.com' % room_jid])

    q.expect('dbus-signal', signal='MembersChangedDetailed',
        predicate=lambda e: e.args[0:4] == [[foobar_handle], [], [], []])
    q.expect('dbus-signal', signal='MembersChangedDetailed',
        predicate=lambda e: e.args[0:4] == [[handle], [], [], []])

    group_props = text_chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP)
    assertEquals(handle_, group_props['SelfHandle'])
    assertSameSets([handle, handle_, foobar_handle], group_props['Members'])
def test(q, bus, conn, stream):
    iq_event = q.expect('stream-iq',
                        to=None,
                        query_ns='vcard-temp',
                        query_name='vCard')

    acknowledge_iq(stream, iq_event.stanza)

    buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo')
    act_prop_iface = dbus.Interface(conn,
                                    'org.laptop.Telepathy.ActivityProperties')
    bob_handle = conn.get_contact_handle_sync('bob@localhost')

    # Bob invites us to a chatroom, pre-seeding properties
    message = domish.Element(('jabber:client', 'message'))
    message['from'] = 'bob@localhost'
    message['to'] = 'test@localhost'
    properties = message.addElement((ns.OLPC_ACTIVITY_PROPS, 'properties'))
    properties['room'] = '*****@*****.**'
    properties['activity'] = 'foo_id'
    property = properties.addElement((None, 'property'))
    property['type'] = 'str'
    property['name'] = 'title'
    property.addContent('From the invitation')
    property = properties.addElement((None, 'property'))
    property['type'] = 'bool'
    property['name'] = 'private'
    property.addContent('1')

    stream.send(message)

    message = domish.Element((None, 'message'))
    message['from'] = '*****@*****.**'
    message['to'] = 'test@localhost'
    x = message.addElement((ns.MUC_USER, 'x'))
    invite = x.addElement((None, 'invite'))
    invite['from'] = 'bob@localhost'
    reason = invite.addElement((None, 'reason'))
    reason.addContent('No good reason')

    stream.send(message)

    event = q.expect('dbus-signal', signal='NewChannel')

    assert event.args[1] == cs.CHANNEL_TYPE_TEXT

    assert event.args[2] == 2  # handle type
    assert event.args[3] == 1  # handle
    room_handle = 1

    text_chan = wrap_channel(bus.get_object(conn.bus_name, event.args[0]),
                             'Text')
    group_iface = text_chan.Group

    members = group_iface.GetAllMembers()[0]
    local_pending = group_iface.GetAllMembers()[1]
    remote_pending = group_iface.GetAllMembers()[2]

    assert len(members) == 1
    assert conn.inspect_contact_sync(members[0]) == 'bob@localhost'
    bob_handle = members[0]
    assert len(local_pending) == 1
    # FIXME: the username-part-is-nickname assumption
    assert conn.inspect_contact_sync(local_pending[0]) == \
            '[email protected]/test'
    assert len(remote_pending) == 0

    room_self_handle = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP,
                                                "SelfHandle")
    assert room_self_handle == local_pending[0]

    # by now, we should have picked up the extra activity properties
    buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo')
    call_async(q, buddy_iface, 'GetActivities', bob_handle)

    event = q.expect('stream-iq', iq_type='get', to='bob@localhost')
    # Bob still has no (public) activities
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'bob@localhost'
    stream.send(event.stanza)

    event = q.expect('dbus-return', method='GetActivities')

    assert event.value == ([('foo_id', room_handle)], )

    props = act_prop_iface.GetProperties(room_handle)
    assert len(props) == 2
    assert props['title'] == 'From the invitation'
    assert props['private'] == True

    # Now Bob changes the properties
    message = domish.Element(('jabber:client', 'message'))
    message['from'] = 'bob@localhost'
    message['to'] = 'test@localhost'
    properties = message.addElement((ns.OLPC_ACTIVITY_PROPS, 'properties'))
    properties['room'] = '*****@*****.**'
    properties['activity'] = 'foo_id'
    property = properties.addElement((None, 'property'))
    property['type'] = 'str'
    property['name'] = 'title'
    property.addContent('Mushroom, mushroom')
    property = properties.addElement((None, 'property'))
    property['type'] = 'bool'
    property['name'] = 'private'
    property.addContent('0')

    stream.send(message)

    event = q.expect('dbus-signal', signal='ActivityPropertiesChanged')

    assert event.args == [
        room_handle, {
            'title': 'Mushroom, mushroom',
            'private': False
        }
    ]
    assert act_prop_iface.GetProperties(room_handle) == \
            event.args[1]

    # OK, now accept the invitation
    call_async(q, group_iface, 'AddMembers', [room_self_handle], 'Oh, OK then')

    q.expect_many(
        EventPattern('stream-presence', to='[email protected]/test'),
        EventPattern('dbus-signal',
                     signal='MembersChanged',
                     args=[
                         '', [], [bob_handle], [], [room_self_handle], 0,
                         cs.GC_REASON_INVITED
                     ]),
        EventPattern('dbus-return', method='AddMembers'),
    )

    # Send presence for own membership of room.
    stream.send(
        make_muc_presence('owner', 'moderator', '*****@*****.**', 'test'))

    event = q.expect('dbus-signal', signal='MembersChanged')
    assert event.args == ['', [room_self_handle], [], [], [], 0, 0]

    call_async(q, buddy_iface, 'SetActivities', [('foo_id', room_handle)])

    event = q.expect('stream-iq', iq_type='set')
    # Now that it's not private, it'll go in my PEP
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    q.expect('dbus-return', method='SetActivities')

    # Bob changes the properties and tells the room he's done so
    message = domish.Element(('jabber:client', 'message'))
    message['from'] = '[email protected]/bob'
    message['to'] = '*****@*****.**'
    properties = message.addElement((ns.OLPC_ACTIVITY_PROPS, 'properties'))
    properties['activity'] = 'foo_id'
    property = properties.addElement((None, 'property'))
    property['type'] = 'str'
    property['name'] = 'title'
    property.addContent('Badger badger badger')
    property = properties.addElement((None, 'property'))
    property['type'] = 'bool'
    property['name'] = 'private'
    property.addContent('0')

    stream.send(message)

    event = q.expect('stream-iq', iq_type='set')
    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
                                     message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'Badger badger badger'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '0'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen

    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    act_prop_iface = dbus.Interface(conn,
                                    'org.laptop.Telepathy.ActivityProperties')

    # test sets the title and sets private back to True
    call_async(q, act_prop_iface, 'SetProperties', room_handle, {
        'title': 'I can set the properties too',
        'private': True
    })

    event = q.expect('stream-message', to='*****@*****.**')
    message = event.stanza

    properties = xpath.queryForNodes('/message/properties', message)
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'I can set the properties too'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '1'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
                                     message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert properties is None, repr(properties)

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
                                     message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITIES

    activity = xpath.queryForNodes('/activities/activity', activities[0])
    assert activity is None, repr(activity)

    q.expect('dbus-return', method='SetProperties')

    # test sets the title and sets private back to True
    call_async(q, act_prop_iface, 'SetProperties', room_handle, {
        'title': 'I can set the properties too',
        'private': False
    })

    event = q.expect('stream-message', to='*****@*****.**')
    message = event.stanza

    properties = xpath.queryForNodes('/message/properties', message)
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'I can set the properties too'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '0'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
                                     message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'I can set the properties too'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '0'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
                                     message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITIES

    activity = xpath.queryForNodes('/activities/activity', activities[0])
    assert (activity is not None and len(activity) == 1), repr(activity)
    assert activity[0]['room'] == '*****@*****.**'
    assert activity[0]['type'] == 'foo_id'  # sic

    q.expect('dbus-return', method='SetProperties')

    text_chan.Close()

    # we must echo the MUC presence so the room will actually close
    event = q.expect('stream-presence',
                     to='[email protected]/test',
                     presence_type='unavailable')
    echo_muc_presence(q, stream, event.stanza, 'none', 'participant')

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
                                     message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITIES

    activity = xpath.queryForNodes('/activities/activity', activities[0])
    assert activity is None, repr(activity)

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
                                     message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert properties is None, repr(properties)
Example #40
0
def test_join(q, bus, conn, stream, room_jid, transient_conflict):
    """
    Tells Gabble to join a MUC, but make the first nick it tries conflict with
    an existing member of the MUC.  If transient_conflict is True, then when
    Gabble successfully joins with a different nick the originally conflicting
    user turns out not actually to be in the room (they left while we were
    retrying).
    """
    # Implementation detail: Gabble uses the first part of your jid (if you
    # don't have an alias) as your room nickname, and appends an underscore a
    # few times before giving up.
    member, member_ = [room_jid + '/' + x for x in ['test', 'test_']]

    call_async(q, conn.Requests, 'CreateChannel',
        dbus.Dictionary({ cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
                          cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
                          cs.TARGET_ID: room_jid,
                        }, signature='sv'))

    # Gabble first tries to join as test
    q.expect('stream-presence', to=member)

    # MUC says no: there's already someone called test in room_jid
    presence = elem('presence', from_=member, type='error')(
        elem(ns.MUC, 'x'),
        elem('error', type='cancel')(
          elem(ns.STANZA, 'conflict'),
        ))
    stream.send(presence)

    # Gabble tries again as test_
    q.expect('stream-presence', to=member_)

    # MUC says yes!

    if not transient_conflict:
        # Send the other member of the room's presence. This is the nick we
        # originally wanted.
        stream.send(make_muc_presence('owner', 'moderator', room_jid, 'test'))

    # If gabble erroneously thinks the other user's presence is our own, it'll
    # think that it's got the whole userlist now. If so, syncing here will make
    # CreateChannel incorrectly return here.
    sync_stream(q, stream)
    sync_dbus(bus, q, conn)

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', room_jid, 'test_'))

    # Only now should we have finished joining the room.
    event = q.expect('dbus-return', method='CreateChannel')
    path, props = event.value
    text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')
    group_props = unwrap(text_chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP))

    t, t_ = conn.RequestHandles(cs.HT_CONTACT, [member, member_])

    # Check that Gabble think our nickname in the room is test_, not test
    muc_self_handle = group_props['SelfHandle']
    assert muc_self_handle == t_, (muc_self_handle, t_, t)

    members = group_props['Members']

    if transient_conflict:
        # The user we originally conflicted with isn't actually here; check
        # there's exactly one member (test_).
        assert members == [t_], (members, t_, t)
    else:
        # Check there are exactly two members (test and test_)
        assertSameSets([t, t_], members)

    # In either case, there should be no pending members.
    assert len(group_props['LocalPendingMembers']) == 0, group_props
    assert len(group_props['RemotePendingMembers']) == 0, group_props

    # Check that test_'s handle owner is us, and that test (if it's there) has
    # no owner.
    handle_owners = group_props['HandleOwners']
    assertEquals (conn.GetSelfHandle(), handle_owners[t_])
    if not transient_conflict:
        assertEquals (0, handle_owners[t])

    # test that closing the channel results in an unavailable message to the
    # right jid
    text_chan.Close()

    event = q.expect('stream-presence', to=member_)
    assertEquals('unavailable', event.stanza['type'])
    echo_muc_presence(q, stream, event.stanza, 'none', 'participant')
    sync_stream(q, stream)

    # rejoin the room
    call_async(q, conn.Requests, 'CreateChannel',
        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
          cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
          cs.TARGET_ID: '*****@*****.**' })

    q.expect('stream-presence', to='[email protected]/test')

    # Bob is in the room and in the tube
    bob_in_tube()

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', muc, 'test'))

    def new_tube(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE

    def new_text(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT

    # tube and text is created
    text_event, tube_event = q.expect_many(EventPattern('dbus-signal', signal='NewChannels',
                                                        predicate=new_text),
                                           EventPattern('dbus-signal', signal='NewChannels',
                                                        predicate=new_tube))
def test(q, bus, conn, stream):
    iq_event, disco_event = q.expect_many(
        EventPattern('stream-iq', to=None, query_ns='vcard-temp',
            query_name='vCard'),
        EventPattern('stream-iq', to='localhost', query_ns=ns.DISCO_ITEMS))

    acknowledge_iq(stream, iq_event.stanza)

    announce_socks5_proxy(q, stream, disco_event.stanza)

    join_muc(q, bus, conn, stream, '*****@*****.**')

    # bob offers a stream tube
    stream_tube_id = 1

    presence = make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob')
    tubes = presence.addElement((ns.TUBES, 'tubes'))
    tube = tubes.addElement((None, 'tube'))
    tube['type'] = 'stream'
    tube['service'] = 'echo'
    tube['id'] = str(stream_tube_id)
    parameters = tube.addElement((None, 'parameters'))
    stream.send(presence)

    def new_chan_predicate(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE

    e = q.expect('dbus-signal', signal='NewChannels',
                 predicate=new_chan_predicate)
    channels = e.args[0]
    assert len(channels) == 1
    path, props = channels[0]
    assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE

    tube_chan = bus.get_object(conn.bus_name, path)
    tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE)

    call_async(q, tube_iface, 'Accept', 0, 0, '',
        byte_arrays=True)

    accept_return_event, _ = q.expect_many(
        EventPattern('dbus-return', method='Accept'),
        EventPattern('dbus-signal', signal='TubeChannelStateChanged',
            args=[cs.TUBE_CHANNEL_STATE_OPEN]))

    unix_socket_adr = accept_return_event.value[0]

    factory = EventProtocolClientFactory(q)
    reactor.connectUNIX(unix_socket_adr, factory)

     # expect SI request
    e = q.expect('stream-iq', to='[email protected]/bob', query_ns=ns.SI,
        query_name='si')

    bytestream, profile = create_from_si_offer(stream, q, BytestreamS5BRelay, e.stanza,
        '[email protected]/bob')

    result, si = bytestream.create_si_reply(e.stanza, 'test@localhost/Resource')
    si.addElement((ns.TUBES, 'tube'))
    stream.send(result)

    # wait SOCKS5 init iq
    id, mode, si, hosts = bytestream._expect_socks5_init()
    for jid, host, port in hosts:
        # the proxy is not announced because we are in a muc
        assert jid != 'proxy.localhost'
def test(q, bus, conn, stream):
    conn.Connect()

    _, iq_event = q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged',
            args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]),
        EventPattern('stream-iq', to=None, query_ns='vcard-temp',
            query_name='vCard'))

    acknowledge_iq(stream, iq_event.stanza)

    call_async(q, conn, 'RequestHandles', cs.HT_ROOM, ['*****@*****.**'])

    event = q.expect('stream-iq', to='conf.localhost',
            query_ns='http://jabber.org/protocol/disco#info')
    result = make_result_iq(stream, event.stanza)
    feature = result.firstChildElement().addElement('feature')
    feature['var'] = 'http://jabber.org/protocol/muc'
    stream.send(result)

    event = q.expect('dbus-return', method='RequestHandles')
    handles = event.value[0]
    room_handle = handles[0]

    # join the muc
    call_async(q, conn, 'RequestChannel',
        cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM, room_handle, True)

    _, stream_event = q.expect_many(
        EventPattern('dbus-signal', signal='MembersChanged',
            args=[u'', [], [], [], [2], 0, 0]),
        EventPattern('stream-presence', to='[email protected]/test'))

    # Send presence for other member of room.
    stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob'))

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', '*****@*****.**', 'test'))

    q.expect('dbus-signal', signal='MembersChanged',
            args=[u'', [2, 3], [], [], [], 0, 0])

    assert conn.InspectHandles(cs.HT_CONTACT, [2, 3]) == \
        ['[email protected]/test', '[email protected]/bob']
    bob_handle = 3

    event = q.expect('dbus-return', method='RequestChannel')
    text_chan = bus.get_object(conn.bus_name, event.value[0])

    # Bob offers a muc tube
    tube_id = 666
    stream_id = 1234
    presence = make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob')
    tubes = presence.addElement((ns.TUBES, 'tubes'))
    tube = tubes.addElement((None, 'tube'))
    tube['type'] = 'dbus'
    tube['service'] = 'org.telepathy.freedesktop.test'
    tube['id'] = str(tube_id)
    tube['stream-id'] = str(stream_id)
    tube['dbus-name'] = ':2.Y2Fzc2lkeS10ZXN0MgAA'
    tube['initiator'] = '[email protected]/bob'
    parameters = tube.addElement((None, 'parameters'))
    parameter = parameters.addElement((None, 'parameter'))
    parameter['name'] = 's'
    parameter['type'] = 'str'
    parameter.addContent('hello')
    parameter = parameters.addElement((None, 'parameter'))
    parameter['name'] = 'ay'
    parameter['type'] = 'bytes'
    parameter.addContent('aGVsbG8=')
    parameter = parameters.addElement((None, 'parameter'))
    parameter['name'] = 'u'
    parameter['type'] = 'uint'
    parameter.addContent('123')
    parameter = parameters.addElement((None, 'parameter'))
    parameter['name'] = 'i'
    parameter['type'] = 'int'
    parameter.addContent('-123')

    stream.send(presence)

    # tubes channel is automatically created
    event = q.expect('dbus-signal', signal='NewChannel')

    if event.args[1] == cs.CHANNEL_TYPE_TEXT:
        # skip this one, try the next one
        event = q.expect('dbus-signal', signal='NewChannel')

    assert event.args[1] == cs.CHANNEL_TYPE_TUBES, event.args
    assert event.args[2] == cs.HT_ROOM
    assert event.args[3] == room_handle

    tubes_chan = bus.get_object(conn.bus_name, event.args[0])
    tubes_iface = dbus.Interface(tubes_chan, event.args[1])

    channel_props = tubes_chan.GetAll(
        cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE)
    assert channel_props['TargetID'] == '*****@*****.**', channel_props
    assert channel_props['Requested'] == False
    assert channel_props['InitiatorID'] == ''
    assert channel_props['InitiatorHandle'] == 0

    tubes_self_handle = tubes_chan.GetSelfHandle(
        dbus_interface=cs.CHANNEL_IFACE_GROUP)

    q.expect('dbus-signal', signal='NewTube',
        args=[tube_id, bob_handle, 0, 'org.telepathy.freedesktop.test', sample_parameters, 0])

    expected_tube = (tube_id, bob_handle, cs.TUBE_TYPE_DBUS,
        'org.telepathy.freedesktop.test', sample_parameters,
        cs.TUBE_STATE_LOCAL_PENDING)
    tubes = tubes_iface.ListTubes(byte_arrays=True)
    assert len(tubes) == 1, unwrap(tubes)
    t.check_tube_in_tubes(expected_tube, tubes)

    # reject the tube
    tubes_iface.CloseTube(tube_id)
    q.expect('dbus-signal', signal='TubeClosed', args=[tube_id])

    # close the text channel
    text_chan.Close()
def test(q, bus, conn, stream):
    iq_event, disco_event = q.expect_many(
        EventPattern('stream-iq',
                     to=None,
                     query_ns='vcard-temp',
                     query_name='vCard'),
        EventPattern('stream-iq', to='localhost', query_ns=ns.DISCO_ITEMS))

    acknowledge_iq(stream, iq_event.stanza)

    announce_socks5_proxy(q, stream, disco_event.stanza)

    join_muc(q, bus, conn, stream, '*****@*****.**')

    # bob offers a stream tube
    stream_tube_id = 1

    presence = make_muc_presence('owner', 'moderator', '*****@*****.**',
                                 'bob')
    tubes = presence.addElement((ns.TUBES, 'tubes'))
    tube = tubes.addElement((None, 'tube'))
    tube['type'] = 'stream'
    tube['service'] = 'echo'
    tube['id'] = str(stream_tube_id)
    parameters = tube.addElement((None, 'parameters'))
    stream.send(presence)

    def new_chan_predicate(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE

    e = q.expect('dbus-signal',
                 signal='NewChannels',
                 predicate=new_chan_predicate)
    channels = e.args[0]
    assert len(channels) == 1
    path, props = channels[0]
    assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE

    tube_chan = bus.get_object(conn.bus_name, path)
    tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE)

    call_async(q, tube_iface, 'Accept', 0, 0, '', byte_arrays=True)

    accept_return_event, _ = q.expect_many(
        EventPattern('dbus-return', method='Accept'),
        EventPattern('dbus-signal',
                     signal='TubeChannelStateChanged',
                     args=[cs.TUBE_CHANNEL_STATE_OPEN]))

    unix_socket_adr = accept_return_event.value[0]

    factory = EventProtocolClientFactory(q)
    reactor.connectUNIX(unix_socket_adr, factory)

    # expect SI request
    e = q.expect('stream-iq',
                 to='[email protected]/bob',
                 query_ns=ns.SI,
                 query_name='si')

    bytestream, profile = create_from_si_offer(stream, q, BytestreamS5BRelay,
                                               e.stanza,
                                               '[email protected]/bob')

    result, si = bytestream.create_si_reply(e.stanza,
                                            'test@localhost/Resource')
    si.addElement((ns.TUBES, 'tube'))
    stream.send(result)

    # wait SOCKS5 init iq
    id, mode, si, hosts = bytestream._expect_socks5_init()
    for jid, host, port in hosts:
        # the proxy is not announced because we are in a muc
        assert jid != 'proxy.localhost'
Example #45
0
def test(q, bus, conn, stream):
    room = '*****@*****.**'
    handle = request_muc_handle(q, conn, stream, room)

    call_async(q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_HANDLE: handle})

    expected_muc_jid = '%s/%s' % (room, 'test')
    q.expect('stream-presence', to=expected_muc_jid)

    # tell gabble the room needs a password
    denied = \
        elem('jabber:client', 'presence', from_=expected_muc_jid,
            type='error')(
          elem(ns.MUC, 'x'),
          elem('error', type='auth')(
            elem(ns.STANZA, 'not-authorized'),
          ),
        )
    stream.send(denied)

    cc, _, _ = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('dbus-signal', signal='NewChannels'),
        EventPattern('dbus-signal', signal='PasswordFlagsChanged',
            args=[cs.PASSWORD_FLAG_PROVIDE, 0]))

    chan = wrap_channel(bus.get_object(conn.bus_name, cc.value[0]), 'Text',
        ['Password'])

    flags = chan.Password.GetPasswordFlags()
    assertEquals(cs.PASSWORD_FLAG_PROVIDE, flags)

    call_async(q, chan.Password, 'ProvidePassword', 'brand new benz')
    expect_attempt(q, expected_muc_jid, 'brand new benz')

    # Try again while the first attempt is outstanding. Gabble should say no.
    call_async(q, chan.Password, 'ProvidePassword', 'faster faster')
    q.expect('dbus-error', method='ProvidePassword')

    # Sorry, wrong password.
    stream.send(denied)
    ret = q.expect('dbus-return', method='ProvidePassword')
    assert not ret.value[0]

    call_async(q, chan.Password, 'ProvidePassword', 'bougie friends')
    expect_attempt(q, expected_muc_jid, 'bougie friends')

    # Well, this may be the right password, but actually that nick is in use.
    presence = elem('presence', from_=expected_muc_jid, type='error')(
        elem(ns.MUC, 'x'),
        elem('error', type='cancel')(
          elem(ns.STANZA, 'conflict'),
        ))
    stream.send(presence)

    # Okay, so Gabble tries again, with a new JID *and the same password*.
    expected_muc_jid = expected_muc_jid + '_'
    expect_attempt(q, expected_muc_jid, 'bougie friends')

    # Hey this worked.
    stream.send(make_muc_presence('none', 'participant', room, 'test_'))
    ret, _ = q.expect_many(
        EventPattern('dbus-return', method='ProvidePassword'),
        EventPattern('dbus-signal', signal='PasswordFlagsChanged',
            args=[0, cs.PASSWORD_FLAG_PROVIDE]))
    assert ret.value[0]
def test(q, bus, conn, stream, bytestream_cls, address_type, access_control,
         access_control_param):
    if bytestream_cls in [BytestreamS5BRelay, BytestreamS5BRelayBugged]:
        # disable SOCKS5 relay tests because proxy can't be used with muc
        # contacts atm
        return

    if access_control == cs.SOCKET_ACCESS_CONTROL_CREDENTIALS:
        print("Skip Socket_Access_Control_Credentials (fdo #45445)")
        return

    iq_event, disco_event = q.expect_many(
        EventPattern('stream-iq',
                     to=None,
                     query_ns='vcard-temp',
                     query_name='vCard'),
        EventPattern('stream-iq', to='localhost', query_ns=ns.DISCO_ITEMS))

    acknowledge_iq(stream, iq_event.stanza)

    announce_socks5_proxy(q, stream, disco_event.stanza)

    # join the muc
    call_async(
        q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: '*****@*****.**'
        })

    q.expect_many(
        EventPattern(
            'dbus-signal',
            signal='MembersChangedDetailed',
            predicate=lambda e: e.args[0] == [] and  # added
            e.args[1] == [] and  # removed
            e.args[2] == [] and  # local pending
            len(e.args[3]) == 1 and  # remote pending
            e.args[4].get('actor', 0) == 0 and e.args[4].get(
                'change-reason', 0) == 0 and e.args[4]['contact-ids'][e.args[
                    3][0]] == '[email protected]/test'),
        EventPattern('stream-presence', to='[email protected]/test'))

    # Send presence for other member of room.
    stream.send(
        make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob'))

    # Send presence for own membership of room.
    stream.send(
        make_muc_presence('none', 'participant', '*****@*****.**',
                          'test'))

    event = q.expect(
        'dbus-signal',
        signal='MembersChangedDetailed',
        predicate=lambda e: len(e.args[0]) == 2 and  # added
        e.args[1] == [] and  # removed
        e.args[2] == [] and  # local pending
        e.args[3] == [] and  # remote pending
        e.args[4].get('actor', 0) == 0 and e.args[4].get('change-reason', 0) ==
        0 and set([e.args[4]['contact-ids'][h] for h in e.args[0]]) == set(
            ['[email protected]/test', '[email protected]/bob']))

    for h in event.args[0]:
        if event.args[4]['contact-ids'][h] == '[email protected]/bob':
            bob_handle = h

    event = q.expect('dbus-return', method='CreateChannel')

    # Bob offers a stream tube
    stream_tube_id = 666
    presence = make_muc_presence('owner', 'moderator', '*****@*****.**',
                                 'bob')
    tubes = presence.addElement((ns.TUBES, 'tubes'))
    tube = tubes.addElement((None, 'tube'))
    tube['type'] = 'stream'
    tube['service'] = 'echo'
    tube['id'] = str(stream_tube_id)
    parameters = tube.addElement((None, 'parameters'))
    parameter = parameters.addElement((None, 'parameter'))
    parameter['name'] = 's'
    parameter['type'] = 'str'
    parameter.addContent('hello')
    parameter = parameters.addElement((None, 'parameter'))
    parameter['name'] = 'ay'
    parameter['type'] = 'bytes'
    parameter.addContent('aGVsbG8=')
    parameter = parameters.addElement((None, 'parameter'))
    parameter['name'] = 'u'
    parameter['type'] = 'uint'
    parameter.addContent('123')
    parameter = parameters.addElement((None, 'parameter'))
    parameter['name'] = 'i'
    parameter['type'] = 'int'
    parameter.addContent('-123')

    stream.send(presence)

    # text channel
    new_event = q.expect('dbus-signal', signal='NewChannels')

    channels = new_event.args[0]
    assert len(channels) == 1
    path, props = channels[0]
    assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT

    def new_chan_predicate(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE

    # tube channel is announced
    new_event = q.expect('dbus-signal',
                         signal='NewChannels',
                         predicate=new_chan_predicate)

    channels = new_event.args[0]
    assert len(channels) == 1
    path, props = channels[0]
    assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE
    assert props[cs.INITIATOR_HANDLE] == bob_handle
    assert props[cs.INITIATOR_ID] == '[email protected]/bob'
    assertSameSets([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE],
                   props[cs.INTERFACES])
    assert props[cs.REQUESTED] == False
    assert props[cs.TARGET_ID] == '*****@*****.**'
    assert props[cs.STREAM_TUBE_SERVICE] == 'echo'
    assert props[cs.TUBE_PARAMETERS] == {
        's': 'hello',
        'ay': b'hello',
        'u': 123,
        'i': -123
    }
    assert access_control in \
            props[cs.STREAM_TUBE_SUPPORTED_SOCKET_TYPES][address_type]

    tube_chan = bus.get_object(conn.bus_name, path)
    tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE,
                                  dbus_interface=cs.PROPERTIES_IFACE,
                                  byte_arrays=True)
    tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE)
    assert tube_props['Parameters'] == sample_parameters
    assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_LOCAL_PENDING

    # Accept the tube
    call_async(q,
               tube_iface,
               'Accept',
               address_type,
               access_control,
               access_control_param,
               byte_arrays=True)

    accept_return_event, _ = q.expect_many(
        EventPattern('dbus-return', method='Accept'),
        EventPattern('dbus-signal', signal='TubeChannelStateChanged',
                     args=[2]))

    address = accept_return_event.value[0]
    if isinstance(address, bytes):
        address = address.decode()

    socket_event, si_event, conn_id = t.connect_to_cm_socket(
        q, '[email protected]/bob', address_type, address, access_control,
        access_control_param)

    protocol = socket_event.protocol
    protocol.sendData(b"hello initiator")

    def accept_tube_si_connection():
        bytestream, profile = create_from_si_offer(stream, q, bytestream_cls,
                                                   si_event.stanza,
                                                   '[email protected]/test')

        assert profile == ns.TUBES

        muc_stream_node = xpath.queryForNodes(
            '/iq/si/muc-stream[@xmlns="%s"]' % ns.TUBES, si_event.stanza)[0]
        assert muc_stream_node is not None
        assert muc_stream_node['tube'] == str(stream_tube_id)

        # set the real jid of the target as 'to' because the XMPP server changes
        # it when delivering the IQ
        result, si = bytestream.create_si_reply(si_event.stanza,
                                                'test@localhost/Resource')
        si.addElement((ns.TUBES, 'tube'))
        stream.send(result)

        bytestream.wait_bytestream_open()
        return bytestream

    bytestream = accept_tube_si_connection()

    binary = bytestream.get_data()
    assert binary == b'hello initiator'

    # reply on the socket
    bytestream.send_data(b'hi joiner!')

    q.expect('socket-data', protocol=protocol, data=b"hi joiner!")

    # peer closes the bytestream
    bytestream.close()
    e = q.expect('dbus-signal', signal='ConnectionClosed')
    assertEquals(conn_id, e.args[0])
    assertEquals(cs.CONNECTION_LOST, e.args[1])

    # establish another tube connection
    socket_event, si_event, conn_id = t.connect_to_cm_socket(
        q, '[email protected]/bob', address_type, address, access_control,
        access_control_param)

    # bytestream is refused
    send_error_reply(stream, si_event.stanza)
    e, _ = q.expect_many(
        EventPattern('dbus-signal', signal='ConnectionClosed'),
        EventPattern('socket-disconnected'))
    assertEquals(conn_id, e.args[0])
    assertEquals(cs.CONNECTION_REFUSED, e.args[1])

    # establish another tube connection
    socket_event, si_event, conn_id = t.connect_to_cm_socket(
        q, '[email protected]/bob', address_type, address, access_control,
        access_control_param)

    protocol = socket_event.protocol
    bytestream = accept_tube_si_connection()

    # disconnect local socket
    protocol.transport.loseConnection()
    e, _ = q.expect_many(
        EventPattern('dbus-signal', signal='ConnectionClosed'),
        EventPattern('socket-disconnected'))
    assertEquals(conn_id, e.args[0])
    assertEquals(cs.CANCELLED, e.args[1])

    # OK, we're done
    disconnect_conn(q, conn, stream)
def test(q, bus, conn, stream):
    conn.Connect()

    _, iq_event, disco_event = q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged',
            args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]),
        EventPattern('stream-iq', to=None, query_ns='vcard-temp',
            query_name='vCard'),
        EventPattern('stream-iq', to='localhost', query_ns=ns.DISCO_ITEMS))

    acknowledge_iq(stream, iq_event.stanza)
    announce_gadget(q, stream, disco_event.stanza)

    act_prop_iface = dbus.Interface(conn, 'org.laptop.Telepathy.ActivityProperties')
    buddy_info_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo')
    simple_presence_iface = dbus.Interface(conn, 'org.freedesktop.Telepathy.Connection.Interface.SimplePresence')

    q.expect('dbus-signal', signal='GadgetDiscovered')
    gadget_publish(q, stream, conn, True)

    # join a room
    room_handle, room_path = join_channel('*****@*****.**',
            q, conn, stream)

    call_async (q, buddy_info_iface, 'SetActivities', [("roomid", room_handle)])

    # pubsub activity iq
    event = q.expect('stream-iq', iq_type='set', query_name='pubsub',
        query_ns=ns.PUBSUB)
    acknowledge_iq(stream, event.stanza)

    event = q.expect('dbus-return', method='SetActivities')

    # make activity public
    call_async(q, act_prop_iface, 'SetProperties',
            1, {'title': 'My test activity', 'private': False})

    # pseudo invite
    event = q.expect('stream-message', to='gadget.localhost')
    message = event.stanza
    properties = xpath.queryForNodes('/message/properties', message)
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'roomid'

    # invite
    event = q.expect('stream-message', to='*****@*****.**')
    message = event.stanza
    x = xpath.queryForNodes('/message/x', message)
    assert (x is not None and len(x) == 1), repr(x)
    assert x[0].uri == ns.MUC_USER

    invites = xpath.queryForNodes('/x/invite', x[0])
    assert (invites is not None and len(invites) == 1), repr(invites)
    assert invites[0]['to'] == 'gadget.localhost'

    # pubsub activity prop iq
    event = q.expect('stream-iq')
    acknowledge_iq(stream, event.stanza)

    # pubsub activity iq
    event = q.expect('stream-iq')
    acknowledge_iq(stream, event.stanza)

    event = q.expect('dbus-return', method='SetProperties')

    # Gadget joins the room
    stream.send(make_muc_presence('none', 'participant', '*****@*****.**',
        'inspector', 'gadget.localhost'))

    muc = bus.get_object(conn.bus_name, room_path)
    muc_group = dbus.Interface(muc, "org.freedesktop.Telepathy.Channel.Interface.Group")

    sync_stream(q, stream)
    members = muc_group.GetMembers()
    assert conn.InspectHandles(1, members) == ['[email protected]/test']

    # Regression test for a nasty bug caused by the presence cache handling
    # the inspector presence as a non-MUC one because the inspector is not
    # added to MUC's members.
    handle = conn.RequestHandles(1, ['*****@*****.**'])[0]
    presence = simple_presence_iface.GetPresences([handle])
    assert presence[handle] == (7, 'unknown', '')

    # PEP activity update
    disconnect_conn(q, conn, stream, [EventPattern('stream-iq')])[0]
        conn.Requests,
        "CreateChannel",
        {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: "*****@*****.**",
        },
    )

    q.expect("stream-presence", to="[email protected]/test")

    # Bob is in the room and in the tube
    bob_in_tube()

    # Send presence for own membership of room.
    stream.send(make_muc_presence("none", "participant", muc, "test"))

    # tube is created as well
    e = q.expect("dbus-signal", signal="NewChannels")
    tube_path, props = e.args[0][0]
    assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE])
    assertEquals("[email protected]/test", props[cs.INITIATOR_ID])
    assertEquals(False, props[cs.REQUESTED])
    assertEquals(cs.HT_ROOM, props[cs.TARGET_HANDLE_TYPE])
    assertEquals("com.example.TestCase", props[cs.DBUS_TUBE_SERVICE_NAME])

    # text channel is created
    e = q.expect("dbus-signal", signal="NewChannels")
    path, props = e.args[0][0]
    assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE])
    assertEquals(True, props[cs.REQUESTED])
def test_create_ensure(q, conn, bus, stream, room_jid):
    # Call both Create and Ensure for the same channel.
    call_async(q, conn.Requests, 'CreateChannel',
           { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
             cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
             cs.TARGET_ID: room_jid,
           })
    call_async(q, conn.Requests, 'EnsureChannel',
           { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
             cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
             cs.TARGET_ID: room_jid,
           })

    mc, _ = q.expect_many(
        EventPattern('dbus-signal', signal='MembersChangedDetailed'),
        EventPattern('stream-presence', to=('%s/test' % room_jid)))
    added, removed, local_pending, remote_pending, details = mc.args

    assert added == [], mc.args
    assert removed == [], mc.args
    assert local_pending == [], mc.args
    assert len(remote_pending) == 1, mc.args

    # Send presence for other member of room.
    stream.send(make_muc_presence('owner', 'moderator', room_jid, 'bob'))

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', room_jid, 'test'))

    mc = q.expect('dbus-signal', signal='MembersChangedDetailed')
    added, removed, local_pending, remote_pending, details = mc.args

    assert len(added) == 2, mc.args
    assert removed == [], mc.args
    assert local_pending == [], mc.args
    assert remote_pending == [], mc.args

    members = conn.inspect_contacts_sync(added)
    members.sort()
    assert members == ['%s/bob' % room_jid, '%s/test' % room_jid], members

    create_event, ensure_event = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('dbus-return', method='EnsureChannel'))

    assert len(create_event.value) == 2
    c_path, c_props = create_event.value

    assert len(ensure_event.value) == 3
    yours, e_path, e_props = ensure_event.value

    assert c_path == e_path, (c_path, e_path)
    assert c_props == e_props, (c_props, e_props)

    assert not yours

    assertContains('text/plain', c_props[cs.SUPPORTED_CONTENT_TYPES])
    assertEquals(0, c_props[cs.MESSAGE_PART_SUPPORT_FLAGS])
    assertEquals(
            cs.DELIVERY_REPORTING_SUPPORT_FLAGS_RECEIVE_FAILURES |
            cs.DELIVERY_REPORTING_SUPPORT_FLAGS_RECEIVE_SUCCESSES,
            c_props[cs.DELIVERY_REPORTING_SUPPORT])
    # rejoin the room
    call_async(
        q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: '*****@*****.**'
        })

    q.expect('stream-presence', to='[email protected]/test')

    # Bob is in the room and in the tube
    bob_in_tube()

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', muc, 'test'))

    def new_tube(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE

    def new_text(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT

    # tube and text is created
    text_event, tube_event = q.expect_many(
        EventPattern('dbus-signal', signal='NewChannels', predicate=new_text),
        EventPattern('dbus-signal', signal='NewChannels', predicate=new_tube))

    channels = e.args[0]
def test(q, bus, conn, stream):
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    call_async(q, conn.Requests, 'CreateChannel',
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
              cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
              cs.TARGET_ID: '*****@*****.**'
            })

    gfc, _, _, _ = q.expect_many(
        # Initial group flags
        EventPattern('dbus-signal', signal='GroupFlagsChanged',
            predicate=lambda e: e.args[0] != 0),
        EventPattern('dbus-signal', signal='MembersChangedDetailed',
            predicate=lambda e: e.args[3] == [2]),
        # Removing CAN_ADD
        EventPattern('dbus-signal', signal='GroupFlagsChanged',
          args = [0, cs.GF_CAN_ADD], predicate=lambda e: e.args[0] == 0),
        EventPattern('stream-presence', to='[email protected]/test'))
    assert gfc.args[1] == 0

    # Send presence for anonymous other member of room.
    stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob'))

    # Send presence for anonymous other member of room (2)
    stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'brian'))

    # Send presence for nonymous other member of room.
    stream.send(make_muc_presence('none', 'participant', '*****@*****.**',
        'che', '*****@*****.**'))

    # Send presence for nonymous other member of room (2)
    stream.send(make_muc_presence('none', 'participant', '*****@*****.**',
        'chris', '*****@*****.**'))

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', '*****@*****.**', 'test'))

    # Since we received MUC presence that contains an owner JID, the
    # OWNERS_NOT_AVAILABLE flag should be removed.
    event = q.expect('dbus-signal', signal='GroupFlagsChanged',
        args = [0, cs.GF_HANDLE_OWNERS_NOT_AVAILABLE ])

    event = q.expect('dbus-signal', signal='HandleOwnersChanged')
    owners = event.args[0]

    event = q.expect('dbus-signal', signal='MembersChangedDetailed')
    added = event.args[0]

    [test, bob, brian, che, che_owner, chris, chris_owner] = \
        conn.get_contact_handles_sync(
            [ '[email protected]/test', '[email protected]/bob',
              '[email protected]/brian', '[email protected]/che',
              '*****@*****.**', '[email protected]/chris', '*****@*****.**',
            ])
    expected_members = sorted([test, bob, brian, che, chris])
    expected_owners = { test: self_handle,
                        bob: 0,
                        brian: 0,
                        che: che_owner,
                        chris: chris_owner
                      }
    assertEquals(expected_members, sorted(added))
    assertEquals(expected_owners, owners)

    event = q.expect('dbus-return', method='CreateChannel')

    chan = wrap_channel(bus.get_object(conn.bus_name, event.value[0]), 'Text')

    # Exercise HandleOwners
    owners = chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'HandleOwners')
    assertEquals(che_owner, owners[che])
    assertEquals(chris_owner, owners[chris])

    # Exercise D-Bus properties
    all = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP)

    assert all[u'LocalPendingMembers'] == [], all
    assert sorted(all[u'Members']) == expected_members, all
    assert all[u'RemotePendingMembers'] == [], all
    assert all[u'SelfHandle'] == test, all
    assert all[u'HandleOwners'] == expected_owners, all

    flags = all[u'GroupFlags']
    assertFlagsSet(cs.GF_CHANNEL_SPECIFIC_HANDLES, flags)
    assertFlagsUnset(cs.GF_HANDLE_OWNERS_NOT_AVAILABLE, flags)
Example #52
0
def run_outgoing_test(q, bus, conn, stream, close_channel=False):
    jp = JingleProtocol031 ()
    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', muc + '/bob')
    jt.prepare()

    self_handle = conn.GetSelfHandle()

    # Not allowed to have muji related presences before we accept the channel
    forbidden = [ no_muji_presences (muc) ]

    (path, props) = create_muji_channel (q, conn, stream, muc)

    q.forbid_events(forbidden)
    general_tests (jp, q, bus, conn, stream, path, props)

    channel = bus.get_object (conn.bus_name, path)

    props = channel.GetAll (cs.CHANNEL_TYPE_CALL,
        dbus_interface = dbus.PROPERTIES_IFACE)

    content = bus.get_object (conn.bus_name, props['Contents'][0])
    codecs = jt.get_call_audio_codecs_dbus()

    # Accept codec offer
    props = content.GetAll(cs.CALL_CONTENT_IFACE_MEDIA,
        dbus_interface=dbus.PROPERTIES_IFACE)
    offer = bus.get_object (conn.bus_name, props["CodecOffer"][0])
    offer.Accept(codecs, dbus_interface=cs.CALL_CONTENT_CODECOFFER)

    # Accept the channel, which means we can get muji presences
    q.unforbid_events (forbidden)
    channel.Accept()

    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')
    mujinode = xpath.queryForNodes("/presence/muji", e.stanza)
    assertLength (1, mujinode)

    # The one with the codecs
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Gabble shouldn't send new presences for a while
    q.forbid_events(forbidden)

    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    presence.addElement ((ns.MUJI, 'muji')).addElement('preparing')
    stream.send(presence)

    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    muji =  ('muji', ns.MUJI, {},
        [('content', ns.MUJI, { "name": "Audio" },
            [( 'description', ns.JINGLE_RTP, {"media": "audio"},
            jt.generate_payloads(jt.audio_codecs))])])
    presence.addChild(jp._simple_xml(muji))
    stream.send(presence)

    q.expect('dbus-signal', signal = 'CallStateChanged')

    # Bob appears and starts a session right afterwards
    q.expect('dbus-signal', signal = 'CallMembersChanged')

    e = q.expect('dbus-signal', signal = 'NewCodecOffer')
    offer = bus.get_object (conn.bus_name, e.args[1])
    offer.Accept(codecs, dbus_interface=cs.CALL_CONTENT_CODECOFFER)

    jt.incoming_call(audio = "Audio")

    e = q.expect ('dbus-signal', signal = 'StreamsAdded')
    cstream = bus.get_object (conn.bus_name, e.args[0][0])

    candidates = jt.get_call_remote_transports_dbus ()
    cstream.AddCandidates (candidates,
        dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

    # Fake our endpoint being connected
    endpoints = cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
        "Endpoints", dbus_interface=dbus.PROPERTIES_IFACE)
    assertLength (1, endpoints)

    endpoint = bus.get_object (conn.bus_name, endpoints[0])

    endpoint.SetStreamState (cs.MEDIA_STREAM_STATE_CONNECTED,
        dbus_interface=cs.CALL_STREAM_ENDPOINT)

    e = q.expect ('stream-iq',
        predicate = jp.action_predicate ('session-accept'))
    stream.send(jp.xml(jp.ResultIq(jt.peer, e.stanza, [])))

    # But we want video as well !
    c = channel.AddContent ("Camera!", cs.MEDIA_STREAM_TYPE_VIDEO,
        dbus_interface=cs.CHANNEL_TYPE_CALL)

    q.expect('dbus-signal', signal = 'ContentAdded')

    content = bus.get_object (conn.bus_name, c)
    codecs = jt.get_call_video_codecs_dbus()

    # wait for the CodecOffer and Accept it
    q.expect('dbus-signal', signal = 'NewCodecOffer')
    props = content.GetAll(cs.CALL_CONTENT_IFACE_MEDIA,
        dbus_interface=dbus.PROPERTIES_IFACE)
    offer = bus.get_object (conn.bus_name, props["CodecOffer"][0])
    offer.Accept(codecs, dbus_interface=cs.CALL_CONTENT_CODECOFFER)

    q.unforbid_events(forbidden)

    # preparing
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    #codecs
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Bob would like to join our video party
    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    muji =  ('muji', ns.MUJI, {},
        [('content', ns.MUJI, { "name": "Audio" },
            [( 'description', ns.JINGLE_RTP, {"media": "audio"},
            jt.generate_payloads(jt.audio_codecs))]),
         ('content', ns.MUJI, { "name": "Camera!" },
            [( 'description', ns.JINGLE_RTP, {"media": "video"},
            jt.generate_payloads(jt.video_codecs))]),
        ])
    presence.addChild(jp._simple_xml(muji))
    stream.send(presence)

    # new codec offer as bob threw in some codecs
    q.expect('dbus-signal', signal='NewCodecOffer')
    check_and_accept_offer (q, bus, conn, self_handle, 0,
            content, codecs, check_codecs_changed = False)

    # Bob sends a content
    node = jp.SetIq(jt.peer, jt.jid, [
        jp.Jingle(jt.sid, jt.peer, 'content-add', [
            jp.Content('videostream', 'initiator', 'both',
                jp.Description('video', [
                    jp.PayloadType(name, str(rate), str(id), parameters) for
                        (name, id, rate, parameters) in jt.video_codecs ]),
            jp.TransportGoogleP2P()) ]) ])
    stream.send(jp.xml(node))

    # We get a new stream
    q.expect('dbus-signal', signal = 'StreamsAdded')

    # Sync up the stream to ensure we sent out all the xmpp traffic that was
    # the result of a stream being added
    sync_stream (q, stream)

    # happiness.. Now let's hang up
    if close_channel:
        channel.Close()
        hangup_event = EventPattern ('dbus-signal', signal = "Closed",
            path = path)
    else:
        channel.Hangup (0, "", "", dbus_interface=cs.CHANNEL_TYPE_CALL)
        hangup_event = EventPattern ('dbus-signal', signal='CallStateChanged')

    # Should change the call state to ended, send a session-terminate to our
    # only peer and send a muc presence without any mention of muji
    q.forbid_events(forbidden)
    q.expect_many (EventPattern ('stream-presence', to = muc + "/test"),
        EventPattern ('stream-iq',
                predicate=jp.action_predicate ('session-terminate')),
        hangup_event)

    if not close_channel:
        channel.Close()
        q.expect ('dbus-signal', signal="Closed", path = path)

    try:
        channel.Close()
        raise AssertionError ("Channel didn't actually close")
    except DBusException:
        pass
Example #53
0
def test(q, bus, conn, stream):
    # Bob has invited us to an activity.
    message = domish.Element((None, 'message'))
    message['from'] = '*****@*****.**'
    message['to'] = 'test@localhost'
    x = message.addElement(('http://jabber.org/protocol/muc#user', 'x'))
    invite = x.addElement((None, 'invite'))
    invite['from'] = 'bob@localhost'
    reason = invite.addElement((None, 'reason'))
    reason.addContent('No good reason')

    stream.send(message)

    event = q.expect('dbus-signal', signal='NewChannels')
    path, props = event.args[0][0]
    assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE])
    assertEquals(cs.HT_ROOM, props[cs.TARGET_HANDLE_TYPE])
    assertEquals(1, props[cs.TARGET_HANDLE])

    text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    members = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'Members')
    local_pending = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP,
                                             'LocalPendingMembers')
    remote_pending = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP,
                                              'RemotePendingMembers')

    assert len(members) == 1
    assert conn.inspect_contact_sync(members[0]) == 'bob@localhost'
    bob_handle = members[0]
    assert len(local_pending) == 1
    # FIXME: the username-part-is-nickname assumption
    assert conn.inspect_contact_sync(local_pending[0][0]) == \
            '[email protected]/test'
    assert len(remote_pending) == 0

    room_self_handle = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP,
                                                "SelfHandle")
    assert room_self_handle == local_pending[0][0]

    channel_props = text_chan.Properties.GetAll(cs.CHANNEL)
    assert channel_props['TargetID'] == '*****@*****.**', channel_props
    assert channel_props['Requested'] == False
    assert channel_props['InitiatorID'] == 'bob@localhost'
    assert channel_props['InitiatorHandle'] == bob_handle

    # set ourselves to away and back again, to check that we don't send any
    # presence to the MUC before the invite has been accepted
    conn.SimplePresence.SetPresence('away', 'failure')
    conn.SimplePresence.SetPresence('available', 'success')

    # accept the invitation
    call_async(q, text_chan.Group, 'AddMembers', [room_self_handle],
               'Oh, OK then')

    event, event2, _ = q.expect_many(
        EventPattern('stream-presence', to='[email protected]/test'),
        EventPattern('dbus-signal', signal='MembersChangedDetailed'),
        EventPattern('dbus-return', method='AddMembers'))

    # check that the status we joined with was available / success
    elem = event.stanza
    show = [e for e in elem.elements() if e.name == 'show']
    assert not show
    status = [e for e in elem.elements() if e.name == 'status'][0]
    assert status
    assert status.children[0] == u'success'

    # We are added as remote pending while joining the room. The inviter (Bob)
    # is removed for now. It will be re-added with his channel specific handle
    # once we have joined.
    added, removed, local_pending, remote_pending, details = event2.args
    assertEquals([], added)
    assertEquals([bob_handle], removed)
    assertEquals([], local_pending)
    assertEquals([room_self_handle], remote_pending)
    assertEquals(cs.GC_REASON_INVITED, details['change-reason'])

    # Send presence for Bob's membership of room.
    stream.send(
        make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob'))

    # Send presence for own membership of room.
    stream.send(
        make_muc_presence('owner', 'moderator', '*****@*****.**', 'test'))

    event = q.expect('dbus-signal', signal='MembersChangedDetailed')

    room_bob_handle = conn.get_contact_handle_sync('[email protected]/bob')

    added, removed, local_pending, remote_pending, details = event.args
    assertEquals([room_self_handle, room_bob_handle], added)
    assertEquals([], removed)
    assertEquals([], local_pending)
    assertEquals([], remote_pending)

    # Test sending an invitation
    alice_handle = conn.get_contact_handle_sync('alice@localhost')
    call_async(q, text_chan.Group, 'AddMembers', [alice_handle],
               'I want to test invitations')

    event = q.expect('stream-message', to='*****@*****.**')
    message = event.stanza

    x = xpath.queryForNodes('/message/x', message)
    assert (x is not None and len(x) == 1), repr(x)
    assert x[0].uri == 'http://jabber.org/protocol/muc#user'

    invites = xpath.queryForNodes('/x/invite', x[0])
    assert (invites is not None and len(invites) == 1), repr(invites)
    assert invites[0]['to'] == 'alice@localhost'

    reasons = xpath.queryForNodes('/invite/reason', invites[0])
    assert (reasons is not None and len(reasons) == 1), repr(reasons)
    assert str(reasons[0]) == 'I want to test invitations'
Example #54
0
def run_incoming_test(q, bus, conn, stream, bob_leaves_room = False):
    jp = JingleProtocol031 ()
    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', muc + "/bob")
    jt.prepare()
    forbidden = [ no_muji_presences (muc) ]

    self_handle = conn.GetSelfHandle()

    _, _, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, muc)

    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    muji =  ('muji', ns.MUJI, {},
        [('content', ns.MUJI, { "name": "Voice" },
            [( 'description', ns.JINGLE_RTP, {"media": "audio"},
            jt.generate_payloads(jt.audio_codecs))])])
    presence.addChild(jp._simple_xml(muji))

    stream.send(presence)

    e = q.expect ('dbus-signal',
        signal='NewChannels',
        predicate=lambda e: \
            e.args[0][0][1][cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_CALL )

    (path, props) = e.args[0][0]

    assertContains((cs.CHANNEL_TYPE_CALL + '.InitialAudio', True),
        props.items())
    assertContains((cs.CHANNEL_TYPE_CALL + '.InitialVideo', False),
        props.items())

    general_tests (jp, q, bus, conn, stream, path, props)

    channel = bus.get_object (conn.bus_name, path)
    props = channel.GetAll (cs.CHANNEL_TYPE_CALL,
        dbus_interface = dbus.PROPERTIES_IFACE)

    content = bus.get_object (conn.bus_name, props['Contents'][0])

    check_state (q, channel, cs.CALL_STATE_PENDING_RECEIVER)

    codecs = jt.get_call_audio_codecs_dbus()

    check_and_accept_offer (q, bus, conn, self_handle, 0,
            content, codecs)
    channel.Accept (dbus_interface=cs.CHANNEL_TYPE_CALL)

    # Preparing stanza
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Codecs stanza
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Gabble shouldn't send new presences for a while
    q.forbid_events(forbidden)

    e = q.expect ('dbus-signal', signal = 'StreamsAdded')
    cstream = bus.get_object (conn.bus_name, e.args[0][0])

    cstream.SetCredentials(jt.ufrag, jt.pwd,
        dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

    candidates = jt.get_call_remote_transports_dbus ()
    cstream.AddCandidates (candidates,
        dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

    e = q.expect('stream-iq',
        predicate=jp.action_predicate('session-initiate'))
    jt.parse_session_initiate (e.query)

    jt.accept()

   # Bob adds a Video content
    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    presence.addElement ((ns.MUJI, 'muji')).addElement('preparing')
    stream.send(presence)

    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    muji =  ('muji', ns.MUJI, {},
        [('content', ns.MUJI, { "name": "Voice" },
            [( 'description', ns.JINGLE_RTP, {"media": "audio"},
            jt.generate_payloads(jt.audio_codecs))]),
         ('content', ns.MUJI, { "name": "Camera" },
            [( 'description', ns.JINGLE_RTP, {"media": "video"},
            jt.generate_payloads(jt.video_codecs))]),
        ])
    presence.addChild(jp._simple_xml(muji))
    stream.send(presence)

    # Gabble noticed bob added a content
    e = q.expect('dbus-signal', signal = 'ContentAdded')

    q.unforbid_events (forbidden)
    content = bus.get_object (conn.bus_name, e.args[0])
    check_and_accept_offer (q, bus, conn, self_handle, 0,
            content, jt.get_call_video_codecs_dbus(),
            check_codecs_changed = False)

    # Gabble sends a presence to prepare
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Gabble sends a presence with the video codecs
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Gabble adds a content to the jingle session and thus a stream is added
    e = q.expect ('dbus-signal', signal = 'StreamsAdded')
    cstream = bus.get_object (conn.bus_name, e.args[0][0])

    candidates = jt.get_call_remote_transports_dbus ()
    cstream.AddCandidates (candidates,
        dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

    # And now the content-add on the jingle streams
    e = q.expect('stream-iq', to = muc + "/bob",
        predicate = lambda x: \
        xpath.queryForNodes("/iq/jingle[@action='content-add']", x.stanza))

    # Bob leaves the call, bye bob
    if bob_leaves_room:
        presence = make_muc_presence('owner', 'moderator', muc, 'bob')
        presence['type'] = 'unavailable'
    else:
        presence = make_muc_presence('owner', 'moderator', muc, 'bob')

    stream.send(presence)
    (cmembers, _, _) = q.expect_many(
        EventPattern ('dbus-signal', signal = 'CallMembersChanged'),
        # Audio and video stream
        EventPattern ('dbus-signal', signal = 'StreamsRemoved'),
        EventPattern ('dbus-signal', signal = 'StreamsRemoved'))


    # Just bob left
    assertLength (1, cmembers.args[1])
Example #55
0
def test(q, bus, conn, stream):
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    # When Gabble initially requests its avatar from the server, it discovers
    # it has none.
    expect_and_handle_get_vcard(q, stream)
    handle, signalled_token = q.expect('dbus-signal', signal='AvatarUpdated').args

    assertEquals(self_handle, handle)
    assertEquals('', signalled_token)

    # The user sets an avatar.
    call_async(q, conn.Avatars, 'SetAvatar', AVATAR_1_DATA, AVATAR_1_MIME_TYPE)
    expect_and_handle_get_vcard(q, stream)
    expect_and_handle_set_vcard(q, stream)

    # It's signalled on D-Bus …
    set_ret, avatar_updated = q.expect_many(
        EventPattern('dbus-return', method='SetAvatar'),
        EventPattern('dbus-signal', signal='AvatarUpdated'),
        )

    returned_token, = set_ret.value
    handle, signalled_token = avatar_updated.args

    assertEquals(self_handle, handle)
    assertEquals(returned_token, signalled_token)

    # … and also on XMPP.
    broadcast = q.expect('stream-presence', to=None)
    broadcast_hash = extract_hash_from_presence(broadcast.stanza)
    assertEquals(AVATAR_1_SHA1, broadcast_hash)

    # If applications ask Gabble for information about the user's own avatar,
    # it should be able to answer. (Strictly speaking, expecting Gabble to know
    # the avatar data is risky because Gabble discards cached vCards after a
    # while, but we happen to know it takes 20 seconds or so for that to
    # happen.)
    known = conn.Avatars.GetKnownAvatarTokens([self_handle])
    assertEquals({self_handle: signalled_token}, known)

    conn.Avatars.RequestAvatars([self_handle])
    retrieved = q.expect('dbus-signal', signal='AvatarRetrieved')
    handle, token, data, mime_type = retrieved.args
    assertEquals(self_handle, handle)
    assertEquals(signalled_token, token)
    assertEquals(AVATAR_1_DATA, data)
    assertEquals(AVATAR_1_MIME_TYPE, mime_type)

    # Well, that was quite easy. How about we join a MUC? XEP-0153 §4.1 says:
    #     If a client supports the protocol defined herein, it […] SHOULD
    #     also include the update child in directed presence stanzas (e.g.,
    #     directed presence sent when joining Multi-User Chat [5] rooms).
    #         — http://xmpp.org/extensions/xep-0153.html#bizrules-presence
    join_event = try_to_join_muc(q, bus, conn, stream, MUC)
    directed_hash = extract_hash_from_presence(join_event.stanza)
    assertEquals(AVATAR_1_SHA1, directed_hash)

    # There are two others in the MUC: fredrik has no avatar, wendy has an
    # avatar. We, of course, have our own avatar.
    stream.send(make_muc_presence('none', 'participant', MUC, 'fredrik'))
    stream.send(make_muc_presence('none', 'participant', MUC, 'wendy',
          photo=AVATAR_2_SHA1))
    stream.send(make_muc_presence('owner', 'moderator', MUC, 'test',
          photo=AVATAR_1_SHA1))

    path, _ = q.expect('dbus-return', method='CreateChannel').value
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    members = chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'Members')
    assertLength(3, members)

    fredrik, wendy, muc_self_handle = conn.get_contact_handles_sync(
        ['%s/%s' % (MUC, x) for x in ["fredrik", "wendy", "test"]])

    known = conn.Avatars.GetKnownAvatarTokens(members)
    # <https://bugs.freedesktop.org/show_bug.cgi?id=32017>: this assertion
    # failed, the MUC self handle's token was the empty string.
    assertEquals(AVATAR_1_SHA1, known[muc_self_handle])
    assertEquals(AVATAR_2_SHA1, known[wendy])
    assertEquals('', known[fredrik])

    # 'k, cool. Wendy loves our avatar and switches to it.
    stream.send(make_muc_presence('none', 'participant', MUC, 'wendy',
          photo=AVATAR_1_SHA1))
    # Okay this is technically assuming that we just expose the SHA1 sums
    # directly which is not guaranteed … but we do.
    q.expect('dbus-signal', signal='AvatarUpdated',
        args=[wendy, AVATAR_1_SHA1])

    # Fredrik switches too.
    stream.send(make_muc_presence('none', 'participant', MUC, 'fredrik',
          photo=AVATAR_1_SHA1))
    q.expect('dbus-signal', signal='AvatarUpdated',
        args=[fredrik, AVATAR_1_SHA1])

    # And we switch to some other avatar. Gabble should update its vCard, and
    # then update its MUC presence (which the test, acting as the MUC server,
    # must echo).
    call_async(q, conn.Avatars, 'SetAvatar', AVATAR_2_DATA, AVATAR_2_MIME_TYPE)
    expect_and_handle_get_vcard(q, stream)
    expect_and_handle_set_vcard(q, stream)

    muc_presence = q.expect('stream-presence', to=('%s/test' % MUC))
    directed_hash = extract_hash_from_presence(muc_presence.stanza)
    stream.send(make_muc_presence('owner', 'moderator', MUC, 'test',
          photo=directed_hash))

    # Gabble should signal an avatar update for both our global self-handle and
    # our MUC self-handle. (The first of these of course does not need to wait
    # for the MUC server to echo our presence.)
    q.expect_many(
        EventPattern('dbus-signal', signal='AvatarUpdated',
            args=[self_handle, AVATAR_2_SHA1]),
        EventPattern('dbus-signal', signal='AvatarUpdated',
            args=[muc_self_handle, AVATAR_2_SHA1]),
        )
def test_subject(q, bus, conn, stream, change_subject, send_first,
        moderator):
    room = '*****@*****.**'

    chan, path, props, disco = join_muc(q, bus, conn, stream,
            room,
            also_capture=[EventPattern('stream-iq', iq_type='get',
                query_name='query', query_ns=ns.DISCO_INFO, to=room)],
            role=(moderator and 'moderator' or 'participant'))

    assert chan.Properties.Get(cs.CHANNEL_IFACE_SUBJECT, "CanSet")

    if send_first:
        # Someone sets a subject.
        message = domish.Element((None, 'message'))
        message['from'] = room + '/bob'
        message['type'] = 'groupchat'
        message.addElement('subject', content='Testing')
        stream.send(message)

        q.expect('dbus-signal', interface=cs.PROPERTIES_IFACE,
                 signal='PropertiesChanged',
                 predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_SUBJECT)
        check_subject_props(chan, 'Testing', room + '/bob', True)

    # Reply to the disco
    iq = make_result_iq(stream, disco.stanza)
    query = iq.firstChildElement()
    feat = query.addElement('feature')
    feat['var'] = 'muc_public'

    x = query.addElement((ns.X_DATA, 'x'))
    x['type'] = 'result'

    if change_subject is not None:
        # When fd.o #13157 has been fixed, this will actually do something.
        field = x.addElement('field')
        field['var'] = 'muc#roomconfig_changesubject'
        field.addElement('value',
                content=(change_subject and 'true' or 'false'))

    stream.send(iq)

    # Someone sets a subject.
    message = domish.Element((None, 'message'))
    message['from'] = room + '/bob'
    message['type'] = 'groupchat'
    message.addElement('subject', content='lalala')
    stream.send(message)

    q.expect('dbus-signal', interface=cs.PROPERTIES_IFACE,
             signal='PropertiesChanged',
             predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_SUBJECT)
    check_subject_props(chan, 'lalala', room + '/bob', True)

    # test changing the subject
    call_async(q, chan, 'SetSubject', 'le lolz', dbus_interface=cs.CHANNEL_IFACE_SUBJECT)

    e = q.expect('stream-message', to=room)
    elem = e.stanza
    assertEquals('groupchat', elem['type'])
    assertEquals(1, len(elem.children))
    assertEquals(elem.children[0].name, 'subject')
    assertEquals(str(elem.children[0]), 'le lolz')

    elem['from'] = room + '/test'
    stream.send(elem)

    q.expect_many(EventPattern('dbus-signal', interface=cs.PROPERTIES_IFACE,
                               signal='PropertiesChanged',
                               predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_SUBJECT),
                  EventPattern('dbus-return', method='SetSubject'),
                 )

    check_subject_props(chan, 'le lolz', room + '/test', True)

    # Test changing the subject and getting an error back.
    call_async(q, chan, 'SetSubject', 'CHICKEN MAN', dbus_interface=cs.CHANNEL_IFACE_SUBJECT)

    e = q.expect('stream-message', to=room)
    elem = e.stanza
    elem['from'] = room
    elem['type'] = 'error'
    error = elem.addElement((None, 'error'))
    error['type'] = 'auth'
    error.addElement((ns.STANZA, 'forbidden'))
    stream.send(elem)
    q.expect('dbus-error', method='SetSubject', name=cs.PERMISSION_DENIED)

    # Test changing the subject and getting an error back which doesn't echo
    # the <subject> element.
    call_async(q, chan, 'SetSubject', 'CHICKEN MAN', dbus_interface=cs.CHANNEL_IFACE_SUBJECT)

    e = q.expect('stream-message', to=room)
    message = domish.Element((None, 'message'))
    message['from'] = room
    message['id'] = e.stanza['id']
    message['type'] = 'error'
    error = message.addElement((None, 'error'))
    error.addElement((ns.STANZA, 'forbidden'))
    stream.send(message)

    q.expect('dbus-error', method='SetSubject', name=cs.PERMISSION_DENIED)

    # Test changing the subject just before we leave the room (and hence not
    # getting a reply). While we're here, check that you can't have more than
    # one call in flight at a time.
    call_async(q, chan, 'SetSubject', 'le lolz', dbus_interface=cs.CHANNEL_IFACE_SUBJECT)
    e = q.expect('stream-message', to=room)

    call_async(q, chan, 'SetSubject', 'le lolz', dbus_interface=cs.CHANNEL_IFACE_SUBJECT)
    q.expect('dbus-error', method='SetSubject', name=cs.NOT_AVAILABLE)

    chan.Close()

    event = q.expect('stream-presence', to=room + '/test')
    elem = event.stanza
    assertEquals('unavailable', elem['type'])

    q.expect('dbus-error', method='SetSubject', name=cs.CANCELLED)

    call_async(q, chan, 'SetSubject', 'how about now?',
        dbus_interface=cs.CHANNEL_IFACE_SUBJECT)
    q.expect('dbus-error', method='SetSubject', name=cs.NOT_AVAILABLE)

    # The MUC confirms that we've left the room.
    echo = make_muc_presence('member', 'none', room, 'test')
    echo['type'] = 'unavailable'
    stream.send(echo)
    q.expect('dbus-signal', signal='ChannelClosed')