def join_muc(q, bus, conn, stream, muc, request=None): """ Joins 'muc', returning the muc's handle, a proxy object for the channel, its path and its immutable properties just after the CreateChannel event has fired. The room contains one other member. """ if request is None: request = { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: muc, } muc_handle = request_muc_handle(q, conn, stream, muc) requests = dbus.Interface(conn, cs.CONN_IFACE_REQUESTS) call_async(q, requests, 'CreateChannel', dbus.Dictionary(request, signature='sv')) q.expect('stream-presence', to='%s/test' % muc) # Send presence for other member of room. stream.send(make_muc_presence('owner', 'moderator', muc, 'bob')) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', muc, 'test')) event = q.expect('dbus-return', method='CreateChannel') path, props = event.value chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text', ['Messages']) return (muc_handle, chan, path, props)
def test(q, bus, conn, stream): muc_handle = request_muc_handle(q, conn, stream, '*****@*****.**') call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM, muc_handle, True) q.expect('stream-presence', to='[email protected]/test') # Send presence for own membership of room. stream.send( make_muc_presence('owner', 'moderator', '*****@*****.**', 'test')) iq, ret = q.expect_many( EventPattern('stream-iq', to='*****@*****.**', iq_type='get', query_ns=ns.MUC_OWNER), EventPattern('dbus-return', method='RequestChannel')) handle_muc_get_iq(stream, iq.stanza) text_chan = wrap_channel( bus.get_object(conn.bus_name, ret.value[0]), 'Text') props = dict([(name, id) for id, name, sig, flags in text_chan.TpProperties.ListProperties()]) call_async(q, text_chan.TpProperties, 'SetProperties', [(props['password'], 'foo'), (props['password-required'], True)]) event = q.expect('stream-iq', to='*****@*****.**', iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_get_iq(stream, event.stanza) event = q.expect('stream-iq', to='*****@*****.**', iq_type='set', query_ns=ns.MUC_OWNER) fields = xpath.queryForNodes('/iq/query/x/field', event.stanza) form = {} for field in fields: values = xpath.queryForNodes('/field/value', field) form[field['var']] = [str(v) for v in values] assert form == {'password': ['foo'], 'password_protected': ['1'], 'muc#roomconfig_presencebroadcast' : ['moderator', 'participant', 'visitor']} acknowledge_iq(stream, event.stanza) event = q.expect('dbus-signal', signal='PropertiesChanged') assert event.args == [[(props['password'], 'foo'), (props['password-required'], True)]] q.expect('dbus-return', method='SetProperties', value=()) call_async(q, text_chan.TpProperties, 'SetProperties', [(31337, 'foo'), (props['password-required'], True)]) q.expect('dbus-error', name=cs.INVALID_ARGUMENT) call_async(q, text_chan.TpProperties, 'SetProperties', [(props['password'], True), (props['password-required'], 'foo')]) q.expect('dbus-error', name=cs.NOT_AVAILABLE) call_async(q, text_chan.TpProperties, 'SetProperties', [(props['subject-contact'], 42)]) q.expect('dbus-error', name=cs.PERMISSION_DENIED)
def test_with_password(q, bus, conn, stream): room = '*****@*****.**' handle = request_muc_handle(q, conn, stream, room) call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_HANDLE: handle}) expected_muc_jid = '%s/%s' % (room, 'test') q.expect('stream-presence', to=expected_muc_jid) # tell gabble the room needs a password stream.send( elem('jabber:client', 'presence', from_=expected_muc_jid, type='error')( elem(ns.MUC, 'x'), elem('error', type='auth')( elem(ns.STANZA, 'not-authorized'), ), )) cc, _ = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='PasswordFlagsChanged', args=[cs.PASSWORD_FLAG_PROVIDE, 0])) chan = wrap_channel(bus.get_object(conn.bus_name, cc.value[0]), 'Text') forbidden = [EventPattern('stream-presence', to=expected_muc_jid)] q.forbid_events(forbidden) # we call Close... call_async(q, chan, 'Close') # ...but this time no unavailable presence because we were in the # auth state, so the channel closes immediately. q.expect_many(EventPattern('dbus-return', method='Close'), EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed')) q.unforbid_events(forbidden)
def test(q, bus, conn, stream): conn.Connect() expect_and_handle_get_vcard(q, stream) self_handle = conn.GetSelfHandle() conn.Aliasing.SetAliases({self_handle: 'lala'}) expect_and_handle_set_vcard(q, stream) event = q.expect('dbus-signal', signal='AliasesChanged', args=[[(self_handle, u'lala')]]) room_jid = '*****@*****.**' room_handle = request_muc_handle(q, conn, stream, room_jid) call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM, room_handle, True) gfc, _, _ = q.expect_many( EventPattern('dbus-signal', signal='GroupFlagsChanged'), EventPattern('dbus-signal', signal='MembersChanged', args=[u'', [], [], [], [2], 0, 0]), EventPattern('stream-presence', to='%s/lala' % room_jid)) assert gfc.args[1] == 0 # Send presence for other member of room. stream.send(make_muc_presence('owner', 'moderator', room_jid, 'bob')) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', room_jid, 'lala')) event = q.expect('dbus-signal', signal='MembersChanged', args=[u'', [2, 3], [], [], [], 0, 0]) assert conn.InspectHandles(1, [2]) == ['[email protected]/lala'] assert conn.InspectHandles(1, [3]) == ['[email protected]/bob'] event = q.expect('dbus-return', method='RequestChannel')
def join_muc(q, bus, conn, stream, muc, request=None, also_capture=[], role='participant'): """ Joins 'muc', returning the muc's handle, a proxy object for the channel, its path and its immutable properties just after the CreateChannel event has fired. The room contains one other member. """ muc_handle = request_muc_handle(q, conn, stream, muc) try_to_join_muc(q, bus, conn, stream, muc, request=request) # Send presence for other member of room. stream.send(make_muc_presence('owner', 'moderator', muc, 'bob')) # Send presence for own membership of room. stream.send(make_muc_presence('none', role, muc, 'test')) captured = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), *also_capture) path, props = captured[0].value chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text', ['Messages']) return (muc_handle, chan, path, props) + tuple(captured[1:])
def test(q, bus, conn, stream): room = '*****@*****.**' handle = request_muc_handle(q, conn, stream, room) call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_HANDLE: handle}) expected_muc_jid = '%s/%s' % (room, 'test') q.expect('stream-presence', to=expected_muc_jid) # tell gabble the room needs a password denied = \ elem('jabber:client', 'presence', from_=expected_muc_jid, type='error')( elem(ns.MUC, 'x'), elem('error', type='auth')( elem(ns.STANZA, 'not-authorized'), ), ) stream.send(denied) cc, _, _ = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannels'), EventPattern('dbus-signal', signal='PasswordFlagsChanged', args=[cs.PASSWORD_FLAG_PROVIDE, 0])) chan = wrap_channel(bus.get_object(conn.bus_name, cc.value[0]), 'Text', ['Password']) flags = chan.Password.GetPasswordFlags() assertEquals(cs.PASSWORD_FLAG_PROVIDE, flags) call_async(q, chan.Password, 'ProvidePassword', 'brand new benz') expect_attempt(q, expected_muc_jid, 'brand new benz') # Try again while the first attempt is outstanding. Gabble should say no. call_async(q, chan.Password, 'ProvidePassword', 'faster faster') q.expect('dbus-error', method='ProvidePassword') # Sorry, wrong password. stream.send(denied) ret = q.expect('dbus-return', method='ProvidePassword') assert not ret.value[0] call_async(q, chan.Password, 'ProvidePassword', 'bougie friends') expect_attempt(q, expected_muc_jid, 'bougie friends') # Well, this may be the right password, but actually that nick is in use. presence = elem('presence', from_=expected_muc_jid, type='error')( elem(ns.MUC, 'x'), elem('error', type='cancel')( elem(ns.STANZA, 'conflict'), )) stream.send(presence) # Okay, so Gabble tries again, with a new JID *and the same password*. expected_muc_jid = expected_muc_jid + '_' expect_attempt(q, expected_muc_jid, 'bougie friends') # Hey this worked. stream.send(make_muc_presence('none', 'participant', room, 'test_')) ret, _ = q.expect_many( EventPattern('dbus-return', method='ProvidePassword'), EventPattern('dbus-signal', signal='PasswordFlagsChanged', args=[0, cs.PASSWORD_FLAG_PROVIDE])) assert ret.value[0]
def test(q, bus, conn, stream): conn.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) self_handle = conn.GetSelfHandle() requests = dbus.Interface(conn, CONN_IFACE_REQUESTS) room_jid = '*****@*****.**' room_handle = request_muc_handle(q, conn, stream, room_jid) call_async(q, requests, 'CreateChannel', dbus.Dictionary({ CHANNEL_TYPE: CHANNEL_TYPE_TEXT, TARGET_HANDLE_TYPE: HT_ROOM, TARGET_HANDLE: room_handle, }, signature='sv')) expected_jid = '%s/%s' % (room_jid, 'test') q.expect('stream-presence', to=expected_jid) # Send presence for another member of the MUC stream.send(make_muc_presence('owner', 'moderator', room_jid, 'liz')) # This is a themed discussion, so the MUC server forces you to have an # appropriate name. self_presence = make_muc_presence('none', 'participant', room_jid, 'toofer') x = [elt for elt in self_presence.elements() if elt.name == 'x'][0] status = x.addElement('status') status['code'] = '110' # "This is you" status = x.addElement('status') status['code'] = '210' # "I renamed you. Muahaha." stream.send(self_presence) # Gabble should figure out from 110 that it's in the room, and from 210 # that we've been renamed. event = q.expect('dbus-return', method='CreateChannel') path, props = event.value text_chan = bus.get_object(conn.bus_name, path) group_props = unwrap(text_chan.GetAll(CHANNEL_IFACE_GROUP, dbus_interface=dbus.PROPERTIES_IFACE)) liz, toofer, expected_handle = conn.RequestHandles(HT_CONTACT, ["%s/%s" % (room_jid, m) for m in ['liz', 'toofer', 'test']]) # Check that Gabble think our nickname in the room is toofer not test muc_self_handle = group_props['SelfHandle'] assert muc_self_handle == toofer, (muc_self_handle, toofer, expected_handle) members = group_props['Members'] # Check there are exactly two members (liz and toofer) expected_members = [liz, toofer] assert sorted(members) == sorted(expected_members), \ (members, expected_members) # There should be no pending members. assert len(group_props['LocalPendingMembers']) == 0, group_props assert len(group_props['RemotePendingMembers']) == 0, group_props # Check that toofer's handle owner is us, and that liz has # no owner. handle_owners = group_props['HandleOwners'] assert handle_owners[toofer] == self_handle, \ (handle_owners, toofer, handle_owners[toofer], self_handle) assert handle_owners[liz] == 0, (handle_owners, liz)
def test_join(q, bus, conn, stream, room_jid, transient_conflict): """ Tells Gabble to join a MUC, but make the first nick it tries conflict with an existing member of the MUC. If transient_conflict is True, then when Gabble successfully joins with a different nick the originally conflicting user turns out not actually to be in the room (they left while we were retrying). """ self_handle = conn.GetSelfHandle() requests = dbus.Interface(conn, CONN_IFACE_REQUESTS) room_handle = request_muc_handle(q, conn, stream, room_jid) # Implementation detail: Gabble uses the first part of your jid (if you # don't have an alias) as your room nickname, and appends an underscore a # few times before giving up. member, member_ = [room_jid + '/' + x for x in ['test', 'test_']] call_async(q, requests, 'CreateChannel', dbus.Dictionary({ CHANNEL_TYPE: CHANNEL_TYPE_TEXT, TARGET_HANDLE_TYPE: HT_ROOM, TARGET_HANDLE: room_handle, }, signature='sv')) # Gabble first tries to join as test q.expect('stream-presence', to=member) # MUC says no: there's already someone called test in room_jid presence = domish.Element((None, 'presence')) presence['from'] = member presence['type'] = 'error' x = presence.addElement((ns.MUC, 'x')) error = presence.addElement((None, 'error')) error['type'] = 'cancel' error.addElement((ns.STANZA, 'conflict')) stream.send(presence) # Gabble tries again as test_ q.expect('stream-presence', to=member_) # MUC says yes! if not transient_conflict: # Send the other member of the room's presence. This is the nick we # originally wanted. stream.send(make_muc_presence('owner', 'moderator', room_jid, 'test')) # If gabble erroneously thinks the other user's presence is our own, it'll # think that it's got the whole userlist now. If so, syncing here will make # CreateChannel incorrectly return here. sync_stream(q, stream) sync_dbus(bus, q, conn) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', room_jid, 'test_')) # Only now should we have finished joining the room. event = q.expect('dbus-return', method='CreateChannel') path, props = event.value text_chan = bus.get_object(conn.bus_name, path) group_props = unwrap(text_chan.GetAll(CHANNEL_IFACE_GROUP, dbus_interface=dbus.PROPERTIES_IFACE)) t, t_ = conn.RequestHandles(HT_CONTACT, [member, member_]) # Check that Gabble think our nickname in the room is test_, not test muc_self_handle = group_props['SelfHandle'] assert muc_self_handle == t_, (muc_self_handle, t_, t) members = group_props['Members'] if transient_conflict: # The user we originally conflicted with isn't actually here; check # there's exactly one member (test_). assert members == [t_], (members, t_, t) else: # Check there are exactly two members (test and test_) assert sorted(members) == sorted([t, t_]), (members, [t, t_]) # In either case, there should be no pending members. assert len(group_props['LocalPendingMembers']) == 0, group_props assert len(group_props['RemotePendingMembers']) == 0, group_props # Check that test_'s handle owner is us, and that test (if it's there) has # no owner. handle_owners = group_props['HandleOwners'] assert handle_owners[t_] == self_handle, \ (handle_owners, t_, handle_owners[t_], self_handle) if not transient_conflict: assert handle_owners[t] == 0, (handle_owners, t) # test that closing the channel results in an unavailable message to the # right jid text_chan.Close() event = q.expect('stream-presence', to=member_) elem = event.stanza assert elem['type'] == 'unavailable'