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)
Example #2
0
def test(q, bus, conn, stream):
    jp = JingleProtocol031()
    remote_jid = '[email protected]/misc'
    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid)

    jt.prepare()

    self_handle = conn.GetSelfHandle()
    remote_handle = conn.RequestHandles(cs.HT_CONTACT, [remote_jid])[0]
    path, _ = conn.Requests.CreateChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_HANDLE: remote_handle})

    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia')

    # In Gabble, the StreamedMedia channel is secretly also the SessionHandler.
    # Let's make up a proxy and call some methods on it. They should fail
    # gracefully, rather than crashing Gabble.
    session_handler = make_channel_proxy(conn, path, 'Media.SessionHandler')

    try:
        session_handler.Ready()
    except DBusException, e:
        assertEquals(cs.NOT_AVAILABLE, e.get_dbus_name())
Example #3
0
def setup(q, bus, conn, stream, op_user=True):
    conn.Connect()
    q.expect('dbus-signal', signal='StatusChanged',
        args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])

    # test MUC channel
    call_async(q, conn.Requests, 'CreateChannel',
        {cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
        cs.TARGET_ID: '#test'})

    ret, _, _ = q.expect_many(EventPattern('dbus-return', method='CreateChannel'),
                              EventPattern('dbus-signal', signal='MembersChanged'),
                              EventPattern('stream-MODE', data=['#test']))

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

    change_channel_mode(stream, '+n')

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

    if op_user:
        change_channel_mode(stream, '+o test')

        q.expect_many(EventPattern('dbus-signal', signal='GroupFlagsChanged',
                                   args=[cs.GF_MESSAGE_REMOVE | cs.GF_CAN_REMOVE, 0]),
                      EventPattern('dbus-signal', signal='PropertiesChanged',
                                   args=[cs.CHANNEL_IFACE_ROOM_CONFIG,
                                         {'CanUpdateConfiguration': True},
                                         []]))

    return chan
def check_neither(q, conn, bus, stream, remote_handle):
    """
    Make a channel without specifying InitialAudio or InitialVideo; check
    that it's announced with both False, and that they're both present and
    false in GetAll().
    """

    path, props = conn.Requests.CreateChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_HANDLE: remote_handle})

    assertContains((cs.INITIAL_AUDIO, False), props.items())
    assertContains((cs.INITIAL_VIDEO, False), props.items())

    chan = wrap_channel(bus.get_object(conn.bus_name, path),
        cs.CHANNEL_TYPE_STREAMED_MEDIA, ['MediaSignalling'])
    props = chan.Properties.GetAll(cs.CHANNEL_TYPE_STREAMED_MEDIA)
    assertContains(('InitialAudio', False), props.items())
    assertContains(('InitialVideo', False), props.items())

    # We shouldn't have started a session yet, so there shouldn't be any
    # session handlers. Strictly speaking, there could be a session handler
    # with no stream handlers, but...
    session_handlers = chan.MediaSignalling.GetSessionHandlers()
    assertLength(0, session_handlers)
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:])
def incoming(jp, q, bus, conn, stream):
    remote_jid = 'skinny.fists@heaven/antennas'
    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid)
    jt.prepare()

    self_handle = conn.GetSelfHandle()
    remote_handle = conn.RequestHandles(cs.HT_CONTACT, [remote_jid])[0]

    for a, v in [(True, False), (False, True), (True, True)]:
        if v and not jp.can_do_video():
            continue
        if not a and v and not jp.can_do_video_only():
            continue

        jt.incoming_call(audio=a, video=v)
        e = q.expect('dbus-signal', signal='NewChannels')
        chans = e.args[0]
        assertLength(1, chans)

        path, props = chans[0]

        assertEquals(cs.CHANNEL_TYPE_STREAMED_MEDIA, props[cs.CHANNEL_TYPE])
        assertEquals(a, props[cs.INITIAL_AUDIO])
        assertEquals(v, props[cs.INITIAL_VIDEO])

        chan = wrap_channel(bus.get_object(conn.bus_name, path),
            cs.CHANNEL_TYPE_STREAMED_MEDIA)
        chan.Close()
def test(jp, q, bus, conn, stream):
    if not jp.can_do_video_only():
        return

    remote_jid = '[email protected]/Foo'
    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid)
    jt.prepare()

    self_handle = conn.GetSelfHandle()
    handle = conn.RequestHandles(cs.HT_CONTACT, [remote_jid])[0]

    chan_path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA,
            cs.HT_CONTACT, handle, True)
    chan = wrap_channel(bus.get_object(conn.bus_name, chan_path),
            'StreamedMedia', ['MediaSignalling', 'Group', 'CallState', 'DTMF'])
    chan_props = chan.Properties.GetAll(cs.CHANNEL)
    assert cs.CHANNEL_IFACE_DTMF in chan_props['Interfaces'], \
        chan_props['Interfaces']

    chan.StreamedMedia.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_VIDEO])

    # S-E gets notified about new session handler, and calls Ready on it
    e = q.expect('dbus-signal', signal='NewSessionHandler')
    assert e.args[1] == 'rtp'

    session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler')
    session_handler.Ready()

    e = q.expect('dbus-signal', signal='NewStreamHandler')
    video_path = e.args[0]
    stream_handler = make_channel_proxy(conn, video_path, 'Media.StreamHandler')

    stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus())
    stream_handler.Ready(jt.get_video_codecs_dbus())
    stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED)

    e = q.expect('stream-iq', predicate=jp.action_predicate('session-initiate'))
    stream.send(make_result_iq(stream, e.stanza))

    jt.parse_session_initiate(e.query)

    jt.accept()

    # Gabble tells s-e to start sending
    q.expect('dbus-signal', signal='SetStreamSending', args=[True],
            path=video_path)

    # We don't actually have an audio stream, so this is a non-starter.
    call_async(q, chan.DTMF, 'StartTone', 666, 3)
    q.expect('dbus-error', method='StartTone', name=cs.NOT_AVAILABLE)
    call_async(q, chan.DTMF, 'MultipleTones', '**666##')
    q.expect('dbus-error', method='MultipleTones', name=cs.NOT_AVAILABLE)

    # We can still stop all the tones that are playing (a no-op).
    call_async(q, chan.DTMF, 'StopTone', 666)
    q.expect('dbus-return', method='StopTone')

    chan.Group.RemoveMembers([self_handle], 'closed')
    e = q.expect('dbus-signal', signal='Closed', path=chan_path)
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)

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

    channels = e.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, e:
        assertEquals(e.get_dbus_name(), cs.INVALID_ARGUMENT)
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 join(q, bus, conn):
    call_async(q, conn.Requests, "CreateChannel", {
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.ROOM_NAME: CHANNEL,
    })
    q.expect('stream-JOIN')
    event = q.expect('dbus-return', method='CreateChannel')
    path, props = event.value
    return wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['Destroyable', 'Messages'])
Example #11
0
def join(q, bus, conn):
    call_async(q, conn.Requests, "CreateChannel", {
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.ROOM_NAME: CHANNEL,
    })
    q.expect('stream-JOIN')
    event = q.expect('dbus-return', method='CreateChannel')
    path, props = event.value
    return wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
                        ['Destroyable', 'Messages'])
def test(q, bus, conn, stream):
    def send_own_message(to, text):
        iq = elem_iq(stream, 'set',
                     from_='chat.facebook.com')(elem(NS_FACEBOOK_MESSAGES,
                                                     'own-message',
                                                     to=to,
                                                     self='false')(
                                                         elem('body')(text)))
        stream.send(iq)
        q.expect('stream-iq', iq_type='result', iq_id=iq['id'])

    # First, test receiving an own-message stanza for a message sent to a
    # contact we have an open channel for.
    jid = '*****@*****.**'
    _, path, props = conn.Requests.EnsureChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_ID: jid,
    })
    channel = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
                           ['Messages'])
    handle = props[cs.TARGET_HANDLE]

    text = u'omg omg its ur birthdayy <3 <3 xoxoxoxo'
    send_own_message(to=jid, text=text)
    e = q.expect('dbus-signal', signal='MessageReceived')
    message, = e.args
    assertLength(1, message)
    header = message[0]

    assertEquals(handle, header['message-sender'])
    assertEquals(cs.MT_DELIVERY_REPORT, header['message-type'])
    assertEquals(cs.DELIVERY_STATUS_ACCEPTED, header['delivery-status'])

    assertContains('delivery-echo', header)
    echo = header['delivery-echo']
    echo_header, echo_body = echo

    assertEquals(conn.Properties.Get(cs.CONN, "SelfHandle"),
                 echo_header['message-sender'])
    assertEquals('text/plain', echo_body['content-type'])
    assertEquals(text, echo_body['content'])

    channel.Text.AcknowledgePendingMessages([header['pending-message-id']])
    channel.Close()

    # Now test receiving an own-message stanza for a message sent to a contact
    # we don't have a channel open for. It should be ignored (but acked). This
    # is consistent with delivery failure reports.
    q.forbid_events([EventPattern('dbus-signal', signal='MessageReceived')])
    send_own_message(to='*****@*****.**',
                     text=u'please ignore this message')
    sync_dbus(bus, q, conn)
def test(q, bus, conn, stream):
    def send_own_message(to, text):
        iq = elem_iq(stream, 'set', from_='chat.facebook.com')(
              elem(NS_FACEBOOK_MESSAGES, 'own-message', to=to, self='false')(
                elem('body')(text)
              )
            )
        stream.send(iq)
        q.expect('stream-iq', iq_type='result', iq_id=iq['id'])

    # First, test receiving an own-message stanza for a message sent to a
    # contact we have an open channel for.
    jid = '*****@*****.**'
    _, path, props = conn.Requests.EnsureChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_ID: jid,
    })
    channel = wrap_channel(bus.get_object(conn.bus_name, path),
        'Text', ['Messages'])
    handle = props[cs.TARGET_HANDLE]

    text = u'omg omg its ur birthdayy <3 <3 xoxoxoxo'
    send_own_message(to=jid, text=text)
    e = q.expect('dbus-signal', signal='MessageReceived')
    message, = e.args
    assertLength(1, message)
    header = message[0]

    assertEquals(handle, header['message-sender'])
    assertEquals(cs.MT_DELIVERY_REPORT, header['message-type'])
    assertEquals(cs.DELIVERY_STATUS_ACCEPTED, header['delivery-status'])

    assertContains('delivery-echo', header)
    echo = header['delivery-echo']
    echo_header, echo_body = echo

    assertEquals(conn.GetSelfHandle(), echo_header['message-sender'])
    assertEquals('text/plain', echo_body['content-type'])
    assertEquals(text, echo_body['content'])

    channel.Text.AcknowledgePendingMessages([header['pending-message-id']])
    channel.Close()

    # Now test receiving an own-message stanza for a message sent to a contact
    # we don't have a channel open for. It should be ignored (but acked). This
    # is consistent with delivery failure reports.
    q.forbid_events([EventPattern('dbus-signal', signal='MessageReceived')])
    send_own_message(to='*****@*****.**',
        text=u'please ignore this message')
    sync_dbus(bus, q, conn)
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)

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

    channels = e.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, e:
        assertEquals(e.get_dbus_name(), cs.INVALID_ARGUMENT)
def text_channel(q, bus, conn, method, jid, presence=True):
    request_text_channel(q, bus, conn, method, jid)
    e, _ = q.expect_many(EventPattern('dbus-return', method=method),
                         EventPattern('dbus-signal', signal='NewChannels'))

    # sigh
    if method == 'EnsureChannel':
        path = e.value[1]
    else:
        path = e.value[0]

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

    return (text_chan,) + e.value
def test(q, bus, conn, stream):
    conn.Connect()
    q.expect_many(
            EventPattern('dbus-signal', signal='StatusChanged', args=[1, 1]),
            EventPattern('irc-connected'))
    e = q.expect('dbus-signal', signal='NewChannels')
    channels = e.args[0]
    path, props = channels[0]

    channel = wrap_channel(bus.get_object(conn.bus_name, path),
        cs.CHANNEL_TYPE_SERVER_TLS_CONNECTION)
    channel.Close()

    q.expect('dbus-signal', signal='StatusChanged', args=[2, 2])
def stream_tube(q, bus, conn, method, jid):
    request_stream_tube(q, bus, conn, method, jid)
    e, _ = q.expect_many(EventPattern('dbus-return', method=method),
                         EventPattern('dbus-signal', signal='NewChannels'))

    # sigh
    if method == 'EnsureChannel':
        path = e.value[1]
    else:
        path = e.value[0]

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

    return (tube_chan,) + e.value
Example #18
0
def test(q, bus, conn, stream):
    conn.Connect()
    q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged', args=[1, 1]),
        EventPattern('irc-connected'))
    e = q.expect('dbus-signal', signal='NewChannels')
    channels = e.args[0]
    path, props = channels[0]

    channel = wrap_channel(bus.get_object(conn.bus_name, path),
                           cs.CHANNEL_TYPE_SERVER_TLS_CONNECTION)
    channel.Close()

    q.expect('dbus-signal', signal='StatusChanged', args=[2, 2])
def test(q, bus, conn, stream):
    conn.Connect()

    event = q.expect('stream-iq', query_ns=ns.ROSTER)
    # send back empty roster
    event.stanza['type'] = 'result'
    stream.send(event.stanza)

    while True:
        event = q.expect('dbus-signal', signal='NewChannel')
        path, type, handle_type, handle, suppress_handler = event.args

        if type != cs.CHANNEL_TYPE_CONTACT_LIST:
            continue

        chan_name = conn.InspectHandles(handle_type, [handle])[0]

        if chan_name == 'subscribe':
            break

    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'ContactList')
    assertLength(0, chan.Group.GetMembers())

    # request subscription
    handle = conn.RequestHandles(cs.HT_CONTACT, ['*****@*****.**'])[0]
    chan.Group.AddMembers([handle], '')

    event = q.expect('stream-iq', iq_type='set', query_ns=ns.ROSTER)
    item = event.query.firstChildElement()
    assertEquals('*****@*****.**', item["jid"])

    acknowledge_iq(stream, event.stanza)

    event = q.expect('stream-presence', presence_type='subscribe')

    presence = domish.Element(('jabber:client', 'presence'))
    presence['from'] = '*****@*****.**'
    presence['type'] = 'subscribed'
    stream.send(presence)

    q.expect_many(
            EventPattern('dbus-signal', signal='MembersChanged',
                args=['', [handle], [], [], [], 0, 0]),
            EventPattern('stream-presence'),
            )
Example #20
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 #21
0
def test(q, bus, conn, stream):
    path = conn.Requests.CreateChannel(
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
              cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
              cs.TARGET_ID: GUYBRUSH,
              })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    # Let's start out with an empty roster, eh?
    e = q.expect('stream-iq', iq_type='get', query_ns=ns.ROSTER)
    e.stanza['type'] = 'result'
    stream.send(e.stanza)

    report_received_on_open_channel(q, bus, conn, stream, chan)
    report_ignored_without_channel(q, bus, conn, stream)
    not_sending_request_to_contact(q, bus, conn, stream, chan)

    # FIXME: This test is disabled because of stupidity in the presence cache.
    # See the comment in receipts_conceivably_supported().
    #sending_request_to_presenceless_contact(q, bus, conn, stream, chan)

    sending_request_to_cappy_contact(q, bus, conn, stream, chan)

    replying_to_requests(q, bus, conn, stream)
def incoming(jp, q, bus, conn, stream):
    remote_jid = 'skinny.fists@heaven/antennas'
    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid)
    jt.prepare()

    self_handle = conn.GetSelfHandle()
    remote_handle = conn.RequestHandles(cs.HT_CONTACT, [remote_jid])[0]

    for a, v in [("audio1", None), (None, "video1"), ("audio1", "video1")]:
        if v!= None and not jp.can_do_video():
            continue
        if a == None and v != None and not jp.can_do_video_only():
            continue

        jt.incoming_call(audio=a, video=v)
        e = q.expect('dbus-signal', signal='NewChannels',
            predicate=lambda e:
                cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values())
        chans = e.args[0]
        assertLength(1, chans)

        path, props = chans[0]

        assertEquals(cs.CHANNEL_TYPE_STREAMED_MEDIA, props[cs.CHANNEL_TYPE])
        assertEquals(a != None, props[cs.INITIAL_AUDIO])
        assertEquals(v != None, props[cs.INITIAL_VIDEO])

        # FIXME: This doesn't check non-Google contacts that can only do one
        # media type, as such contacts as simulated by JingleTest2 can always
        # do both.
        assertEquals(not jp.can_do_video() or not jp.can_do_video_only(),
            props[cs.IMMUTABLE_STREAMS])

        chan = wrap_channel(bus.get_object(conn.bus_name, path),
            cs.CHANNEL_TYPE_STREAMED_MEDIA)
        chan.Close()
Example #23
0
def test(q, bus, conn):
    self_name = 'testsuite' + '@' + avahitest.get_host_name()

    conn.Connect()

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

    # FIXME: this is a hack to be sure to have all the contact list channels
    # announced so they won't interfere with the muc ones announces.
    wait_for_contact_list(q, conn)

    # check if we can request tube channels
    properties = conn.Properties.GetAll(cs.CONN_IFACE_REQUESTS)
    assert ({cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE,
             cs.TARGET_HANDLE_TYPE: cs.HT_ROOM},
             [cs.TARGET_HANDLE, cs.TARGET_ID, cs.STREAM_TUBE_SERVICE],
             ) in properties.get('RequestableChannelClasses'),\
                     properties['RequestableChannelClasses']

    # create muc channel using new API
    call_async(q, conn.Requests, 'CreateChannel',
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE,
              cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
              cs.TARGET_ID: 'my-second-room',
              cs.STREAM_TUBE_SERVICE: 'loldongs',
              })

    ret, new_sig = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('dbus-signal', signal='NewChannels'),
        )
    tube_path = ret.value[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, tube_path),
                        'StreamTube')

    tube_props = ret.value[1]
    assert tube_props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE
    assert tube_props[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM
    assert tube_props[cs.TARGET_ID] == 'my-second-room'
    assert tube_props[cs.REQUESTED] == True
    assert tube_props[cs.INITIATOR_HANDLE] == conn.Properties.Get(cs.CONN, "SelfHandle")
    assert tube_props[cs.INITIATOR_ID] == self_name

    # text and tube channels are announced
    channels = new_sig.args[0]
    assert len(channels) == 1

    handle = tube_props[cs.TARGET_HANDLE]

    path, props = channels[0]
    assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE
    assert path == tube_path
    assert props == tube_props
    assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM
    assert props[cs.TARGET_HANDLE] == handle
    assert props[cs.TARGET_ID] == 'my-second-room'
    assert props[cs.INITIATOR_HANDLE] == conn.Properties.Get(cs.CONN, "SelfHandle")
    assert props[cs.INITIATOR_ID] == self_name

    # ensure the same channel

# TODO: the muc channel doesn't bother to look at existing tubes
# before creating a new one. once that's fixed, uncomment this.
#    yours, ensured_path, _ = conn.Requests.EnsureChannel(
#            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE,
#              cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
#              cs.TARGET_HANDLE: handle,
#              cs.STREAM_TUBE_SERVICE: 'loldongs',
#              })

#    assert not yours
#    assert ensured_path == tube_path, (ensured_path, tube_path)

    conn.Disconnect()

    q.expect_many(
            EventPattern('dbus-signal', signal='Closed',
                path=tube_path),
            EventPattern('dbus-signal', signal='ChannelClosed', args=[tube_path]),
            EventPattern('dbus-signal', signal='StatusChanged', args=[2, 1]),
            )
def test(q, bus, conn, stream):
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    jid = '*****@*****.**'
    full_jid = '[email protected]/Foo'
    foo_handle = conn.get_contact_handle_sync(jid)

    path = conn.Requests.CreateChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_HANDLE: foo_handle,
    })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    presence = make_presence(full_jid,
                             status='hello',
                             caps={
                                 'node':
                                 'http://telepathy.freedesktop.org/homeopathy',
                                 'ver': '0.1',
                             })
    stream.send(presence)

    version_event = q.expect(
        'stream-iq',
        to=full_jid,
        query_ns=ns.DISCO_INFO,
        query_node='http://telepathy.freedesktop.org/homeopathy#0.1')

    result = make_result_iq(stream, version_event.stanza)
    query = result.firstChildElement()
    feature = query.addElement('feature')
    feature['var'] = ns.CHAT_STATES
    stream.send(result)

    sync_stream(q, stream)

    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
    assertEquals(cs.CHAT_STATE_INACTIVE,
                 states.get(self_handle, cs.CHAT_STATE_INACTIVE))
    assertEquals(cs.CHAT_STATE_INACTIVE,
                 states.get(foo_handle, cs.CHAT_STATE_INACTIVE))

    # Receiving chat states:

    # Composing...
    stream.send(make_message(full_jid, state='composing'))

    changed = q.expect('dbus-signal',
                       signal='ChatStateChanged',
                       path=chan.object_path)
    handle, state = changed.args
    assertEquals(foo_handle, handle)
    assertEquals(cs.CHAT_STATE_COMPOSING, state)

    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
    assertEquals(cs.CHAT_STATE_INACTIVE,
                 states.get(self_handle, cs.CHAT_STATE_INACTIVE))
    assertEquals(cs.CHAT_STATE_COMPOSING,
                 states.get(foo_handle, cs.CHAT_STATE_INACTIVE))

    # Message!
    stream.send(make_message(full_jid, body='hello', state='active'))

    changed = q.expect('dbus-signal',
                       signal='ChatStateChanged',
                       path=chan.object_path)
    handle, state = changed.args
    assertEquals(foo_handle, handle)
    assertEquals(cs.CHAT_STATE_ACTIVE, state)

    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
    assertEquals(cs.CHAT_STATE_INACTIVE,
                 states.get(self_handle, cs.CHAT_STATE_INACTIVE))
    assertEquals(cs.CHAT_STATE_ACTIVE,
                 states.get(foo_handle, cs.CHAT_STATE_INACTIVE))

    # Assert that a redundant chat-state change doesn't emit a signal

    forbidden = [
        EventPattern('dbus-signal',
                     signal='ChatStateChanged',
                     args=[foo_handle, cs.CHAT_STATE_ACTIVE])
    ]
    q.forbid_events(forbidden)

    m = domish.Element((None, 'message'))
    m['from'] = '[email protected]/Foo'
    m['type'] = 'chat'
    m.addElement((ns.CHAT_STATES, 'active'))
    m.addElement('body', content='hello')
    stream.send(m)

    sync_dbus(bus, q, conn)
    sync_stream(q, stream)

    q.unforbid_events(forbidden)

    # Sending chat states:

    # Composing...
    chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING)

    stream_message = q.expect('stream-message')
    check_state_notification(stream_message.stanza, 'composing')

    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
    assertEquals(cs.CHAT_STATE_COMPOSING,
                 states.get(self_handle, cs.CHAT_STATE_INACTIVE))
    assertEquals(cs.CHAT_STATE_ACTIVE,
                 states.get(foo_handle, cs.CHAT_STATE_INACTIVE))

    # XEP 0085:
    #   every content message SHOULD contain an <active/> notification.
    chan.send_msg_sync('hi.')

    stream_message = q.expect('stream-message')
    elem = stream_message.stanza
    assertEquals('chat', elem['type'])

    check_state_notification(elem, 'active', allow_body=True)

    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
    assertEquals(cs.CHAT_STATE_ACTIVE,
                 states.get(self_handle, cs.CHAT_STATE_INACTIVE))
    assertEquals(cs.CHAT_STATE_ACTIVE,
                 states.get(foo_handle, cs.CHAT_STATE_INACTIVE))

    def is_body(e):
        if e.name == 'body':
            assert e.children[0] == u'hi.', e.toXml()
            return True
        return False

    assert len([x for x in elem.elements() if is_body(x)]) == 1, elem.toXml()

    # Close the channel without acking the received message. The peer should
    # get a <gone/> notification, and the channel should respawn.
    chan.Close()

    gone, _ = q.expect_many(
        EventPattern('stream-message'),
        EventPattern('dbus-signal', signal='Closed'),
    )
    check_state_notification(gone.stanza, 'gone')

    # Reusing the proxy object because we happen to know it'll be at the same
    # path...

    # Destroy the channel. The peer shouldn't get a <gone/> notification, since
    # we already said we were gone and haven't sent them any messages to the
    # contrary.
    es = [EventPattern('stream-message')]
    q.forbid_events(es)

    chan.Destroyable.Destroy()
    sync_stream(q, stream)

    # Make the channel anew.
    path = conn.Requests.CreateChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_HANDLE: foo_handle,
    })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    # Close it immediately; the peer should again not get a <gone/>
    # notification, since we haven't sent any notifications on that channel.
    chan.Close()
    sync_stream(q, stream)
    q.unforbid_events(es)

    # XEP-0085 §5.1 defines how to negotiate support for chat states with a
    # contact in the absence of capabilities. This is useful when talking to
    # invisible contacts, for example.

    # First, if we receive a message from a contact, containing an <active/>
    # notification, they support chat states, so we should send them.

    jid = '*****@*****.**'
    full_jid = jid + '/GTalk'

    path = conn.Requests.CreateChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_ID: jid,
    })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    stream.send(make_message(full_jid, body='i am invisible', state='active'))

    changed = q.expect('dbus-signal',
                       signal='ChatStateChanged',
                       path=chan.object_path)
    assertEquals(cs.CHAT_STATE_ACTIVE, changed.args[1])

    # We've seen them send a chat state notification, so we should send them
    # notifications when the UI tells us to.
    chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING)
    stream_message = q.expect('stream-message', to=full_jid)
    check_state_notification(stream_message.stanza, 'composing')

    changed = q.expect('dbus-signal',
                       signal='ChatStateChanged',
                       path=chan.object_path)
    handle, state = changed.args
    assertEquals(cs.CHAT_STATE_COMPOSING, state)
    assertEquals(self_handle, handle)

    chan.send_msg_sync('very convincing')
    stream_message = q.expect('stream-message', to=full_jid)
    check_state_notification(stream_message.stanza, 'active', allow_body=True)

    # Now, test the case where we start the negotiation, and the contact
    # turns out to support chat state notifications.

    jid = '*****@*****.**'
    full_jid = jid + '/GTalk'
    path = conn.Requests.CreateChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_ID: jid,
    })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    # We shouldn't send any notifications until we actually send a message.
    # But ChatStateChanged is still emitted locally
    e = EventPattern('stream-message', to=jid)
    q.forbid_events([e])
    for i in [
            cs.CHAT_STATE_ACTIVE, cs.CHAT_STATE_COMPOSING,
            cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_INACTIVE
    ]:
        chan.ChatState.SetChatState(i)
        changed = q.expect('dbus-signal',
                           signal='ChatStateChanged',
                           path=chan.object_path)
        handle, state = changed.args
        assertEquals(i, state)
        assertEquals(self_handle, handle)

    sync_stream(q, stream)
    q.unforbid_events([e])

    # When we send a message, say we're active.
    chan.send_msg_sync('is anyone there?')
    stream_message = q.expect('stream-message', to=jid)
    check_state_notification(stream_message.stanza, 'active', allow_body=True)

    # The D-Bus property changes, too
    changed = q.expect('dbus-signal',
                       signal='ChatStateChanged',
                       path=chan.object_path)
    handle, state = changed.args
    assertEquals(cs.CHAT_STATE_ACTIVE, state)
    assertEquals(self_handle, handle)

    # We get a notification back from our contact.
    stream.send(make_message(full_jid, state='composing'))

    # Wait until gabble tells us the chat-state of the remote party has
    # changed so we know gabble knows chat state notification are supported
    changed = q.expect('dbus-signal',
                       signal='ChatStateChanged',
                       path=chan.object_path)
    handle, state = changed.args
    assertEquals(cs.CHAT_STATE_COMPOSING, state)
    assertNotEquals(foo_handle, handle)

    # So now we know they support notification, so should send notifications.
    chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING)

    # This doesn't check whether we're sending to the bare jid, or the
    # jid+resource. In fact, the notification is sent to the bare jid, because
    # we only update which jid we send to when we actually receive a message,
    # not when we receive a notification. wjt thinks this is less surprising
    # than the alternative:
    #
    #  • I'm talking to you on my N900, and signed in on my laptop;
    #  • I enter one character in a tab to you on my laptop, and then delete
    #    it;
    #  • Now your messages to me appear on my laptop (until I send you another
    #    one from my N900)!
    stream_message = q.expect('stream-message')
    check_state_notification(stream_message.stanza, 'composing')

    # The D-Bus property changes, too
    changed = q.expect('dbus-signal',
                       signal='ChatStateChanged',
                       path=chan.object_path)
    handle, state = changed.args
    assertEquals(cs.CHAT_STATE_COMPOSING, state)
    assertEquals(self_handle, handle)

    # But! Now they start messaging us from a different client, which *doesn't*
    # support notifications.
    other_jid = jid + '/Library'
    stream.send(make_message(other_jid, body='grr, library computers'))
    q.expect('dbus-signal', signal='MessageReceived')

    # Okay, we should stop sending typing notifications.
    e = EventPattern('stream-message', to=other_jid)
    q.forbid_events([e])
    for i in [
            cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE,
            cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE
    ]:
        chan.ChatState.SetChatState(i)
    sync_stream(q, stream)
    q.unforbid_events([e])

    # Now, test the case where we start the negotiation, and the contact
    # does not support chat state notifications

    jid = '*****@*****.**'
    full_jid = jid + '/Nonsense'
    path = conn.Requests.CreateChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_ID: jid,
    })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    # We shouldn't send any notifications until we actually send a message.
    e = EventPattern('stream-message', to=jid)
    q.forbid_events([e])
    for i in [
            cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE,
            cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE
    ]:
        chan.ChatState.SetChatState(i)
    sync_stream(q, stream)
    q.unforbid_events([e])

    # When we send a message, say we're active.
    chan.send_msg_sync('#n900 #maemo #zomg #woo #yay http://bit.ly/n900')
    stream_message = q.expect('stream-message', to=jid)
    check_state_notification(stream_message.stanza, 'active', allow_body=True)

    # They reply without a chat state.
    stream.send(make_message(full_jid, body="posted."))
    q.expect('dbus-signal', signal='MessageReceived')

    # Okay, we shouldn't send any more.
    e = EventPattern('stream-message', to=other_jid)
    q.forbid_events([e])
    for i in [
            cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE,
            cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE
    ]:
        chan.ChatState.SetChatState(i)
    sync_stream(q, stream)
    q.unforbid_events([e])

    chan.send_msg_sync('@stephenfry simmer down')
    message = q.expect('stream-message')
    states = [x for x in message.stanza.elements() if x.uri == ns.CHAT_STATES]
    assertLength(0, states)
def test(q, bus, conn, stream, send_early_description_info=False):
    jp = JingleProtocol031()
    jt2 = JingleTest2(jp, conn, q, stream, 'test@localhost', '[email protected]/Foo')
    jt2.prepare()

    self_handle = conn.GetSelfHandle()
    remote_handle = conn.RequestHandles(cs.HT_CONTACT, ["[email protected]/Foo"])[0]

    # Remote end calls us
    jt2.incoming_call()

    # FIXME: these signals are not observable by real clients, since they
    #        happen before NewChannels.
    # The caller is in members
    e = q.expect('dbus-signal', signal='MembersChanged',
             args=[u'', [remote_handle], [], [], [], 0, 0])

    # We're pending because of remote_handle
    e = q.expect('dbus-signal', signal='MembersChanged',
             args=[u'', [], [], [self_handle], [], remote_handle,
                   cs.GC_REASON_INVITED])

    chan = wrap_channel(bus.get_object(conn.bus_name,  e.path),
        'StreamedMedia')

    # S-E gets notified about new session handler, and calls Ready on it
    e = q.expect('dbus-signal', signal='NewSessionHandler')
    assert e.args[1] == 'rtp'

    if send_early_description_info:
        """
        Regression test for a bug where Gabble would crash if you sent it
        description-info before calling Ready() on the relevant StreamHandler,
        and then for a bug where Gabble would never accept the call if a
        description-info was received before all StreamHandlers were Ready().
        """
        node = jp.SetIq(jt2.peer, jt2.jid, [
            jp.Jingle(jt2.sid, jt2.peer, 'description-info', [
                jp.Content('stream1', 'initiator', 'both',
                    jp.Description('audio', [ ])) ]) ])
        stream.send(jp.xml(node))

        sync_stream(q, stream)

    session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler')
    session_handler.Ready()

    chan.Group.AddMembers([self_handle], 'accepted')

    # S-E gets notified about a newly-created stream
    e = q.expect('dbus-signal', signal='NewStreamHandler')
    id1 = e.args[1]

    stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler')

    # We are now in members too
    e = q.expect('dbus-signal', signal='MembersChanged',
             args=[u'', [self_handle], [], [], [], self_handle,
                   cs.GC_REASON_NONE])

    # we are now both in members
    members = chan.Group.GetMembers()
    assert set(members) == set([self_handle, remote_handle]), members

    local_codecs = [('GSM', 3, 8000, {}),
                    ('PCMA', 8, 8000, {'helix':'woo yay'}),
                    ('PCMU', 0, 8000, {}) ]
    local_codecs_dbus = jt2.dbusify_codecs_with_params(local_codecs)

    stream_handler.NewNativeCandidate("fake", jt2.get_remote_transports_dbus())
    stream_handler.Ready(local_codecs_dbus)
    stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED)

    stream_handler.CodecsUpdated(local_codecs_dbus)

    local_codecs = [('GSM', 3, 8000, {}),
                    ('PCMA', 8, 8000, {'gstreamer':'rock on'}),
                    ('PCMU', 0, 8000, {}) ]
    local_codecs_dbus = jt2.dbusify_codecs_with_params(local_codecs)
    stream_handler.CodecsUpdated(local_codecs_dbus)


    # First IQ is transport-info; also, we expect to be told what codecs the
    # other end wants.
    e, src = q.expect_many(
        EventPattern('stream-iq',
            predicate=jp.action_predicate('transport-info')),
        EventPattern('dbus-signal', signal='SetRemoteCodecs')
        )
    assertEquals('[email protected]/Foo', e.query['initiator'])

    assert jt2.audio_codecs == [ (name, id, rate, parameters)
        for id, name, type, rate, channels, parameters in unwrap(src.args[0]) ], \
        (jt2.audio_codecs, unwrap(src.args[0]))

    stream.send(jp.xml(jp.ResultIq('test@localhost', e.stanza, [])))

    # S-E reports codec intersection, after which gabble can send acceptance
    stream_handler.SupportedCodecs(local_codecs_dbus)

    # Second one is session-accept
    e = q.expect('stream-iq', predicate=jp.action_predicate('session-accept'))

    # farstream is buggy, and tells tp-fs to tell Gabble to change the third
    # codec's clockrate. This isn't legal, so Gabble says no.
    new_codecs = [ ('GSM', 3, 8000, {}),
                   ('PCMA', 8, 8000, {}),
                   ('PCMU', 0, 4000, {}) ]
    call_async(q, stream_handler, 'CodecsUpdated',
        jt2.dbusify_codecs(new_codecs))
    event = q.expect('dbus-error', method='CodecsUpdated')
    assert event.error.get_dbus_name() == cs.INVALID_ARGUMENT, \
        event.error.get_dbus_name()

    # With its tail between its legs, tp-fs decides it wants to add some
    # parameters to the first two codecs, not changing the third.
    new_codecs = [ ('GSM', 3, 8000, {'type': 'banana'}),
                   ('PCMA', 8, 8000, {'helix': 'BUFFERING'}),
                   ('PCMU', 0, 8000, {}) ]
    stream_handler.CodecsUpdated(jt2.dbusify_codecs_with_params(new_codecs))

    audio_content = jt2.audio_names[0]

    e = q.expect('stream-iq', iq_type='set', predicate=lambda x:
        xpath.queryForNodes("/iq/jingle[@action='description-info']",
            x.stanza))
    payload_types = xpath.queryForNodes(
        "/iq/jingle/content[@name='%s']/description/payload-type"
            % audio_content,
        e.stanza)
    # Gabble SHOULD only include the changed codecs in description-info
    assert len(payload_types) == 2, payload_types

    payload_types_tupled = [ (pt['name'], int(pt['id']), int(pt['clockrate']),
                              extract_params(pt))
                             for pt in payload_types ]
    assert sorted(payload_types_tupled) == sorted(new_codecs[0:2]), \
        (payload_types_tupled, new_codecs[0:2])

    # The remote end decides it wants to change the number of channels in the
    # third codec. This is not meant to happen, so Gabble should send it an IQ
    # error back.
    node = jp.SetIq(jt2.peer, jt2.jid, [
        jp.Jingle(jt2.sid, jt2.peer, 'description-info', [
            jp.Content(audio_content, 'initiator', 'both',
                jp.Description('audio', [
                    jp.PayloadType('PCMU', '1600', '0') ])) ]) ])
    stream.send(jp.xml(node))
    q.expect('stream-iq', iq_type='error',
        predicate=lambda x: x.stanza['id'] == node[2]['id'])

    # Instead, the remote end decides to add a parameter to the third codec.
    new_codecs = [ ('GSM', 3, 8000, {}),
                   ('PCMA', 8, 8000, {}),
                   ('PCMU', 0, 8000, {'choppy': 'false'}),
                 ]
    # As per the XEP, it only sends the ones which have changed.
    c = new_codecs[2]
    node = jp.SetIq(jt2.peer, jt2.jid, [
        jp.Jingle(jt2.sid, jt2.peer, 'description-info', [
            jp.Content(audio_content, 'initiator', 'both',
                jp.Description('audio', [
                    jp.PayloadType(c[0], str(c[2]), str(c[1]), c[3])
                ])) ]) ])
    stream.send(jp.xml(node))

    # Gabble should patch its idea of the remote codecs with the update it just
    # got, and emit SetRemoteCodecs for them all.
    e = q.expect('dbus-signal', signal='SetRemoteCodecs')
    new_codecs_dbus = unwrap(jt2.dbusify_codecs_with_params(new_codecs))
    announced = unwrap(e.args[0])
    assert new_codecs_dbus == announced, (new_codecs_dbus, announced)

    # We close the session by removing the stream
    chan.StreamedMedia.RemoveStreams([id1])

    e = q.expect('stream-iq', iq_type='set', predicate=lambda x:
        xpath.queryForNodes("/iq/jingle[@action='session-terminate']",
            x.stanza))
Example #26
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]
Example #27
0
def test(jp, q, bus, conn, stream):
    # this test uses multiple streams
    if not jp.is_modern_jingle():
        return

    remote_jid = '[email protected]/Foo'
    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid)
    jt.prepare()

    self_handle = conn.GetSelfHandle()
    handle = conn.RequestHandles(cs.HT_CONTACT, [remote_jid])[0]

    chan_path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA,
            cs.HT_CONTACT, handle, True)
    chan = wrap_channel(bus.get_object(conn.bus_name, chan_path),
            'StreamedMedia', ['MediaSignalling', 'Group', 'CallState', 'DTMF'])
    chan_props = chan.Properties.GetAll(cs.CHANNEL)
    assert cs.CHANNEL_IFACE_DTMF in chan_props['Interfaces'], \
        chan_props['Interfaces']

    assertEquals('',
            chan.Properties.Get(cs.CHANNEL_IFACE_DTMF, 'InitialTones'))
    assertEquals('',
            chan.Properties.Get(cs.CHANNEL_IFACE_DTMF, 'DeferredTones'))

    chan.StreamedMedia.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_AUDIO])

    # S-E gets notified about new session handler, and calls Ready on it
    e = q.expect('dbus-signal', signal='NewSessionHandler')
    assert e.args[1] == 'rtp'

    session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler')
    session_handler.Ready()

    e = q.expect('dbus-signal', signal='NewStreamHandler')
    audio_path = e.args[0]
    stream_handler = make_channel_proxy(conn, audio_path, 'Media.StreamHandler')

    stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus())
    stream_handler.Ready(jt.get_audio_codecs_dbus())
    stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED)

    e = q.expect('stream-iq', predicate=jp.action_predicate('session-initiate'))
    stream.send(make_result_iq(stream, e.stanza))

    jt.parse_session_initiate(e.query)

    jt.accept()

    # Gabble tells s-e to start sending
    q.expect('dbus-signal', signal='SetStreamSending', args=[True],
            path=audio_path)

    chan.StreamedMedia.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_AUDIO])

    e = q.expect('dbus-signal', signal='NewStreamHandler')
    audio2_path = e.args[0]

    # The Stream_ID is specified to be ignored; we use 666 here.
    call_async(q, chan.DTMF, 'StartTone', 666, 3)
    q.expect_many(
            EventPattern('dbus-signal', signal='StartTelephonyEvent',
                path=audio2_path),
            EventPattern('dbus-signal', signal='StartTelephonyEvent',
                path=audio_path),
            EventPattern('dbus-signal', signal='SendingTones', args=['3'],
                path=chan_path),
            EventPattern('dbus-return', method='StartTone'),
            )

    call_async(q, chan.DTMF, 'StopTone', 666)
    q.expect_many(
            EventPattern('dbus-signal', signal='StopTelephonyEvent',
                path=audio_path),
            EventPattern('dbus-signal', signal='StopTelephonyEvent',
                path=audio2_path),
            EventPattern('dbus-signal', signal='StoppedTones', args=[True],
                path=chan_path),
            EventPattern('dbus-return', method='StopTone'),
            )

    call_async(q, chan.DTMF, 'MultipleTones', '123w*#')
    q.expect_many(
            EventPattern('dbus-signal', signal='StartTelephonyEvent',
                path=audio_path, args=[1]),
            EventPattern('dbus-signal', signal='StartTelephonyEvent',
                path=audio2_path, args=[1]),
            EventPattern('dbus-signal', signal='SendingTones', args=['123w*#'],
                path=chan_path),
            EventPattern('dbus-return', method='MultipleTones'),
            )
    q.expect_many(
            EventPattern('dbus-signal', signal='StopTelephonyEvent',
                path=audio_path),
            EventPattern('dbus-signal', signal='StopTelephonyEvent',
                path=audio2_path),
            )
    q.expect_many(
            EventPattern('dbus-signal', signal='StartTelephonyEvent',
                path=audio_path, args=[2]),
            EventPattern('dbus-signal', signal='StartTelephonyEvent',
                path=audio2_path, args=[2]),
            )
    q.expect_many(
            EventPattern('dbus-signal', signal='StopTelephonyEvent',
                path=audio_path),
            EventPattern('dbus-signal', signal='StopTelephonyEvent',
                path=audio2_path),
            )
    q.expect_many(
            EventPattern('dbus-signal', signal='StartTelephonyEvent',
                path=audio_path, args=[3]),
            EventPattern('dbus-signal', signal='StartTelephonyEvent',
                path=audio2_path, args=[3]),
            )
    q.expect_many(
            EventPattern('dbus-signal', signal='StopTelephonyEvent',
                path=audio_path),
            EventPattern('dbus-signal', signal='StopTelephonyEvent',
                path=audio2_path),
            EventPattern('dbus-signal', signal='StoppedTones', args=[False],
                path=chan_path),
            EventPattern('dbus-signal', signal='TonesDeferred',
                args=['*#']),
            )

    assertEquals('*#',
            chan.Properties.Get(cs.CHANNEL_IFACE_DTMF, 'DeferredTones'))

    forbidden = [EventPattern('dbus-signal', signal='StartTelephonyEvent',
        args=[9])]
    q.forbid_events(forbidden)

    # This is technically a race condition, but this dialstring is almost
    # certainly long enough that the Python script will win the race, i.e.
    # cancel before Gabble processes the whole dialstring.
    call_async(q, chan.DTMF, 'MultipleTones',
            '1,1' * 100)
    q.expect('dbus-return', method='MultipleTones')

    call_async(q, chan.DTMF, 'MultipleTones', '9')
    q.expect('dbus-error', method='MultipleTones',
            name=cs.SERVICE_BUSY)
    call_async(q, chan.DTMF, 'StartTone', 666, 9)
    q.expect('dbus-error', method='StartTone', name=cs.SERVICE_BUSY)
    call_async(q, chan.DTMF, 'StopTone', 666)
    q.expect_many(
            EventPattern('dbus-signal', signal='StopTelephonyEvent',
                path=audio_path),
            EventPattern('dbus-signal', signal='StopTelephonyEvent',
                path=audio2_path),
            EventPattern('dbus-signal', signal='StoppedTones', args=[True],
                path=chan_path),
            EventPattern('dbus-return', method='StopTone'),
            )

    # emitting any sound resets TonesDeferred
    assertEquals('',
            chan.Properties.Get(cs.CHANNEL_IFACE_DTMF, 'DeferredTones'))

    q.unforbid_events(forbidden)

    chan.Group.RemoveMembers([self_handle], 'closed')
    e = q.expect('dbus-signal', signal='Closed', path=chan_path)
def test(q, bus, conn, stream):
    # <wjt> I need a random name generator
    # <fledermaus> Macro-Variable Spin Gel
    contact = '*****@*****.**'
    contact_a = '%s/n810' % contact
    contact_b = '%s/laptop' % contact

    path, _ = conn.Requests.CreateChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_ID: contact,
    })
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    # When we start a conversation, Gabble should send to the bare JID.
    chan.send_msg_sync('hey, you around?')
    q.expect('stream-message', to=contact)

    # A particular resource replies.
    m = domish.Element((None, 'message'))
    m['from'] = contact_a
    m['type'] = 'chat'
    m.addElement('body', content="i'm on a beach at Gran Canaria!")
    stream.send(m)

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

    # Now that we got a reply from a particular resource, Gabble should reply
    # there.
    chan.send_msg_sync('nice')
    q.expect('stream-message', to=contact_a)

    # Now another resource messages us
    m = domish.Element((None, 'message'))
    m['from'] = contact_b
    m['type'] = 'chat'
    m.addElement('body', content="I brought my laptop to the Empathy hackfest")
    stream.send(m)

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

    # Gabble should have updated the resource it's sending to.
    chan.send_msg_sync("don't get sand in the keyboard")
    e = q.expect('stream-message', to=contact_b)

    # But actually that resource has gone offline:
    m = e.stanza
    m['from'] = contact_b
    m['type'] = 'error'
    del m['to']

    err = m.addElement((None, 'error'))
    err['type'] = 'cancel'
    err.addElement((ns.STANZA, 'item-not-found'))

    stream.send(m)
    q.expect('dbus-signal', signal='MessageReceived')

    # So as a result, Gabble should send the next message to the bare JID.
    chan.send_msg_sync("... i guess my warning was too late")
    q.expect('stream-message', to=contact)
Example #29
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_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'])
Example #31
0
def test(q, bus, conn, stream):
    conn.Connect()

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

    alice_handle, bob_handle = conn.get_contact_handles_sync(['alice', 'bob'])

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

    q.expect('stream-JOIN')
    event = q.expect('dbus-return', method='CreateChannel')
    path = event.value[0]

    channel = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
                           ['Subject2'])

    assertContains(CHANNEL_IFACE_SUBJECT,
                   channel.Properties.Get(CHANNEL, 'Interfaces'))

    # No topic set
    subject_props = channel.Properties.GetAll(CHANNEL_IFACE_SUBJECT)
    assertEquals('', subject_props['Subject'])
    assertEquals(0x7fffffffffffffffL, subject_props['Timestamp'])
    assertEquals('', subject_props['Actor'])
    assertEquals(0, subject_props['ActorHandle'])

    # Before the topic arrives from the server, check that our API works okay.
    # FIXME: when we make SetSubject return asynchronously, this will need
    # revising.
    test_can_set(q, stream, channel)

    # We're told the channel's topic, and (in a separte message) who set it and
    # when.
    stream.sendMessage('332',
                       stream.nick,
                       room,
                       ':Test123',
                       prefix='idle.test.server')
    stream.sendMessage('333',
                       stream.nick,
                       room,
                       'bob',
                       '1307802600',
                       prefix='idle.test.server')

    # FIXME: signal these together, if possible.
    expect_subject_props_changed(q, {'Subject': 'Test123'})
    expect_subject_props_changed(q, {
        'Timestamp': 1307802600,
        'Actor': 'bob',
        'ActorHandle': bob_handle,
    },
                                 exact_timestamp=True)

    # Another user changes the topic.
    stream.sendMessage('TOPIC',
                       room,
                       ':I am as high as a kite',
                       prefix='alice')
    expect_subject_props_changed(
        q, {
            'Subject': 'I am as high as a kite',
            'Actor': 'alice',
            'ActorHandle': alice_handle,
            'Timestamp': 1234,
        })

    # BIP omits the : for the trailing parameter if it's a single word, make
    # sure we pass that as well
    stream.sendMessage('TOPIC', room, 'badgers!', prefix='alice')
    expect_subject_props_changed(
        q, {
            'Subject': 'badgers!',
            'Actor': 'alice',
            'ActorHandle': alice_handle,
            'Timestamp': 1234,
        })

    test_can_set(q, stream, channel)

    # Topic is read/write, if we get ops it should stay that way
    forbidden = [
        EventPattern('dbus-signal',
                     signal='PropertiesChanged',
                     predicate=lambda e: e.args[0] == CHANNEL_IFACE_SUBJECT)
    ]
    q.forbid_events(forbidden)

    # Set ops, check that t flag becomes a no-op
    change_channel_mode(stream, '+o ' + stream.nick)
    change_channel_mode(stream, '+t')
    change_channel_mode(stream, '-t')
    change_channel_mode(stream, '-o ' + stream.nick)

    # Check that other flags don't cause issues
    change_channel_mode(stream, '+n')
    change_channel_mode(stream, '+n')

    change_channel_mode(stream, '+to ' + stream.nick)
    change_channel_mode(stream, '-to ' + stream.nick)

    sync_stream(q, stream)
    sync_dbus(bus, q, conn)
    q.unforbid_events(forbidden)

    # back to normal?
    test_can_set(q, stream, channel)

    # Check if setting ops gives us write access on +t channels
    change_channel_mode(stream, '+t')
    expect_and_check_can_set(q, channel, False)

    change_channel_mode(stream, '+o ' + stream.nick)
    expect_and_check_can_set(q, channel, True)

    change_channel_mode(stream, '-o ' + stream.nick)
    expect_and_check_can_set(q, channel, False)

    change_channel_mode(stream, '-t')
    expect_and_check_can_set(q, channel, True)

    # And back to normal again ?
    test_can_set(q, stream, channel)

    channel.Subject2.SetSubject('')
    # Verify that we send an empty final parameter ("clear the topic") as
    # opposed to no final parameter ("what is the topic").
    q.expect('stream-TOPIC', data=[room, ''])
Example #32
0
    def initiate(self):
        if self.incoming:
            self.context.incoming_call(self.medias)
        else:
            self.chan_path = self.conn.Requests.CreateChannel({
                cs.CHANNEL_TYPE:
                cs.CHANNEL_TYPE_CALL,
                cs.TARGET_HANDLE_TYPE:
                cs.HT_CONTACT,
                cs.TARGET_HANDLE:
                self.remote_handle,
                cs.CALL_INITIAL_AUDIO:
                self.initial_audio_content_name is not None,
                cs.CALL_INITIAL_AUDIO_NAME:
                self.initial_audio_content_name or "",
                cs.CALL_INITIAL_VIDEO:
                self.initial_video_content_name is not None,
                cs.CALL_INITIAL_VIDEO_NAME:
                self.initial_video_content_name or "",
            })[0]

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

        assertLength(1, nc.args)
        assertLength(1, nc.args[0])  # one channel
        assertLength(2, nc.args[0][0])  # two struct members
        self.chan_path, props = nc.args[0][0]
        self.check_channel_props(props, True)

        self.chan = wrap_channel(
            self.bus.get_object(self.conn.bus_name, self.chan_path), 'Call1',
            ['Hold'])

        call_props = self.chan.Properties.GetAll(cs.CHANNEL_TYPE_CALL)
        self.check_call_properties(call_props)
        for c in call_props['Contents']:
            self.add_content(c, True)

        if not self.incoming:
            self.chan.Call1.Accept()

            self.q.expect_many(*self.stream_dbus_signal_event(
                'ReceivingStateChanged',
                args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START]))

            for c in self.contents:
                c.stream.Media.CompleteReceivingStateChange(
                    cs.CALL_STREAM_FLOW_STATE_STARTED)

                mdo = c.Get(cs.CALL_CONTENT_IFACE_MEDIA,
                            'MediaDescriptionOffer')
                md = self.bus.get_object(self.conn.bus_name, mdo[0])
                md.Accept(self.context.get_audio_md_dbus(self.remote_handle))

                self.q.expect_many(
                    EventPattern('dbus-signal',
                                 signal='MediaDescriptionOfferDone',
                                 path=c.__dbus_object_path__),
                    EventPattern('dbus-signal',
                                 signal='LocalMediaDescriptionChanged',
                                 path=c.__dbus_object_path__),
                    EventPattern('dbus-signal',
                                 signal='RemoteMediaDescriptionsChanged',
                                 path=c.__dbus_object_path__))

                mdo = c.Get(cs.CALL_CONTENT_IFACE_MEDIA,
                            'MediaDescriptionOffer')
                assertEquals(('/', {}), mdo)

                self.add_candidates(c.stream)

            self.invite_event = self.q.expect('sip-invite')
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 test(q, bus, conn, stream, channel_type):
    jt = JingleTest2(JingleProtocol031(), conn, q, stream, "test@localhost", "*****@*****.**")
    jt.prepare()

    self_handle = conn.GetSelfHandle()
    handle = conn.RequestHandles(cs.HT_CONTACT, [jt.peer])[0]

    request = {cs.CHANNEL_TYPE: channel_type, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, cs.TARGET_HANDLE: handle}

    if channel_type == cs.CHANNEL_TYPE_CALL:
        request[cs.CALL_INITIAL_AUDIO] = True

    # Ensure a channel that doesn't exist yet.
    call_async(q, conn.Requests, "EnsureChannel", request)

    ret, old_sig, new_sig = q.expect_many(
        EventPattern("dbus-return", method="EnsureChannel"),
        EventPattern(
            "dbus-signal", signal="NewChannel", predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args
        ),
        EventPattern(
            "dbus-signal",
            signal="NewChannels",
            predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values(),
        ),
    )

    yours, path, props = ret.value

    # this channel was created in response to our EnsureChannel call, so it
    # should be ours.
    assert yours, ret.value

    sig_path, sig_ct, sig_ht, sig_h, sig_sh = old_sig.args

    assertEquals(sig_path, path)
    assertEquals(channel_type, sig_ct)
    assertEquals(cs.HT_CONTACT, sig_ht)
    assertEquals(handle, sig_h)
    assert sig_sh  # suppress handler

    assertLength(1, new_sig.args)
    assertLength(1, new_sig.args[0])  # one channel
    assertLength(2, new_sig.args[0][0])  # two struct members
    assertEquals(path, new_sig.args[0][0][0])
    emitted_props = new_sig.args[0][0][1]

    assertEquals(channel_type, emitted_props[cs.CHANNEL_TYPE])
    assertEquals(cs.HT_CONTACT, emitted_props[cs.TARGET_HANDLE_TYPE])
    assertEquals(handle, emitted_props[cs.TARGET_HANDLE])
    assertEquals(jt.peer_bare_jid, emitted_props[cs.TARGET_ID])
    assert emitted_props[cs.REQUESTED]
    assertEquals(self_handle, emitted_props[cs.INITIATOR_HANDLE])
    assertEquals("test@localhost", emitted_props[cs.INITIATOR_ID])

    # Now ensure a media channel with the same contact, and check it's the
    # same.
    call_async(q, conn.Requests, "EnsureChannel", request)

    event = q.expect("dbus-return", method="EnsureChannel")
    yours2, path2, props2 = event.value

    # We should have got back the same channel we created a page or so ago.
    assertEquals(path2, path)
    # It's not been created for this call, so Yours should be False.
    assert not yours2

    # Time passes ... afterwards we close the chan

    chan = wrap_channel(bus.get_object(conn.bus_name, path), "StreamedMedia")
    chan.Close()

    # Ensure a channel that doesn't exist yet.
    call_async(q, conn.Requests, "EnsureChannel", request)

    # Re-ensure a channel that is hopefully still pending creation.
    call_async(q, conn.Requests, "EnsureChannel", request)

    ret, ret2, old_sig, new_sig = q.expect_many(
        EventPattern("dbus-return", method="EnsureChannel"),
        EventPattern("dbus-return", method="EnsureChannel"),
        EventPattern(
            "dbus-signal", signal="NewChannel", predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args
        ),
        EventPattern(
            "dbus-signal",
            signal="NewChannels",
            predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values(),
        ),
    )

    yours, path, props = ret.value

    # this channel was created in response to our EnsureChannel call, so it
    # should be ours.
    assert yours, ret.value

    sig_path, sig_ct, sig_ht, sig_h, sig_sh = old_sig.args

    assertEquals(sig_path, path)
    assertEquals(channel_type, sig_ct)
    assertEquals(cs.HT_CONTACT, sig_ht)
    assertEquals(handle, sig_h)
    assert sig_sh  # suppress handler

    assertLength(1, new_sig.args)
    assertLength(1, new_sig.args[0])  # one channel
    assertLength(2, new_sig.args[0][0])  # two struct members
    assertEquals(path, new_sig.args[0][0][0])
    emitted_props = new_sig.args[0][0][1]

    assertEquals(channel_type, emitted_props[cs.CHANNEL_TYPE])
    assertEquals(cs.HT_CONTACT, emitted_props[cs.TARGET_HANDLE_TYPE])
    assertEquals(handle, emitted_props[cs.TARGET_HANDLE])
    assertEquals(jt.peer_bare_jid, emitted_props[cs.TARGET_ID])
    assert emitted_props[cs.REQUESTED]
    assertEquals(self_handle, emitted_props[cs.INITIATOR_HANDLE])
    assertEquals("test@localhost", emitted_props[cs.INITIATOR_ID])

    yours2, path2, props2 = ret2.value

    # We should have got back the same channel we created a page or so ago.
    assertEquals(path2, path)
    # It's not been created for this call, so Yours should be False.
    assert not yours2

    # Time passes ... afterwards we close the chan

    chan = wrap_channel(bus.get_object(conn.bus_name, path), "StreamedMedia")
    chan.Close()

    # The remaining checks don't apply to calls
    if channel_type == cs.CHANNEL_TYPE_CALL:
        return

    # Now, create an anonymous channel with RequestChannel, add the other
    # person to it with RequestStreams, then Ensure a media channel with that
    # person.  We should get the anonymous channel back.
    call_async(q, conn, "RequestChannel", channel_type, 0, 0, True)

    ret, old_sig, new_sig = q.expect_many(
        EventPattern("dbus-return", method="RequestChannel"),
        EventPattern(
            "dbus-signal", signal="NewChannel", predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args
        ),
        EventPattern(
            "dbus-signal",
            signal="NewChannels",
            predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values(),
        ),
    )

    path = ret.value[0]
    assertEquals([path, channel_type, cs.HT_NONE, 0, True], old_sig.args)

    assertLength(1, new_sig.args)
    assertLength(1, new_sig.args[0])  # one channel
    assertLength(2, new_sig.args[0][0])  # two struct members
    assertEquals(path, new_sig.args[0][0][0])
    emitted_props = new_sig.args[0][0][1]

    assertEquals(channel_type, emitted_props[cs.CHANNEL_TYPE])
    assertEquals(cs.HT_NONE, emitted_props[cs.TARGET_HANDLE_TYPE])
    assertEquals(0, emitted_props[cs.TARGET_HANDLE])
    assertEquals("", emitted_props[cs.TARGET_ID])
    assert emitted_props[cs.REQUESTED]
    assertEquals(self_handle, emitted_props[cs.INITIATOR_HANDLE])
    assertEquals("test@localhost", emitted_props[cs.INITIATOR_ID])

    chan = wrap_channel(bus.get_object(conn.bus_name, path), "StreamedMedia")

    # Request streams with the other person.  This should make them the
    # channel's "peer" property.
    chan.StreamedMedia.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_AUDIO])

    # Now, Ensuring a media channel with handle should yield the channel just
    # created.

    call_async(q, conn.Requests, "EnsureChannel", request)

    event = q.expect("dbus-return", method="EnsureChannel")
    yours, path2, _ = event.value

    # we should have got back the anonymous channel we got with requestchannel
    # and called RequestStreams(handle) on.
    assertEquals(path2, path)
    # It's not been created for this call, so Yours should be False.
    assert not yours

    chan.Close()
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'))
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 #37
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]
Example #38
0
def test(q, bus, conn, stream):
    id = '1845a1a9-f7bc-4a2e-a885-633aadc81e1b'

    # <message type="chat"><body>hello</body</message>
    m = domish.Element((None, 'message'))
    m['from'] = '[email protected]/Pidgin'
    m['id'] = id
    m['type'] = 'chat'
    m.addElement('body', content='hello')
    stream.send(m)

    event = q.expect('dbus-signal', signal='NewChannels')
    path, props = event.args[0][0]
    text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')
    assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE])
    assertEquals(cs.HT_CONTACT, props[cs.TARGET_HANDLE_TYPE])
    foo_at_bar_dot_com_handle = props[cs.TARGET_HANDLE]
    jid = conn.inspect_contact_sync(foo_at_bar_dot_com_handle)
    assertEquals('*****@*****.**', jid)

    # Exercise basic Channel Properties from spec 0.17.7
    channel_props = text_chan.Properties.GetAll(cs.CHANNEL)
    assertEquals(props[cs.TARGET_HANDLE], channel_props.get('TargetHandle'))
    assertEquals(cs.HT_CONTACT, channel_props.get('TargetHandleType'))
    assertEquals(cs.CHANNEL_TYPE_TEXT, channel_props.get('ChannelType'))
    assertContains(cs.CHANNEL_IFACE_CHAT_STATE, channel_props.get('Interfaces'))
    assertContains(cs.CHANNEL_IFACE_MESSAGES, channel_props.get('Interfaces'))
    assertEquals(jid, channel_props['TargetID'])
    assertEquals(False, channel_props['Requested'])
    assertEquals(props[cs.INITIATOR_HANDLE], channel_props['InitiatorHandle'])
    assertEquals(jid, channel_props['InitiatorID'])

    message_received = q.expect('dbus-signal', signal='MessageReceived')

    # Check that C.I.Messages.MessageReceived looks right.
    message = message_received.args[0]

    # message should have two parts: the header and one content part
    assert len(message) == 2, message
    header, body = message

    assert header['message-sender'] == foo_at_bar_dot_com_handle, header
    # the spec says that message-type "MAY be omitted for normal chat
    # messages."
    assert 'message-type' not in header or header['message-type'] == 0, header

    # We don't make any uniqueness guarantees about the tokens on incoming
    # messages, so we use the id='' provided at the protocol level.
    assertEquals(id, header['message-token'])

    assert body['content-type'] == 'text/plain', body
    assert body['content'] == 'hello', body

    # Remove the message from the pending message queue, and check that
    # PendingMessagesRemoved fires.
    message_id = header['pending-message-id']

    text_chan.Text.AcknowledgePendingMessages([message_id])

    removed = q.expect('dbus-signal', signal='PendingMessagesRemoved')

    removed_ids = removed.args[0]
    assert len(removed_ids) == 1, removed_ids
    assert removed_ids[0] == message_id, (removed_ids, message_id)

    # Send a Notice using the Messages API
    greeting = [
        dbus.Dictionary({ 'message-type': 2, # Notice
                        }, signature='sv'),
        { 'content-type': 'text/plain',
          'content': u"what up",
        }
    ]

    sent_token = text_chan.Messages.SendMessage(greeting, dbus.UInt32(0))

    stream_message, message_sent = q.expect_many(
        EventPattern('stream-message'),
        EventPattern('dbus-signal', signal='MessageSent'),
        )

    elt = stream_message.stanza
    assert elt.name == 'message'
    assert elt['type'] == 'normal'
    body = list(stream_message.stanza.elements())[0]
    assert body.name == 'body'
    assert body.children[0] == u'what up'

    sent_message = message_sent.args[0]
    assert len(sent_message) == 2, sent_message
    header = sent_message[0]
    assert header['message-type'] == 2, header # Notice
    assert header['message-token'] == sent_token, header
    assertEquals(conn.Properties.Get(cs.CONN, "SelfHandle"), header['message-sender'])
    assertEquals('test@localhost', header['message-sender-id'])
    body = sent_message[1]
    assert body['content-type'] == 'text/plain', body
    assert body['content'] == u'what up', body

    assert message_sent.args[2] == sent_token

    # Send a message using Channel.Type.Text API
    text_chan.Text.Send(0, 'goodbye')

    stream_message, message_sent = q.expect_many(
        EventPattern('stream-message'),
        EventPattern('dbus-signal', signal='MessageSent'),
        )

    elt = stream_message.stanza
    assert elt.name == 'message'
    assert elt['type'] == 'chat'
    body = list(stream_message.stanza.elements())[0]
    assert body.name == 'body'
    assert body.children[0] == u'goodbye'

    sent_message = message_sent.args[0]
    assert len(sent_message) == 2, sent_message
    header = sent_message[0]
    # the spec says that message-type "MAY be omitted for normal chat
    # messages."
    assert 'message-type' not in header or header['message-type'] == 0, header
    body = sent_message[1]
    assert body['content-type'] == 'text/plain', body
    assert body['content'] == u'goodbye', body

    # And now let's try a message with a malformed type='' attribute.
    malformed = elem(
        'message', from_='[email protected]/fubber', type="'")(
          elem('body')(u'Internettt!'),
          elem('subject')(u'xyzzy'),
          elem('thread')(u'6666'),
        )
    stream.send(malformed)

    event = q.expect('dbus-signal', signal='MessageReceived')
    message, = event.args
    assertLength(2, message)
    header, body = message

    # Gabble should treat the unparseable type as if it were 'normal' or
    # omitted (not to be confused with Telepathy's Normal, which is 'chat' in
    # XMPP...)
    assertEquals(cs.MT_NOTICE, header['message-type'])
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 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 #41
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'
def worker(jp, q, bus, conn, stream):
    jp.features.append(ns.JINGLE_TRANSPORT_ICEUDP)
    jt2 = JingleTest2(jp, conn, q, stream, 'test@localhost', '[email protected]/Foo')
    jt2.prepare()

    remote_handle = conn.RequestHandles(cs.HT_CONTACT, ["[email protected]/Foo"])[0]

    # Remote end calls us
    node = jp.SetIq(jt2.peer, jt2.jid, [
        jp.Jingle(jt2.sid, jt2.peer, 'session-initiate', [
            jp.Content('stream1', 'initiator', 'both',
                jp.Description('audio', [
                    jp.PayloadType(name, str(rate), str(id), parameters) for
                        (name, id, rate, parameters) in jt2.audio_codecs ]),
            jp.TransportIceUdp()) ]) ])
    stream.send(jp.xml(node))

    nc, e = q.expect_many(
        EventPattern('dbus-signal', signal='NewChannel',
            predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args),
        EventPattern('dbus-signal', signal='NewSessionHandler'),
        )
    path = nc.args[0]

    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia')

    hrggh = chan.ListProperties(dbus_interface=cs.TP_AWKWARD_PROPERTIES)
    id = [x for x, name, _, _ in hrggh if name == 'nat-traversal'][0]
    nrgrg = chan.GetProperties([id], dbus_interface=cs.TP_AWKWARD_PROPERTIES)
    _, nat_traversal = nrgrg[0]
    assertEquals('ice-udp', nat_traversal)

    session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler')
    session_handler.Ready()

    chan.Group.AddMembers([conn.GetSelfHandle()], 'accepted')

    # S-E gets notified about a newly-created stream
    e = q.expect('dbus-signal', signal='NewStreamHandler')

    stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler')

    stream_handler.NewNativeCandidate("fake", jt2.get_remote_transports_dbus())
    stream_handler.Ready(jt2.get_audio_codecs_dbus())
    stream_handler.StreamState(2)

    # First one is transport-info
    e = q.expect('stream-iq', predicate=jp.action_predicate('transport-info'))
    transport_stanza = xpath.queryForNodes(
        "/iq/jingle/content/transport[@xmlns='%s']"
        % ns.JINGLE_TRANSPORT_ICEUDP, e.stanza)[0]

    # username
    assertEquals(transport_stanza['ufrag'], jt2.remote_transports[0][7])
    # password
    assertEquals(transport_stanza['pwd'], jt2.remote_transports[0][8])

    children = list(transport_stanza.elements())
    assertLength(1, children)

    stream.send(jp.xml(jp.ResultIq('test@localhost', e.stanza, [])))

    # Set codec intersection so gabble can accept the session
    stream_handler.SupportedCodecs(jt2.get_audio_codecs_dbus())

    # Second one is session-accept
    e = q.expect('stream-iq', predicate=jp.action_predicate('session-accept'))
    assert xpath.queryForNodes("/iq/jingle/content/transport[@xmlns='%s']" %
        ns.JINGLE_TRANSPORT_ICEUDP, e.stanza)

    stream.send(jp.xml(jp.ResultIq('test@localhost', e.stanza, [])))

    # Connected! Blah, blah, ...

    jt2.terminate()

    e = q.expect('dbus-signal', signal='Close')
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):
    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 #45
0
def test(q, bus, conn, stream):
    self_handle = conn.GetSelfHandle()

    jid = '*****@*****.**'
    full_jid = '[email protected]/Foo'
    foo_handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0]

    path = conn.Requests.CreateChannel(
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
              cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
              cs.TARGET_HANDLE: foo_handle,
              })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['ChatState', 'Destroyable'])

    presence = make_presence(full_jid, status='hello',
        caps={
            'node': 'http://telepathy.freedesktop.org/homeopathy',
            'ver' : '0.1',
        })
    stream.send(presence)

    version_event = q.expect('stream-iq', to=full_jid,
        query_ns=ns.DISCO_INFO,
        query_node='http://telepathy.freedesktop.org/homeopathy#0.1')

    result = make_result_iq(stream, version_event.stanza)
    query = result.firstChildElement()
    feature = query.addElement('feature')
    feature['var'] = ns.CHAT_STATES
    stream.send(result)

    sync_stream(q, stream)

    # Receiving chat states:

    # Composing...
    stream.send(make_message(full_jid, state='composing'))

    changed = q.expect('dbus-signal', signal='ChatStateChanged')
    handle, state = changed.args
    assertEquals(foo_handle, handle)
    assertEquals(cs.CHAT_STATE_COMPOSING, state)

    # Message!
    stream.send(make_message(full_jid, body='hello', state='active'))

    changed = q.expect('dbus-signal', signal='ChatStateChanged')
    handle, state = changed.args
    assertEquals(foo_handle, handle)
    assertEquals(cs.CHAT_STATE_ACTIVE, state)

    # Sending chat states:

    # Composing...
    chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING)

    stream_message = q.expect('stream-message')
    check_state_notification(stream_message.stanza, 'composing')

    # XEP 0085:
    #   every content message SHOULD contain an <active/> notification.
    chan.Text.Send(0, 'hi.')

    stream_message = q.expect('stream-message')
    elem = stream_message.stanza
    assertEquals('chat', elem['type'])

    check_state_notification(elem, 'active', allow_body=True)

    def is_body(e):
        if e.name == 'body':
            assert e.children[0] == u'hi.', e.toXml()
            return True
        return False

    assert len([x for x in elem.elements() if is_body(x)]) == 1, elem.toXml()

    # Close the channel without acking the received message. The peer should
    # get a <gone/> notification, and the channel should respawn.
    chan.Close()

    gone, _, _ = q.expect_many(
        EventPattern('stream-message'),
        EventPattern('dbus-signal', signal='Closed'),
        EventPattern('dbus-signal', signal='NewChannel'),
        )
    check_state_notification(gone.stanza, 'gone')

    # Reusing the proxy object because we happen to know it'll be at the same
    # path...

    # Destroy the channel. The peer shouldn't get a <gone/> notification, since
    # we already said we were gone and haven't sent them any messages to the
    # contrary.
    es = [EventPattern('stream-message')]
    q.forbid_events(es)

    chan.Destroyable.Destroy()
    sync_stream(q, stream)

    # Make the channel anew.
    path = conn.Requests.CreateChannel(
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
              cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
              cs.TARGET_HANDLE: foo_handle,
              })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['ChatState', 'Destroyable'])

    # Close it immediately; the peer should again not get a <gone/>
    # notification, since we haven't sent any notifications on that channel.
    chan.Close()
    sync_stream(q, stream)
    q.unforbid_events(es)

    # XEP-0085 §5.1 defines how to negotiate support for chat states with a
    # contact in the absence of capabilities. This is useful when talking to
    # invisible contacts, for example.

    # First, if we receive a message from a contact, containing an <active/>
    # notification, they support chat states, so we should send them.

    jid = '*****@*****.**'
    full_jid = jid + '/GTalk'

    path = conn.Requests.CreateChannel(
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
              cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
              cs.TARGET_ID: jid,
              })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['ChatState'])

    stream.send(make_message(full_jid, body='i am invisible', state='active'))

    changed = q.expect('dbus-signal', signal='ChatStateChanged')
    assertEquals(cs.CHAT_STATE_ACTIVE, changed.args[1])

    # We've seen them send a chat state notification, so we should send them
    # notifications when the UI tells us to.
    chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING)
    stream_message = q.expect('stream-message', to=full_jid)
    check_state_notification(stream_message.stanza, 'composing')

    changed = q.expect('dbus-signal', signal='ChatStateChanged')
    handle, state = changed.args
    assertEquals(cs.CHAT_STATE_COMPOSING, state)
    assertEquals(self_handle, handle)

    chan.Text.Send(0, 'very convincing')
    stream_message = q.expect('stream-message', to=full_jid)
    check_state_notification(stream_message.stanza, 'active', allow_body=True)

    # Now, test the case where we start the negotiation, and the contact
    # turns out to support chat state notifications.

    jid = '*****@*****.**'
    full_jid = jid + '/GTalk'
    path = conn.Requests.CreateChannel(
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
              cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
              cs.TARGET_ID: jid,
              })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['ChatState'])

    # We shouldn't send any notifications until we actually send a message.
    e = EventPattern('stream-message', to=jid)
    q.forbid_events([e])
    for i in [cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE,
              cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE]:
        chan.ChatState.SetChatState(i)
    sync_stream(q, stream)
    q.unforbid_events([e])

    # When we send a message, say we're active.
    chan.Text.Send(0, 'is anyone there?')
    stream_message = q.expect('stream-message', to=jid)
    check_state_notification(stream_message.stanza, 'active', allow_body=True)

    # We get a notification back from our contact.
    stream.send(make_message(full_jid, state='composing'))

    # Wait until gabble tells us the chat-state of the remote party has
    # changed so we know gabble knows chat state notification are supported
    changed = q.expect('dbus-signal', signal='ChatStateChanged')
    handle, state = changed.args
    assertEquals(cs.CHAT_STATE_COMPOSING, state)
    assertNotEquals(self_handle, handle)

    # So now we know they support notification, so should send notifications.
    chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING)

    # This doesn't check whether we're sending to the bare jid, or the
    # jid+resource. In fact, the notification is sent to the bare jid, because
    # we only update which jid we send to when we actually receive a message,
    # not when we receive a notification. wjt thinks this is less surprising
    # than the alternative:
    #
    #  • I'm talking to you on my N900, and signed in on my laptop;
    #  • I enter one character in a tab to you on my laptop, and then delete
    #    it;
    #  • Now your messages to me appear on my laptop (until I send you another
    #    one from my N900)!
    stream_message = q.expect('stream-message')
    check_state_notification(stream_message.stanza, 'composing')

    # But! Now they start messaging us from a different client, which *doesn't*
    # support notifications.
    other_jid = jid + '/Library'
    stream.send(make_message(other_jid, body='grr, library computers'))
    q.expect('dbus-signal', signal='Received')

    # Okay, we should stop sending typing notifications.
    e = EventPattern('stream-message', to=other_jid)
    q.forbid_events([e])
    for i in [cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE,
              cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE]:
        chan.ChatState.SetChatState(i)
    sync_stream(q, stream)
    q.unforbid_events([e])

    # Now, test the case where we start the negotiation, and the contact
    # does not support chat state notifications

    jid = '*****@*****.**'
    full_jid = jid + '/Nonsense'
    path = conn.Requests.CreateChannel(
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
              cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
              cs.TARGET_ID: jid,
              })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['ChatState'])

    # We shouldn't send any notifications until we actually send a message.
    e = EventPattern('stream-message', to=jid)
    q.forbid_events([e])
    for i in [cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE,
              cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE]:
        chan.ChatState.SetChatState(i)
    sync_stream(q, stream)
    q.unforbid_events([e])

    # When we send a message, say we're active.
    chan.Text.Send(0, '#n900 #maemo #zomg #woo #yay http://bit.ly/n900')
    stream_message = q.expect('stream-message', to=jid)
    check_state_notification(stream_message.stanza, 'active', allow_body=True)

    # They reply without a chat state.
    stream.send(make_message(full_jid, body="posted."))
    q.expect('dbus-signal', signal='Received')

    # Okay, we shouldn't send any more.
    e = EventPattern('stream-message', to=other_jid)
    q.forbid_events([e])
    for i in [cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE,
              cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE]:
        chan.ChatState.SetChatState(i)
    sync_stream(q, stream)
    q.unforbid_events([e])

    chan.Text.Send(0, '@stephenfry simmer down')
    message = q.expect('stream-message')
    states = [x for x in message.stanza.elements() if x.uri == ns.CHAT_STATES]
    assertLength(0, states)
def test(q, bus, conn):

    contact1_name, conn2, contact2_name, contact2_handle_on_conn1,\
        contact1_handle_on_conn2 = t.connect_two_accounts(q, bus, conn)

    conn1_self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")
    conn2_self_handle = conn2.Properties.Get(cs.CONN, "SelfHandle")

    # first connection: join muc
    muc_handle1, group1 = t.join_muc(q, conn, muc_name)

    # Can we request muc D-Bus tubes?
    properties = conn.GetAll(cs.CONN_IFACE_REQUESTS,
                             dbus_interface=cs.PROPERTIES_IFACE)

    assert ({cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_DBUS_TUBE,
             cs.TARGET_HANDLE_TYPE: cs.HT_ROOM},
         [cs.TARGET_HANDLE, cs.TARGET_ID, cs.DBUS_TUBE_SERVICE_NAME]
        ) in properties.get('RequestableChannelClasses'),\
                 properties['RequestableChannelClasses']

    # request a stream tube channel (new API)
    requestotron = dbus.Interface(conn, cs.CONN_IFACE_REQUESTS)

    requestotron.CreateChannel({
        cs.CHANNEL_TYPE:
        cs.CHANNEL_TYPE_DBUS_TUBE,
        cs.TARGET_HANDLE_TYPE:
        cs.HT_ROOM,
        cs.TARGET_ID:
        muc_name,
        cs.DBUS_TUBE_SERVICE_NAME:
        'com.example.TestCase'
    })

    e = q.expect('dbus-signal', signal='NewChannels')
    channels = e.args[0]
    assert len(channels) == 1

    # get the list of all channels to check that newly announced ones are in it
    all_channels = conn.Get(cs.CONN_IFACE_REQUESTS,
                            'Channels',
                            dbus_interface=cs.PROPERTIES_IFACE,
                            byte_arrays=True)

    path, props = channels[0]

    assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE
    assert props[cs.REQUESTED] == True
    assertSameSets([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE],
                   props[cs.INTERFACES])
    assert props[cs.DBUS_TUBE_SERVICE_NAME] == 'com.example.TestCase'
    assert props[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS] == [
        cs.SOCKET_ACCESS_CONTROL_CREDENTIALS,
        cs.SOCKET_ACCESS_CONTROL_LOCALHOST
    ]

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

    assert (path, props) in all_channels, (path, props)

    state = contact1_tube.Properties.Get(cs.CHANNEL_IFACE_TUBE, 'State')
    assert state == cs.TUBE_CHANNEL_STATE_NOT_OFFERED

    call_async(q, contact1_tube.DBusTube, 'Offer', sample_parameters,
               cs.SOCKET_ACCESS_CONTROL_CREDENTIALS)

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

    tube_addr1 = e.value[0]

    state = contact1_tube.Properties.Get(cs.CHANNEL_IFACE_TUBE, 'State')
    assert state == cs.TUBE_CHANNEL_STATE_OPEN

    check_dbus_names(contact1_tube, [conn1_self_handle])

    t.invite_to_muc(q, group1, conn2, contact2_handle_on_conn1,
                    contact1_handle_on_conn2)

    # tubes channel is created
    e, dbus_names_e = q.expect_many(
        EventPattern('dbus-signal', signal='NewChannels'),
        EventPattern('dbus-signal',
                     signal='DBusNamesChanged',
                     interface=cs.CHANNEL_TYPE_DBUS_TUBE))

    channels = e.args[0]
    assert len(channels) == 1

    # get the list of all channels to check that newly announced ones are in it
    all_channels = conn2.Get(cs.CONN_IFACE_REQUESTS,
                             'Channels',
                             dbus_interface=cs.PROPERTIES_IFACE,
                             byte_arrays=True)

    path, props = channels[0]

    assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE
    assert props[cs.REQUESTED] == False
    assertSameSets([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE],
                   props[cs.INTERFACES])
    assert props[cs.TUBE_PARAMETERS] == sample_parameters
    assert props[cs.DBUS_TUBE_SERVICE_NAME] == 'com.example.TestCase'
    assert props[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS] == [
        cs.SOCKET_ACCESS_CONTROL_CREDENTIALS,
        cs.SOCKET_ACCESS_CONTROL_LOCALHOST
    ]

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

    assert (path, props) in all_channels, (path, props)

    # second connection: check DBusNamesChanged signal
    assert dbus_names_e.path == tube2_path
    added, removed = dbus_names_e.args
    assert added.keys() == [contact1_handle_on_conn2]
    assert removed == []

    state = contact2_tube.Properties.Get(cs.CHANNEL_IFACE_TUBE, 'State')
    assert state == cs.TUBE_CHANNEL_STATE_LOCAL_PENDING

    # first connection: contact2 is not in the tube yet
    check_dbus_names(contact1_tube, [conn1_self_handle])

    # second connection: accept the tube (new API)
    tube_addr2 = unix_socket_adr = contact2_tube.DBusTube.Accept(
        cs.SOCKET_ACCESS_CONTROL_CREDENTIALS)

    state = contact2_tube.Properties.Get(cs.CHANNEL_IFACE_TUBE, 'State')
    assert state == cs.TUBE_CHANNEL_STATE_OPEN

    e, dbus_names_e = q.expect_many(
        EventPattern('dbus-signal',
                     signal='TubeChannelStateChanged',
                     path=tube2_path,
                     args=[cs.TUBE_CHANNEL_STATE_OPEN]),
        EventPattern('dbus-signal',
                     signal='DBusNamesChanged',
                     interface=cs.CHANNEL_TYPE_DBUS_TUBE,
                     path=tube1_path))

    added, removed = dbus_names_e.args
    assert added.keys() == [contact2_handle_on_conn1]
    assert removed == []

    check_dbus_names(contact1_tube,
                     [conn1_self_handle, contact2_handle_on_conn1])
    check_dbus_names(contact2_tube,
                     [conn2_self_handle, contact1_handle_on_conn2])

    tube2_names = contact2_tube.Get(cs.CHANNEL_TYPE_DBUS_TUBE,
                                    'DBusNames',
                                    dbus_interface=cs.PROPERTIES_IFACE)

    tube_conn1 = dbus.connection.Connection(tube_addr1)
    tube_conn2 = dbus.connection.Connection(tube_addr2)

    obj1 = Test(tube_conn1, q)

    # fire 'MySig' signal on the tube
    def my_sig_cb(arg, sender=None):
        assert tube2_names[contact1_handle_on_conn2] == sender

        q.append(Event('tube-dbus-signal', signal='MySig', args=[arg]))

    tube_conn2.add_signal_receiver(my_sig_cb,
                                   'MySig',
                                   IFACE,
                                   path=PATH,
                                   sender_keyword='sender')

    obj1.MySig('hello')
    q.expect('tube-dbus-signal', signal='MySig', args=['hello'])

    # call remote method
    def my_method_cb(result):
        q.append(Event('tube-dbus-return', method='MyMethod', value=[result]))

    def my_method_error(e):
        assert False, e

    tube_conn2.get_object(tube2_names[contact1_handle_on_conn2],
                          PATH).MyMethod(42,
                                         dbus_interface=IFACE,
                                         reply_handler=my_method_cb,
                                         error_handler=my_method_error)

    q.expect('tube-dbus-call', method='MyMethod', args=[42])
    q.expect('tube-dbus-return', method='MyMethod', value=[420])

    call_async(q, contact1_tube, 'Close')
    _, _, _, dbus_names_e = q.expect_many(
        EventPattern('dbus-return', method='Close'),
        EventPattern('dbus-signal', signal='Closed'),
        EventPattern('dbus-signal', signal='ChannelClosed'),
        EventPattern('dbus-signal',
                     signal='DBusNamesChanged',
                     interface=cs.CHANNEL_TYPE_DBUS_TUBE,
                     path=tube2_path))

    # Contact1 is removed from the tube
    added, removed = dbus_names_e.args
    assert added == {}
    assert removed == [contact1_handle_on_conn2]

    check_dbus_names(contact2_tube, [conn2_self_handle])

    call_async(q, contact2_tube, 'Close')
    q.expect_many(EventPattern('dbus-return', method='Close'),
                  EventPattern('dbus-signal', signal='Closed'),
                  EventPattern('dbus-signal', signal='ChannelClosed'))

    conn.Disconnect()
    conn2.Disconnect()
Example #47
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)
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

    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)

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

    address = t.create_server(q, address_type)

    def new_chan_predicate(e):
        types = []
        for _, props in e.args[0]:
            types.append(props[cs.CHANNEL_TYPE])

        return cs.CHANNEL_TYPE_STREAM_TUBE in types

    def find_stream_tube(channels):
        for path, props in channels:
            if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE:
                return path, props

        return None, None

    # offer a stream tube to another room (new API)
    address = t.create_server(q, address_type, block_reading=True)

    request = {
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE,
        cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
        cs.TARGET_ID: '*****@*****.**',
        cs.STREAM_TUBE_SERVICE: 'newecho',
    }
    _, new_tube_path, new_tube_props = \
        join_muc(q, bus, conn, stream, '*****@*****.**', request)

    e = q.expect('dbus-signal',
                 signal='NewChannels',
                 predicate=new_chan_predicate)

    path, prop = find_stream_tube(e.args[0])
    assert prop[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_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.STREAM_TUBE_SERVICE] == 'newecho'

    # 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), 'StreamTube')
    tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE,
                                  dbus_interface=cs.PROPERTIES_IFACE)

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

    # offer the tube
    call_async(q, tube_chan.StreamTube, 'Offer', address_type, address,
               access_control, {'foo': 'bar'})

    stream_event, _, status_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]))

    tube_self_handle = tube_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP,
                                                'SelfHandle')
    assert conn.inspect_contact_sync(
        tube_self_handle) == '[email protected]/test'

    presence = stream_event.stanza
    tubes_nodes = xpath.queryForNodes(
        '/presence/tubes[@xmlns="%s"]' % ns.TUBES, presence)
    assert tubes_nodes is not None
    assert len(tubes_nodes) == 1

    stream_tube_id = 666

    tube_nodes = xpath.queryForNodes('/tubes/tube', tubes_nodes[0])
    assert tube_nodes is not None
    assert len(tube_nodes) == 1
    for tube in tube_nodes:
        assert tube['type'] == 'stream'
        assert not tube.hasAttribute('initiator')
        assert tube['service'] == 'newecho'
        assert not tube.hasAttribute('stream-id')
        assert not tube.hasAttribute('dbus-name')

        stream_tube_id = int(tube['id'])

    params = {}
    parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube)
    for node in parameter_nodes:
        assert node['name'] not in params
        params[node['name']] = (node['type'], str(node))
    assert params == {'foo': ('str', 'bar')}

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

    bytestream = connect_to_tube(stream, q, bytestream_cls,
                                 '*****@*****.**', stream_tube_id)

    iq_event, socket_event, conn_event = q.expect_many(
        EventPattern('stream-iq', iq_type='result'),
        EventPattern('socket-connected'),
        EventPattern('dbus-signal',
                     signal='NewRemoteConnection',
                     interface=cs.CHANNEL_TYPE_STREAM_TUBE))

    handle, access, conn_id = conn_event.args
    assert handle == bob_handle

    protocol = socket_event.protocol
    # start to read from the transport so we can read the control byte
    protocol.transport.startReading()
    t.check_new_connection_access(q, access_control, access, protocol)

    # handle iq_event
    bytestream.check_si_reply(iq_event.stanza)
    tube = xpath.queryForNodes('/iq//si/tube[@xmlns="%s"]' % ns.TUBES,
                               iq_event.stanza)
    assert len(tube) == 1

    use_tube(q, bytestream, protocol, conn_id)

    tube_chan.Channel.Close()
    q.expect_many(EventPattern('dbus-signal', signal='Closed'),
                  EventPattern('dbus-signal', signal='ChannelClosed'))

    t.cleanup()
def test(q, bus, conn, stream):
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    jid = '*****@*****.**'
    foo_handle = conn.get_contact_handle_sync(jid)

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

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

    text_chan = wrap_channel(bus.get_object(conn.bus_name, ret.value[0]), 'Text')
    chan_iface = dbus.Interface(text_chan, cs.CHANNEL)

    assert len(new_sig.args) == 1
    assert len(new_sig.args[0]) == 1        # one channel
    assert len(new_sig.args[0][0]) == 2     # two struct members
    assert new_sig.args[0][0][0] == ret.value[0]
    emitted_props = new_sig.args[0][0][1]
    assert emitted_props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT
    assert emitted_props[cs.TARGET_HANDLE_TYPE] == cs.HT_CONTACT
    assert emitted_props[cs.TARGET_HANDLE] == foo_handle
    assert emitted_props[cs.TARGET_ID] == jid
    assert emitted_props[cs.REQUESTED] == True
    assert emitted_props[cs.INITIATOR_HANDLE] == self_handle
    assert emitted_props[cs.INITIATOR_ID] == 'test@localhost'

    channel_props = text_chan.GetAll(
        cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE)
    assert channel_props['TargetID'] == jid,\
            (channel_props['TargetID'], jid)
    assert channel_props['Requested'] == True
    assert channel_props['InitiatorHandle'] == self_handle,\
            (channel_props['InitiatorHandle'], self_handle)
    assert channel_props['InitiatorID'] == 'test@localhost',\
            channel_props['InitiatorID']

    text_chan.send_msg_sync('hey')

    event = q.expect('stream-message')

    elem = event.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'chat'
    body = list(event.stanza.elements())[0]
    assert body.name == 'body'
    assert body.children[0] == u'hey'

    # <message type="chat"><body>hello</body</message>
    m = domish.Element((None, 'message'))
    m['from'] = '[email protected]/Pidgin'
    m['type'] = 'chat'
    m.addElement('body', content='hello')
    stream.send(m)

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

    msg = event.args[0]
    assertEquals(foo_handle, msg[0]['message-sender'])
    assertEquals('hello', msg[1]['content'])

    messages = text_chan.Properties.Get(cs.CHANNEL_IFACE_MESSAGES, 'PendingMessages')
    assertEquals([msg], messages)

    # close the channel without acking the message; it comes back

    call_async(q, chan_iface, 'Close')

    old, new = q.expect_many(
            EventPattern('dbus-signal', signal='Closed'),
            EventPattern('dbus-signal', signal='ChannelClosed'),
            )
    assert old.path == text_chan.object_path,\
            (old.path, text_chan.object_path)
    assert new.args[0] == text_chan.object_path,\
            (new.args[0], text_chan.object_path)

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

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

    # it now behaves as if the message had initiated it

    channel_props = text_chan.GetAll(
        cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE)
    assert channel_props['TargetID'] == jid,\
            (channel_props['TargetID'], jid)
    assert channel_props['Requested'] == False
    assert channel_props['InitiatorHandle'] == foo_handle,\
            (channel_props['InitiatorHandle'], foo_handle)
    assert channel_props['InitiatorID'] == '*****@*****.**',\
            channel_props['InitiatorID']

    # the message is still there

    messages = text_chan.Properties.Get(cs.CHANNEL_IFACE_MESSAGES, 'PendingMessages')
    msg[0]['rescued'] = True
    assertEquals([msg], messages)

    # acknowledge it

    text_chan.Text.AcknowledgePendingMessages([msg[0]['pending-message-id']])

    messages = text_chan.Properties.Get(cs.CHANNEL_IFACE_MESSAGES, 'PendingMessages')
    assertEquals([], messages)

    # close the channel again

    call_async(q, chan_iface, 'Close')

    event = q.expect('dbus-signal', signal='Closed')
    assert event.path == text_chan.object_path,\
            (event.path, text_chan.object_path)

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

    # assert that it stays dead this time!

    try:
        chan_iface.GetChannelType()
    except dbus.DBusException:
        pass
    else:
        raise AssertionError("Why won't it die?")
Example #50
0
def test(q, bus, conn, stream, use_room=False):
    conn.Connect()
    q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged', args=[1, 1]),
        EventPattern('irc-connected'))
    q.expect('dbus-signal', signal='SelfHandleChanged')
    q.expect('dbus-signal', signal='StatusChanged', args=[0, 1])

    self_handle = conn.Get(cs.CONN,
                           'SelfHandle',
                           dbus_interface=cs.PROPERTIES_IFACE)

    request = build_request(conn, '#idletest', use_room)
    call_async(q, conn.Requests, 'CreateChannel', request)

    # Idle should try to join the channel.
    q.expect('stream-JOIN')

    # Meanwhile, in another application...

    call_async(q,
               conn,
               'EnsureChannel',
               request,
               dbus_interface=cs.CONN_IFACE_REQUESTS)

    sync_dbus(bus, q, conn)

    # Now the ircd responds:
    stream.sendJoin('#idletest')

    cc, ec = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('dbus-return', method='EnsureChannel'),
    )
    nc = q.expect('dbus-signal', signal='NewChannels')

    path, props = cc.value

    assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT
    assertSameSets([
        cs.CHANNEL_IFACE_GROUP,
        cs.CHANNEL_IFACE_PASSWORD,
        cs.CHANNEL_IFACE_MESSAGES,
        cs.CHANNEL_IFACE_ROOM,
        cs.CHANNEL_IFACE_SUBJECT,
        cs.CHANNEL_IFACE_ROOM_CONFIG,
        cs.CHANNEL_IFACE_DESTROYABLE,
    ], props[cs.INTERFACES])
    assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM
    assert props[cs.TARGET_ID] == '#idletest'
    assertEquals('#idletest', props[cs.ROOM_NAME])
    assertEquals('', props[cs.ROOM_SERVER])
    assert props[cs.REQUESTED]
    assert props[cs.INITIATOR_HANDLE] == self_handle
    assert props[cs.INITIATOR_ID] == \
            conn.inspect_contacts_sync([self_handle])[0]

    ec_yours, ec_path, ec_props = ec.value
    assert not ec_yours
    assert ec_path == path
    assert ec_props == props

    channels = nc.args[0]
    assert len(channels) == 1
    nc_path, nc_props = channels[0]
    assert nc_path == path
    assert nc_props == props

    # And again?
    ec_ = conn.EnsureChannel(request, dbus_interface=cs.CONN_IFACE_REQUESTS)
    assert ec.value == ec_

    chans = conn.Get(cs.CONN_IFACE_REQUESTS,
                     'Channels',
                     dbus_interface=cs.PROPERTIES_IFACE)
    assert len(chans) == 1
    assert chans[0] == (path, props)

    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
                        ['Destroyable', 'Messages'])

    # Put an unacknowledged message into the channel
    stream.sendMessage('PRIVMSG', '#idletest', ':oi oi', prefix='lol')
    q.expect('dbus-signal', signal='MessageReceived', path=path)

    # Make sure Close()ing the channel makes it respawn. This avoids the old
    # bug where empathy-chat crashing booted you out of all your channels.
    patterns = [EventPattern('stream-PART')]
    q.forbid_events(patterns)
    chan.Close()
    q.expect('dbus-signal', signal='Closed', path=chan.object_path)
    e = q.expect('dbus-signal', signal='NewChannels')

    path, props = e.args[0][0]
    assertEquals(chan.object_path, path)
    # We requested the channel originally, but we didn't request it popping
    # back up.
    assertEquals(0, props[cs.INITIATOR_HANDLE])
    assert not props[cs.REQUESTED]

    # The unacknowledged message should still be there and be marked as rescued.
    messages = chan.Properties.Get(cs.CHANNEL_IFACE_MESSAGES,
                                   'PendingMessages')
    assertLength(1, messages)
    assert messages[0][0]['rescued'], messages[0]

    # Check that ensuring a respawned channel does what you'd expect.
    ec_yours, ec_path, ec_props = conn.EnsureChannel(
        request, dbus_interface=cs.CONN_IFACE_REQUESTS)
    assert not ec_yours
    assertEquals(chan.object_path, ec_path)
    assertEquals(props, ec_props)

    sync_stream(q, stream)
    q.unforbid_events(patterns)

    chan.RemoveMembers([self_handle],
                       "bye bye cruel\r\nworld",
                       dbus_interface=cs.CHANNEL_IFACE_GROUP)

    part_event = q.expect('stream-PART')

    # This is a regression test for
    # <https://bugs.freedesktop.org/show_bug.cgi?id=34812>, where part messages
    # were not correctly colon-quoted.
    #
    # It is also a regression test for
    # <https://bugs.freedesktop.org/show_bug.cgi?id=34840>, where newlines
    # weren't stripped from part messages. We check that both \r and \n are
    # replaced by harmless spaces.
    assertEquals("bye bye cruel  world", part_event.data[1])

    stream.sendPart('#idletest', stream.nick)

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

    chans = conn.Get(cs.CONN_IFACE_REQUESTS,
                     'Channels',
                     dbus_interface=cs.PROPERTIES_IFACE)
    assert len(chans) == 0
def test(q, bus, conn, stream):
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    jid = '*****@*****.**'
    foo_handle = conn.get_contact_handle_sync(jid)

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

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

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

    path, props = sig.args[0][0]
    assertEquals(ret.value[0], path)
    assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE])
    # check that handle type == contact handle
    assertEquals(cs.HT_CONTACT, props[cs.TARGET_HANDLE_TYPE])
    assertEquals(foo_handle, props[cs.TARGET_HANDLE])

    # Exercise basic Channel Properties from spec 0.17.7
    channel_props = text_chan.GetAll(cs.CHANNEL,
                                     dbus_interface=dbus.PROPERTIES_IFACE)
    assert channel_props.get('TargetHandle') == foo_handle,\
            (channel_props.get('TargetHandle'), foo_handle)
    assert channel_props.get('TargetHandleType') == 1,\
            channel_props.get('TargetHandleType')
    assert channel_props.get('ChannelType') == \
            cs.CHANNEL_TYPE_TEXT,\
            channel_props.get('ChannelType')
    assert cs.CHANNEL_IFACE_CHAT_STATE in \
            channel_props.get('Interfaces', ()), \
            channel_props.get('Interfaces')
    assert channel_props['TargetID'] == jid,\
            (channel_props['TargetID'], jid)
    assert channel_props['Requested'] == True
    assert channel_props['InitiatorHandle'] == self_handle,\
            (channel_props['InitiatorHandle'], self_handle)
    assert channel_props['InitiatorID'] == 'test@localhost',\
            channel_props['InitiatorID']

    text_chan.send_msg_sync('hey')

    event = q.expect('stream-message')

    elem = event.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'chat'
    body = list(event.stanza.elements())[0]
    assert body.name == 'body'
    assert body.children[0] == u'hey'

    # <message type="chat"><body>hello</body</message>
    m = domish.Element((None, 'message'))
    m['from'] = '[email protected]/Pidgin'
    m['type'] = 'chat'
    m.addElement('body', content='hello')
    stream.send(m)

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

    msg = event.args[0]
    assertEquals('hello', msg[1]['content'])
def test(jp, q, bus, conn, stream, peer_removes_final_content):
    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', '[email protected]/Foo')
    jt.prepare()

    handle = conn.RequestHandles(cs.HT_CONTACT, [jt.peer])[0]
    path = conn.RequestChannel(
        cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.HT_CONTACT, handle, True)

    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia')

    chan.StreamedMedia.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_AUDIO])

    # S-E gets notified about new session handler, and calls Ready on it
    e = q.expect('dbus-signal', signal='NewSessionHandler')
    assert e.args[1] == 'rtp'

    session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler')
    session_handler.Ready()

    e = q.expect('dbus-signal', signal='NewStreamHandler')
    stream_id = e.args[1]

    stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler')

    stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus())

    # Before sending the initiate, request another stream

    chan.StreamedMedia.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_VIDEO])

    e = q.expect('dbus-signal', signal='NewStreamHandler')
    stream_id2 = e.args[1]

    stream_handler2 = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler')
    stream_handler2.NewNativeCandidate("fake", jt.get_remote_transports_dbus())

    # Before the CM can initiate session, we modify a stream direction. This
    # should result in a no-op since there's no need to inform the peer of
    # change.
    chan.StreamedMedia.RequestStreamDirection(stream_id2,
        cs.MEDIA_STREAM_DIRECTION_RECEIVE)

    # We set both streams as ready, which will trigger the session initiate
    stream_handler.Ready(jt.get_audio_codecs_dbus())
    stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED)
    stream_handler2.Ready(jt.get_audio_codecs_dbus())
    stream_handler2.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED)

    # We changed our mind locally, don't want video
    chan.StreamedMedia.RemoveStreams([stream_id2])

    e = q.expect('stream-iq', predicate=jp.action_predicate('session-initiate'))
    stream.send(make_result_iq(stream, e.stanza))

    jt.parse_session_initiate(e.query)

    # Gabble sends content-remove for the video stream...
    e2 = q.expect('stream-iq', predicate=jp.action_predicate('content-remove'))

    # ...but before the peer notices, they accept the call.
    jt.accept()

    # Only now the remote end removes the video stream; if gabble mistakenly
    # marked it as accepted on session acceptance, it'll crash right about
    # now. If it's good, stream will be really removed, and
    # we can proceed.
    stream.send(make_result_iq(stream, e2.stanza))

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

    # Actually, we *do* want video!
    chan.StreamedMedia.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_VIDEO])

    e = q.expect('dbus-signal', signal='NewStreamHandler')
    stream2_id = e.args[1]

    stream_handler2 = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler')

    stream_handler2.NewNativeCandidate("fake", jt.get_remote_transports_dbus())
    stream_handler2.Ready(jt.get_audio_codecs_dbus())
    stream_handler2.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED)

    e = q.expect('stream-iq', predicate=jp.action_predicate('content-add'))
    c = e.query.firstChildElement()
    assertEquals('initiator', c['creator'])
    stream.send(make_result_iq(stream, e.stanza))

    # Peer accepts
    jt.content_accept(e.query, 'video')

    # Let's start sending and receiving video!
    q.expect_many(
        EventPattern('dbus-signal', signal='SetStreamPlaying', args=[True]),
        EventPattern('dbus-signal', signal='SetStreamSending', args=[True]),
        )

    # Now, the call draws to a close.
    # We first remove the original stream
    chan.StreamedMedia.RemoveStreams([stream_id])

    e = q.expect('stream-iq', predicate=jp.action_predicate('content-remove'))
    content_remove_ack = make_result_iq(stream, e.stanza)

    if peer_removes_final_content:
        # The peer removes the final countdo^W content. From a footnote (!) in
        # XEP 0166:
        #     If the content-remove results in zero content definitions for the
        #     session, the entity that receives the content-remove SHOULD send
        #     a session-terminate action to the other party (since a session
        #     with no content definitions is void).
        # So, Gabble should respond to the content-remove with a
        # session-terminate.
        node = jp.SetIq(jt.peer, jt.jid, [
            jp.Jingle(jt.sid, jt.peer, 'content-remove', [
                jp.Content(c['name'], c['creator'], c['senders']) ]) ])
        stream.send(jp.xml(node))
    else:
        # The Telepathy client removes the second stream; Gabble should
        # terminate the session rather than sending a content-remove.
        chan.StreamedMedia.RemoveStreams([stream2_id])

    st, closed = q.expect_many(
        EventPattern('stream-iq',
            predicate=jp.action_predicate('session-terminate')),
        # Gabble shouldn't wait for the peer to ack the terminate before
        # considering the call finished.
        EventPattern('dbus-signal', signal='Closed', path=path))

    # Only now does the peer ack the content-remove. This serves as a
    # regression test for contents outliving the session; if the content didn't
    # die properly, this crashed Gabble.
    stream.send(content_remove_ack)
    sync_stream(q, stream)

    # The peer can ack the terminate too, just for completeness.
    stream.send(make_result_iq(stream, st.stanza))
def test(q, bus, conn, stream):
    conn.Connect()
    q.expect('dbus-signal', signal='StatusChanged',
            args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])

    self_handle = conn.GetSelfHandle()

    jid = '*****@*****.**'
    foo_handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0]

    path = conn.Requests.CreateChannel(
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
              cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
              cs.TARGET_HANDLE: foo_handle,
              })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['ChatState', 'Destroyable'])

    presence = make_presence('[email protected]/Foo', status='hello',
        caps={
            'node': 'http://telepathy.freedesktop.org/homeopathy',
            'ver' : '0.1',
        })
    stream.send(presence)

    version_event = q.expect('stream-iq', to='[email protected]/Foo',
        query_ns='http://jabber.org/protocol/disco#info',
        query_node='http://telepathy.freedesktop.org/homeopathy#0.1')

    result = make_result_iq(stream, version_event.stanza)
    query = result.firstChildElement()
    feature = query.addElement('feature')
    feature['var'] = 'http://jabber.org/protocol/chatstates'
    stream.send(result)

    sync_stream(q, stream)

    # Receiving chat states:

    # Composing...
    m = domish.Element((None, 'message'))
    m['from'] = '[email protected]/Foo'
    m['type'] = 'chat'
    m.addElement((ns.CHAT_STATES, 'composing'))
    stream.send(m)

    changed = q.expect('dbus-signal', signal='ChatStateChanged')
    handle, state = changed.args
    assertEquals(foo_handle, handle)
    assertEquals(cs.CHAT_STATE_COMPOSING, state)

    # Message!

    m = domish.Element((None, 'message'))
    m['from'] = '[email protected]/Foo'
    m['type'] = 'chat'
    m.addElement((ns.CHAT_STATES, 'active'))
    m.addElement('body', content='hello')
    stream.send(m)

    changed = q.expect('dbus-signal', signal='ChatStateChanged')
    handle, state = changed.args
    assertEquals(foo_handle, handle)
    assertEquals(cs.CHAT_STATE_ACTIVE, state)

    # Sending chat states:

    # Composing...
    call_async(q, chan.ChatState, 'SetChatState', cs.CHAT_STATE_COMPOSING)

    stream_message = q.expect('stream-message')
    check_state_notification(stream_message.stanza, 'composing')

    # XEP 0085:
    #   every content message SHOULD contain an <active/> notification.
    call_async(q, chan.Text, 'Send', 0, 'hi.')

    stream_message = q.expect('stream-message')
    elem = stream_message.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'chat', elem['type']

    def is_body(e):
        if e.name == 'body':
            assert e.children[0] == u'hi.', e.toXml()
            return True
        return False

    def is_active(e):
        if e.uri == ns.CHAT_STATES:
            assert e.name == 'active', e.toXml()
            return True
        return False

    children = list(elem.elements())

    assert len(filter(is_body,   children)) == 1, elem.toXml()
    assert len(filter(is_active, children)) == 1, elem.toXml()

    # Close the channel without acking the received message. The peer should
    # get a <gone/> notification, and the channel should respawn.
    chan.Close()

    gone, _, _ = q.expect_many(
        EventPattern('stream-message'),
        EventPattern('dbus-signal', signal='Closed'),
        EventPattern('dbus-signal', signal='NewChannel'),
        )
    check_state_notification(gone.stanza, 'gone')

    # Reusing the proxy object because we happen to know it'll be at the same
    # path...

    # Destroy the channel. The peer shouldn't get a <gone/> notification, since
    # we already said we were gone and haven't sent them any messages to the
    # contrary.
    es = [EventPattern('stream-message')]
    q.forbid_events(es)

    chan.Destroyable.Destroy()
    sync_stream(q, stream)

    # Make the channel anew.
    path = conn.Requests.CreateChannel(
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
              cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
              cs.TARGET_HANDLE: foo_handle,
              })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['ChatState', 'Destroyable'])

    # Close it immediately; the peer should again not get a <gone/>
    # notification, since we haven't sent any notifications on that channel.
    chan.Close()
    sync_stream(q, stream)
Example #54
0
    def initiate(self):
        """Brind the call to INITIALISING state. This method will fill the
            channel, contents and streams members."""
        # Ensure a channel that doesn't exist yet.
        if self.incoming:
            if self.initial_audio and self.initial_video:
                self.jt2.incoming_call(audio='audio1', video='video1')
            elif self.initial_audio:
                self.jt2.incoming_call(audio='audio1', video=None)
            else:
                self.jt2.incoming_call(audio=None, video='video1')
        else:
            ret = self.conn.Requests.CreateChannel(
                { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL,
                  cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
                  cs.TARGET_HANDLE: self.peer_handle,
                  cs.CALL_INITIAL_AUDIO: self.initial_audio,
                  cs.CALL_INITIAL_VIDEO: self.initial_video,
                })

        signal = self.q.expect('dbus-signal', signal='NewChannels',
            predicate=lambda e:
                cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values())

        assertLength(1, signal.args)
        assertLength(1, signal.args[0])       # one channel
        assertLength(2, signal.args[0][0])    # two struct members
        emitted_props = signal.args[0][0][1]

        assertEquals(
            cs.CHANNEL_TYPE_CALL, emitted_props[cs.CHANNEL_TYPE])

        peer_bare_jid = self.PEER_JID.split('/')[0]
        assertEquals(self.peer_handle, emitted_props[cs.TARGET_HANDLE])
        assertEquals(cs.HT_CONTACT, emitted_props[cs.TARGET_HANDLE_TYPE])
        assertEquals(peer_bare_jid, emitted_props[cs.TARGET_ID])

        assertEquals(not self.incoming, emitted_props[cs.REQUESTED])
        if self.incoming:
            assertEquals(self.peer_handle, emitted_props[cs.INITIATOR_HANDLE])
            assertEquals(peer_bare_jid, emitted_props[cs.INITIATOR_ID])
        else:
            assertEquals(self.self_handle, emitted_props[cs.INITIATOR_HANDLE])
            assertEquals(self.SELF_JID, emitted_props[cs.INITIATOR_ID])

        assertEquals(self.initial_audio, emitted_props[cs.CALL_INITIAL_AUDIO])
        assertEquals(self.initial_video, emitted_props[cs.CALL_INITIAL_VIDEO])

        chan_path = signal.args[0][0][0]
        self.chan = wrap_channel(
                self.bus.get_object(self.conn.bus_name, chan_path), 'Call')

        properties = self.chan.GetAll(cs.CHANNEL_TYPE_CALL,
            dbus_interface=dbus.PROPERTIES_IFACE)

        # Check if all the properties are there
        assertEquals(sorted([ "Contents", "CallMembers",
            "CallState", "CallFlags", "CallStateReason", "CallStateDetails",
            "HardwareStreaming", "InitialAudio", "InitialAudioName",
            "InitialVideo", "InitialVideoName", "MutableContents",
            "InitialTransport", "MemberIdentifiers" ]),
            sorted(properties.keys()))

        # Remote member is the target
        assertEquals([self.peer_handle], list(properties["CallMembers"].keys()))
        assertEquals(0, properties["CallMembers"][self.peer_handle])

        # No Hardware Streaming for you
        assertEquals(False, properties["HardwareStreaming"])

        # Store content and stream
        nb_contents = self.initial_audio + self.initial_video
        assertLength(nb_contents, properties["Contents"])

        for content_path in  properties["Contents"]:
            self.store_content(content_path)

        if self.initial_audio:
            assert self.audio_content
        if self.initial_video:
            assert self.video_content
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

    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)

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

    address = t.create_server(q, address_type)

    def new_chan_predicate(e):
        types = []
        for _, props in e.args[0]:
            types.append(props[cs.CHANNEL_TYPE])

        return cs.CHANNEL_TYPE_STREAM_TUBE in types

    def find_stream_tube(channels):
        for path, props in channels:
            if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE:
                return path, props

        return None, None

    # offer a stream tube to another room (new API)
    address = t.create_server(q, address_type, block_reading=True)

    request = {
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE,
        cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
        cs.TARGET_ID: '*****@*****.**',
        cs.STREAM_TUBE_SERVICE: 'newecho',
    }
    _, new_tube_path, new_tube_props = \
        join_muc(q, bus, conn, stream, '*****@*****.**', request)

    e = q.expect('dbus-signal', signal='NewChannels',
                 predicate=new_chan_predicate)

    path, prop = find_stream_tube(e.args[0])
    assert prop[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_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.STREAM_TUBE_SERVICE] == 'newecho'

    # 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), 'StreamTube')
    tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE)

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

    # offer the tube
    call_async(q, tube_chan.StreamTube, 'Offer', address_type, address, access_control, {'foo': 'bar'})

    stream_event, _, status_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]))

    tube_self_handle = tube_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'SelfHandle')
    assert conn.inspect_contact_sync(tube_self_handle) == '[email protected]/test'

    presence = stream_event.stanza
    tubes_nodes = xpath.queryForNodes('/presence/tubes[@xmlns="%s"]'
        % ns.TUBES, presence)
    assert tubes_nodes is not None
    assert len(tubes_nodes) == 1

    stream_tube_id = 666

    tube_nodes = xpath.queryForNodes('/tubes/tube', tubes_nodes[0])
    assert tube_nodes is not None
    assert len(tube_nodes) == 1
    for tube in tube_nodes:
        assert tube['type'] == 'stream'
        assert not tube.hasAttribute('initiator')
        assert tube['service'] == 'newecho'
        assert not tube.hasAttribute('stream-id')
        assert not tube.hasAttribute('dbus-name')

        stream_tube_id = int(tube['id'])

    params = {}
    parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube)
    for node in parameter_nodes:
        assert node['name'] not in params
        params[node['name']] = (node['type'], str(node))
    assert params == {'foo': ('str', 'bar')}

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

    bytestream = connect_to_tube(stream, q, bytestream_cls, '*****@*****.**', stream_tube_id)

    iq_event, socket_event, conn_event = q.expect_many(
        EventPattern('stream-iq', iq_type='result'),
        EventPattern('socket-connected'),
        EventPattern('dbus-signal', signal='NewRemoteConnection',
            interface=cs.CHANNEL_TYPE_STREAM_TUBE))

    handle, access, conn_id = conn_event.args
    assert handle == bob_handle

    protocol = socket_event.protocol
    # start to read from the transport so we can read the control byte
    protocol.transport.startReading()
    t.check_new_connection_access(q, access_control, access, protocol)

    # handle iq_event
    bytestream.check_si_reply(iq_event.stanza)
    tube = xpath.queryForNodes('/iq//si/tube[@xmlns="%s"]' % ns.TUBES, iq_event.stanza)
    assert len(tube) == 1

    use_tube(q, bytestream, protocol, conn_id)

    tube_chan.Channel.Close()
    q.expect_many(
        EventPattern('dbus-signal', signal='Closed'),
        EventPattern('dbus-signal', signal='ChannelClosed'))

    t.cleanup()
Example #56
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 #57
0
def test(q, bus, conn):
    self_name = 'testsuite' + '@' + avahitest.get_host_name()

    conn.Connect()

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

    # FIXME: this is a hack to be sure to have all the contact list channels
    # announced so they won't interfere with the roomlist ones announces.
    wait_for_contact_list(q, conn)

    # check if we can request roomlist channels
    properties = conn.GetAll(tp_name_prefix + '.Connection.Interface.Requests',
                             dbus_interface='org.freedesktop.DBus.Properties')
    assert ({tp_name_prefix + '.Channel.ChannelType':
                cs.CHANNEL_TYPE_ROOM_LIST,
             tp_name_prefix + '.Channel.TargetHandleType': 0,
             },
             [],
             ) in properties.get('RequestableChannelClasses'),\
                     properties['RequestableChannelClasses']

    requestotron = dbus.Interface(
        conn, tp_name_prefix + '.Connection.Interface.Requests')

    # create roomlist channel using new API
    call_async(
        q, requestotron, 'CreateChannel', {
            tp_name_prefix + '.Channel.ChannelType': cs.CHANNEL_TYPE_ROOM_LIST,
            tp_name_prefix + '.Channel.TargetHandleType': 0,
        })

    ret, new_sig = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('dbus-signal', signal='NewChannels'),
    )
    path2 = ret.value[0]
    chan2 = wrap_channel(bus.get_object(conn.bus_name, path2), "RoomList")

    props = ret.value[1]
    assert props[tp_name_prefix + '.Channel.ChannelType'] ==\
            cs.CHANNEL_TYPE_ROOM_LIST
    assert props[tp_name_prefix + '.Channel.TargetHandleType'] == 0
    assert props[tp_name_prefix + '.Channel.TargetHandle'] == 0
    assert props[tp_name_prefix + '.Channel.TargetID'] == ''
    assert props[tp_name_prefix + '.Channel.Requested'] == True
    assert props[tp_name_prefix + '.Channel.InitiatorHandle'] \
            == conn.Properties.Get(cs.CONN, "SelfHandle")
    assert props[tp_name_prefix + '.Channel.InitiatorID'] \
            == self_name
    assert props[tp_name_prefix + '.Channel.Type.RoomList.Server'] == ''

    assert new_sig.args[0][0][0] == path2
    assert new_sig.args[0][0][1] == props

    assert chan2.Properties.Get(cs.CHANNEL_TYPE_ROOM_LIST, 'Server') == ''

    # ensure roomlist channel
    yours, ensured_path, ensured_props = requestotron.EnsureChannel({
        tp_name_prefix + '.Channel.ChannelType':
        cs.CHANNEL_TYPE_ROOM_LIST,
        tp_name_prefix + '.Channel.TargetHandleType':
        0,
    })

    assert not yours
    assert ensured_path == path2, (ensured_path, path2)

    # Closing roomlist channels crashed Salut for a while.
    chan2.Close()
    q.expect_many(
        EventPattern('dbus-signal', signal='Closed', path=path2),
        EventPattern('dbus-signal', signal='ChannelClosed', args=[path2]),
    )

    conn.Disconnect()

    q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged', args=[2, 1]), )