def test(q, bus, conn, stream): iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, iq_event.stanza) t.check_conn_properties(q, conn) # Create new style tube channel and make sure that is indeed # returned. muc = '*****@*****.**' call_async( q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_DBUS_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: muc, cs.DBUS_TUBE_SERVICE_NAME: 'com.example.LolDongs' }) q.expect('stream-presence', to='%s/test' % muc) stream.send(make_muc_presence('owner', 'moderator', muc, 'bob')) stream.send(make_muc_presence('none', 'participant', muc, 'test')) ret, _ = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) _, props = ret.value assertEquals(props[cs.CHANNEL_TYPE], cs.CHANNEL_TYPE_DBUS_TUBE) assertEquals(props[cs.TARGET_HANDLE_TYPE], cs.HT_ROOM) assertEquals(props[cs.TARGET_ID], muc) # Now try joining the text muc before asking for the tube channel. muc = '*****@*****.**' join_muc(q, bus, conn, stream, muc) call_async( q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_DBUS_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: muc, cs.DBUS_TUBE_SERVICE_NAME: 'com.example.LolDongs' }) ret, _ = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) _, props = ret.value assertEquals(props[cs.CHANNEL_TYPE], cs.CHANNEL_TYPE_DBUS_TUBE) assertEquals(props[cs.TARGET_HANDLE_TYPE], cs.HT_ROOM) assertEquals(props[cs.TARGET_ID], muc)
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): room = '*****@*****.**' chan, path, props, disco = join_muc(q, bus, conn, stream, room, also_capture=[ EventPattern( 'stream-iq', iq_type='get', query_name='query', query_ns=ns.DISCO_INFO, to=room) ]) sync_dbus(bus, q, conn) # we call Close... call_async(q, chan, 'Close') q.expect('dbus-return', method='Close') # ...so gabble announces our unavailable presence to the MUC. event = q.expect('stream-presence', to=room + '/test') elem = event.stanza assertEquals('unavailable', elem['type']) # while we wait for the conference server to echo our unavailable # presence, we try and create the same channel again... call_async( q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: room }) # ...which should fail because the channel hasn't closed yet. q.expect('dbus-error', method='CreateChannel', name=cs.NOT_AVAILABLE) # the conference server finally gets around to echoing our # unavailable presence... echo_muc_presence(q, stream, elem, 'none', 'participant') # ...and only now is the channel closed. q.expect_many(EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed')) # now that the channel has finally closed, let's try and request # it again which should succeed! chan, _, _ = join_muc(q, bus, conn, stream, room) # let's clear up though. chan.Close() event = q.expect('stream-presence', to=room + '/test') echo_muc_presence(q, stream, event.stanza, 'none', 'participant') q.expect_many(EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed'))
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): room = '*****@*****.**' chan, path, props, disco = join_muc(q, bus, conn, stream, room, also_capture=[EventPattern('stream-iq', iq_type='get', query_name='query', query_ns=ns.DISCO_INFO, to=room)]) sync_dbus(bus, q, conn) # we call Close... call_async(q, chan, 'Close') q.expect('dbus-return', method='Close') # ...so gabble announces our unavailable presence to the MUC. event = q.expect('stream-presence', to=room + '/test') elem = event.stanza assertEquals('unavailable', elem['type']) # while we wait for the conference server to echo our unavailable # presence, we try and create the same channel again... call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: room }) # ...which should fail because the channel hasn't closed yet. q.expect('dbus-error', method='CreateChannel', name=cs.NOT_AVAILABLE) # the conference server finally gets around to echoing our # unavailable presence... echo_muc_presence(q, stream, elem, 'none', 'participant') # ...and only now is the channel closed. q.expect_many(EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed')) # now that the channel has finally closed, let's try and request # it again which should succeed! chan, _, _ = join_muc(q, bus, conn, stream, room) # let's clear up though. chan.Close() event = q.expect('stream-presence', to=room + '/test') echo_muc_presence(q, stream, event.stanza, 'none', 'participant') q.expect_many(EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed'))
def test(q, bus, conn, stream): # The user happily joins a MUC chan, _, _ = join_muc(q, bus, conn, stream, MUC) muc_self_handle = chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, "SelfHandle") muc_self_jid = conn.inspect_contact_sync(muc_self_handle) # But then Bob kicks us. bob_jid = '%s/bob' % MUC bob_handle = conn.get_contact_handle_sync(bob_jid) stream.send( elem('presence', from_=muc_self_jid, type='unavailable')( elem(ns.MUC_USER, 'x')( elem('item', affiliation='none', role='none')( elem('actor', jid=bob_jid), elem('reason')( u'bye' ) ), elem('status', code='307'), ) )) mcd_event = q.expect('dbus-signal', signal='MembersChangedDetailed') added, removed, local_pending, remote_pending, details = mcd_event.args assertEquals([], added) assertEquals([muc_self_handle], removed) assertEquals([], local_pending) assertEquals([], remote_pending) assertContains('actor', details) assertEquals(bob_handle, details['actor']) assertEquals(cs.GC_REASON_KICKED, details['change-reason']) assertEquals('bye', details['message']) q.expect('dbus-signal', signal='ChannelClosed')
def test(q, bus, conn, stream): # The user happily joins a MUC _, chan, _, _ = join_muc(q, bus, conn, stream, MUC) muc_self_handle = chan.Group.GetSelfHandle() muc_self_jid, = conn.InspectHandles(cs.HT_CONTACT, [muc_self_handle]) # But then Bob kicks us. bob_jid = "%s/bob" % MUC bob_handle, = conn.RequestHandles(cs.HT_CONTACT, [bob_jid]) stream.send( elem("presence", from_=muc_self_jid, type="unavailable")( elem(ns.MUC_USER, "x")( elem("item", affiliation="none", role="none")(elem("actor", jid=bob_jid), elem("reason")(u"bye")), elem("status", code="307"), ) ) ) mcd_event = q.expect("dbus-signal", signal="MembersChangedDetailed") added, removed, local_pending, remote_pending, details = mcd_event.args assertEquals([], added) assertEquals([muc_self_handle], removed) assertEquals([], local_pending) assertEquals([], remote_pending) assertContains("actor", details) assertEquals(bob_handle, details["actor"]) assertEquals(cs.GC_REASON_KICKED, details["change-reason"]) assertEquals("bye", details["message"]) q.expect("dbus-signal", signal="ChannelClosed")
def test(q, bus, conn, stream): # The user happily joins a MUC chan, _, _ = join_muc(q, bus, conn, stream, MUC) muc_self_handle = chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, "SelfHandle") muc_self_jid = conn.inspect_contact_sync(muc_self_handle) # But then Bob kicks us. bob_jid = '%s/bob' % MUC bob_handle = conn.get_contact_handle_sync(bob_jid) stream.send( elem('presence', from_=muc_self_jid, type='unavailable')(elem(ns.MUC_USER, 'x')( elem('item', affiliation='none', role='none')(elem('actor', jid=bob_jid), elem('reason')(u'bye')), elem('status', code='307'), ))) mcd_event = q.expect('dbus-signal', signal='MembersChangedDetailed') added, removed, local_pending, remote_pending, details = mcd_event.args assertEquals([], added) assertEquals([muc_self_handle], removed) assertEquals([], local_pending) assertEquals([], remote_pending) assertContains('actor', details) assertEquals(bob_handle, details['actor']) assertEquals(cs.GC_REASON_KICKED, details['change-reason']) assertEquals('bye', details['message']) q.expect('dbus-signal', signal='ChannelClosed')
def join_me_up_buttercup(muc): chan, _, _ = join_muc(q, bus, conn, stream, muc, affiliation='owner') # Gabble grabs the owner configuration form to see whether it's # possible to change the room description. owner_iq = q.expect('stream-iq', to=muc, iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_owner_get_iq(stream, owner_iq.stanza) call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {'Persistent': True}) e = q.expect('stream-iq', to=muc, iq_type='get', query_ns=ns.MUC_OWNER) return chan, e
def test_broken_server(q, bus, conn, stream): MUC = 'bro@ken' chan, _ , _ = join_muc(q, bus, conn, stream, MUC, affiliation='owner') owner_iq = q.expect('stream-iq', to=MUC, iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_owner_get_iq(stream, owner_iq.stanza) call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {'Private': False}) e = q.expect('stream-iq', to=MUC, iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_owner_get_iq(stream, e.stanza) # The server doesn't actually have a form field for configuring whether the # room is private or not. q.expect('dbus-error', method='UpdateConfiguration', name=cs.SERVICE_CONFUSED)
def test_then_disconnect(q, bus, conn, stream): room = '*****@*****.**' chan, path, props, disco = join_muc(q, bus, conn, stream, room, also_capture=[ EventPattern( 'stream-iq', iq_type='get', query_name='query', query_ns=ns.DISCO_INFO, to=room) ]) sync_dbus(bus, q, conn) # we call Close... call_async(q, chan, 'Close') q.expect('dbus-return', method='Close') # ...so gabble announces our unavailable presence to the MUC. event = q.expect('stream-presence', to=room + '/test') elem = event.stanza assertEquals('unavailable', elem['type']) # oh no, but now we want to disconnect. call_async(q, conn, 'Disconnect') # the muc factory is told to close everything, so it does so # without announcing it to the channel because it does it # forcibly, so the channels disappear. q.expect_many(EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed')) # now echo the unavailable presence; this shouldn't be handled # because the channel has already closed. echo_muc_presence(q, stream, elem, 'none', 'participant') # send the stream footer so that the connection thinks it's # property disconnected now. stream.sendFooter() # finally, Disconnect returns q.expect('dbus-return', method='Disconnect')
def test_broken_server(q, bus, conn, stream): MUC = 'bro@ken' chan, _, _ = join_muc(q, bus, conn, stream, MUC, affiliation='owner') owner_iq = q.expect('stream-iq', to=MUC, iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_owner_get_iq(stream, owner_iq.stanza) call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {'Private': False}) e = q.expect('stream-iq', to=MUC, iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_owner_get_iq(stream, e.stanza) # The server doesn't actually have a form field for configuring whether the # room is private or not. q.expect('dbus-error', method='UpdateConfiguration', name=cs.SERVICE_CONFUSED)
def test_then_disconnect(q, bus, conn, stream): room = '*****@*****.**' chan, path, props, disco = join_muc(q, bus, conn, stream, room, also_capture=[EventPattern('stream-iq', iq_type='get', query_name='query', query_ns=ns.DISCO_INFO, to=room)]) sync_dbus(bus, q, conn) # we call Close... call_async(q, chan, 'Close') q.expect('dbus-return', method='Close') # ...so gabble announces our unavailable presence to the MUC. event = q.expect('stream-presence', to=room + '/test') elem = event.stanza assertEquals('unavailable', elem['type']) # oh no, but now we want to disconnect. call_async(q, conn, 'Disconnect') # the muc factory is told to close everything, so it does so # without announcing it to the channel because it does it # forcibly, so the channels disappear. q.expect_many(EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed')) # now echo the unavailable presence; this shouldn't be handled # because the channel has already closed. echo_muc_presence(q, stream, elem, 'none', 'participant') # send the stream footer so that the connection thinks it's # property disconnected now. stream.sendFooter() # finally, Disconnect returns q.expect('dbus-return', method='Disconnect')
def test_subject(q, bus, conn, stream, change_subject, send_first, moderator): room = '*****@*****.**' chan, path, props, disco = join_muc(q, bus, conn, stream, room, also_capture=[EventPattern('stream-iq', iq_type='get', query_name='query', query_ns=ns.DISCO_INFO, to=room)], role=(moderator and 'moderator' or 'participant')) assert chan.Properties.Get(cs.CHANNEL_IFACE_SUBJECT, "CanSet") if send_first: # Someone sets a subject. message = domish.Element((None, 'message')) message['from'] = room + '/bob' message['type'] = 'groupchat' message.addElement('subject', content='Testing') stream.send(message) q.expect('dbus-signal', interface=cs.PROPERTIES_IFACE, signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_SUBJECT) check_subject_props(chan, 'Testing', room + '/bob', True) # Reply to the disco iq = make_result_iq(stream, disco.stanza) query = iq.firstChildElement() feat = query.addElement('feature') feat['var'] = 'muc_public' x = query.addElement((ns.X_DATA, 'x')) x['type'] = 'result' if change_subject is not None: # When fd.o #13157 has been fixed, this will actually do something. field = x.addElement('field') field['var'] = 'muc#roomconfig_changesubject' field.addElement('value', content=(change_subject and 'true' or 'false')) stream.send(iq) # Someone sets a subject. message = domish.Element((None, 'message')) message['from'] = room + '/bob' message['type'] = 'groupchat' message.addElement('subject', content='lalala') stream.send(message) q.expect('dbus-signal', interface=cs.PROPERTIES_IFACE, signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_SUBJECT) check_subject_props(chan, 'lalala', room + '/bob', True) # test changing the subject call_async(q, chan, 'SetSubject', 'le lolz', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) e = q.expect('stream-message', to=room) elem = e.stanza assertEquals('groupchat', elem['type']) assertEquals(1, len(elem.children)) assertEquals(elem.children[0].name, 'subject') assertEquals(str(elem.children[0]), 'le lolz') elem['from'] = room + '/test' stream.send(elem) q.expect_many(EventPattern('dbus-signal', interface=cs.PROPERTIES_IFACE, signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_SUBJECT), EventPattern('dbus-return', method='SetSubject'), ) check_subject_props(chan, 'le lolz', room + '/test', True) # Test changing the subject and getting an error back. call_async(q, chan, 'SetSubject', 'CHICKEN MAN', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) e = q.expect('stream-message', to=room) elem = e.stanza elem['from'] = room elem['type'] = 'error' error = elem.addElement((None, 'error')) error['type'] = 'auth' error.addElement((ns.STANZA, 'forbidden')) stream.send(elem) q.expect('dbus-error', method='SetSubject', name=cs.PERMISSION_DENIED) # Test changing the subject and getting an error back which doesn't echo # the <subject> element. call_async(q, chan, 'SetSubject', 'CHICKEN MAN', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) e = q.expect('stream-message', to=room) message = domish.Element((None, 'message')) message['from'] = room message['id'] = e.stanza['id'] message['type'] = 'error' error = message.addElement((None, 'error')) error.addElement((ns.STANZA, 'forbidden')) stream.send(message) q.expect('dbus-error', method='SetSubject', name=cs.PERMISSION_DENIED) # Test changing the subject just before we leave the room (and hence not # getting a reply). While we're here, check that you can't have more than # one call in flight at a time. call_async(q, chan, 'SetSubject', 'le lolz', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) e = q.expect('stream-message', to=room) call_async(q, chan, 'SetSubject', 'le lolz', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) q.expect('dbus-error', method='SetSubject', name=cs.NOT_AVAILABLE) chan.Close() event = q.expect('stream-presence', to=room + '/test') elem = event.stanza assertEquals('unavailable', elem['type']) q.expect('dbus-error', method='SetSubject', name=cs.CANCELLED) call_async(q, chan, 'SetSubject', 'how about now?', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) q.expect('dbus-error', method='SetSubject', name=cs.NOT_AVAILABLE) # The MUC confirms that we've left the room. echo = make_muc_presence('member', 'none', room, 'test') echo['type'] = 'unavailable' stream.send(echo) q.expect('dbus-signal', signal='ChannelClosed')
def test_subject(q, bus, conn, stream, change_subject, send_first, moderator): # FIXME: fd.o#21152: using many different rooms here because the join_muc() # utility function (via request_muc_handle()) only copes with requesting # the handle for the first time, due to having to expect the disco#info # query to the server and reply to it. Fixing fd.o#21152 will remove the # distinction between the first and nth time, at which point we can just # join the same room repeatedly. global counter room = '*****@*****.**' % counter counter += 1 room_handle, chan, path, props, disco = join_muc(q, bus, conn, stream, room, also_capture=[EventPattern('stream-iq', iq_type='get', query_name='query', query_ns=ns.DISCO_INFO, to=room)], role=(moderator and 'moderator' or 'participant')) # Until the disco returns, we appear to have no properties except subject. prop_list = chan.TpProperties.ListProperties() props = dict([(name, id) for id, name, sig, flags in prop_list]) prop_flags = dict([(name, flags) for id, name, sig, flags in prop_list]) for name in props: if name == 'subject': # subject can always be changed, until fd.o#13157 is fixed assertEquals(cs.PROPERTY_FLAG_WRITE, prop_flags[name]) else: assertEquals(0, prop_flags[name]) if send_first: # Someone sets a subject. message = domish.Element((None, 'message')) message['from'] = room + '/bob' message['type'] = 'groupchat' message.addElement('subject', content='Testing') stream.send(message) q.expect('dbus-signal', signal='PropertiesChanged', predicate=lambda e: (props['subject'], 'Testing') in e.args[0]) e = q.expect('dbus-signal', signal='PropertyFlagsChanged', predicate=lambda e: (props['subject'], cs.PROPERTY_FLAGS_RW) in e.args[0]) assertContains((props['subject-contact'], cs.PROPERTY_FLAG_READ), e.args[0]) assertContains((props['subject-timestamp'], cs.PROPERTY_FLAG_READ), e.args[0]) check_room_props(chan, 'Testing', room + '/bob') # Reply to the disco iq = make_result_iq(stream, disco.stanza) query = iq.firstChildElement() x = query.addElement((ns.X_DATA, 'x')) x['type'] = 'result' feat = x.addElement('feature') feat['var'] = 'muc_public' if change_subject is not None: # When fd.o #13157 has been fixed, this will actually do something. field = x.addElement('field') field['var'] = 'muc#roomconfig_changesubject' field.addElement('value', content=(change_subject and 'true' or 'false')) stream.send(iq) # Someone sets a subject. message = domish.Element((None, 'message')) message['from'] = room + '/bob' message['type'] = 'groupchat' message.addElement('subject', content='lalala') stream.send(message) q.expect('dbus-signal', signal='PropertiesChanged', predicate=lambda e: (props['subject'], 'lalala') in e.args[0]) check_room_props(chan, 'lalala', room + '/bob') # if send_first was true, then we already got this if not send_first: e = q.expect('dbus-signal', signal='PropertyFlagsChanged', predicate=lambda e: (props['subject'], cs.PROPERTY_FLAGS_RW) in e.args[0]) assertContains((props['subject-contact'], cs.PROPERTY_FLAG_READ), e.args[0]) assertContains((props['subject-timestamp'], cs.PROPERTY_FLAG_READ), e.args[0]) check_room_props(chan, 'lalala', room + '/bob') chan.Close() event = q.expect('stream-presence', to=room + '/test') elem = event.stanza assertEquals('unavailable', elem['type'])
def test_role_changes(q, bus, conn, stream): # The test user joins a room. Bob is an owner (and moderator); the test # user starts out with no affiliation and the rôle of participant. MUC = 'aoeu@snth' chan, _, immutable_props, disco = join_muc(q, bus, conn, stream, MUC, role='participant', also_capture=[ EventPattern('stream-iq', to=MUC, iq_type='get', query_ns=ns.DISCO_INFO), ]) assertContains(cs.CHANNEL_IFACE_ROOM_CONFIG, immutable_props[cs.INTERFACES]) handle_disco_info_iq(stream, disco.stanza) q.expect('dbus-signal', signal='PropertiesChanged', args=[cs.CHANNEL_IFACE_ROOM_CONFIG, {'ConfigurationRetrieved': True}, [] ]) # If we try to change the configuration, Gabble should say no: it knows # we're not allowed to do that. call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {}) q.expect('dbus-error', name=cs.PERMISSION_DENIED) config = chan.Properties.GetAll(cs.CHANNEL_IFACE_ROOM_CONFIG) assert not config['CanUpdateConfiguration'], config # If we acquire affiliation='owner', this should be signalled as our # becoming able to modify the channel configuration. stream.send(make_muc_presence('owner', 'moderator', MUC, 'test')) q.expect('dbus-signal', signal='PropertiesChanged', args=[cs.CHANNEL_IFACE_ROOM_CONFIG, {'CanUpdateConfiguration': True}, [] ]) # Due to silliness, Gabble has to grab the owner configuration form to see # whether it's possible to change the room description. owner_iq = q.expect('stream-iq', to=MUC, iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_owner_get_iq(stream, owner_iq.stanza) # Bob's ownership rights being taken away should have no effect. stream.send(make_muc_presence('none', 'participant', MUC, 'bob')) # So now we're an owner, and CanUpdateConfiguration is True, we should be # able to change some configuration. props = dbus.Dictionary( { 'Persistent': True, }, signature='sv') call_async(q, chan.RoomConfig1, 'UpdateConfiguration', props) owner_iq = q.expect('stream-iq', to=MUC, iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_owner_get_iq(stream, owner_iq.stanza) event = q.expect('stream-iq', to=MUC, iq_type='set', query_ns=ns.MUC_OWNER) handle_muc_owner_set_iq(stream, event.stanza, {'muc#roomconfig_persistentroom': ['1']}) q.expect_many( EventPattern('dbus-return', method='UpdateConfiguration'), EventPattern('dbus-signal', signal='PropertiesChanged', args=[cs.CHANNEL_IFACE_ROOM_CONFIG, {'Persistent': True}, [] ])) # If we lose our affiliation, that should be signalled too. stream.send(make_muc_presence('none', 'participant', MUC, 'test')) q.expect('dbus-signal', signal='PropertiesChanged', args=[cs.CHANNEL_IFACE_ROOM_CONFIG, {'CanUpdateConfiguration': False}, [] ]) # Gabble should once again reject attempts to change the configuration call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {}) q.expect('dbus-error', name=cs.PERMISSION_DENIED)
def test_some_stuff(q, bus, conn, stream): text_chan, _, _, disco_iq, owner_iq, _ = join_muc(q, bus, conn, stream, '*****@*****.**', role='moderator', affiliation='owner', also_capture=[ EventPattern('stream-iq', to='*****@*****.**', iq_type='get', query_ns=ns.DISCO_INFO), EventPattern('stream-iq', to='*****@*****.**', iq_type='get', query_ns=ns.MUC_OWNER), # We discovered that we're an owner. Emitting a signal seems # acceptable, although technically this happens before the channel # request finishes so the channel could just as well not be on the bus. EventPattern('dbus-signal', signal='PropertiesChanged', args=[cs.CHANNEL_IFACE_ROOM_CONFIG, {'CanUpdateConfiguration': True}, [] ]), ]) # This tells Gabble that the MUC is well-behaved and lets owners modify the # room description. Technically we could also pull the description out of # here, but as an implementation detail we only read configuration out of # the disco reply. handle_muc_owner_get_iq(stream, owner_iq.stanza) pc = q.expect('dbus-signal', signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_ROOM_CONFIG) _, changed, invalidated = pc.args assertEquals(['MutableProperties'], changed.keys()) assertContains('Description', changed['MutableProperties']) handle_disco_info_iq(stream, disco_iq.stanza) pc = q.expect('dbus-signal', signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_ROOM_CONFIG) q.expect('dbus-signal', signal='PropertiesChanged', args=[cs.CHANNEL_IFACE_ROOM_CONFIG, {'ConfigurationRetrieved': True}, [] ]) _, changed, invalidated = pc.args assertEquals( { 'Anonymous': True, 'Moderated': True, 'Title': ROOM_NAME, 'Description': ROOM_DESCRIPTION, 'Private': True, }, changed) assertEquals([], invalidated) config = text_chan.Properties.GetAll(cs.CHANNEL_IFACE_ROOM_CONFIG) # Verify that all of the config properties (besides the password ones) # correspond to the flags set in handle_disco_info_iq(). assertEquals(True, config['Anonymous']) assertEquals(False, config['InviteOnly']) assertEquals(0, config['Limit']) assertEquals(True, config['Moderated']) assertEquals(ROOM_NAME, config['Title']) assertEquals(ROOM_DESCRIPTION, config['Description']) assertEquals(False, config['Persistent']) assertEquals(True, config['Private']) # This is affirmed to be false both by the disco reply and by the muc#owner # reply. assertEquals(False, config['PasswordProtected']) # This comes from the muc#owner reply. assertEquals('', config['Password']) # We're a room owner, so we should be able to modify the room configuration assertEquals(True, config['CanUpdateConfiguration']) assertSameSets( ['Anonymous', 'InviteOnly', # TODO: when we understand member limit fields, add Limit 'Moderated', 'Title', 'Description', 'Persistent', 'Private', 'PasswordProtected', 'Password', ], config['MutableProperties']) props = dbus.Dictionary( { 'Password': '******', 'PasswordProtected': True, }, signature='sv') call_async(q, text_chan.RoomConfig1, 'UpdateConfiguration', props) event = q.expect('stream-iq', to='*****@*****.**', iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_owner_get_iq(stream, event.stanza) event = q.expect('stream-iq', to='*****@*****.**', iq_type='set', query_ns=ns.MUC_OWNER) handle_muc_owner_set_iq(stream, event.stanza, {'password': ['foo'], 'password_protected': ['1'], }) pc, _ = q.expect_many( EventPattern('dbus-signal', signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_ROOM_CONFIG), EventPattern('dbus-return', method='UpdateConfiguration'), ) _, changed, invalidated = pc.args assertEquals(props, changed) assertEquals([], invalidated) config = text_chan.Properties.GetAll(cs.CHANNEL_IFACE_ROOM_CONFIG) assertEquals(True, config['PasswordProtected']) assertEquals('foo', config['Password']) # Check unknown fields are rejected. props = dbus.Dictionary( { 'PasswordProtected': True, 'Riding on a donkey': True, }, signature='sv') call_async(q, text_chan.RoomConfig1, 'UpdateConfiguration', props) q.expect('dbus-error', name=cs.INVALID_ARGUMENT) # Check that mis-typed fields are rejected. props = dbus.Dictionary( { 'PasswordProtected': 'foo', 'Password': True, }, signature='sv') call_async(q, text_chan.RoomConfig1, 'UpdateConfiguration', props) q.expect('dbus-error', name=cs.INVALID_ARGUMENT) # Updating no fields should be a no-op, and not wait on any network # traffic. text_chan.RoomConfig1.UpdateConfiguration({})
def test(q, bus, conn, stream): iq_event, disco_event = q.expect_many( EventPattern('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard'), EventPattern('stream-iq', to='localhost', query_ns=ns.DISCO_ITEMS)) acknowledge_iq(stream, iq_event.stanza) announce_socks5_proxy(q, stream, disco_event.stanza) join_muc(q, bus, conn, stream, '*****@*****.**') # bob offers a stream tube stream_tube_id = 1 presence = make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob') tubes = presence.addElement((ns.TUBES, 'tubes')) tube = tubes.addElement((None, 'tube')) tube['type'] = 'stream' tube['service'] = 'echo' tube['id'] = str(stream_tube_id) parameters = tube.addElement((None, 'parameters')) stream.send(presence) def new_chan_predicate(e): path, props = e.args[0][0] return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE e = q.expect('dbus-signal', signal='NewChannels', predicate=new_chan_predicate) channels = e.args[0] assert len(channels) == 1 path, props = channels[0] assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE tube_chan = bus.get_object(conn.bus_name, path) tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE) call_async(q, tube_iface, 'Accept', 0, 0, '', byte_arrays=True) accept_return_event, _ = q.expect_many( EventPattern('dbus-return', method='Accept'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[cs.TUBE_CHANNEL_STATE_OPEN])) unix_socket_adr = accept_return_event.value[0] factory = EventProtocolClientFactory(q) reactor.connectUNIX(unix_socket_adr, factory) # expect SI request e = q.expect('stream-iq', to='[email protected]/bob', query_ns=ns.SI, query_name='si') bytestream, profile = create_from_si_offer(stream, q, BytestreamS5BRelay, e.stanza, '[email protected]/bob') result, si = bytestream.create_si_reply(e.stanza, 'test@localhost/Resource') si.addElement((ns.TUBES, 'tube')) stream.send(result) # wait SOCKS5 init iq id, mode, si, hosts = bytestream._expect_socks5_init() for jid, host, port in hosts: # the proxy is not announced because we are in a muc assert jid != 'proxy.localhost'
def test(q, bus, conn, stream): iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, iq_event.stanza) t.check_conn_properties(q, conn) # Create new style tube channel and make sure that is indeed # returned. muc = '*****@*****.**' call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_DBUS_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: muc, cs.DBUS_TUBE_SERVICE_NAME: 'com.example.LolDongs'}) q.expect('stream-presence', to='%s/test' % muc) stream.send(make_muc_presence('owner', 'moderator', muc, 'bob')) stream.send(make_muc_presence('none', 'participant', muc, 'test')) ret, _, _ = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) _, props = ret.value assertEquals(props[cs.CHANNEL_TYPE], cs.CHANNEL_TYPE_DBUS_TUBE) assertEquals(props[cs.TARGET_HANDLE_TYPE], cs.HT_ROOM) assertEquals(props[cs.TARGET_ID], muc) # Now try joining the text muc before asking for the tube channel. muc = '*****@*****.**' join_muc(q, bus, conn, stream, muc) call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_DBUS_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: muc, cs.DBUS_TUBE_SERVICE_NAME: 'com.example.LolDongs'}) ret, _, _ = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) _, props = ret.value assertEquals(props[cs.CHANNEL_TYPE], cs.CHANNEL_TYPE_DBUS_TUBE) assertEquals(props[cs.TARGET_HANDLE_TYPE], cs.HT_ROOM) assertEquals(props[cs.TARGET_ID], muc) # Now make sure we can get our Tubes channel if we request it. muc = '*****@*****.**' call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TUBES, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: muc}) q.expect('stream-presence', to='%s/test' % muc) stream.send(make_muc_presence('owner', 'moderator', muc, 'bob')) stream.send(make_muc_presence('none', 'participant', muc, 'test')) ret, _, _ = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) _, props = ret.value assertEquals(props[cs.CHANNEL_TYPE], cs.CHANNEL_TYPE_TUBES) assertEquals(props[cs.TARGET_HANDLE_TYPE], cs.HT_ROOM) assertEquals(props[cs.TARGET_ID], muc)
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.GetSelfHandle() self_name = conn.InspectHandles(1, [self_handle])[0] handle, tubes_chan, tubes_iface = get_muc_tubes_channel(q, bus, conn, stream, "*****@*****.**") # Exercise basic Channel Properties from spec 0.17.7 channel_props = tubes_chan.GetAll(cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE) assert channel_props.get("TargetHandle") == handle, (channel_props.get("TargetHandle"), handle) assert channel_props.get("TargetHandleType") == 2, channel_props.get("TargetHandleType") assert channel_props.get("ChannelType") == cs.CHANNEL_TYPE_TUBES, channel_props.get("ChannelType") assert "Interfaces" in channel_props, channel_props assert cs.CHANNEL_IFACE_GROUP in channel_props["Interfaces"], channel_props["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 = tubes_chan.GetAll(cs.CHANNEL_IFACE_GROUP, dbus_interface=dbus.PROPERTIES_IFACE) assert "SelfHandle" in group_props, group_props 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 tubes_self_handle = tubes_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) assert group_props["SelfHandle"] == tubes_self_handle # Offer a D-Bus tube (old API) call_async(q, tubes_iface, "OfferDBusTube", "com.example.TestCase", sample_parameters) new_tube_event, presence_event, offer_return_event, dbus_changed_event = q.expect_many( EventPattern("dbus-signal", signal="NewTube"), EventPattern("stream-presence", to="[email protected]/test"), EventPattern("dbus-return", method="OfferDBusTube"), EventPattern("dbus-signal", signal="DBusNamesChanged", interface=cs.CHANNEL_TYPE_TUBES), ) # handle new_tube_event dbus_tube_id = new_tube_event.args[0] assert new_tube_event.args[1] == tubes_self_handle assert new_tube_event.args[2] == cs.TUBE_TYPE_DBUS assert new_tube_event.args[3] == "com.example.TestCase" assert new_tube_event.args[4] == sample_parameters assert new_tube_event.args[5] == cs.TUBE_STATE_OPEN # handle offer_return_event assert offer_return_event.value[0] == dbus_tube_id # handle presence_event # We announce our newly created tube in our muc presence presence = presence_event.stanza dbus_stream_id, my_bus_name = check_tube_in_presence(presence, dbus_tube_id, "[email protected]/test") # handle dbus_changed_event assert dbus_changed_event.args[0] == dbus_tube_id assert dbus_changed_event.args[1][0][0] == tubes_self_handle assert dbus_changed_event.args[1][0][1] == my_bus_name # handle offer_return_event assert dbus_tube_id == offer_return_event.value[0] tubes = tubes_iface.ListTubes(byte_arrays=True) assert len(tubes) == 1 expected_tube = ( dbus_tube_id, tubes_self_handle, cs.TUBE_TYPE_DBUS, "com.example.TestCase", sample_parameters, cs.TUBE_STATE_OPEN, ) t.check_tube_in_tubes(expected_tube, tubes) dbus_tube_adr = tubes_iface.GetDBusTubeAddress(dbus_tube_id) tube = Connection(dbus_tube_adr) fire_signal_on_tube(q, tube, "*****@*****.**", dbus_stream_id, my_bus_name) # 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) # The order in which the NewChannels signals are fired is # undefined -- it could be the (tubes, text) channels first, or it # could be the tube channel first; so let's accept either order # here. first, second = q.expect_many( EventPattern("dbus-signal", signal="NewChannels"), EventPattern("dbus-signal", signal="NewChannels") ) # NewChannels signal with the text and tubes channels together. def nc_textandtubes(event): channels = event.args[0] assert len(channels) == 2 path1, prop1 = channels[0] path2, prop2 = channels[1] assert sorted([prop1[cs.CHANNEL_TYPE], prop2[cs.CHANNEL_TYPE]]) == [cs.CHANNEL_TYPE_TEXT, cs.CHANNEL_TYPE_TUBES] got_text, got_tubes = False, False for path, props in channels: if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT: got_text = True text_chan = dbus.Interface(bus.get_object(conn.bus_name, path), cs.CHANNEL) elif props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TUBES: got_tubes = True tubes_iface = dbus.Interface(bus.get_object(conn.bus_name, path), cs.CHANNEL_TYPE_TUBES) else: assert False assert props[cs.INITIATOR_HANDLE] == self_handle assert props[cs.INITIATOR_ID] == self_name assert cs.CHANNEL_IFACE_GROUP in props[cs.INTERFACES] assert props[cs.TARGET_ID] == "*****@*****.**" assert props[cs.REQUESTED] == False assert (got_text, got_tubes) == (True, True) return text_chan # NewChannels signal with the tube channel. def nc_tube(event): # FIXME: in this case, all channels should probably be announced together channels = event.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, ] return path, prop if len(first.args[0]) == 1: path, prop = nc_tube(first) text_chan = nc_textandtubes(second) else: text_chan = nc_textandtubes(first) path, prop = nc_tube(second) # 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 = bus.get_object(conn.bus_name, path) dbus_tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_DBUS_TUBE) chan_iface = dbus.Interface(tube_chan, cs.CHANNEL) tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assert tube_props["State"] == cs.TUBE_CHANNEL_STATE_NOT_OFFERED # try to offer using a wrong access control try: dbus_tube_iface.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, 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) # check if we can request muc D-Bus tube t.check_conn_properties(q, conn) self_handle = conn.GetSelfHandle() self_name = conn.InspectHandles(1, [self_handle])[0] handle, tubes_chan, tubes_iface = get_muc_tubes_channel(q, bus, conn, stream, '*****@*****.**') # Exercise basic Channel Properties from spec 0.17.7 channel_props = tubes_chan.GetAll(cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE) assert channel_props.get('TargetHandle') == handle,\ (channel_props.get('TargetHandle'), handle) assert channel_props.get('TargetHandleType') == 2,\ channel_props.get('TargetHandleType') assert channel_props.get('ChannelType') == cs.CHANNEL_TYPE_TUBES,\ channel_props.get('ChannelType') assert 'Interfaces' in channel_props, channel_props assert cs.CHANNEL_IFACE_GROUP in channel_props['Interfaces'], \ channel_props['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 = tubes_chan.GetAll(cs.CHANNEL_IFACE_GROUP, dbus_interface=dbus.PROPERTIES_IFACE) assert 'SelfHandle' in group_props, group_props 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 tubes_self_handle = tubes_chan.GetSelfHandle( dbus_interface=cs.CHANNEL_IFACE_GROUP) assert group_props['SelfHandle'] == tubes_self_handle # Offer a D-Bus tube (old API) call_async(q, tubes_iface, 'OfferDBusTube', 'com.example.TestCase', sample_parameters) new_tube_event, presence_event, offer_return_event, dbus_changed_event = \ q.expect_many( EventPattern('dbus-signal', signal='NewTube'), EventPattern('stream-presence', to='[email protected]/test'), EventPattern('dbus-return', method='OfferDBusTube'), EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_TUBES)) # handle new_tube_event dbus_tube_id = new_tube_event.args[0] assert new_tube_event.args[1] == tubes_self_handle assert new_tube_event.args[2] == cs.TUBE_TYPE_DBUS assert new_tube_event.args[3] == 'com.example.TestCase' assert new_tube_event.args[4] == sample_parameters assert new_tube_event.args[5] == cs.TUBE_STATE_OPEN # handle offer_return_event assert offer_return_event.value[0] == dbus_tube_id # handle presence_event # We announce our newly created tube in our muc presence presence = presence_event.stanza dbus_stream_id, my_bus_name = check_tube_in_presence(presence, dbus_tube_id, '[email protected]/test') # handle dbus_changed_event assert dbus_changed_event.args[0] == dbus_tube_id assert dbus_changed_event.args[1][0][0] == tubes_self_handle assert dbus_changed_event.args[1][0][1] == my_bus_name # handle offer_return_event assert dbus_tube_id == offer_return_event.value[0] tubes = tubes_iface.ListTubes(byte_arrays=True) assert len(tubes) == 1 expected_tube = (dbus_tube_id, tubes_self_handle, cs.TUBE_TYPE_DBUS, 'com.example.TestCase', sample_parameters, cs.TUBE_STATE_OPEN) t.check_tube_in_tubes(expected_tube, tubes) dbus_tube_adr = tubes_iface.GetDBusTubeAddress(dbus_tube_id) tube = Connection(dbus_tube_adr) fire_signal_on_tube(q, tube, '*****@*****.**', dbus_stream_id, my_bus_name) # 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) # first text and tubes channels are announced event = q.expect('dbus-signal', signal='NewChannels') channels = event.args[0] assert len(channels) == 2 path1, prop1 = channels[0] path2, prop2 = channels[1] assert sorted([prop1[cs.CHANNEL_TYPE], prop2[cs.CHANNEL_TYPE]]) == \ [cs.CHANNEL_TYPE_TEXT, cs.CHANNEL_TYPE_TUBES] got_text, got_tubes = False, False for path, props in channels: if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT: got_text = True text_chan = dbus.Interface(bus.get_object(conn.bus_name, path), cs.CHANNEL) elif props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TUBES: got_tubes = True tubes_iface = dbus.Interface(bus.get_object(conn.bus_name, path), cs.CHANNEL_TYPE_TUBES) else: assert False assert props[cs.INITIATOR_HANDLE] == self_handle assert props[cs.INITIATOR_ID] == self_name assert cs.CHANNEL_IFACE_GROUP in props[cs.INTERFACES] assert props[cs.TARGET_ID] == '*****@*****.**' assert props[cs.REQUESTED] == False assert (got_text, got_tubes) == (True, True) # now the tube channel is announced # FIXME: in this case, all channels should probably be announced together event = q.expect('dbus-signal', signal='NewChannels') channels = event.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 = bus.get_object(conn.bus_name, path) dbus_tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_DBUS_TUBE) chan_iface = dbus.Interface(tube_chan, cs.CHANNEL) tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_NOT_OFFERED # try to offer using a wrong access control try: dbus_tube_iface.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): expect_and_handle_get_vcard(q, stream) jid = u'*****@*****.**' alias = u'Horza' handle = conn.get_contact_handle_sync(jid) # We don't have an interesting alias for Horza assertEquals({handle: jid}, get_aliases(conn, [handle])) # Horza sends us a message containing his preferred nickname. stream.send( elem('message', from_=jid, type='chat')(elem('body')(u"It's a long story."), elem(ns.NICK, 'nick')(alias))) _, mr = q.expect_many( EventPattern('dbus-signal', signal='AliasesChanged', args=[[(handle, alias)]]), EventPattern('dbus-signal', signal='MessageReceived'), ) channel = wrap_channel(bus.get_object(conn.bus_name, mr.path), 'Text') # So now we know his alias. assertEquals({handle: alias}, get_aliases(conn, [handle])) # Presumably to avoid non-contacts being able to make Gabble's memory # footprint grow forever, Gabble throws the alias away when we close the # channel. header = mr.args[0][0] channel.Text.AcknowledgePendingMessages([header['pending-message-id']]) channel.Close() # FIXME: Gabble forgets the alias, but it doesn't signal that it has done # so; it probably should. # q.expect('dbus-signal', signal='AliasesChanged', args=[[(handle, jid)]]) assertEquals({handle: jid}, get_aliases(conn, [handle])) # Basically the same test, but in a MUC. # # It's a bit questionable whether this ought to work. # <http://xmpp.org/extensions/xep-0172.html#muc> doesn't have anything to # say about including <nick/> in messages; it does talk about including # <nick> in your MUC presence, which is actually equally sketchy! If I join # a muc with the resource '/wjt', and you join with resource '/ohai' but # say that your nickname is 'wjt', what on earth is Alice's UI supposed to # show when you send a message? # # But anyway, at the time of writing this "works", so I'm adding a test to # make it explicit. Perhaps in future we might change this test to verify # that it doesn't "work". room_jid = '*****@*****.**' muc, _, _ = join_muc(q, bus, conn, stream, room_jid) bob_jid = room_jid + '/bob' bob_handle = conn.get_contact_handle_sync(bob_jid) assertEquals({bob_handle: 'bob'}, get_aliases(conn, [bob_handle])) stream.send( elem('message', from_=bob_jid, type='groupchat')( elem('body')(u'My religion dies with me.'), elem(ns.NICK, 'nick')(alias), )) q.expect_many( EventPattern('dbus-signal', signal='AliasesChanged', args=[[(bob_handle, alias)]]), EventPattern('dbus-signal', signal='MessageReceived'), ) assertEquals({bob_handle: alias}, get_aliases(conn, [bob_handle])) muc.Close() q.expect('stream-presence', to=room_jid + '/test') echo = make_muc_presence('member', 'none', room_jid, 'test') echo['type'] = 'unavailable' stream.send(echo) q.expect('dbus-signal', signal='ChannelClosed') # FIXME: Gabble forgets the alias, but it doesn't signal that it has done # so; it probably should. # q.expect('dbus-signal', signal='AliasesChanged', # args=[[(bob_handle, 'bob')]]) assertEquals({bob_handle: 'bob'}, get_aliases(conn, [bob_handle]))
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_subject(q, bus, conn, stream, change_subject, send_first, moderator): room = '*****@*****.**' room_handle, chan, path, props, disco = join_muc(q, bus, conn, stream, room, also_capture=[EventPattern('stream-iq', iq_type='get', query_name='query', query_ns=ns.DISCO_INFO, to=room)], role=(moderator and 'moderator' or 'participant')) assert chan.Properties.Get(cs.CHANNEL_IFACE_SUBJECT, "CanSet") if send_first: # Someone sets a subject. message = domish.Element((None, 'message')) message['from'] = room + '/bob' message['type'] = 'groupchat' message.addElement('subject', content='Testing') stream.send(message) q.expect('dbus-signal', interface=cs.PROPERTIES_IFACE, signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_SUBJECT) check_subject_props(chan, 'Testing', room + '/bob', True) # Reply to the disco iq = make_result_iq(stream, disco.stanza) query = iq.firstChildElement() feat = query.addElement('feature') feat['var'] = 'muc_public' x = query.addElement((ns.X_DATA, 'x')) x['type'] = 'result' if change_subject is not None: # When fd.o #13157 has been fixed, this will actually do something. field = x.addElement('field') field['var'] = 'muc#roomconfig_changesubject' field.addElement('value', content=(change_subject and 'true' or 'false')) stream.send(iq) # Someone sets a subject. message = domish.Element((None, 'message')) message['from'] = room + '/bob' message['type'] = 'groupchat' message.addElement('subject', content='lalala') stream.send(message) q.expect('dbus-signal', interface=cs.PROPERTIES_IFACE, signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_SUBJECT) check_subject_props(chan, 'lalala', room + '/bob', True) # test changing the subject call_async(q, chan, 'SetSubject', 'le lolz', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) e = q.expect('stream-message', to=room) elem = e.stanza assertEquals('groupchat', elem['type']) assertEquals(1, len(elem.children)) assertEquals(elem.children[0].name, 'subject') assertEquals(str(elem.children[0]), 'le lolz') elem['from'] = room + '/test' stream.send(elem) q.expect_many(EventPattern('dbus-signal', interface=cs.PROPERTIES_IFACE, signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_SUBJECT), EventPattern('dbus-return', method='SetSubject'), ) check_subject_props(chan, 'le lolz', room + '/test', True) # Test changing the subject and getting an error back. call_async(q, chan, 'SetSubject', 'CHICKEN MAN', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) e = q.expect('stream-message', to=room) elem = e.stanza elem['from'] = room elem['type'] = 'error' error = elem.addElement((None, 'error')) error['type'] = 'auth' error.addElement((ns.STANZA, 'forbidden')) stream.send(elem) q.expect('dbus-error', method='SetSubject', name=cs.PERMISSION_DENIED) # Test changing the subject and getting an error back which doesn't echo # the <subject> element. call_async(q, chan, 'SetSubject', 'CHICKEN MAN', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) e = q.expect('stream-message', to=room) message = domish.Element((None, 'message')) message['from'] = room message['id'] = e.stanza['id'] message['type'] = 'error' error = message.addElement((None, 'error')) error.addElement((ns.STANZA, 'forbidden')) stream.send(message) q.expect('dbus-error', method='SetSubject', name=cs.PERMISSION_DENIED) # Test changing the subject just before we leave the room (and hence not # getting a reply). While we're here, check that you can't have more than # one call in flight at a time. call_async(q, chan, 'SetSubject', 'le lolz', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) e = q.expect('stream-message', to=room) call_async(q, chan, 'SetSubject', 'le lolz', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) q.expect('dbus-error', method='SetSubject', name=cs.NOT_AVAILABLE) chan.Close() event = q.expect('stream-presence', to=room + '/test') elem = event.stanza assertEquals('unavailable', elem['type']) q.expect('dbus-error', method='SetSubject', name=cs.CANCELLED) call_async(q, chan, 'SetSubject', 'how about now?', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) q.expect('dbus-error', method='SetSubject', name=cs.NOT_AVAILABLE) # The MUC confirms that we've left the room. echo = make_muc_presence('member', 'none', room, 'test') echo['type'] = 'unavailable' stream.send(echo) q.expect('dbus-signal', signal='ChannelClosed')
def test_some_stuff(q, bus, conn, stream): text_chan, _, _, disco_iq, owner_iq, _ = join_muc( q, bus, conn, stream, '*****@*****.**', role='moderator', affiliation='owner', also_capture=[ EventPattern('stream-iq', to='*****@*****.**', iq_type='get', query_ns=ns.DISCO_INFO), EventPattern('stream-iq', to='*****@*****.**', iq_type='get', query_ns=ns.MUC_OWNER), # We discovered that we're an owner. Emitting a signal seems # acceptable, although technically this happens before the channel # request finishes so the channel could just as well not be on the bus. EventPattern('dbus-signal', signal='PropertiesChanged', args=[ cs.CHANNEL_IFACE_ROOM_CONFIG, { 'CanUpdateConfiguration': True }, [] ]), ]) # This tells Gabble that the MUC is well-behaved and lets owners modify the # room description. Technically we could also pull the description out of # here, but as an implementation detail we only read configuration out of # the disco reply. handle_muc_owner_get_iq(stream, owner_iq.stanza) pc = q.expect( 'dbus-signal', signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_ROOM_CONFIG) _, changed, invalidated = pc.args assertEquals(['MutableProperties'], changed.keys()) assertContains('Description', changed['MutableProperties']) handle_disco_info_iq(stream, disco_iq.stanza) pc = q.expect( 'dbus-signal', signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_ROOM_CONFIG) q.expect('dbus-signal', signal='PropertiesChanged', args=[ cs.CHANNEL_IFACE_ROOM_CONFIG, { 'ConfigurationRetrieved': True }, [] ]) _, changed, invalidated = pc.args assertEquals( { 'Anonymous': True, 'Moderated': True, 'Title': ROOM_NAME, 'Description': ROOM_DESCRIPTION, 'Private': True, }, changed) assertEquals([], invalidated) config = text_chan.Properties.GetAll(cs.CHANNEL_IFACE_ROOM_CONFIG) # Verify that all of the config properties (besides the password ones) # correspond to the flags set in handle_disco_info_iq(). assertEquals(True, config['Anonymous']) assertEquals(False, config['InviteOnly']) assertEquals(0, config['Limit']) assertEquals(True, config['Moderated']) assertEquals(ROOM_NAME, config['Title']) assertEquals(ROOM_DESCRIPTION, config['Description']) assertEquals(False, config['Persistent']) assertEquals(True, config['Private']) # This is affirmed to be false both by the disco reply and by the muc#owner # reply. assertEquals(False, config['PasswordProtected']) # This comes from the muc#owner reply. assertEquals('', config['Password']) # We're a room owner, so we should be able to modify the room configuration assertEquals(True, config['CanUpdateConfiguration']) assertSameSets( [ 'Anonymous', 'InviteOnly', # TODO: when we understand member limit fields, add Limit 'Moderated', 'Title', 'Description', 'Persistent', 'Private', 'PasswordProtected', 'Password', ], config['MutableProperties']) props = dbus.Dictionary({ 'Password': '******', 'PasswordProtected': True, }, signature='sv') call_async(q, text_chan.RoomConfig1, 'UpdateConfiguration', props) event = q.expect('stream-iq', to='*****@*****.**', iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_owner_get_iq(stream, event.stanza) event = q.expect('stream-iq', to='*****@*****.**', iq_type='set', query_ns=ns.MUC_OWNER) handle_muc_owner_set_iq(stream, event.stanza, { 'password': ['foo'], 'password_protected': ['1'], }) pc, _ = q.expect_many( EventPattern( 'dbus-signal', signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_ROOM_CONFIG), EventPattern('dbus-return', method='UpdateConfiguration'), ) _, changed, invalidated = pc.args assertEquals(props, changed) assertEquals([], invalidated) config = text_chan.Properties.GetAll(cs.CHANNEL_IFACE_ROOM_CONFIG) assertEquals(True, config['PasswordProtected']) assertEquals('foo', config['Password']) # Check unknown fields are rejected. props = dbus.Dictionary( { 'PasswordProtected': True, 'Riding on a donkey': True, }, signature='sv') call_async(q, text_chan.RoomConfig1, 'UpdateConfiguration', props) q.expect('dbus-error', name=cs.INVALID_ARGUMENT) # Check that mis-typed fields are rejected. props = dbus.Dictionary({ 'PasswordProtected': 'foo', 'Password': True, }, signature='sv') call_async(q, text_chan.RoomConfig1, 'UpdateConfiguration', props) q.expect('dbus-error', name=cs.INVALID_ARGUMENT) # Updating no fields should be a no-op, and not wait on any network # traffic. text_chan.RoomConfig1.UpdateConfiguration({})
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_role_changes(q, bus, conn, stream): # The test user joins a room. Bob is an owner (and moderator); the test # user starts out with no affiliation and the rôle of participant. MUC = 'aoeu@snth' chan, _, immutable_props, disco = join_muc(q, bus, conn, stream, MUC, role='participant', also_capture=[ EventPattern( 'stream-iq', to=MUC, iq_type='get', query_ns=ns.DISCO_INFO), ]) assertContains(cs.CHANNEL_IFACE_ROOM_CONFIG, immutable_props[cs.INTERFACES]) handle_disco_info_iq(stream, disco.stanza) q.expect('dbus-signal', signal='PropertiesChanged', args=[ cs.CHANNEL_IFACE_ROOM_CONFIG, { 'ConfigurationRetrieved': True }, [] ]) # If we try to change the configuration, Gabble should say no: it knows # we're not allowed to do that. call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {}) q.expect('dbus-error', name=cs.PERMISSION_DENIED) config = chan.Properties.GetAll(cs.CHANNEL_IFACE_ROOM_CONFIG) assert not config['CanUpdateConfiguration'], config # If we acquire affiliation='owner', this should be signalled as our # becoming able to modify the channel configuration. stream.send(make_muc_presence('owner', 'moderator', MUC, 'test')) q.expect('dbus-signal', signal='PropertiesChanged', args=[ cs.CHANNEL_IFACE_ROOM_CONFIG, { 'CanUpdateConfiguration': True }, [] ]) # Due to silliness, Gabble has to grab the owner configuration form to see # whether it's possible to change the room description. owner_iq = q.expect('stream-iq', to=MUC, iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_owner_get_iq(stream, owner_iq.stanza) # Bob's ownership rights being taken away should have no effect. stream.send(make_muc_presence('none', 'participant', MUC, 'bob')) # So now we're an owner, and CanUpdateConfiguration is True, we should be # able to change some configuration. props = dbus.Dictionary({ 'Persistent': True, }, signature='sv') call_async(q, chan.RoomConfig1, 'UpdateConfiguration', props) owner_iq = q.expect('stream-iq', to=MUC, iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_owner_get_iq(stream, owner_iq.stanza) event = q.expect('stream-iq', to=MUC, iq_type='set', query_ns=ns.MUC_OWNER) handle_muc_owner_set_iq(stream, event.stanza, {'muc#roomconfig_persistentroom': ['1']}) q.expect_many( EventPattern('dbus-return', method='UpdateConfiguration'), EventPattern( 'dbus-signal', signal='PropertiesChanged', args=[cs.CHANNEL_IFACE_ROOM_CONFIG, { 'Persistent': True }, []])) # If we lose our affiliation, that should be signalled too. stream.send(make_muc_presence('none', 'participant', MUC, 'test')) q.expect('dbus-signal', signal='PropertiesChanged', args=[ cs.CHANNEL_IFACE_ROOM_CONFIG, { 'CanUpdateConfiguration': False }, [] ]) # Gabble should once again reject attempts to change the configuration call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {}) q.expect('dbus-error', name=cs.PERMISSION_DENIED)
def test(q, bus, conn, stream, 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 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) self_handle = conn.GetSelfHandle() self_name = conn.InspectHandles(cs.HT_CONTACT, [self_handle])[0] t.check_conn_properties(q, conn) room_handle, tubes_chan, tubes_iface = get_muc_tubes_channel(q, bus, conn, stream, "*****@*****.**") tubes_self_handle = tubes_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) bob_handle = conn.RequestHandles(cs.HT_CONTACT, ["[email protected]/bob"])[0] address = t.create_server(q, address_type) # offer stream tube (old API) using an Unix socket call_async( q, tubes_iface, "OfferStreamTube", "echo", sample_parameters, address_type, address, access_control, access_control_param, ) new_tube_event, stream_event, _, new_channels_event = q.expect_many( EventPattern("dbus-signal", signal="NewTube"), EventPattern("stream-presence", to="[email protected]/test"), EventPattern("dbus-return", method="OfferStreamTube"), EventPattern("dbus-signal", signal="NewChannels"), ) # handle new_tube_event stream_tube_id = new_tube_event.args[0] assert new_tube_event.args[1] == tubes_self_handle assert new_tube_event.args[2] == 1 # Stream assert new_tube_event.args[3] == "echo" assert new_tube_event.args[4] == sample_parameters assert new_tube_event.args[5] == cs.TUBE_CHANNEL_STATE_OPEN # handle stream_event # We announce our newly created tube in our muc presence presence = stream_event.stanza x_nodes = xpath.queryForNodes('/presence/x[@xmlns="http://jabber.org/' 'protocol/muc"]', presence) assert x_nodes is not None assert len(x_nodes) == 1 tubes_nodes = xpath.queryForNodes('/presence/tubes[@xmlns="%s"]' % ns.TUBES, presence) assert tubes_nodes is not None assert len(tubes_nodes) == 1 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"] == "echo" assert not tube.hasAttribute("stream-id") assert not tube.hasAttribute("dbus-name") assert tube["id"] == str(stream_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 == {"ay": ("bytes", "aGVsbG8="), "s": ("str", "hello"), "i": ("int", "-123"), "u": ("uint", "123")} # tube is also announced using new API channels = new_channels_event.args[0] assert len(channels) == 1 path, props = channels[0] assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE assert props[cs.INITIATOR_HANDLE] == tubes_self_handle assert props[cs.INITIATOR_ID] == "[email protected]/test" assert props[cs.INTERFACES] == [cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE] assert props[cs.REQUESTED] == True assert props[cs.TARGET_HANDLE] == room_handle assert props[cs.TARGET_ID] == "*****@*****.**" assert props[cs.STREAM_TUBE_SERVICE] == "echo" tube_chan = bus.get_object(conn.bus_name, path) tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assert tube_props["Parameters"] == sample_parameters assert tube_props["State"] == cs.TUBE_CHANNEL_STATE_OPEN tubes = tubes_iface.ListTubes(byte_arrays=True) assert tubes == [ (stream_tube_id, tubes_self_handle, 1, "echo", sample_parameters, cs.TUBE_CHANNEL_STATE_OPEN) # Stream ] assert len(tubes) == 1, unwrap(tubes) expected_tube = ( stream_tube_id, tubes_self_handle, cs.TUBE_TYPE_STREAM, "echo", sample_parameters, cs.TUBE_STATE_OPEN, ) t.check_tube_in_tubes(expected_tube, tubes) # FIXME: if we use an unknown JID here, everything fails # (the code uses lookup where it should use ensure) 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="StreamTubeNewConnection", args=[stream_tube_id, bob_handle], interface=cs.CHANNEL_TYPE_TUBES, ), EventPattern("dbus-signal", signal="NewRemoteConnection", interface=cs.CHANNEL_TYPE_STREAM_TUBE), ) protocol = socket_event.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 handle, access, conn_id = conn_event.args assert handle == bob_handle use_tube(q, bytestream, protocol, conn_id) # 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) # first text and tubes channels are announced event = q.expect("dbus-signal", signal="NewChannels") channels = event.args[0] assert len(channels) == 2 path1, prop1 = channels[0] path2, prop2 = channels[1] assert sorted([prop1[cs.CHANNEL_TYPE], prop2[cs.CHANNEL_TYPE]]) == [cs.CHANNEL_TYPE_TEXT, cs.CHANNEL_TYPE_TUBES] got_text, got_tubes = False, False for path, props in channels: if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT: got_text = True elif props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TUBES: got_tubes = True else: assert False assert props[cs.INITIATOR_HANDLE] == self_handle assert props[cs.INITIATOR_ID] == self_name assert cs.CHANNEL_IFACE_GROUP in props[cs.INTERFACES] assert props[cs.TARGET_ID] == "*****@*****.**" assert props[cs.REQUESTED] == False assert (got_text, got_tubes) == (True, True) # now the tube channel is announced # FIXME: in this case, all channels should probably be announced together event = q.expect("dbus-signal", signal="NewChannels") channels = event.args[0] assert len(channels) == 1 path, prop = channels[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 = bus.get_object(conn.bus_name, path) stream_tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE) chan_iface = dbus.Interface(tube_chan, cs.CHANNEL) 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, stream_tube_iface, "Offer", address_type, address, access_control, {"foo": "bar"}) new_tube_event, stream_event, _, status_event = q.expect_many( EventPattern("dbus-signal", signal="NewTube"), EventPattern("stream-presence", to="[email protected]/test"), EventPattern("dbus-return", method="Offer"), EventPattern("dbus-signal", signal="TubeChannelStateChanged", args=[cs.TUBE_CHANNEL_STATE_OPEN]), ) tube_self_handle = tube_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) assert conn.InspectHandles(cs.HT_CONTACT, [tube_self_handle]) == ["[email protected]/test"] # handle new_tube_event stream_tube_id = new_tube_event.args[0] assert new_tube_event.args[2] == 1 # Stream assert new_tube_event.args[3] == "newecho" assert new_tube_event.args[4] == {"foo": "bar"} assert new_tube_event.args[5] == cs.TUBE_CHANNEL_STATE_OPEN presence = stream_event.stanza x_nodes = xpath.queryForNodes('/presence/x[@xmlns="http://jabber.org/' 'protocol/muc"]', presence) assert x_nodes is not None assert len(x_nodes) == 1 tubes_nodes = xpath.queryForNodes('/presence/tubes[@xmlns="%s"]' % ns.TUBES, presence) assert tubes_nodes is not None assert len(tubes_nodes) == 1 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") assert tube["id"] == str(stream_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.RequestHandles(cs.HT_CONTACT, ["[email protected]/bob"])[0] 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) chan_iface.Close() q.expect_many(EventPattern("dbus-signal", signal="Closed"), EventPattern("dbus-signal", signal="ChannelClosed"))
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) self_handle = conn.GetSelfHandle() self_name = conn.InspectHandles(cs.HT_CONTACT, [self_handle])[0] t.check_conn_properties(q, conn) room_handle, tubes_chan, tubes_iface = get_muc_tubes_channel(q, bus, conn, stream, '*****@*****.**') tubes_self_handle = tubes_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) bob_handle = conn.RequestHandles(cs.HT_CONTACT, ['[email protected]/bob'])[0] address = t.create_server(q, address_type) # offer stream tube (old API) using an Unix socket call_async(q, tubes_iface, 'OfferStreamTube', 'echo', sample_parameters, address_type, address, access_control, access_control_param) new_tube_event, stream_event, _, new_channels_event = q.expect_many( EventPattern('dbus-signal', signal='NewTube'), EventPattern('stream-presence', to='[email protected]/test'), EventPattern('dbus-return', method='OfferStreamTube'), EventPattern('dbus-signal', signal='NewChannels')) # handle new_tube_event stream_tube_id = new_tube_event.args[0] assert new_tube_event.args[1] == tubes_self_handle assert new_tube_event.args[2] == 1 # Stream assert new_tube_event.args[3] == 'echo' assert new_tube_event.args[4] == sample_parameters assert new_tube_event.args[5] == cs.TUBE_CHANNEL_STATE_OPEN # handle stream_event # We announce our newly created tube in our muc presence 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 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'] == 'echo' assert not tube.hasAttribute('stream-id') assert not tube.hasAttribute('dbus-name') assert tube['id'] == str(stream_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 == {'ay': ('bytes', 'aGVsbG8='), 's': ('str', 'hello'), 'i': ('int', '-123'), 'u': ('uint', '123'), } # tube is also announced using new API channels = new_channels_event.args[0] assert len(channels) == 1 path, props = channels[0] assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE assert props[cs.INITIATOR_HANDLE] == tubes_self_handle assert props[cs.INITIATOR_ID] == '[email protected]/test' assert props[cs.INTERFACES] == [cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE] assert props[cs.REQUESTED] == True assert props[cs.TARGET_HANDLE] == room_handle assert props[cs.TARGET_ID] == '*****@*****.**' assert props[cs.STREAM_TUBE_SERVICE] == 'echo' tube_chan = bus.get_object(conn.bus_name, path) tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assert tube_props['Parameters'] == sample_parameters assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_OPEN tubes = tubes_iface.ListTubes(byte_arrays=True) assert tubes == [( stream_tube_id, tubes_self_handle, 1, # Stream 'echo', sample_parameters, cs.TUBE_CHANNEL_STATE_OPEN )] assert len(tubes) == 1, unwrap(tubes) expected_tube = (stream_tube_id, tubes_self_handle, cs.TUBE_TYPE_STREAM, 'echo', sample_parameters, cs.TUBE_STATE_OPEN) t.check_tube_in_tubes(expected_tube, tubes) # FIXME: if we use an unknown JID here, everything fails # (the code uses lookup where it should use ensure) 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='StreamTubeNewConnection', args=[stream_tube_id, bob_handle], interface=cs.CHANNEL_TYPE_TUBES), EventPattern('dbus-signal', signal='NewRemoteConnection', interface=cs.CHANNEL_TYPE_STREAM_TUBE)) protocol = socket_event.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 handle, access, conn_id = conn_event.args assert handle == bob_handle use_tube(q, bytestream, protocol, conn_id) # 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) # The order in which the NewChannels signals are fired is # undefined -- it could be the (tubes, text) channels first, or it # could be the tube channel first; so let's accept either order # here. first, second = q.expect_many( EventPattern('dbus-signal', signal='NewChannels'), EventPattern('dbus-signal', signal='NewChannels')) # NewChannels signal with the text and tubes channels together. def nc_textandtubes(event): channels = event.args[0] assert len(channels) == 2 path1, prop1 = channels[0] path2, prop2 = channels[1] assert sorted([prop1[cs.CHANNEL_TYPE], prop2[cs.CHANNEL_TYPE]]) == \ [cs.CHANNEL_TYPE_TEXT, cs.CHANNEL_TYPE_TUBES] got_text, got_tubes = False, False for path, props in channels: if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT: got_text = True elif props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TUBES: got_tubes = True else: assert False assert props[cs.INITIATOR_HANDLE] == self_handle assert props[cs.INITIATOR_ID] == self_name assert cs.CHANNEL_IFACE_GROUP in props[cs.INTERFACES] assert props[cs.TARGET_ID] == '*****@*****.**' assert props[cs.REQUESTED] == False assert (got_text, got_tubes) == (True, True) # NewChannels signal with the tube channel. def nc_tube(event): # FIXME: in this case, all channels should probably be announced together channels = event.args[0] assert len(channels) == 1 path, prop = channels[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' return path, prop if len(first.args[0]) == 1: path, prop = nc_tube(first) nc_textandtubes(second) else: nc_textandtubes(first) path, prop = nc_tube(second) # 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 = bus.get_object(conn.bus_name, path) stream_tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE) chan_iface = dbus.Interface(tube_chan, cs.CHANNEL) 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, stream_tube_iface, 'Offer', address_type, address, access_control, {'foo': 'bar'}) new_tube_event, stream_event, _, status_event = q.expect_many( EventPattern('dbus-signal', signal='NewTube'), EventPattern('stream-presence', to='[email protected]/test'), EventPattern('dbus-return', method='Offer'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[cs.TUBE_CHANNEL_STATE_OPEN])) tube_self_handle = tube_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) assert conn.InspectHandles(cs.HT_CONTACT, [tube_self_handle]) == ['[email protected]/test'] # handle new_tube_event stream_tube_id = new_tube_event.args[0] assert new_tube_event.args[2] == 1 # Stream assert new_tube_event.args[3] == 'newecho' assert new_tube_event.args[4] == {'foo': 'bar'} assert new_tube_event.args[5] == cs.TUBE_CHANNEL_STATE_OPEN 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 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') assert tube['id'] == str(stream_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.RequestHandles(cs.HT_CONTACT, ['[email protected]/bob'])[0] 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) chan_iface.Close() q.expect_many( EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed'))
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): expect_and_handle_get_vcard(q, stream) jid = u"*****@*****.**" alias = u"Horza" handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] # We don't have an interesting alias for Horza assertEquals({handle: jid}, conn.Aliasing.GetAliases([handle])) # Horza sends us a message containing his preferred nickname. stream.send( elem("message", from_=jid, type="chat")(elem("body")(u"It's a long story."), elem(ns.NICK, "nick")(alias)) ) _, mr = q.expect_many( EventPattern("dbus-signal", signal="AliasesChanged", args=[[(handle, alias)]]), EventPattern("dbus-signal", signal="MessageReceived"), ) channel = wrap_channel(bus.get_object(conn.bus_name, mr.path), "Text") # So now we know his alias. assertEquals({handle: alias}, conn.Aliasing.GetAliases([handle])) # Presumably to avoid non-contacts being able to make Gabble's memory # footprint grow forever, Gabble throws the alias away when we close the # channel. header = mr.args[0][0] channel.Text.AcknowledgePendingMessages([header["pending-message-id"]]) channel.Close() # FIXME: Gabble forgets the alias, but it doesn't signal that it has done # so; it probably should. # q.expect('dbus-signal', signal='AliasesChanged', args=[[(handle, jid)]]) assertEquals({handle: jid}, conn.Aliasing.GetAliases([handle])) # Basically the same test, but in a MUC. # # It's a bit questionable whether this ought to work. # <http://xmpp.org/extensions/xep-0172.html#muc> doesn't have anything to # say about including <nick/> in messages; it does talk about including # <nick> in your MUC presence, which is actually equally sketchy! If I join # a muc with the resource '/wjt', and you join with resource '/ohai' but # say that your nickname is 'wjt', what on earth is Alice's UI supposed to # show when you send a message? # # But anyway, at the time of writing this "works", so I'm adding a test to # make it explicit. Perhaps in future we might change this test to verify # that it doesn't "work". room_jid = "*****@*****.**" _, muc, _, _ = join_muc(q, bus, conn, stream, room_jid) bob_jid = room_jid + "/bob" bob_handle = conn.RequestHandles(cs.HT_CONTACT, [bob_jid])[0] assertEquals({bob_handle: "bob"}, conn.Aliasing.GetAliases([bob_handle])) stream.send( elem("message", from_=bob_jid, type="groupchat")( elem("body")(u"My religion dies with me."), elem(ns.NICK, "nick")(alias) ) ) q.expect_many( EventPattern("dbus-signal", signal="AliasesChanged", args=[[(bob_handle, alias)]]), EventPattern("dbus-signal", signal="MessageReceived"), ) assertEquals({bob_handle: alias}, conn.Aliasing.GetAliases([bob_handle])) muc.Close() q.expect("stream-presence", to=room_jid + "/test") echo = make_muc_presence("member", "none", room_jid, "test") echo["type"] = "unavailable" stream.send(echo) q.expect("dbus-signal", signal="ChannelClosed") # FIXME: Gabble forgets the alias, but it doesn't signal that it has done # so; it probably should. # q.expect('dbus-signal', signal='AliasesChanged', # args=[[(bob_handle, 'bob')]]) assertEquals({bob_handle: "bob"}, conn.Aliasing.GetAliases([bob_handle]))