Beispiel #1
0
def test(q, bus, conn, stream):
    (muc_handle, chan, user, bob) = join_muc_and_check(q, bus, conn, stream,
        MUC)

    stream.send(
        elem('message', from_=BOB, to='test@localhost/Resource',
                        type='groupchat', jid='*****@*****.**')(
          elem(ns.CHAT_STATES, 'composing'),
          elem('google:nosave', 'x', value='disabled'),
          elem('http://jabber.org/protocol/archive', 'record', otr='false'),
        ))

    e = q.expect('dbus-signal', signal='ChatStateChanged')
    contact, state = e.args
    assertEquals(bob, contact)
    assertEquals(cs.CHAT_STATE_COMPOSING, state)

    stream.send(
        elem('message', from_=BOB, to='test@localhost/Resource',
                        type='groupchat', jid='*****@*****.**')(
          elem(ns.CHAT_STATES, 'paused'),
          elem('google:nosave', 'x', value='disabled'),
          elem('http://jabber.org/protocol/archive', 'record', otr='false'),
        ))

    e = q.expect('dbus-signal', signal='ChatStateChanged')
    contact, state = e.args
    assertEquals(bob, contact)
    assertEquals(cs.CHAT_STATE_PAUSED, state)
Beispiel #2
0
def test(q, bus, conn, stream):
    room = '*****@*****.**'
    our_jid = room + '/test'
    bob_jid = room + '/bob'
    marco_jid = room + '/marco'

    room_handle, chan, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, room)

    # Here are a few scrollback messages. One from us; one from bob; and one
    # from marco, who's no longer in the room.
    stream.send(
        elem('message', from_=our_jid, type='groupchat')(
          elem('body')(
            u'i really hate the muc xep'
          ),
          elem(ns.X_DELAY, 'x', from_=room, stamp='20090910T12:34:56')
        )
      )
    stream.send(
        elem('message', from_=bob_jid, type='groupchat')(
          elem('body')(
            u'yeah, it totally sucks'
          ),
          elem(ns.X_DELAY, 'x', from_=room, stamp='20090910T12:45:56')
        )
      )
    stream.send(
        elem('message', from_=marco_jid, type='groupchat')(
          elem('body')(
            u'we should start a riot'
          ),
          elem(ns.X_DELAY, 'x', from_=room, stamp='20090910T12:56:56')
        )
      )

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

    def badger(event):
        assertEquals(chan.object_path, event.path)

        message, = event.args
        header = message[0]

        assertContains('scrollback', header)
        assert header['scrollback']

        assertContains('message-sender', header)
        return header['message-sender']

    me = badger(m1)
    bob = badger(m2)
    marco = badger(m3)

    assertEquals([our_jid, bob_jid, marco_jid],
        conn.InspectHandles(cs.HT_CONTACT,
            [ me, bob, marco ]))
def test(q, bus, conn, stream):
    room = '*****@*****.**'
    our_jid = room + '/test'
    bob_jid = room + '/bob'
    marco_jid = room + '/marco'

    chan, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, room)

    # Here are a few scrollback messages. One from us; one from bob; and one
    # from marco, who's no longer in the room.
    stream.send(
        elem('message', from_=our_jid,
             type='groupchat')(elem('body')(u'i really hate the muc xep'),
                               elem(ns.X_DELAY,
                                    'x',
                                    from_=room,
                                    stamp='20090910T12:34:56')))
    stream.send(
        elem('message', from_=bob_jid,
             type='groupchat')(elem('body')(u'yeah, it totally sucks'),
                               elem(ns.X_DELAY,
                                    'x',
                                    from_=room,
                                    stamp='20090910T12:45:56')))
    stream.send(
        elem('message', from_=marco_jid,
             type='groupchat')(elem('body')(u'we should start a riot'),
                               elem(ns.X_DELAY,
                                    'x',
                                    from_=room,
                                    stamp='20090910T12:56:56')))

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

    def badger(event):
        assertEquals(chan.object_path, event.path)

        message, = event.args
        header = message[0]

        assertContains('scrollback', header)
        assert header['scrollback']

        assertContains('message-sender', header)
        return header['message-sender']

    me = badger(m1)
    bob = badger(m2)
    marco = badger(m3)

    assertEquals([our_jid, bob_jid, marco_jid],
                 conn.inspect_contacts_sync([me, bob, marco]))
def test(q, bus, conn, stream):
    muc = '*****@*****.**'
    text_chan, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, muc)

    # Suppose we don't have permission to speak in this MUC.  Send a message to
    # the channel, and have the MUC reject it as unauthorized.
    send_message_and_expect_error(q, stream,
        text_chan, test_handle, bob_handle,
        u"hi r ther ne warez n this chanel?",
        '401', 'auth', 'not-authorized',
        delivery_status=cs.DELIVERY_STATUS_PERMANENTLY_FAILED,
        send_error_value=cs.SendError.PERMISSION_DENIED)

    # This time, we get rate-limited.
    # <https://bugs.freedesktop.org/show_bug.cgi?id=43166>
    send_message_and_expect_error(q, stream,
        text_chan, test_handle, bob_handle,
        "faster faster",
        '500', 'wait', 'resource-constraint',
        delivery_status=cs.DELIVERY_STATUS_TEMPORARILY_FAILED,
        # Yuck this isn't a very good name is it?
        send_error_value=cs.SendError.TOO_LONG)

    # How about an error message in the reply? This is from Prosody. See
    # https://bugs.freedesktop.org/show_bug.cgi?id=43166#c9
    send_message_and_expect_error(q, stream,
        text_chan, test_handle, bob_handle,
        content=u"fair enough",
        code=None,
        type_='wait',
        element='policy-violation',
        error_message='The room is currently overactive, please try again later',
        delivery_status=cs.DELIVERY_STATUS_TEMPORARILY_FAILED,
        # Maybe we should expand the SendError codes some day, because this one
        # is l-a-m-e.
        send_error_value=cs.SendError.PERMISSION_DENIED)
Beispiel #5
0
def test(q, bus, conn, stream):
    room = '*****@*****.**'
    room_handle, chan, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, room)

    # Exercise basic Channel Properties from spec 0.17.7
    channel_props = chan.Properties.GetAll(cs.CHANNEL)
    assertEquals(room_handle, channel_props.get('TargetHandle'))
    assertEquals(cs.HT_ROOM, channel_props.get('TargetHandleType'))
    assertEquals(cs.CHANNEL_TYPE_TEXT, channel_props.get('ChannelType'))

    interfaces = channel_props.get('Interfaces')
    assertContains(cs.CHANNEL_IFACE_GROUP, interfaces)
    assertContains(cs.CHANNEL_IFACE_PASSWORD, interfaces)
    assertDoesNotContain(cs.TP_AWKWARD_PROPERTIES, interfaces)
    assertContains(cs.CHANNEL_IFACE_CHAT_STATE, interfaces)
    assertContains(cs.CHANNEL_IFACE_MESSAGES, interfaces)

    assert channel_props['TargetID'] == '*****@*****.**', channel_props
    assert channel_props['Requested'] == True
    assert channel_props['InitiatorID'] == 'test@localhost'
    assert channel_props['InitiatorHandle'] == conn.GetSelfHandle()

    # Exercise Group Properties from spec 0.17.6 (in a basic way)
    group_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP)
    assert 'HandleOwners' in group_props, group_props
    assert 'Members' in group_props, group_props
    assert 'LocalPendingMembers' in group_props, group_props
    assert 'RemotePendingMembers' in group_props, group_props
    assert 'GroupFlags' in group_props, group_props


    # Test receiving a message from Bob in the MUC
    message = domish.Element((None, 'message'))
    message['from'] = '[email protected]/bob'
    message['type'] = 'groupchat'
    body = message.addElement('body', content='hello')
    stream.send(message)

    received, message_received = q.expect_many(
        EventPattern('dbus-signal', signal='Received'),
        EventPattern('dbus-signal', signal='MessageReceived'),
        )

    # Check Channel.Type.Text.Received:
    # sender: bob
    assert received.args[2] == bob_handle
    # message type: normal
    assert received.args[3] == 0
    # flags: none
    assert received.args[4] == 0
    # body
    assert received.args[5] == 'hello'

    # Check Channel.Interface.Messages.MessageReceived:
    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'] == bob_handle, header
    # the spec says that message-type "SHOULD be omitted for normal chat
    # messages."
    assert 'message-type' not in header, header

    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']

    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 an action using the Messages API
    greeting = [
        dbus.Dictionary({ 'message-type': 1, # Action
                        }, signature='sv'),
        { 'content-type': 'text/plain',
          'content': u"peers through a gap in the curtains",
        }
    ]

    # We ask for delivery reports (which MUCs provide) and read reports (which
    # MUCs do not provide).
    sent_token = chan.Messages.SendMessage(greeting,
        cs.MSG_SENDING_FLAGS_REPORT_DELIVERY |
        cs.MSG_SENDING_FLAGS_REPORT_READ)

    assert sent_token

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

    sent_message, flags, token = message_sent.args
    assert len(sent_message) == 2, sent_message
    header = sent_message[0]
    assert header['message-type'] == 1, header # Action
    assertEquals(test_handle, header['message-sender'])
    assertEquals('[email protected]/test', header['message-sender-id'])
    body = sent_message[1]
    assert body['content-type'] == 'text/plain', body
    assert body['content'] == u'peers through a gap in the curtains', body

    # Of the flags passed to SendMessage, Gabble should only report the
    # DELIVERY flag, since the other is not supported.
    assertEquals(cs.MSG_SENDING_FLAGS_REPORT_DELIVERY, flags)
    assertEquals(sent_token, token)

    assert sent.args[1] == 1, sent.args # Action
    assert sent.args[2] == u'peers through a gap in the curtains', sent.args

    assert message_sent.args[2] == sent_token

    elem = stream_message.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'groupchat', repr(elem)
    assert elem['id'] == sent_token, repr(elem)
    assert elem['to'] == '*****@*****.**', repr(elem)
    for sub_elem in stream_message.stanza.elements():
        if sub_elem.name == 'body':
            found_body = True
            assert sub_elem.children[0] == u'/me peers through a gap in the curtains'
            break
    assert found_body


    # reflect the sent message back to the MUC
    elem['from'] = '[email protected]/test'
    stream.send(elem)

    # Check that we got the corresponding delivery report
    report, old_received = q.expect_many(
        EventPattern('dbus-signal', signal='MessageReceived'),
        EventPattern('dbus-signal', signal='Received'),
        )

    assert len(report.args) == 1, report.args
    parts = report.args[0]
    # The delivery report should just be a header, no body.
    assert len(parts) == 1, parts
    part = parts[0]
    # The intended recipient was the MUC, so there's no contact handle
    # suitable for being 'message-sender'.
    assert 'message-sender' not in part or part['message-sender'] == 0, part
    assert part['message-type'] == 4, part # Message_Type_Delivery_Report
    assert part['delivery-status'] == 1, part # Delivery_Status_Delivered
    assert part['delivery-token'] == sent_token, part
    assert 'delivery-error' not in part, part
    assert 'delivery-echo' in part, part

    # Check that the included echo is from us, and matches all the keys in the
    # message we sent.
    echo = part['delivery-echo']
    assert len(echo) == len(greeting), (echo, greeting)
    assert echo[0]['message-sender'] == test_handle, echo[0]
    assert echo[0]['message-token'] == sent_token, echo[0]
    for i in range(0, len(echo)):
        for key in greeting[i]:
            assert key in echo[i], (i, key, echo)
            assert echo[i][key] == greeting[i][key], (i, key, echo, greeting)

    # The Text.Received signal should be a "you're not tall enough" stub
    id, timestamp, sender, type, flags, text = old_received.args
    assert sender == 0, old_received.args
    assert type == 4, old_received.args # Message_Type_Delivery_Report
    assert flags == 2, old_received.args # Non_Text_Content
    assert text == '', old_received.args


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

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

    sent_message, flags, _ = message_sent.args
    assert len(sent_message) == 2, sent_message
    header = sent_message[0]
    assert 'message-type' not in header, header # Normal
    body = sent_message[1]
    assert body['content-type'] == 'text/plain', body
    assert body['content'] == u'goodbye', body

    # The caller didn't ask for delivery reports (how could they? they're using
    # the old API), but the server's going to send us an echo anyway, so
    # Gabble's within its rights to pretend that the caller asked.
    assert flags in [0, cs.MSG_SENDING_FLAGS_REPORT_DELIVERY], flags

    assert sent.args[1] == 0, sent.args # Normal
    assert sent.args[2] == u'goodbye', sent.args

    sent_token = message_sent.args[2]

    elem = event.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'groupchat'
    assert elem['id'] == message_sent.args[2]
    body = list(event.stanza.elements())[0]
    assert body.name == 'body'
    assert body.children[0] == u'goodbye'

    # reflect the sent message back to the MUC
    elem['from'] = '[email protected]/test'
    stream.send(elem)

    # TODO: check for a delivery report.


    # test that presence changes are sent via the MUC
    conn.SimplePresence.SetPresence('away', 'hurrah')

    event = q.expect('stream-presence', to='[email protected]/test')
    elem = event.stanza
    show = [e for e in elem.elements() if e.name == 'show'][0]
    assert show
    assert show.children[0] == u'away'
    status = [e for e in elem.elements() if e.name == 'status'][0]
    assert status
    assert status.children[0] == u'hurrah'

    # Check that there's no <x xmlns='.../muc'/> element in the <presence>
    # stanza when we're just updating our presence, as opposed to joining the
    # MUC in the first place. This is a regression test for
    # <https://bugs.freedesktop.org/show_bug.cgi?id=29147>. XEP-0045 §7.4 shows
    # that you do not need to include this element in presence updates; if we
    # erroneously include it, some implementations take this to mean that we're
    # trying to join the MUC again and helpfully send us all the scrollback
    # again.
    x_muc_nodes = xpath.queryForNodes('/presence/x[@xmlns="%s"]' % ns.MUC, elem)
    assert x_muc_nodes is None, elem.toXml()

    # test that leaving the channel results in an unavailable message
    chan.Group.RemoveMembers([chan.Group.GetSelfHandle()], 'booo')

    event = q.expect('stream-presence', to='[email protected]/test')
    elem = event.stanza
    assert elem['type'] == 'unavailable'
    status = [e for e in elem.elements() if e.name == 'status']
    assertLength(1, status)
    assertEquals(status[0].children[0], u'booo')
def test(q, bus, conn, stream, access_control):
    conn.Connect()

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

    acknowledge_iq(stream, iq_event.stanza)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    tube_chan_iface.Close()
    q.expect_many(
        EventPattern('dbus-signal', signal='Closed'),
        EventPattern('dbus-signal', signal='ChannelClosed'))
def test(q, bus, conn, stream):
    (muc_handle, chan, user, bob) = join_muc_and_check(q, bus, conn, stream,
        MUC)

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

    stream.send(
        elem('message', from_=BOB, to='test@localhost/Resource',
                        type='groupchat', jid='*****@*****.**')(
          elem(ns.CHAT_STATES, 'composing'),
          elem('google:nosave', 'x', value='disabled'),
          elem('http://jabber.org/protocol/archive', 'record', otr='false'),
        ))

    e = q.expect('dbus-signal', signal='ChatStateChanged')
    contact, state = e.args
    assertEquals(bob, contact)
    assertEquals(cs.CHAT_STATE_COMPOSING, state)

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

    stream.send(
        elem('message', from_=BOB, to='test@localhost/Resource',
                        type='groupchat', jid='*****@*****.**')(
          elem(ns.CHAT_STATES, 'paused'),
          elem('google:nosave', 'x', value='disabled'),
          elem('http://jabber.org/protocol/archive', 'record', otr='false'),
        ))

    e = q.expect('dbus-signal', signal='ChatStateChanged')
    contact, state = e.args
    assertEquals(bob, contact)
    assertEquals(cs.CHAT_STATE_PAUSED, state)

    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
    assertEquals(cs.CHAT_STATE_INACTIVE,
            states.get(user, cs.CHAT_STATE_INACTIVE))
    assertEquals(cs.CHAT_STATE_PAUSED,
            states.get(bob, cs.CHAT_STATE_INACTIVE))

#    # Bob leaves
#    stream.send(
#        elem('presence', from_=BOB, to='test@localhost/Resource',
#                        type='unavailable'))

#    e = q.expect('dbus-signal', signal='ChatStateChanged')
#    contact, state = e.args
#    assertEquals(bob, contact)
#    assertEquals(cs.CHAT_STATE_GONE, state)

#    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
#    assertEquals(cs.CHAT_STATE_INACTIVE,
#            states.get(user, cs.CHAT_STATE_INACTIVE))
#    # Bob no longer has any chat state at all
#    assertEquals(None, states.get(bob, None))

    # 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(user, cs.CHAT_STATE_INACTIVE))

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

    stream_message = q.expect('stream-message')
    stanza = stream_message.stanza
    check_state_notification(stanza, 'active', allow_body=True)

    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
    assertEquals(cs.CHAT_STATE_ACTIVE,
            states.get(user, 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 stanza.elements() if is_body(x)]) == 1, stanza.toXml()
def test(q, bus, conn, stream):
    conn.Connect()
    q.expect('dbus-signal', signal='StatusChanged',
            args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])

    room = '*****@*****.**'
    room_handle, chan, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, room)

    # Exercise basic Channel Properties from spec 0.17.7
    channel_props = chan.Properties.GetAll(cs.CHANNEL)
    assert channel_props.get('TargetHandle') == room_handle,\
            (channel_props.get('TargetHandle'), room_handle)
    assert channel_props.get('TargetHandleType') == cs.HT_ROOM,\
            channel_props.get('TargetHandleType')
    assert channel_props.get('ChannelType') == \
            cs.CHANNEL_TYPE_TEXT,\
            channel_props.get('ChannelType')
    assert cs.CHANNEL_IFACE_GROUP in \
            channel_props.get('Interfaces', ()), \
            channel_props.get('Interfaces')
    assert cs.CHANNEL_IFACE_PASSWORD in \
            channel_props.get('Interfaces', ()), \
            channel_props.get('Interfaces')
    assert cs.TP_AWKWARD_PROPERTIES in \
            channel_props.get('Interfaces', ()), \
            channel_props.get('Interfaces')
    assert cs.CHANNEL_IFACE_CHAT_STATE in \
            channel_props.get('Interfaces', ()), \
            channel_props.get('Interfaces')
    assert cs.CHANNEL_IFACE_MESSAGES in \
            channel_props.get('Interfaces', ()), \
            channel_props.get('Interfaces')
    assert channel_props['TargetID'] == '*****@*****.**', channel_props
    assert channel_props['Requested'] == True
    assert channel_props['InitiatorID'] == 'test@localhost'
    assert channel_props['InitiatorHandle'] == conn.GetSelfHandle()

    # Exercise Group Properties from spec 0.17.6 (in a basic way)
    group_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP)
    assert 'HandleOwners' in group_props, group_props
    assert 'Members' in group_props, group_props
    assert 'LocalPendingMembers' in group_props, group_props
    assert 'RemotePendingMembers' in group_props, group_props
    assert 'GroupFlags' in group_props, group_props


    # Test receiving a message from Bob in the MUC
    message = domish.Element((None, 'message'))
    message['from'] = '[email protected]/bob'
    message['type'] = 'groupchat'
    body = message.addElement('body', content='hello')
    stream.send(message)

    received, message_received = q.expect_many(
        EventPattern('dbus-signal', signal='Received'),
        EventPattern('dbus-signal', signal='MessageReceived'),
        )

    # Check Channel.Type.Text.Received:
    # sender: bob
    assert received.args[2] == bob_handle
    # message type: normal
    assert received.args[3] == 0
    # flags: none
    assert received.args[4] == 0
    # body
    assert received.args[5] == 'hello'

    # Check Channel.Interface.Messages.MessageReceived:
    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'] == bob_handle, header
    # the spec says that message-type "SHOULD be omitted for normal chat
    # messages."
    assert 'message-type' not in header, header

    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']

    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 an action using the Messages API
    greeting = [
        dbus.Dictionary({ 'message-type': 1, # Action
                        }, signature='sv'),
        { 'content-type': 'text/plain',
          'content': u"peers through a gap in the curtains",
        }
    ]

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

    assert sent_token

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

    sent_message = message_sent.args[0]
    assert len(sent_message) == 2, sent_message
    header = sent_message[0]
    assert header['message-type'] == 1, header # Action
    body = sent_message[1]
    assert body['content-type'] == 'text/plain', body
    assert body['content'] == u'peers through a gap in the curtains', body

    assert sent.args[1] == 1, sent.args # Action
    assert sent.args[2] == u'peers through a gap in the curtains', sent.args

    assert message_sent.args[2] == sent_token

    elem = stream_message.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'groupchat', repr(elem)
    assert elem['id'] == sent_token, repr(elem)
    assert elem['to'] == '*****@*****.**', repr(elem)
    for sub_elem in stream_message.stanza.elements():
        if sub_elem.name == 'body':
            found_body = True
            assert sub_elem.children[0] == u'/me peers through a gap in the curtains'
            break
    assert found_body


    # reflect the sent message back to the MUC
    elem['from'] = '[email protected]/test'
    stream.send(elem)

    # Check that we got the corresponding delivery report
    report, old_received = q.expect_many(
        EventPattern('dbus-signal', signal='MessageReceived'),
        EventPattern('dbus-signal', signal='Received'),
        )

    assert len(report.args) == 1, report.args
    parts = report.args[0]
    # The delivery report should just be a header, no body.
    assert len(parts) == 1, parts
    part = parts[0]
    # The intended recipient was the MUC, so there's no contact handle
    # suitable for being 'message-sender'.
    assert 'message-sender' not in part or part['message-sender'] == 0, part
    assert part['message-type'] == 4, part # Message_Type_Delivery_Report
    assert part['delivery-status'] == 1, part # Delivery_Status_Delivered
    assert part['delivery-token'] == sent_token, part
    assert 'delivery-error' not in part, part
    assert 'delivery-echo' in part, part

    # Check that the included echo is from us, and matches all the keys in the
    # message we sent.
    echo = part['delivery-echo']
    assert len(echo) == len(greeting), (echo, greeting)
    assert echo[0]['message-sender'] == test_handle, echo[0]
    assert echo[0]['message-token'] == sent_token, echo[0]
    for i in range(0, len(echo)):
        for key in greeting[i]:
            assert key in echo[i], (i, key, echo)
            assert echo[i][key] == greeting[i][key], (i, key, echo, greeting)

    # The Text.Received signal should be a "you're not tall enough" stub
    id, timestamp, sender, type, flags, text = old_received.args
    assert sender == 0, old_received.args
    assert type == 4, old_received.args # Message_Type_Delivery_Report
    assert flags == 2, old_received.args # Non_Text_Content
    assert text == '', old_received.args


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

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

    sent_message = message_sent.args[0]
    assert len(sent_message) == 2, sent_message
    header = sent_message[0]
    assert 'message-type' not in header, header # Normal
    body = sent_message[1]
    assert body['content-type'] == 'text/plain', body
    assert body['content'] == u'goodbye', body

    assert sent.args[1] == 0, sent.args # Normal
    assert sent.args[2] == u'goodbye', sent.args

    sent_token = message_sent.args[2]

    elem = event.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'groupchat'
    assert elem['id'] == message_sent.args[2]
    body = list(event.stanza.elements())[0]
    assert body.name == 'body'
    assert body.children[0] == u'goodbye'

    # reflect the sent message back to the MUC
    elem['from'] = '[email protected]/test'
    stream.send(elem)

    # TODO: check for a delivery report.


    # test that presence changes are sent via the MUC
    conn.Presence.SetStatus({'away':{'message':'hurrah'}})

    event = q.expect('stream-presence', to='[email protected]/test')
    elem = event.stanza
    show = [e for e in elem.elements() if e.name == 'show'][0]
    assert show
    assert show.children[0] == u'away'
    status = [e for e in elem.elements() if e.name == 'status'][0]
    assert status
    assert status.children[0] == u'hurrah'

    # test that leaving the channel results in an unavailable message
    chan.Group.RemoveMembers([chan.Group.GetSelfHandle()], 'booo')

    event = q.expect('stream-presence', to='[email protected]/test')
    elem = event.stanza
    assert elem['type'] == 'unavailable'
    status = [e for e in elem.elements() if e.name == 'status']
    assertLength(1, status)
    assertEquals(status[0].children[0], u'booo')
def test(q, bus, conn, stream):
    conn.Connect()
    q.expect('dbus-signal', signal='StatusChanged',
            args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])

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

    # Suppose we don't have permission to speak in this MUC.  Send a message to
    # the channel, and have the MUC reject it as unauthorized.
    content = u"hi r ther ne warez n this chanel?"
    greeting = [
        dbus.Dictionary({ }, signature='sv'),
        { 'content-type': 'text/plain',
          'content': content,
        }
    ]

    sent_token = dbus.Interface(text_chan, cs.CHANNEL_IFACE_MESSAGES) \
        .SendMessage(greeting, dbus.UInt32(0))

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

    # computer says no
    elem = stream_message.stanza
    elem['from'] = '*****@*****.**'
    elem['to'] = '[email protected]/test'
    elem['type'] = 'error'
    error = elem.addElement('error')
    error['code'] = '401'
    error['type'] = 'auth'
    error.addElement((ns.STANZA, 'not-authorized'))

    stream.send(elem)

    # check that we got a failed delivery report and a SendError
    send_error, received, message_received = q.expect_many(
        EventPattern('dbus-signal', signal='SendError'),
        EventPattern('dbus-signal', signal='Received'),
        EventPattern('dbus-signal', signal='MessageReceived'),
        )

    PERMISSION_DENIED = 3

    err, timestamp, type, text = send_error.args
    assert err == PERMISSION_DENIED, send_error.args
    # there's no way to tell when the original message was sent from the error stanza
    assert timestamp == 0, send_error.args
    # Gabble can't determine the type of the original message; see muc/test-muc.py
    # assert type == 0, send_error.args
    assert text == content, send_error.args

    # The Text.Received signal should be a "you're not tall enough" stub
    id, timestamp, sender, type, flags, text = received.args
    assert sender == 0, received.args
    assert type == 4, received.args # Message_Type_Delivery_Report
    assert flags == 2, received.args # Non_Text_Content
    assert text == '', received.args

    # Check that the Messages.MessageReceived signal was a failed delivery report
    assert len(message_received.args) == 1, message_received.args
    parts = message_received.args[0]
    # The delivery report should just be a header, no body.
    assert len(parts) == 1, parts
    part = parts[0]
    # The intended recipient was the MUC, so there's no contact handle
    # suitable for being 'message-sender'.
    assert 'message-sender' not in part or part['message-sender'] == 0, part
    assert part['message-type'] == 4, part # Message_Type_Delivery_Report
    assert part['delivery-status'] == 3, part # Delivery_Status_Permanently_Failed
    assert part['delivery-error'] == PERMISSION_DENIED, part
    assert part['delivery-token'] == sent_token, part

    # Check that the included echo is from us, and matches all the keys in the
    # message we sent.
    assert 'delivery-echo' in part, part
    echo = part['delivery-echo']
    assert len(echo) == len(greeting), (echo, greeting)
    assert echo[0]['message-sender'] == test_handle, echo[0]
    assert echo[0]['message-token'] == sent_token, echo[0]
    for i in range(0, len(echo)):
        for key in greeting[i]:
            assert key in echo[i], (i, key, echo)
            assert echo[i][key] == greeting[i][key], (i, key, echo, greeting)
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'))
Beispiel #11
0
def test(q, bus, conn, stream):
    muc = "*****@*****.**"
    _, text_chan, test_handle, bob_handle = join_muc_and_check(q, bus, conn, stream, muc)

    # Suppose we don't have permission to speak in this MUC.  Send a message to
    # the channel, and have the MUC reject it as unauthorized.
    content = u"hi r ther ne warez n this chanel?"
    greeting = [dbus.Dictionary({}, signature="sv"), {"content-type": "text/plain", "content": content}]

    sent_token = dbus.Interface(text_chan, cs.CHANNEL_IFACE_MESSAGES).SendMessage(greeting, dbus.UInt32(0))

    stream_message, _, _ = q.expect_many(
        EventPattern("stream-message"),
        EventPattern("dbus-signal", signal="Sent"),
        EventPattern("dbus-signal", signal="MessageSent"),
    )

    # computer says no
    elem = stream_message.stanza
    elem["from"] = "*****@*****.**"
    elem["to"] = "[email protected]/test"
    elem["type"] = "error"
    error = elem.addElement("error")
    error["code"] = "401"
    error["type"] = "auth"
    error.addElement((ns.STANZA, "not-authorized"))

    stream.send(elem)

    # check that we got a failed delivery report and a SendError
    send_error, received, message_received = q.expect_many(
        EventPattern("dbus-signal", signal="SendError"),
        EventPattern("dbus-signal", signal="Received"),
        EventPattern("dbus-signal", signal="MessageReceived"),
    )

    PERMISSION_DENIED = 3

    err, timestamp, type, text = send_error.args
    assert err == PERMISSION_DENIED, send_error.args
    # there's no way to tell when the original message was sent from the error stanza
    assert timestamp == 0, send_error.args
    # Gabble can't determine the type of the original message; see muc/test-muc.py
    # assert type == 0, send_error.args
    assert text == content, send_error.args

    # The Text.Received signal should be a "you're not tall enough" stub
    id, timestamp, sender, type, flags, text = received.args
    assert sender == 0, received.args
    assert type == 4, received.args  # Message_Type_Delivery_Report
    assert flags == 2, received.args  # Non_Text_Content
    assert text == "", received.args

    # Check that the Messages.MessageReceived signal was a failed delivery report
    assert len(message_received.args) == 1, message_received.args
    parts = message_received.args[0]
    # The delivery report should just be a header, no body.
    assert len(parts) == 1, parts
    part = parts[0]
    # The intended recipient was the MUC, so there's no contact handle
    # suitable for being 'message-sender'.
    assert "message-sender" not in part or part["message-sender"] == 0, part
    assert part["message-type"] == 4, part  # Message_Type_Delivery_Report
    assert part["delivery-status"] == 3, part  # Delivery_Status_Permanently_Failed
    assert part["delivery-error"] == PERMISSION_DENIED, part
    assert part["delivery-token"] == sent_token, part

    # Check that the included echo is from us, and matches all the keys in the
    # message we sent.
    assert "delivery-echo" in part, part
    echo = part["delivery-echo"]
    assert len(echo) == len(greeting), (echo, greeting)
    assert echo[0]["message-sender"] == test_handle, echo[0]
    assert echo[0]["message-token"] == sent_token, echo[0]
    for i in range(0, len(echo)):
        for key in greeting[i]:
            assert key in echo[i], (i, key, echo)
            assert echo[i][key] == greeting[i][key], (i, key, echo, greeting)
def test(q, bus, conn, stream):
    room = '*****@*****.**'
    chan, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, room)

    # Exercise basic Channel Properties from spec 0.17.7
    channel_props = chan.Properties.GetAll(cs.CHANNEL)
    assertEquals(cs.HT_ROOM, channel_props.get('TargetHandleType'))
    assertEquals(cs.CHANNEL_TYPE_TEXT, channel_props.get('ChannelType'))

    interfaces = channel_props.get('Interfaces')
    assertContains(cs.CHANNEL_IFACE_GROUP, interfaces)
    assertContains(cs.CHANNEL_IFACE_PASSWORD, interfaces)
    assertContains(cs.CHANNEL_IFACE_CHAT_STATE, interfaces)
    assertContains(cs.CHANNEL_IFACE_MESSAGES, interfaces)

    assert channel_props['TargetID'] == '*****@*****.**', channel_props
    assert channel_props['Requested'] == True
    assert channel_props['InitiatorID'] == 'test@localhost'
    assert channel_props['InitiatorHandle'] == conn.Properties.Get(
        cs.CONN, "SelfHandle")

    # Exercise Group Properties from spec 0.17.6 (in a basic way)
    group_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP)
    assert 'HandleOwners' in group_props, group_props
    assert 'Members' in group_props, group_props
    assert 'LocalPendingMembers' in group_props, group_props
    assert 'RemotePendingMembers' in group_props, group_props
    assert 'GroupFlags' in group_props, group_props

    # Test receiving a message from Bob in the MUC
    message = domish.Element((None, 'message'))
    message['from'] = '[email protected]/bob'
    message['type'] = 'groupchat'
    body = message.addElement('body', content='hello')
    stream.send(message)

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

    # Check Channel.Interface.Messages.MessageReceived:
    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'] == bob_handle, header
    # the spec says that message-type "SHOULD be omitted for normal chat
    # messages."
    assert 'message-type' not in header, header

    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']

    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 an action using the Messages API
    greeting = [
        dbus.Dictionary(
            {
                'message-type': 1,  # Action
            },
            signature='sv'),
        {
            'content-type': 'text/plain',
            'content': u"peers through a gap in the curtains",
        }
    ]

    # We ask for delivery reports (which MUCs provide) and read reports (which
    # MUCs do not provide).
    sent_token = chan.Messages.SendMessage(
        greeting, cs.MSG_SENDING_FLAGS_REPORT_DELIVERY
        | cs.MSG_SENDING_FLAGS_REPORT_READ)

    assert sent_token

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

    sent_message, flags, token = message_sent.args
    assert len(sent_message) == 2, sent_message
    header = sent_message[0]
    assert header['message-type'] == 1, header  # Action
    assertEquals(test_handle, header['message-sender'])
    assertEquals('[email protected]/test', header['message-sender-id'])
    body = sent_message[1]
    assert body['content-type'] == 'text/plain', body
    assert body['content'] == u'peers through a gap in the curtains', body

    # Of the flags passed to SendMessage, Gabble should only report the
    # DELIVERY flag, since the other is not supported.
    assertEquals(cs.MSG_SENDING_FLAGS_REPORT_DELIVERY, flags)
    assertEquals(sent_token, token)

    assert message_sent.args[2] == sent_token

    elem = stream_message.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'groupchat', repr(elem)
    assert elem['id'] == sent_token, repr(elem)
    assert elem['to'] == '*****@*****.**', repr(elem)
    for sub_elem in stream_message.stanza.elements():
        if sub_elem.name == 'body':
            found_body = True
            assert sub_elem.children[
                0] == u'/me peers through a gap in the curtains'
            break
    assert found_body

    # reflect the sent message back to the MUC
    elem['from'] = '[email protected]/test'
    stream.send(elem)

    # Check that we got the corresponding delivery report
    report = q.expect('dbus-signal', signal='MessageReceived')

    assert len(report.args) == 1, report.args
    parts = report.args[0]
    # The delivery report should just be a header, no body.
    assert len(parts) == 1, parts
    part = parts[0]
    # The intended recipient was the MUC, so there's no contact handle
    # suitable for being 'message-sender'.
    assert 'message-sender' not in part or part['message-sender'] == 0, part
    assert part['message-type'] == 4, part  # Message_Type_Delivery_Report
    assert part['delivery-status'] == 1, part  # Delivery_Status_Delivered
    assert part['delivery-token'] == sent_token, part
    assert 'delivery-error' not in part, part
    assert 'delivery-echo' in part, part

    # Check that the included echo is from us, and matches all the keys in the
    # message we sent.
    echo = part['delivery-echo']
    assert len(echo) == len(greeting), (echo, greeting)
    assert echo[0]['message-sender'] == test_handle, echo[0]
    assert echo[0]['message-token'] == sent_token, echo[0]
    for i in range(0, len(echo)):
        for key in greeting[i]:
            assert key in echo[i], (i, key, echo)
            assert echo[i][key] == greeting[i][key], (i, key, echo, greeting)

    # Send a normal message using the Channel.Type.Text API
    chan.send_msg_sync('goodbye')

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

    sent_message, flags, _ = message_sent.args
    assert len(sent_message) == 2, sent_message
    header = sent_message[0]
    body = sent_message[1]
    assert body['content-type'] == 'text/plain', body
    assert body['content'] == u'goodbye', body

    # The caller didn't ask for delivery reports (how could they? they're using
    # the old API), but the server's going to send us an echo anyway, so
    # Gabble's within its rights to pretend that the caller asked.
    assert flags in [0, cs.MSG_SENDING_FLAGS_REPORT_DELIVERY], flags

    sent_token = message_sent.args[2]

    elem = event.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'groupchat'
    assert elem['id'] == message_sent.args[2]
    body = list(event.stanza.elements())[0]
    assert body.name == 'body'
    assert body.children[0] == u'goodbye'

    # reflect the sent message back to the MUC
    elem['from'] = '[email protected]/test'
    stream.send(elem)

    # TODO: check for a delivery report.

    # test that presence changes are sent via the MUC
    conn.SimplePresence.SetPresence('away', 'hurrah')

    event = q.expect('stream-presence', to='[email protected]/test')
    elem = event.stanza
    show = [e for e in elem.elements() if e.name == 'show'][0]
    assert show
    assert show.children[0] == u'away'
    status = [e for e in elem.elements() if e.name == 'status'][0]
    assert status
    assert status.children[0] == u'hurrah'

    # Check that there's no <x xmlns='.../muc'/> element in the <presence>
    # stanza when we're just updating our presence, as opposed to joining the
    # MUC in the first place. This is a regression test for
    # <https://bugs.freedesktop.org/show_bug.cgi?id=29147>. XEP-0045 §7.4 shows
    # that you do not need to include this element in presence updates; if we
    # erroneously include it, some implementations take this to mean that we're
    # trying to join the MUC again and helpfully send us all the scrollback
    # again.
    x_muc_nodes = xpath.queryForNodes('/presence/x[@xmlns="%s"]' % ns.MUC,
                                      elem)
    assert x_muc_nodes is None, elem.toXml()

    # test that leaving the channel results in an unavailable message
    chan.Group.RemoveMembers(
        [chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, "SelfHandle")], 'booo')

    event = q.expect('stream-presence', to='[email protected]/test')
    elem = event.stanza
    assert elem['type'] == 'unavailable'
    status = [e for e in elem.elements() if e.name == 'status']
    assertLength(1, status)
    assertEquals(status[0].children[0], u'booo')
Beispiel #13
0
def test(q, bus, conn, stream):
    (chan, user, bob) = join_muc_and_check(q, bus, conn, stream,
        MUC)

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

    stream.send(
        elem('message', from_=BOB, to='test@localhost/Resource',
                        type='groupchat', jid='*****@*****.**')(
          elem(ns.CHAT_STATES, 'composing'),
          elem('google:nosave', 'x', value='disabled'),
          elem('http://jabber.org/protocol/archive', 'record', otr='false'),
        ))

    e = q.expect('dbus-signal', signal='ChatStateChanged')
    contact, state = e.args
    assertEquals(bob, contact)
    assertEquals(cs.CHAT_STATE_COMPOSING, state)

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

    stream.send(
        elem('message', from_=BOB, to='test@localhost/Resource',
                        type='groupchat', jid='*****@*****.**')(
          elem(ns.CHAT_STATES, 'paused'),
          elem('google:nosave', 'x', value='disabled'),
          elem('http://jabber.org/protocol/archive', 'record', otr='false'),
        ))

    e = q.expect('dbus-signal', signal='ChatStateChanged')
    contact, state = e.args
    assertEquals(bob, contact)
    assertEquals(cs.CHAT_STATE_PAUSED, state)

    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
    assertEquals(cs.CHAT_STATE_INACTIVE,
            states.get(user, cs.CHAT_STATE_INACTIVE))
    assertEquals(cs.CHAT_STATE_PAUSED,
            states.get(bob, cs.CHAT_STATE_INACTIVE))

    # Bob leaves
    presence = make_muc_presence('owner', 'none', MUC, 'bob')
    presence['type'] = 'unavailable'
    stream.send(presence)

    e = q.expect('dbus-signal', signal='ChatStateChanged')
    contact, state = e.args
    assertEquals(bob, contact)
    assertEquals(cs.CHAT_STATE_GONE, state)

    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
    assertEquals(cs.CHAT_STATE_INACTIVE,
            states.get(user, cs.CHAT_STATE_INACTIVE))
    # Bob no longer has any chat state at all
    assertEquals(None, states.get(bob, None))

    # 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(user, 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')
    stanza = stream_message.stanza
    check_state_notification(stanza, 'active', allow_body=True)

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

    bodies = list(stanza.elements(uri=ns.CLIENT, name='body'))
    assertLength(1, bodies)
    assertEquals(u'hi.', bodies[0].children[0])

    # If we get an error with type='wait', stop sending chat states.
    stanza['type'] = 'error'
    stanza['from'] = MUC
    stanza['to'] = 'test@localhost/Resource'

    error = stanza.addElement('error')
    error['type'] = 'wait'
    error.addElement((ns.STANZA, 'resource-constraint'))
    stream.send(stanza)

    q.expect('dbus-signal', signal='MessageReceived',
        predicate=lambda e: e.args[0][0]['message-type'] == cs.MT_DELIVERY_REPORT)

    q.forbid_events([
        EventPattern('stream-message', to=MUC,
            predicate=lambda e: get_state_notification(e.stanza) is not None)
        ])

    # User starts typing again but nothing should be seen or heard on the stream.
    chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING)
    sync_stream(q, stream)