def test_new_channel(q, bus, conn, target_uri, initiator_uri, requested):
    event = q.expect('dbus-signal', signal='NewChannels')
    path, props = event.args[0][0]
    assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE])
    assertEquals(cs.HT_CONTACT, props[cs.TARGET_HANDLE_TYPE])
    handle = props[cs.TARGET_HANDLE]
    obj = bus.get_object(conn._named_service, path)

    initiator_handle = conn.get_contact_handle_sync(initiator_uri)

    text_props = obj.GetAll(cs.CHANNEL,
            dbus_interface='org.freedesktop.DBus.Properties')
    assert text_props['ChannelType'] == cs.CHANNEL_TYPE_TEXT, text_props
    assert 'Interfaces' in text_props, text_props
    assertSameSets((cs.CHANNEL_IFACE_MESSAGES, cs.CHANNEL_IFACE_DESTROYABLE),
            text_props['Interfaces'])
    assert 'TargetHandle' in text_props, text_props
    assert text_props['TargetHandle'] == handle, \
            (text_props, handle)
    assert 'TargetHandleType' in text_props, text_props
    assert text_props['TargetHandleType'] == 1, text_props
    assert text_props['TargetID'] == target_uri, text_props
    assert text_props['InitiatorHandle'] == initiator_handle, \
            (text_props, initiator_handle)
    assert text_props['InitiatorID'] == initiator_uri, \
            (text_props, initiator_uri)
    assert 'Requested' in text_props, text_props
    assert text_props['Requested'] == requested, text_props

    return obj, handle
def test_channel_reference_identity_with_extra_multiple(q, bus, conn, stream):
    props = connect_and_get_tls_properties (q, bus, conn)

    reference_identities = props["ReferenceIdentities"]
    assertSameSets(reference_identities,
                   [ "example.org", "hypnotoad.example.org", "localhost", "other.local" ])
    assertEquals(props["Hostname"], "example.org")
Esempio n. 3
0
def test_new_channel(q, bus, conn, target_uri, initiator_uri, requested):
    event = q.expect('dbus-signal', signal='NewChannels')
    path, props = event.args[0][0]
    assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE])
    assertEquals(cs.HT_CONTACT, props[cs.TARGET_HANDLE_TYPE])
    handle = props[cs.TARGET_HANDLE]
    obj = bus.get_object(conn._named_service, path)

    initiator_handle = conn.get_contact_handle_sync(initiator_uri)

    text_props = obj.GetAll(cs.CHANNEL,
                            dbus_interface='org.freedesktop.DBus.Properties')
    assert text_props['ChannelType'] == cs.CHANNEL_TYPE_TEXT, text_props
    assert 'Interfaces' in text_props, text_props
    assertSameSets((cs.CHANNEL_IFACE_MESSAGES, cs.CHANNEL_IFACE_DESTROYABLE),
                   text_props['Interfaces'])
    assert 'TargetHandle' in text_props, text_props
    assert text_props['TargetHandle'] == handle, \
            (text_props, handle)
    assert 'TargetHandleType' in text_props, text_props
    assert text_props['TargetHandleType'] == 1, text_props
    assert text_props['TargetID'] == target_uri, text_props
    assert text_props['InitiatorHandle'] == initiator_handle, \
            (text_props, initiator_handle)
    assert text_props['InitiatorID'] == initiator_uri, \
            (text_props, initiator_uri)
    assert 'Requested' in text_props, text_props
    assert text_props['Requested'] == requested, text_props

    return obj, handle
def test_channel_reference_identity_with_extra(q, bus, conn, stream):
    props = connect_and_get_tls_properties(q, bus, conn)

    reference_identities = props["ReferenceIdentities"]
    assertSameSets(reference_identities,
                   ["example.org", "hypnotoad.example.org", "localhost"])
    assertEquals(props["Hostname"], "example.org")
Esempio n. 5
0
def test_jabber_pass_success(q, bus, conn, stream):
    conn.Connect()

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

    e = q.expect('auth-initial-iq')
    authenticator = e.authenticator
    authenticator.respondToInitialIq(e.iq)

    chan, props = expect_sasl_channel(q, bus, conn)

    assertSameSets(['X-TELEPATHY-PASSWORD'],
            props.get(cs.SASL_AVAILABLE_MECHANISMS))

    chan.SASLAuthentication.StartMechanismWithData('X-TELEPATHY-PASSWORD',
            PASSWORD)

    e = q.expect('auth-second-iq')
    authenticator.respondToSecondIq(e.iq)

    q.expect('dbus-signal', signal='SASLStatusChanged',
             interface=cs.CHANNEL_IFACE_SASL_AUTH,
             args=[cs.SASL_STATUS_SERVER_SUCCEEDED, '', {}])

    chan.SASLAuthentication.AcceptSASL()

    q.expect('dbus-signal', signal='SASLStatusChanged',
             interface=cs.CHANNEL_IFACE_SASL_AUTH,
             args=[cs.SASL_STATUS_SUCCEEDED, '', {}])

    e = q.expect('dbus-signal', signal='StatusChanged',
                 args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
Esempio n. 6
0
def check_contact_roster(conn, contact, groups=None, subscribe=None, publish=None):
    h = conn.get_contact_handle_sync(contact)
    attrs = conn.Contacts.GetContactAttributes([h],
            [cs.CONN_IFACE_CONTACT_LIST, cs.CONN_IFACE_CONTACT_GROUPS], True)[h]

    if groups is not None:
        assertSameSets(groups, attrs[cs.ATTR_GROUPS])
    if subscribe is not None:
        assertEquals(subscribe, attrs[cs.ATTR_SUBSCRIBE])
    if publish is not None:
        assertEquals(publish, attrs[cs.ATTR_PUBLISH])
Esempio n. 7
0
    def request_ft_channel(self, uri=True):
        request = {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_FILE_TRANSFER,
            cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
            cs.TARGET_HANDLE: self.handle,
            cs.FT_CONTENT_TYPE: self.file.content_type,
            cs.FT_FILENAME: self.file.name,
            cs.FT_SIZE: self.file.size,
            cs.FT_CONTENT_HASH_TYPE: self.file.hash_type,
            cs.FT_CONTENT_HASH: self.file.hash,
            cs.FT_DESCRIPTION: self.file.description,
            cs.FT_DATE: self.file.date,
            cs.FT_INITIAL_OFFSET: 0,
            cs.FT_SERVICE_NAME: self.service_name,
            cs.FT_METADATA: dbus.Dictionary(self.metadata, signature='sas')
        }

        if uri:
            request[cs.FT_URI] = self.file.uri

        self.ft_path, props = self.conn.Requests.CreateChannel(request)

        # Channel D-Bus properties
        assertEquals(cs.CHANNEL_TYPE_FILE_TRANSFER, props[cs.CHANNEL_TYPE])
        assertSameSets([
            cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA,
        ], props[cs.INTERFACES])
        assertEquals(self.handle, props[cs.TARGET_HANDLE])
        assertEquals(self.contact_name, props[cs.TARGET_ID])
        assertEquals(cs.HT_CONTACT, props[cs.TARGET_HANDLE_TYPE])
        assert props[cs.REQUESTED]
        assertEquals(self.self_handle, props[cs.INITIATOR_HANDLE])
        assertEquals(self.self_handle_name, props[cs.INITIATOR_ID])

        # Channel.Type.FileTransfer D-Bus properties
        assertEquals(cs.FT_STATE_PENDING, props[cs.FT_STATE])
        assertEquals(self.file.content_type, props[cs.FT_CONTENT_TYPE])
        assertEquals(self.file.name, props[cs.FT_FILENAME])
        assertEquals(self.file.size, props[cs.FT_SIZE])
        assertEquals(self.file.hash_type, props[cs.FT_CONTENT_HASH_TYPE])
        assertEquals(self.file.hash, props[cs.FT_CONTENT_HASH])
        assertEquals(self.file.description, props[cs.FT_DESCRIPTION])
        assertEquals(self.file.date, props[cs.FT_DATE])
        assertEquals(0, props[cs.FT_TRANSFERRED_BYTES])
        assertEquals(0, props[cs.FT_INITIAL_OFFSET])
        assertEquals(self.service_name, props[cs.FT_SERVICE_NAME])
        assertEquals(self.metadata, props[cs.FT_METADATA])
        if uri:
            assertEquals(self.file.uri, props[cs.FT_URI])
        else:
            assertEquals('', props[cs.FT_URI])

        self.check_platform_socket_types(props[cs.FT_AVAILABLE_SOCKET_TYPES])
Esempio n. 8
0
    def check_new_channel(self):
        def is_ft_channel_event(event):
            channels, = event.args

            if len(channels) > 1:
                return False

            path, props = channels[0]
            return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER

        e = self.q.expect('dbus-signal',
                          signal='NewChannels',
                          path=self.conn.object.object_path,
                          predicate=is_ft_channel_event)

        channels, = e.args
        path, props = channels[0]

        # check channel properties
        # org.freedesktop.Telepathy.Channel D-Bus properties
        assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER, props
        assertSameSets([
            cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA,
        ], props[cs.INTERFACES])
        assert props[cs.TARGET_HANDLE] == self.handle, props
        assert props[cs.TARGET_ID] == self.target, props
        assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_CONTACT, props
        assert props[cs.REQUESTED] == False, props
        assert props[cs.INITIATOR_HANDLE] == self.handle, props
        assert props[cs.INITIATOR_ID] == self.target, props

        # org.freedesktop.Telepathy.Channel.Type.FileTransfer D-Bus properties
        assert props[cs.FT_STATE] == cs.FT_STATE_PENDING, props
        assert props[cs.FT_CONTENT_TYPE] == '', props
        assert props[cs.FT_FILENAME].encode('utf-8') == self.file.name, props
        assert props[cs.FT_SIZE] == self.file.size, props
        # FT's protocol doesn't allow us the send the hash info
        assert props[cs.FT_CONTENT_HASH_TYPE] == cs.FILE_HASH_TYPE_NONE, props
        assert props[cs.FT_CONTENT_HASH] == '', props
        assert props[cs.FT_DESCRIPTION] == '', props
        assert props[cs.FT_DATE] == 0, props
        assert props[cs.FT_AVAILABLE_SOCKET_TYPES] == \
            {cs.SOCKET_ADDRESS_TYPE_UNIX: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST],
            cs.SOCKET_ADDRESS_TYPE_IPV4: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST],
            cs.SOCKET_ADDRESS_TYPE_IPV6: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST]}, \
            props[cs.FT_AVAILABLE_SOCKET_TYPES]
        assert props[cs.FT_TRANSFERRED_BYTES] == 0, props
        assert props[cs.FT_INITIAL_OFFSET] == 0, props

        self.ft_path = path

        self.create_ft_channel()
    def check_new_channel(self):
        def is_ft_channel_event(event):
            channels, = event.args

            if len(channels) > 1:
                return False

            path, props = channels[0]
            return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER

        e = self.q.expect('dbus-signal', signal='NewChannels',
            path=self.conn.object.object_path,
            predicate=is_ft_channel_event)

        channels, = e.args
        path, props = channels[0]

        # check channel properties
        # org.freedesktop.Telepathy.Channel D-Bus properties
        assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER, props
        assertSameSets(
            [ cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA,
            ], props[cs.INTERFACES])
        assert props[cs.TARGET_HANDLE] == self.handle, props
        assert props[cs.TARGET_ID] == self.target, props
        assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_CONTACT, props
        assert props[cs.REQUESTED] == False, props
        assert props[cs.INITIATOR_HANDLE] == self.handle, props
        assert props[cs.INITIATOR_ID] == self.target, props

        # org.freedesktop.Telepathy.Channel.Type.FileTransfer D-Bus properties
        assert props[cs.FT_STATE] == cs.FT_STATE_PENDING, props
        assert props[cs.FT_CONTENT_TYPE] == '', props
        assert props[cs.FT_FILENAME].encode('utf-8') == self.file.name, props
        assert props[cs.FT_SIZE] == self.file.size, props
        # FT's protocol doesn't allow us the send the hash info
        assert props[cs.FT_CONTENT_HASH_TYPE] == cs.FILE_HASH_TYPE_NONE, props
        assert props[cs.FT_CONTENT_HASH] == '', props
        assert props[cs.FT_DESCRIPTION] == '', props
        assert props[cs.FT_DATE] == 0, props
        assert props[cs.FT_AVAILABLE_SOCKET_TYPES] == \
            {cs.SOCKET_ADDRESS_TYPE_UNIX: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST],
            cs.SOCKET_ADDRESS_TYPE_IPV4: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST],
            cs.SOCKET_ADDRESS_TYPE_IPV6: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST]}, \
            props[cs.FT_AVAILABLE_SOCKET_TYPES]
        assert props[cs.FT_TRANSFERRED_BYTES] == 0, props
        assert props[cs.FT_INITIAL_OFFSET] == 0, props

        self.ft_path = path

        self.create_ft_channel()
Esempio n. 10
0
    def check_new_channel(self):
        def is_ft_channel_event(event):
            channels, = event.args

            if len(channels) > 1:
                return False

            path, props = channels[0]
            return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER

        e = self.q.expect('dbus-signal',
                          signal='NewChannels',
                          path=self.conn.object.object_path,
                          predicate=is_ft_channel_event)

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

        # check channel properties
        # Channel D-Bus properties
        assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER
        assertSameSets([
            cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA,
        ], props[cs.INTERFACES])
        assert props[cs.TARGET_HANDLE] == self.handle
        assert props[cs.TARGET_ID] == self.contact_name
        assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_CONTACT
        assert props[cs.REQUESTED] == False
        assert props[cs.INITIATOR_HANDLE] == self.handle
        assert props[cs.INITIATOR_ID] == self.contact_name

        # Channel.Type.FileTransfer D-Bus properties
        assert props[cs.FT_STATE] == cs.FT_STATE_PENDING
        assert props[cs.FT_CONTENT_TYPE] == self.file.content_type
        assert props[cs.FT_FILENAME] == self.file.name
        assert props[cs.FT_SIZE] == self.file.size
        # FT's protocol doesn't allow us the send the hash info
        assert props[cs.FT_CONTENT_HASH_TYPE] == cs.FILE_HASH_TYPE_MD5
        assert props[cs.FT_CONTENT_HASH] == self.file.hash
        assert props[cs.FT_DESCRIPTION] == self.file.description
        assert props[cs.FT_DATE] == self.file.date
        assert props[cs.FT_TRANSFERRED_BYTES] == 0
        assert props[cs.FT_INITIAL_OFFSET] == 0

        self.check_platform_socket_types(props[cs.FT_AVAILABLE_SOCKET_TYPES])

        assertEquals(self.service_name, props[cs.FT_SERVICE_NAME])
        assertEquals(self.metadata, props[cs.FT_METADATA])

        self.ft_path = path
    def request_ft_channel(self, uri=True):
        request = { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_FILE_TRANSFER,
            cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
            cs.TARGET_HANDLE: self.handle,
            cs.FT_CONTENT_TYPE: self.file.content_type,
            cs.FT_FILENAME: self.file.name,
            cs.FT_SIZE: self.file.size,
            cs.FT_CONTENT_HASH_TYPE: self.file.hash_type,
            cs.FT_CONTENT_HASH: self.file.hash,
            cs.FT_DESCRIPTION: self.file.description,
            cs.FT_DATE:  self.file.date,
            cs.FT_INITIAL_OFFSET: 0,
            cs.FT_SERVICE_NAME: self.service_name,
            cs.FT_METADATA: dbus.Dictionary(self.metadata, signature='sas')}

        if uri:
            request[cs.FT_URI] = self.file.uri

        self.ft_path, props = self.conn.Requests.CreateChannel(request)

        # Channel D-Bus properties
        assertEquals(cs.CHANNEL_TYPE_FILE_TRANSFER, props[cs.CHANNEL_TYPE])
        assertSameSets(
            [ cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA,
            ], props[cs.INTERFACES])
        assertEquals(self.handle, props[cs.TARGET_HANDLE])
        assertEquals(self.contact_name, props[cs.TARGET_ID])
        assertEquals(cs.HT_CONTACT, props[cs.TARGET_HANDLE_TYPE])
        assert props[cs.REQUESTED]
        assertEquals(self.self_handle, props[cs.INITIATOR_HANDLE])
        assertEquals(self.self_handle_name, props[cs.INITIATOR_ID])

        # Channel.Type.FileTransfer D-Bus properties
        assertEquals(cs.FT_STATE_PENDING, props[cs.FT_STATE])
        assertEquals(self.file.content_type, props[cs.FT_CONTENT_TYPE])
        assertEquals(self.file.name, props[cs.FT_FILENAME])
        assertEquals(self.file.size, props[cs.FT_SIZE])
        assertEquals(self.file.hash_type, props[cs.FT_CONTENT_HASH_TYPE])
        assertEquals(self.file.hash, props[cs.FT_CONTENT_HASH])
        assertEquals(self.file.description, props[cs.FT_DESCRIPTION])
        assertEquals(self.file.date, props[cs.FT_DATE])
        assertEquals(0, props[cs.FT_TRANSFERRED_BYTES])
        assertEquals(0, props[cs.FT_INITIAL_OFFSET])
        assertEquals(self.service_name, props[cs.FT_SERVICE_NAME])
        assertEquals(self.metadata, props[cs.FT_METADATA])
        if uri:
            assertEquals(self.file.uri, props[cs.FT_URI])
        else:
            assertEquals('', props[cs.FT_URI])

        self.check_platform_socket_types(props[cs.FT_AVAILABLE_SOCKET_TYPES])
    def check_new_channel(self):
        def is_ft_channel_event(event):
            channels, = event.args

            if len(channels) > 1:
                return False

            path, props = channels[0]
            return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER

        e = self.q.expect('dbus-signal', signal='NewChannels',
            path=self.conn.object.object_path,
            predicate=is_ft_channel_event)

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

        # check channel properties
        # Channel D-Bus properties
        assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER
        assertSameSets(
            [ cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA,
            ], props[cs.INTERFACES])
        assert props[cs.TARGET_HANDLE] == self.handle
        assert props[cs.TARGET_ID] == self.contact_name
        assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_CONTACT
        assert props[cs.REQUESTED] == False
        assert props[cs.INITIATOR_HANDLE] == self.handle
        assert props[cs.INITIATOR_ID] == self.contact_name

        # Channel.Type.FileTransfer D-Bus properties
        assert props[cs.FT_STATE] == cs.FT_STATE_PENDING
        assert props[cs.FT_CONTENT_TYPE] == self.file.content_type
        assert props[cs.FT_FILENAME] == self.file.name
        assert props[cs.FT_SIZE] == self.file.size
        # FT's protocol doesn't allow us the send the hash info
        assert props[cs.FT_CONTENT_HASH_TYPE] == cs.FILE_HASH_TYPE_MD5
        assert props[cs.FT_CONTENT_HASH] == self.file.hash
        assert props[cs.FT_DESCRIPTION] == self.file.description
        assert props[cs.FT_DATE] == self.file.date
        assert props[cs.FT_TRANSFERRED_BYTES] == 0
        assert props[cs.FT_INITIAL_OFFSET] == 0

        self.check_platform_socket_types(props[cs.FT_AVAILABLE_SOCKET_TYPES])

        assertEquals(self.service_name, props[cs.FT_SERVICE_NAME])
        assertEquals(self.metadata, props[cs.FT_METADATA])

        self.ft_path = path
def check_contact_roster(conn,
                         contact,
                         groups=None,
                         subscribe=None,
                         publish=None):
    h = conn.get_contact_handle_sync(contact)
    attrs = conn.Contacts.GetContactAttributes(
        [h], [cs.CONN_IFACE_CONTACT_LIST, cs.CONN_IFACE_CONTACT_GROUPS],
        True)[h]

    if groups is not None:
        assertSameSets(groups, attrs[cs.ATTR_GROUPS])
    if subscribe is not None:
        assertEquals(subscribe, attrs[cs.ATTR_SUBSCRIBE])
    if publish is not None:
        assertEquals(publish, attrs[cs.ATTR_PUBLISH])
Esempio n. 14
0
def rccs(q, bus, conn, stream):
    """
    Tests that the connection's RequestableChannelClasses for StreamedMedia are
    sane.
    """
    conn.Connect()

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

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

    rccs = conn.Properties.Get(cs.CONN_IFACE_REQUESTS,
                               'RequestableChannelClasses')

    # Test Channel.Type.StreamedMedia
    media_classes = [
        rcc for rcc in rccs if rcc[0][cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_CALL
    ]

    assertLength(2, media_classes)

    for media_class in media_classes:
        fixed, allowed = media_class

        assertEquals(cs.HT_CONTACT, fixed[cs.TARGET_HANDLE_TYPE])
        assert fixed.has_key(cs.CALL_INITIAL_AUDIO) or fixed.has_key(
            cs.CALL_INITIAL_VIDEO)

        expected_allowed = [
            cs.TARGET_ID,
            cs.TARGET_HANDLE,
            cs.CALL_INITIAL_VIDEO,
            cs.CALL_INITIAL_AUDIO,
            cs.CALL_INITIAL_VIDEO_NAME,
            cs.CALL_INITIAL_AUDIO_NAME,
            cs.CALL_INITIAL_TRANSPORT,
            cs.DTMF_INITIAL_TONES,
        ]

        allowed.sort()
        expected_allowed.sort()
        assertSameSets(expected_allowed, allowed)
Esempio n. 15
0
def test_jabber_pass_fail(q, bus, conn, stream, which):
    conn.Connect()

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

    e = q.expect('auth-initial-iq')
    authenticator = e.authenticator
    authenticator.respondToInitialIq(e.iq)

    chan, props = expect_sasl_channel(q, bus, conn)

    assertSameSets(['X-TELEPATHY-PASSWORD'],
                   props.get(cs.SASL_AVAILABLE_MECHANISMS))

    chan.SASLAuthentication.StartMechanismWithData('X-TELEPATHY-PASSWORD',
                                                   PASSWORD)

    e = q.expect('auth-second-iq')

    result = IQ(stream, 'error')
    result['id'] = e.id
    error = result.addElement('error')
    error['code'] = str(CODES[which])
    error['type'] = TYPES[which]
    error.addElement((ns.STANZA, which))
    stream.send(result)

    e = q.expect('dbus-signal',
                 signal='SASLStatusChanged',
                 interface=cs.CHANNEL_IFACE_SASL_AUTH,
                 predicate=lambda e: e.args[0] == cs.SASL_STATUS_SERVER_FAILED)
    assertEquals(ERRORS[which], e.args[1])
    assertContains('debug-message', e.args[2])

    e = q.expect('dbus-signal', signal='ConnectionError')
    assertEquals(ERRORS[which], e.args[0])
    assertContains('debug-message', e.args[1])

    e = q.expect('dbus-signal', signal='StatusChanged')
    assertEquals(cs.CONN_STATUS_DISCONNECTED, e.args[0])
    assertEquals(CSRS[which], e.args[1])
def complete_search2(q, bus, conn, stream):
    # uses other, dataform specific, fields
    fields = [('given', 'text-single', 'Name', []),
        ('family', 'text-single', 'Family Name', []),
        ('nickname', 'text-single', 'Nickname', [])]

    expected_search_keys = ['nickname', 'x-n-family', 'x-n-given']

    terms = { 'x-n-family': 'Threepwood' }

    g_results = { 'jid': g_jid, 'given': 'Guybrush', 'family': 'Threepwood',
        'nickname': 'Fancy Pants', 'email': g_jid }
    f_results = { 'jid': f_jid, 'given': 'Frederick', 'family': 'Threepwood',
        'nickname': 'Freddie', 'email': f_jid }

    results = { g_jid: g_results, f_jid: f_results }

    search_fields, chan, c_search, c_props = do_one_search (q, bus, conn, stream,
        fields, expected_search_keys, terms, results.values())

    assert len(search_fields) == 1
    assert ('family', 'Threepwood') in search_fields, search_fields

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

    assertSameSets(results.keys(), infos.keys())

    for id in results.keys():
        i = infos[id]
        r = results[id]
        i_ = pformat(unwrap(i))
        assert ("n", [], [r['family'], r['given'], "", "", ""])    in i, i_
        assert ("nickname", [], [r['nickname']]) in i, i_
        assert ("email", [], [r['email']]) in i, i_
        assert ("x-n-family", [], [r['family']]) in i, i_
        assert ("x-n-given", [], [r['given']]) in i, i_

        assert len(i) == 5, i_

    search_done(q, chan, c_search, c_props)
def test2(q, bus, conn, stream):
    marco_pidgin = '[email protected]/Pidgin'
    marco_phone = '[email protected]/N900'
    handle = conn.get_contact_handle_sync(marco_pidgin)

    # pidgin comes online
    contact_online(q, conn, stream, marco_pidgin, PC)

    types = get_client_types(conn, handle)
    assertSameSets(['pc'], types)

    # phone comes online
    contact_online(q, conn, stream, marco_phone, PHONE, initial=False)

    types = get_client_types(conn, handle)
    assertSameSets(['pc'], types)

    sync_stream(q, stream)

    # pidgin goes offline
    stream.send(make_presence(marco_pidgin, type='unavailable'))

    # no presence signal

    q.expect('dbus-signal',
             signal='ClientTypesUpdated',
             args=[handle, ['phone']])

    # pidgin comes back online
    caps, _, _ = build_stuff(PC)
    stream.send(make_presence(marco_pidgin, status='hello', caps=caps))

    q.expect('dbus-signal', signal='ClientTypesUpdated', args=[handle, ['pc']])

    attrs = conn.Contacts.GetContactAttributes([handle],
                                               [cs.CONN_IFACE_CLIENT_TYPES],
                                               False)
    assertContains(handle, attrs)
    attr = cs.CONN_IFACE_CLIENT_TYPES + '/client-types'
    assertContains(attr, attrs[handle])
    assertEquals(['pc'], attrs[handle][attr])
Esempio n. 18
0
def test_jabber_pass_fail(q, bus, conn, stream, which):
    conn.Connect()

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

    e = q.expect('auth-initial-iq')
    authenticator = e.authenticator
    authenticator.respondToInitialIq(e.iq)

    chan, props = expect_sasl_channel(q, bus, conn)

    assertSameSets(['X-TELEPATHY-PASSWORD'],
            props.get(cs.SASL_AVAILABLE_MECHANISMS))

    chan.SASLAuthentication.StartMechanismWithData('X-TELEPATHY-PASSWORD',
            PASSWORD)

    e = q.expect('auth-second-iq')

    result = IQ(stream, 'error')
    result['id'] = e.id
    error = result.addElement('error')
    error['code'] = str(CODES[which])
    error['type'] = TYPES[which]
    error.addElement((ns.STANZA, which))
    stream.send(result)

    e = q.expect('dbus-signal', signal='SASLStatusChanged',
             interface=cs.CHANNEL_IFACE_SASL_AUTH,
             predicate=lambda e: e.args[0] == cs.SASL_STATUS_SERVER_FAILED)
    assertEquals(ERRORS[which], e.args[1])
    assertContains('debug-message', e.args[2])

    e = q.expect('dbus-signal', signal='ConnectionError')
    assertEquals(ERRORS[which], e.args[0])
    assertContains('debug-message', e.args[1])

    e = q.expect('dbus-signal', signal='StatusChanged')
    assertEquals(cs.CONN_STATUS_DISCONNECTED, e.args[0])
    assertEquals(CSRS[which], e.args[1])
Esempio n. 19
0
def test2(q, bus, conn, stream):
    marco_pidgin = '[email protected]/Pidgin'
    marco_phone = '[email protected]/N900'
    handle = conn.get_contact_handle_sync(marco_pidgin)

    # pidgin comes online
    contact_online(q, conn, stream, marco_pidgin, PC)

    types = get_client_types(conn, handle)
    assertSameSets(['pc'], types)

    # phone comes online
    contact_online(q, conn, stream, marco_phone, PHONE, initial=False)

    types = get_client_types(conn, handle)
    assertSameSets(['pc'], types)

    sync_stream(q, stream)

    # pidgin goes offline
    stream.send(make_presence(marco_pidgin, type='unavailable'))

    # no presence signal

    q.expect('dbus-signal', signal='ClientTypesUpdated',
             args=[handle, ['phone']])

    # pidgin comes back online
    caps, _, _ = build_stuff(PC)
    stream.send(make_presence(marco_pidgin, status='hello', caps=caps))

    q.expect('dbus-signal', signal='ClientTypesUpdated',
             args=[handle, ['pc']])

    attrs = conn.Contacts.GetContactAttributes([handle],
        [cs.CONN_IFACE_CLIENT_TYPES], False)
    assertContains(handle, attrs)
    attr = cs.CONN_IFACE_CLIENT_TYPES + '/client-types'
    assertContains(attr, attrs[handle])
    assertEquals(['pc'], attrs[handle][attr])
Esempio n. 20
0
def test(q, bus, conn, stream):
    conn.Connect()

    # bob is offline
    jid = '*****@*****.**'

    event = q.expect('stream-iq', query_ns=ns.ROSTER)

    event.stanza['type'] = 'result'

    item = event.query.addElement('item')
    item['jid'] = jid
    item['subscription'] = 'from'

    stream.send(event.stanza)

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

    bob_handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0]

    # new ContactCapabilities
    ccaps_map = conn.ContactCapabilities.GetContactCapabilities([bob_handle])
    assertLength(1, ccaps_map)

    assertLength(1, ccaps_map[bob_handle])

    fixed, allowed = ccaps_map[bob_handle][0]

    assertEquals({cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
                  cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT}, fixed)
    assertSameSets([cs.TARGET_HANDLE], allowed)

    # old Capabilities
    all_caps = conn.Capabilities.GetCapabilities([bob_handle])
    assertLength(1, all_caps)

    caps = all_caps[0]

    assertEquals((bob_handle, cs.CHANNEL_TYPE_TEXT, 3, 0), caps)
Esempio n. 21
0
def test_jabber_pass_success(q, bus, conn, stream):
    conn.Connect()

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

    e = q.expect('auth-initial-iq')
    authenticator = e.authenticator
    authenticator.respondToInitialIq(e.iq)

    chan, props = expect_sasl_channel(q, bus, conn)

    assertSameSets(['X-TELEPATHY-PASSWORD'],
                   props.get(cs.SASL_AVAILABLE_MECHANISMS))

    chan.SASLAuthentication.StartMechanismWithData('X-TELEPATHY-PASSWORD',
                                                   PASSWORD)

    e = q.expect('auth-second-iq')
    authenticator.respondToSecondIq(e.iq)

    q.expect('dbus-signal',
             signal='SASLStatusChanged',
             interface=cs.CHANNEL_IFACE_SASL_AUTH,
             args=[cs.SASL_STATUS_SERVER_SUCCEEDED, '', {}])

    chan.SASLAuthentication.AcceptSASL()

    q.expect('dbus-signal',
             signal='SASLStatusChanged',
             interface=cs.CHANNEL_IFACE_SASL_AUTH,
             args=[cs.SASL_STATUS_SUCCEEDED, '', {}])

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

    # bob is offline
    jid = '*****@*****.**'

    event = q.expect('stream-iq', query_ns=ns.ROSTER)

    event.stanza['type'] = 'result'

    item = event.query.addElement('item')
    item['jid'] = jid
    item['subscription'] = 'from'

    stream.send(event.stanza)

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

    bob_handle = conn.get_contact_handle_sync(jid)

    # new ContactCapabilities
    ccaps_map = get_contacts_capabilities_sync(conn, [bob_handle])
    assertLength(1, ccaps_map)

    assertLength(1, ccaps_map[bob_handle])

    fixed, allowed = ccaps_map[bob_handle][0]

    assertEquals(
        {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT
        }, fixed)
    assertSameSets([cs.TARGET_HANDLE], allowed)
def openfire_search(q, bus, conn, stream):
    # Openfire only supports one text field and a bunch of checkboxes
    fields = [('search', 'text-single', 'Search', []),
        ('Username', 'boolean', 'Username', []),
        ('Name', 'boolean', 'Name', []),
        ('Email', 'boolean', 'Email', [])]

    expected_search_keys = ['']

    terms = { '': '*badger*' }

    jid = '*****@*****.**'
    results = {jid : { 'jid': jid, 'Name': 'Badger Badger', 'Email': jid, 'Username': '******'}}

    search_fields, chan, c_search, c_props = do_one_search (q, bus, conn, stream,
        fields, expected_search_keys, terms, results.values())

    assert len(search_fields) == 4
    assert ('search', '*badger*') in search_fields, search_fields
    assert ('Username', '1') in search_fields, search_fields
    assert ('Name', '1') in search_fields, search_fields
    assert ('Email', '1') in search_fields, search_fields

    r = q.expect('dbus-signal', signal='SearchResultReceived')
    infos = r.args[0]

    assertSameSets(results.keys(), infos.keys())

    for id in results.keys():
        i = infos[id]
        r = results[id]
        i_ = pformat(unwrap(i))
        assert ("fn", [], [r['Name']]) in i, i_
        assert ("email", [], [r['Email']]) in i, i_

        assert len(i) == 2
def test(q, bus, conn, stream):
    conn.Connect()

    # This test can't be exactly like Gabble's because libpurple doesn't
    # signal that it's connected until it receives a roster; as a result,
    # the publish and subscribe channels already exist on startup.

    q.expect_many(
        EventPattern('dbus-signal',
                     signal='StatusChanged',
                     args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]),
        EventPattern('stream-authenticated'),
    )

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

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    group = item.addElement('group', content='3 letter names')

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'from'
    group = item.addElement('group', content='3 letter names')

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'to'

    stream.send(event.stanza)

    _, s, _ = q.expect_many(
        EventPattern('dbus-signal',
                     signal='StatusChanged',
                     args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]),
        EventPattern('dbus-signal',
                     signal='ContactsChanged',
                     interface=cs.CONN_IFACE_CONTACT_LIST,
                     path=conn.object_path),
        EventPattern('dbus-signal',
                     signal='ContactListStateChanged',
                     args=[cs.CONTACT_LIST_STATE_SUCCESS]),
    )

    amy, bob, chris = conn.get_contact_handles_sync(
        ['*****@*****.**', '*****@*****.**', '*****@*****.**'])

    # Amy, Bob and Chris are all stored on our server-side roster.
    #
    # Everyone on our roster is (falsely!) alleged to have subscribe=YES
    # (in fact this ought to be just Amy and Chris, because we're publishing
    # presence to Bob without being subscribed to his presence, but libpurple
    # apparently can't represent this).
    #
    # The publish value is unknown, because libpurple doesn't have
    # state-recovery.
    assertEquals([{
        amy: (cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_UNKNOWN, ''),
        bob: (cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_UNKNOWN, ''),
        chris: (cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_UNKNOWN, ''),
    }, []], s.args)

    # the XMPP prpl puts people into some sort of group, probably called
    # Buddies
    groups = conn.Properties.Get(cs.CONN_IFACE_CONTACT_GROUPS, 'Groups')
    default_group = None

    for group in groups:
        if group == '3 letter names':
            continue

        if default_group is not None:
            raise AssertionError('Two unexplained groups: %s, %s' %
                                 (group, default_group))

        default_group = group

    call_async(q, conn.ContactList, 'GetContactListAttributes',
               [cs.CONN_IFACE_CONTACT_GROUPS], False)
    r = q.expect('dbus-return', method='GetContactListAttributes')

    assertEquals(cs.SUBSCRIPTION_STATE_YES, r.value[0][amy][cs.ATTR_SUBSCRIBE])
    assertEquals(cs.SUBSCRIPTION_STATE_YES, r.value[0][bob][cs.ATTR_SUBSCRIBE])
    assertEquals(cs.SUBSCRIPTION_STATE_YES,
                 r.value[0][chris][cs.ATTR_SUBSCRIBE])

    assertEquals(cs.SUBSCRIPTION_STATE_UNKNOWN,
                 r.value[0][amy][cs.ATTR_PUBLISH])
    assertEquals(cs.SUBSCRIPTION_STATE_UNKNOWN,
                 r.value[0][bob][cs.ATTR_PUBLISH])
    assertEquals(cs.SUBSCRIPTION_STATE_UNKNOWN,
                 r.value[0][chris][cs.ATTR_PUBLISH])

    assertSameSets(['3 letter names'], r.value[0][amy][cs.ATTR_GROUPS])
    assertSameSets(['3 letter names'], r.value[0][bob][cs.ATTR_GROUPS])
    assertSameSets([default_group], r.value[0][chris][cs.ATTR_GROUPS])
def test(q, bus, conn, stream):
    event = q.expect('stream-iq', query_ns=ns.ROSTER)
    event.stanza['type'] = 'result'

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    item.addElement('group', content='women')
    item.addElement('group', content='affected-by-fdo-12791')

    # This is a broken roster - Amy appears twice. This should only happen
    # if the server is somehow buggy. This was my initial attempt at
    # reproducing fd.o #12791 - I doubt it's very realistic, but we shouldn't
    # assert, regardless of what input we get!
    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    item.addElement('group', content='women')

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'from'
    item.addElement('group', content='men')

    # This is what was *actually* strange about the #12791 submitter's roster -
    # Bob appears, fully subscribed, but also there's an attempt to subscribe
    # to one of Bob's resources. We now ignore such items
    item = event.query.addElement('item')
    item['jid'] = '[email protected]/Resource'
    item['subscription'] = 'none'
    item['ask'] = 'subscribe'

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'to'
    item.addElement('group', content='men')

    stream.send(event.stanza)

    contacts = [
        ('*****@*****.**', cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_YES,
         ''),
        ('*****@*****.**', cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_YES,
         ''),
        ('*****@*****.**', cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_NO,
         ''),
    ]

    q.expect_many(
        EventPattern(
            'dbus-signal',
            signal='ContactsChangedWithID',
            predicate=lambda e: contacts_changed_predicate(e, conn, contacts)),
        EventPattern('dbus-signal',
                     signal='GroupsCreated',
                     predicate=lambda e: groups_created_predicate(
                         e, ['women', 'men', 'affected-by-fdo-12791'])),
    )

    contacts = conn.ContactList.GetContactListAttributes(
        [cs.CONN_IFACE_CONTACT_GROUPS], False)
    assertLength(3, contacts)

    check_contact_roster(conn, '*****@*****.**', ['women'])
    check_contact_roster(conn, '*****@*****.**', ['men'])
    check_contact_roster(conn, '*****@*****.**', ['men'])

    groups = conn.Properties.Get(cs.CONN_IFACE_CONTACT_GROUPS, 'Groups')
    assertSameSets(['men', 'women', 'affected-by-fdo-12791'], groups)
Esempio n. 26
0
def test(q, bus, conn, stream):
    client = 'http://telepathy.freedesktop.org/fake-client'
    contact = '[email protected]/Resource'
    files = [("file", "File.txt", 12345, False),
             ("file", "Image.txt", 54321, True),
             ("folder", "Folder", 123, False),
             ("folder", "Folder no size", None, True)]

    test_ft_caps_from_contact(q, bus, conn, stream, contact, 2L, client)

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

    iq = IQ(stream, "set")
    iq['to'] = jid
    iq['from'] = contact
    session = iq.addElement("session", "http://www.google.com/session")
    session['type'] = "initiate"
    session['id'] = "2156517633"
    session['initiator'] = contact
    session.addElement("transport", "http://www.google.com/transport/p2p")
    description = session.addElement("description",
                                     "http://www.google.com/session/share")

    manifest = description.addElement("manifest")
    for f in files:
        type, name, size, image = f
        file = manifest.addElement(type)
        if size is not None:
            file['size'] = str(size)
        file.addElement("name", None, name)
        if image:
            image = file.addElement("image")
            image['width'] = '1200'
            image['height'] = '1024'

    protocol = description.addElement("protocol")
    http = protocol.addElement("http")
    url = http.addElement("url", None, "/temporary/ade15194140cf7b7bceafe/")
    url['name'] = 'source-path'
    url = http.addElement("url", None, "/temporary/578d715be25ddc28870d3f/")
    url['name'] = 'preview-path'

    stream.send(iq)

    patterns = []
    found = {}

    def get_predicate(name, found, i):
        # This needs to be a function so that name, found, i
        # are part of a closure.

        # /!\ This predicate has side-effects: it writes to 'found'
        def predicate(e):
            path, props = e.args[0][0]
            if props[cs.CHANNEL_TYPE] != cs.CHANNEL_TYPE_FILE_TRANSFER:
                return False

            if props[cs.FT_FILENAME] == name:
                found[i] = (path, props)
                return True

        return predicate

    for i, f in enumerate(files):
        type, name, size, image = f
        if type == "folder":
            name = "%s.tar" % name

            return False

        patterns.append(
            EventPattern('dbus-signal',
                         signal='NewChannels',
                         predicate=get_predicate(name, found, i)))

    # Make sure every file transfer has a channel associated with it
    file_collection = None
    q.expect_many(*patterns)
    assertLength(len(files), found)

    channels = []
    for i in found:
        assert found[i] is not None
        path, props = found[i]
        channels.append((path, props))

        # Get the FileCollection and make sure it exists
        if file_collection is None:
            file_collection = props[cs.FT_FILE_COLLECTION]
            assert file_collection != ''
        assert file_collection is not None

        # FileCollection must be the same for every channel
        assert props[cs.FT_FILE_COLLECTION] == file_collection, props

        type, name, size, image = files[i]
        if size is None:
            size = 0

        assertEquals(size, props[cs.FT_SIZE])

        assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER, props
        assertSameSets([
            cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA,
        ], props[cs.INTERFACES])
        assert props[cs.TARGET_HANDLE] == 2L, props
        assert props[cs.TARGET_ID] == contact.replace("/Resource", ""), props
        assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_CONTACT, props
        assert props[cs.REQUESTED] == False, props
        assert props[cs.INITIATOR_HANDLE] == 2L, props
        assert props[cs.INITIATOR_ID] == contact.replace("/Resource",
                                                         ""), props
        assert props[cs.FT_STATE] == cs.FT_STATE_PENDING, props
        assert props[cs.FT_CONTENT_TYPE] == '', props
        # FT's protocol doesn't allow us the send the hash info
        assert props[cs.FT_CONTENT_HASH_TYPE] == cs.FILE_HASH_TYPE_NONE, props
        assert props[cs.FT_CONTENT_HASH] == '', props
        assert props[cs.FT_DESCRIPTION] == '', props
        assert props[cs.FT_DATE] == 0, props
        assert props[cs.FT_AVAILABLE_SOCKET_TYPES] == \
            {cs.SOCKET_ADDRESS_TYPE_UNIX: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST],
            cs.SOCKET_ADDRESS_TYPE_IPV4: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST],
            cs.SOCKET_ADDRESS_TYPE_IPV6: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST]}, \
            props[cs.FT_AVAILABLE_SOCKET_TYPES]
        assert props[cs.FT_TRANSFERRED_BYTES] == 0, props
        assert props[cs.FT_INITIAL_OFFSET] == 0, props

    event = q.expect('stream-iq',
                     to=contact,
                     iq_type='set',
                     query_name='session')
    session_node = event.query
    assert session_node.attributes['type'] == 'transport-accept'

    # Close all but one of the channels, and make sure Gabble doesn't cancel
    # the multi-FT yet.
    terminate_pattern = EventPattern(
        'stream-iq',
        to=contact,
        iq_type='set',
        query_name='session',
        predicate=lambda event: event.query['type'] == 'terminate')

    q.forbid_events([terminate_pattern])

    for path, props in channels[:-1]:
        ft_chan = bus.get_object(conn.object.bus_name, path)
        channel = dbus.Interface(ft_chan, cs.CHANNEL)
        channel.Close()
        q.expect('dbus-signal', signal='Closed', path=path)

    sync_stream(q, stream)
    q.unforbid_all()

    # Now close the final channel, and make sure Gabble terminates the session.
    last_path, props = channels[-1]

    ft_chan = bus.get_object(conn.object.bus_name, last_path)
    channel = dbus.Interface(ft_chan, cs.CHANNEL)
    channel.Close()

    q.expect_many(terminate_pattern)
Esempio n. 27
0
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({})
Esempio n. 28
0
def test_complex_success(q,
                         bus,
                         conn,
                         stream,
                         with_extra_data=True,
                         accept_early=False):
    chan, props = connect_and_get_sasl_channel(q, bus, conn)

    assertSameSets(MECHANISMS + ['X-TELEPATHY-PASSWORD'],
                   props.get(cs.SASL_AVAILABLE_MECHANISMS))

    call_async(q, chan.SASLAuthentication, 'StartMechanismWithData', "FOO", "")
    q.expect('dbus-error',
             method='StartMechanismWithData',
             name=cs.NOT_IMPLEMENTED)

    if with_extra_data:
        chan.SASLAuthentication.StartMechanismWithData("SCOTTISH-PLAY",
                                                       INITIAL_RESPONSE)
        e = q.expect('sasl-auth', initial_response=INITIAL_RESPONSE)
    else:
        chan.SASLAuthentication.StartMechanism("SCOTTISH-PLAY")
        e = q.expect('sasl-auth', has_initial_response=False)

    authenticator = e.authenticator

    q.expect('dbus-signal',
             signal='SASLStatusChanged',
             interface=cs.CHANNEL_IFACE_SASL_AUTH,
             args=[cs.SASL_STATUS_IN_PROGRESS, '', {}])

    if not with_extra_data:
        # send the stage directions in-band instead
        authenticator.challenge('')
        e = q.expect('dbus-signal',
                     signal='NewChallenge',
                     interface=cs.CHANNEL_IFACE_SASL_AUTH)
        # this ought to be '' but dbus-python has fd.o #28131
        assert e.args in ([''], ['None'])
        chan.SASLAuthentication.Respond(INITIAL_RESPONSE)
        q.expect('sasl-response', response=INITIAL_RESPONSE)

    for challenge, response in CR_PAIRS:
        authenticator.challenge(challenge)
        q.expect('dbus-signal',
                 signal='NewChallenge',
                 interface=cs.CHANNEL_IFACE_SASL_AUTH,
                 args=[challenge])
        chan.SASLAuthentication.Respond(response)
        q.expect('sasl-response', response=response)

    if with_extra_data:
        authenticator.success(SUCCESS_DATA)
    else:
        # The success data is sent in-band as a challenge
        authenticator.challenge(SUCCESS_DATA)

    q.expect('dbus-signal',
             signal='NewChallenge',
             interface=cs.CHANNEL_IFACE_SASL_AUTH,
             args=[SUCCESS_DATA])

    if accept_early:
        # the UI can tell that this challenge isn't actually a challenge,
        # it's a success in disguise
        chan.SASLAuthentication.AcceptSASL()
        q.expect('dbus-signal',
                 signal='SASLStatusChanged',
                 interface=cs.CHANNEL_IFACE_SASL_AUTH,
                 args=[cs.SASL_STATUS_CLIENT_ACCEPTED, '', {}])
    else:
        chan.SASLAuthentication.Respond(dbus.ByteArray(''))

    if with_extra_data:
        # Wocky removes the distinction between a challenge containing
        # success data followed by a plain success, and a success
        # containing initial data, so we won't get to Server_Succeeded
        # til we "respond" to the "challenge". However, at the XMPP level,
        # we shouldn't get a response to a success.
        q.forbid_events([EventPattern('sasl-response')])
    else:
        q.expect('sasl-response', response='')
        authenticator.success(None)

    if not accept_early:
        # *now* we accept
        q.expect('dbus-signal',
                 signal='SASLStatusChanged',
                 interface=cs.CHANNEL_IFACE_SASL_AUTH,
                 args=[cs.SASL_STATUS_SERVER_SUCCEEDED, '', {}])
        # We're willing to accept this SASL transaction
        chan.SASLAuthentication.AcceptSASL()

    q.expect('dbus-signal',
             signal='SASLStatusChanged',
             interface=cs.CHANNEL_IFACE_SASL_AUTH,
             args=[cs.SASL_STATUS_SUCCEEDED, '', {}])

    q.expect('dbus-signal',
             signal='StatusChanged',
             args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
    chan.Close()
    # ... and check that the Connection is still OK
    conn.Properties.Get(cs.CONN, "SelfHandle")
def test(q, bus, conn):

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

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

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

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

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

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

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

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

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

    path, props = channels[0]

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

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

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

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

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

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

    tube_addr1 = e.value[0]

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

    check_dbus_names(contact1_tube, [conn1_self_handle])

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

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

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

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

    path, props = channels[0]

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

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

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

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

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

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

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

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

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

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

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

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

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

    obj1 = Test(tube_conn1, q)

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

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

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

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

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

    def my_method_error(e):
        assert False, e

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

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

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

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

    check_dbus_names(contact2_tube, [conn2_self_handle])

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

    conn.Disconnect()
    conn2.Disconnect()
Esempio n. 30
0
def test(q, bus, mc):
    params = dbus.Dictionary ({"account": "*****@*****.**",
                               "password": "******"},
                              signature='sv')
    (simulated_cm, account) = create_fakecm_account (q, bus, mc, params)

    account_iface = dbus.Interface (account, cs.ACCOUNT)
    account_props = dbus.Interface (account, cs.PROPERTIES_IFACE)
    address_iface = dbus.Interface (account, cs.ACCOUNT_IFACE_ADDRESSING)

    uri_schemes = get_schemes (account_props)

    # initial URI scheme list is empty
    assertEquals (uri_schemes, [])

    # remove URI from empty list:
    address_iface.SetURISchemeAssociation ('mailto', False)
    uri_schemes = get_schemes (account_props)
    assertEquals (uri_schemes, [])

    # add association to empty list
    address_iface.SetURISchemeAssociation ('mailto', True)
    uri_schemes = get_schemes (account_props)
    assertEquals (uri_schemes, ['mailto'])

    # add association to list where it already resides
    address_iface.SetURISchemeAssociation ('mailto', True)
    uri_schemes = get_schemes (account_props)
    assertEquals (uri_schemes, ['mailto'])

    q.expect('dbus-signal', signal='PropertiesChanged',
        predicate=(lambda e:
            e.args[0] == cs.ACCOUNT_IFACE_ADDRESSING and
            set(e.args[1]['URISchemes']) == set(['mailto'])))

    # add a second association
    address_iface.SetURISchemeAssociation ('telnet', True)
    uri_schemes = get_schemes (account_props)
    assertSameSets (['mailto','telnet',], uri_schemes)

    q.expect('dbus-signal', signal='PropertiesChanged',
        predicate=(lambda e:
            e.args[0] == cs.ACCOUNT_IFACE_ADDRESSING and
            set(e.args[1]['URISchemes']) == set(['telnet', 'mailto'])))

    # remove associations to produce empty list
    address_iface.SetURISchemeAssociation ('mailto', False)
    address_iface.SetURISchemeAssociation ('telnet', False)
    uri_schemes = get_schemes (account_props)
    assertEquals (uri_schemes, [])

    # extend list to 3 schemes, with some redundant additions:
    address_iface.SetURISchemeAssociation ('scheme-a', True)
    address_iface.SetURISchemeAssociation ('scheme-b', True)
    address_iface.SetURISchemeAssociation ('scheme-c', True)
    address_iface.SetURISchemeAssociation ('scheme-a', True)
    address_iface.SetURISchemeAssociation ('scheme-c', True)
    uri_schemes = get_schemes (account_props)
    assertSameSets (['scheme-a','scheme-b','scheme-c'], uri_schemes)

    # remove a scheme that's not there from a non-empty list
    address_iface.SetURISchemeAssociation ('scheme-d', False)
    uri_schemes = get_schemes (account_props)
    assertSameSets (['scheme-a','scheme-b','scheme-c'], uri_schemes)

    # remove one that is there:
    address_iface.SetURISchemeAssociation ('scheme-b', False)
    uri_schemes = get_schemes (account_props)
    assertSameSets (['scheme-a','scheme-c'], uri_schemes)
Esempio n. 31
0
def test_gtalk_weirdness(q, bus, conn, stream, room_jid):
    """
    There's a strange bug in the Google Talk MUC server where it sends the
    <conflict/> stanza twice. This has been reported to their server team; but
    in any case it triggered a crazy bug in Gabble, so here's a regression test.
    """

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

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

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

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

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

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

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

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

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

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

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

    group_props = text_chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP)
    assertEquals(handle_, group_props['SelfHandle'])
    assertSameSets([handle, handle_, foobar_handle], group_props['Members'])
Esempio n. 32
0
def test_connection(q, bus, conn, stream):
    event = q.expect('stream-iq', query_ns=ns.ROSTER)
    event.stanza['type'] = 'result'

    normalized_buddies = ['*****@*****.**', '*****@*****.**', '*****@*****.**']
    buddies = ['*****@*****.**', '*****@*****.**', '[email protected]/resource']

    for buddy in normalized_buddies:
        item = event.query.addElement('item')
        item['jid'] = buddy
        item['subscription'] = 'both'

    stream.send(event.stanza)

    requested, attributes = conn.Addressing.GetContactsByVCardField(
        "X-JABBER", buddies[:2] + ['bad!jid'] + buddies[2:], [])

    addresses = []

    assertEquals(3, len(attributes))
    assertEquals(3, len(requested))

    for attr in attributes.values():
        assertContains(cs.CONN_IFACE_ADDRESSING + '/addresses', attr.keys())
        assertContains('x-jabber', attr[cs.CONN_IFACE_ADDRESSING + '/addresses'].keys())
        addresses.append(attr[cs.CONN_IFACE_ADDRESSING + '/addresses']['x-jabber'])

    assertSameSets(normalized_buddies, addresses)
    assertSameSets(buddies, requested.keys());

    normalized_buddies = ['12345', '54321']
    buddies = ['12345', '54321']
    bad_jid_buddies = ['-12345!CHAT.facebook.com', '*****@*****.**']

    for buddy in buddies:
        item = event.query.addElement('item')
        item['jid'] = buddy
        item['subscription'] = 'both'

    stream.send(event.stanza)

    requested, attributes = conn.Addressing.GetContactsByVCardField(
        "X-FACEBOOK-ID", buddies + bad_jid_buddies, [])

    addresses = []

    for attr in attributes.values():
        assertContains(cs.CONN_IFACE_ADDRESSING + '/addresses', attr.keys())
        assertContains('x-facebook-id', attr[cs.CONN_IFACE_ADDRESSING + '/addresses'].keys())
        addr = attr[cs.CONN_IFACE_ADDRESSING + '/addresses']['x-facebook-id']
        addresses.append(addr)
        assertEquals(attr[cs.CONN + '/contact-id'], "-" + addr + "@chat.facebook.com")

    assertSameSets(normalized_buddies, addresses)
    assertSameSets(buddies, requested.keys());

    normalized_buddies = ['*****@*****.**', '*****@*****.**', '*****@*****.**']
    buddies = ['[email protected]', '*****@*****.**', '[email protected]/resource']

    normalized_schemes = ["xmpp", "xmpp", "http"]
    schemes = ["xmpp", "XMPP", "http"]
    valid_schemes = ["xmpp", "XMPP"]

    request_uris = [a + ":" + b for a, b in zip(schemes, buddies)]
    valid_request_uris = [a + ":" + b for a, b in zip(valid_schemes, buddies)]
    normalized_request_uris = [a + ":" + b for a, b in zip(normalized_schemes, normalized_buddies)]

    requested, attributes = conn.Addressing.GetContactsByURI(request_uris, [])

    assertEquals(2, len(attributes))
    assertEquals(2, len(requested))

    for attr in attributes.values():
        assertContains(attr[cs.CONN_IFACE_ADDRESSING + '/uris'][0], normalized_request_uris)
        assertContains(cs.CONN_IFACE_ADDRESSING + '/uris', attr.keys())

    assertSameSets(valid_request_uris, requested.keys())
def test_gtalk_weirdness(q, bus, conn, stream, room_jid):
    """
    There's a strange bug in the Google Talk MUC server where it sends the
    <conflict/> stanza twice. This has been reported to their server team; but
    in any case it triggered a crazy bug in Gabble, so here's a regression test.
    """

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

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

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

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

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

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

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

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

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

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

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

    group_props = text_chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP)
    assertEquals(handle_, group_props['SelfHandle'])
    assertSameSets([handle, handle_, foobar_handle], group_props['Members'])
    def request_ft_channel(self):
        self.ft_path, props = self.conn.Requests.CreateChannel({
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_FILE_TRANSFER,
            cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
            cs.TARGET_HANDLE: self.handle,
            cs.FT_CONTENT_TYPE: self.file.content_type,
            cs.FT_FILENAME: self.file.name,
            cs.FT_SIZE: self.file.size,
            cs.FT_CONTENT_HASH_TYPE: self.file.hash_type,
            cs.FT_CONTENT_HASH: self.file.hash,
            cs.FT_DESCRIPTION: self.file.description,
            cs.FT_DATE:  self.file.date,
            cs.FT_INITIAL_OFFSET: 0,
            })

        # org.freedesktop.Telepathy.Channel D-Bus properties
        assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER
        assertSameSets(
            [ cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA,
            ], props[cs.INTERFACES])
        assert props[cs.TARGET_HANDLE] == self.handle
        assert props[cs.TARGET_ID] == self.target
        assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_CONTACT
        assert props[cs.REQUESTED] == True
        assert props[cs.INITIATOR_HANDLE] == self.self_handle
        assert props[cs.INITIATOR_ID] == self.self_handle_name

        # org.freedesktop.Telepathy.Channel.Type.FileTransfer D-Bus properties
        assert props[cs.FT_STATE] == cs.FT_STATE_PENDING
        assert props[cs.FT_CONTENT_TYPE] == self.file.content_type
        assert props[cs.FT_FILENAME].encode('utf-8') == self.file.name, props
        assert props[cs.FT_SIZE] == self.file.size
        assert props[cs.FT_CONTENT_HASH_TYPE] == self.file.hash_type
        assert props[cs.FT_CONTENT_HASH] == self.file.hash
        assert props[cs.FT_DESCRIPTION] == self.file.description
        assert props[cs.FT_DATE] == self.file.date
        assert props[cs.FT_AVAILABLE_SOCKET_TYPES] == \
            {cs.SOCKET_ADDRESS_TYPE_UNIX: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST],
            cs.SOCKET_ADDRESS_TYPE_IPV4: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST],
            cs.SOCKET_ADDRESS_TYPE_IPV6: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST]}, \
            props[cs.FT_AVAILABLE_SOCKET_TYPES]
        assert props[cs.FT_TRANSFERRED_BYTES] == 0
        assert props[cs.FT_INITIAL_OFFSET] == 0

        self.create_ft_channel()

        self.open = False
        self.offset_defined = False

        def initial_offset_defined_cb(offset):
            self.offset_defined = True
            assert offset == 0, offset

        self.ft_channel.connect_to_signal('InitialOffsetDefined',
                                          initial_offset_defined_cb)


        # Make sure the file transfer is of type jingle-share
        event = self.q.expect('stream-iq', stream=self.stream,
                              query_name = 'session',
                              query_ns = ns.GOOGLE_SESSION)
        description_node = xpath.queryForNodes('/iq/session/description',
                                               event.stanza)[0]
        assert description_node.uri == ns.GOOGLE_SESSION_SHARE, \
            description_node.uri
Esempio n. 35
0
    def request_ft_channel(self):
        self.ft_path, props = self.conn.Requests.CreateChannel({
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_FILE_TRANSFER,
            cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
            cs.TARGET_HANDLE: self.handle,
            cs.FT_CONTENT_TYPE: self.file.content_type,
            cs.FT_FILENAME: self.file.name,
            cs.FT_SIZE: self.file.size,
            cs.FT_CONTENT_HASH_TYPE: self.file.hash_type,
            cs.FT_CONTENT_HASH: self.file.hash,
            cs.FT_DESCRIPTION: self.file.description,
            cs.FT_DATE:  self.file.date,
            cs.FT_INITIAL_OFFSET: 0,
            })

        # org.freedesktop.Telepathy.Channel D-Bus properties
        assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER
        assertSameSets(
            [ cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA,
            ], props[cs.INTERFACES])
        assert props[cs.TARGET_HANDLE] == self.handle
        assert props[cs.TARGET_ID] == self.target
        assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_CONTACT
        assert props[cs.REQUESTED] == True
        assert props[cs.INITIATOR_HANDLE] == self.self_handle
        assert props[cs.INITIATOR_ID] == self.self_handle_name

        # org.freedesktop.Telepathy.Channel.Type.FileTransfer D-Bus properties
        assert props[cs.FT_STATE] == cs.FT_STATE_PENDING
        assert props[cs.FT_CONTENT_TYPE] == self.file.content_type
        assert props[cs.FT_FILENAME] == self.file.name, props
        assert props[cs.FT_SIZE] == self.file.size
        assert props[cs.FT_CONTENT_HASH_TYPE] == self.file.hash_type
        assert props[cs.FT_CONTENT_HASH] == self.file.hash
        assert props[cs.FT_DESCRIPTION] == self.file.description
        assert props[cs.FT_DATE] == self.file.date
        assert props[cs.FT_AVAILABLE_SOCKET_TYPES] == \
            {cs.SOCKET_ADDRESS_TYPE_UNIX: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST],
            cs.SOCKET_ADDRESS_TYPE_IPV4: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST],
            cs.SOCKET_ADDRESS_TYPE_IPV6: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST]}, \
            props[cs.FT_AVAILABLE_SOCKET_TYPES]
        assert props[cs.FT_TRANSFERRED_BYTES] == 0
        assert props[cs.FT_INITIAL_OFFSET] == 0

        self.create_ft_channel()

        self.open = False
        self.offset_defined = False

        def initial_offset_defined_cb(offset):
            self.offset_defined = True
            assert offset == 0, offset

        self.ft_channel.connect_to_signal('InitialOffsetDefined',
                                          initial_offset_defined_cb)


        # Make sure the file transfer is of type jingle-share
        event = self.q.expect('stream-iq', stream=self.stream,
                              query_name = 'session',
                              query_ns = ns.GOOGLE_SESSION)
        description_node = xpath.queryForNodes('/iq/session/description',
                                               event.stanza)[0]
        assert description_node.uri == ns.GOOGLE_SESSION_SHARE, \
            description_node.uri
def test(q, bus, conn, stream):
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    romeo, juliet, duncan = conn.get_contact_handles_sync(
            ['*****@*****.**', '*****@*****.**',
                '*****@*****.**'])

    # receive some roster pushes for the "initial" state
    iq = IQ(stream, 'set')
    iq['id'] = 'roster-push'
    query = iq.addElement(('jabber:iq:roster', 'query'))
    item = query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    group = item.addElement('group', content='Still alive')
    group = item.addElement('group', content='Capulets')
    stream.send(iq)

    iq = IQ(stream, 'set')
    iq['id'] = 'roster-push'
    query = iq.addElement(('jabber:iq:roster', 'query'))
    item = query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    group = item.addElement('group', content='Still alive')
    stream.send(iq)

    iq = IQ(stream, 'set')
    iq['id'] = 'roster-push'
    query = iq.addElement(('jabber:iq:roster', 'query'))
    item = query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    stream.send(iq)

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

    # the XMPP prpl puts people into some sort of group, probably called
    # Buddies
    groups = conn.Properties.Get(cs.CONN_IFACE_CONTACT_GROUPS, 'Groups')
    default_group = None

    for group in groups:
        if group in ('Capulets', 'Still alive'):
            continue

        if default_group is not None:
            raise AssertionError('Two unexplained groups: %s, %s' %
                    (group, default_group))

        default_group = group

    call_async(q, conn.ContactList, 'GetContactListAttributes',
            [cs.CONN_IFACE_CONTACT_GROUPS], False)
    r = q.expect('dbus-return', method='GetContactListAttributes')

    assertSameSets(['Still alive'], r.value[0][romeo][cs.ATTR_GROUPS])
    assertSameSets(['Still alive', 'Capulets'],
            r.value[0][juliet][cs.ATTR_GROUPS])
    assertSameSets([default_group], r.value[0][duncan][cs.ATTR_GROUPS])

    # We can't remove Duncan from the default group, because it's his only
    # group
    call_async(q, conn.ContactGroups, 'RemoveFromGroup', default_group,
            [duncan])
    q.expect('dbus-error', method='RemoveFromGroup',
            name=cs.NOT_AVAILABLE)
    call_async(q, conn.ContactGroups, 'SetGroupMembers', default_group,
            [])
    q.expect('dbus-error', method='SetGroupMembers',
            name=cs.NOT_AVAILABLE)
    # SetContactGroups just doesn't do anything in this situation
    call_async(q, conn.ContactGroups, 'SetContactGroups', duncan, [])
    q.expect('dbus-return', method='SetContactGroups')

    call_async(q, conn.ContactList, 'GetContactListAttributes',
            [cs.CONN_IFACE_CONTACT_GROUPS], False)
    r = q.expect('dbus-return', method='GetContactListAttributes')
    assertSameSets([default_group], r.value[0][duncan][cs.ATTR_GROUPS])

    # Make a new group and add Duncan to it
    call_async(q, conn.ContactGroups, 'AddToGroup', 'Scots', [duncan])
    iq, _, _ = q.expect_many(
            EventPattern('stream-iq', iq_type='set', query_name='query',
                query_ns=ns.ROSTER),
            EventPattern('dbus-signal', signal='GroupsChanged',
                args=[[duncan], ['Scots'], []]),
            EventPattern('dbus-return', method='AddToGroup'),
            )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([str(x) for x in xpath.queryForNodes('/iq/query/item/group',
        iq.stanza)])
    assertLength(2, groups)
    assertContains(default_group, groups)
    assertContains('Scots', groups)

    # Now we can remove him from the default group. Much rejoicing.
    call_async(q, conn.ContactGroups, 'RemoveFromGroup', default_group,
            [duncan])
    iq, _, _ = q.expect_many(
            EventPattern('stream-iq', iq_type='set', query_name='query',
                query_ns=ns.ROSTER),
            EventPattern('dbus-signal', signal='GroupsChanged',
                args=[[duncan], [], [default_group]]),
            EventPattern('dbus-return', method='RemoveFromGroup'),
            )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([str(x) for x in xpath.queryForNodes('/iq/query/item/group',
        iq.stanza)])
    assertLength(1, groups)
    assertContains('Scots', groups)

    # Test SetContactGroups, which didn't previously have proper coverage
    call_async(q, conn.ContactGroups, 'SetContactGroups', duncan,
            ['Scottish former kings'])
    iq, _, _, _ = q.expect_many(
            EventPattern('stream-iq', iq_type='set', query_name='query',
                query_ns=ns.ROSTER),
            EventPattern('dbus-signal', signal='GroupsChanged',
                args=[[duncan], ['Scottish former kings'], []]),
            EventPattern('dbus-signal', signal='GroupsChanged',
                args=[[duncan], [], ['Scots']]),
            EventPattern('dbus-return', method='SetContactGroups'),
            )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([str(x) for x in xpath.queryForNodes('/iq/query/item/group',
        iq.stanza)])
    assertLength(2, groups)
    assertContains('Scots', groups)
    assertContains('Scottish former kings', groups)
    iq, = q.expect_many(
            EventPattern('stream-iq', iq_type='set', query_name='query',
                query_ns=ns.ROSTER),
            )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([str(x) for x in xpath.queryForNodes('/iq/query/item/group',
        iq.stanza)])
    assertLength(1, groups)
    assertContains('Scottish former kings', groups)

    # Romeo dies. If he drops off the roster as a result, that would be
    # fd.o #21294. However, to fix that bug, Haze now puts him in the
    # default group.
    call_async(q, conn.ContactGroups, 'RemoveFromGroup', 'Still alive',
            [romeo])
    iq1, iq2, _, _, _ = q.expect_many(
            EventPattern('stream-iq', iq_type='set', query_name='query',
                query_ns=ns.ROSTER),
            EventPattern('stream-iq', iq_type='set', query_name='query',
                query_ns=ns.ROSTER),
            EventPattern('dbus-signal', signal='GroupsChanged',
                args=[[romeo], [default_group], []]),
            EventPattern('dbus-signal', signal='GroupsChanged',
                args=[[romeo], [], ['Still alive']]),
            EventPattern('dbus-return', method='RemoveFromGroup'),
            )

    assertEquals('*****@*****.**', iq1.stanza.query.item['jid'])
    groups = set([str(x) for x in xpath.queryForNodes('/iq/query/item/group',
        iq1.stanza)])
    assertLength(2, groups)
    assertContains('Still alive', groups)
    assertContains(default_group, groups)

    assertEquals('*****@*****.**', iq2.stanza.query.item['jid'])
    groups = set([str(x) for x in xpath.queryForNodes('/iq/query/item/group',
        iq2.stanza)])
    assertLength(1, groups)
    assertContains(default_group, groups)

    # Juliet dies. She's in another group already, so the workaround for
    # fd.o #21294 is not active.
    call_async(q, conn.ContactGroups, 'SetGroupMembers', 'Still alive', [])
    iq, _, _ = q.expect_many(
            EventPattern('stream-iq', iq_type='set', query_name='query',
                query_ns=ns.ROSTER),
            EventPattern('dbus-signal', signal='GroupsChanged',
                args=[[juliet], [], ['Still alive']]),
            EventPattern('dbus-return', method='SetGroupMembers'),
            )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([str(x) for x in xpath.queryForNodes('/iq/query/item/group',
        iq.stanza)])
    assertLength(1, groups)
    assertContains('Capulets', groups)

    # At the end of a tragedy, everyone dies, so there's no need for this
    # group.
    call_async(q, conn.ContactGroups, 'RemoveGroup', 'Still alive')
    q.expect('dbus-signal', signal='GroupsRemoved', args=[['Still alive']])

    # Deleting a non-empty group is allowed. (It removes everyone.)
    call_async(q, conn.ContactGroups, 'RemoveGroup', 'Capulets')
    q.expect_many(
            EventPattern('dbus-signal', signal='GroupsRemoved',
                args=[['Capulets']]),
            EventPattern('dbus-signal', signal='GroupsChanged',
                args=[[juliet], [default_group], []]),
            EventPattern('dbus-signal', signal='GroupsChanged',
                args=[[juliet], [], ['Capulets']]),
            )
        cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
        cs.TARGET_ID: muc_name,
        cs.STREAM_TUBE_SERVICE: 'test'})

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

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

    path, props = channels[0]
    assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE
    assert props[cs.REQUESTED] == True
    assertSameSets([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE],
            props[cs.INTERFACES])
    assert props[cs.STREAM_TUBE_SERVICE] == 'test'
    assert props[cs.INITIATOR_HANDLE] == conn1_self_handle
    assert props[cs.INITIATOR_ID] == contact1_name
    assert props[cs.TARGET_ID] == muc_name

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

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

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

    call_async(q, contact1_tube.StreamTube, 'Offer',
            SOCKET_ADDRESS_TYPE_UNIX, dbus.ByteArray(server_socket_address),
def test(q, bus, conn, stream, bytestream_cls, address_type, access_control,
         access_control_param):
    if bytestream_cls in [BytestreamS5BRelay, BytestreamS5BRelayBugged]:
        # disable SOCKS5 relay tests because proxy can't be used with muc
        # contacts atm
        return

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

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

    acknowledge_iq(stream, iq_event.stanza)

    announce_socks5_proxy(q, stream, disco_event.stanza)

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

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

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

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

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

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

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

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

    stream.send(presence)

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

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

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

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

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

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

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

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

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

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

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

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

        assert profile == ns.TUBES

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

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

        bytestream.wait_bytestream_open()
        return bytestream

    bytestream = accept_tube_si_connection()

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

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

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

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

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

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

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

    protocol = socket_event.protocol
    bytestream = accept_tube_si_connection()

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

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

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

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

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

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

    # MUC says yes!

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

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

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

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

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

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

    members = group_props['Members']

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

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

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

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

    event = q.expect('stream-presence', to=member_)
    assertEquals('unavailable', event.stanza['type'])
def test(q, bus, conn, stream, use_room=False):
    conn.Connect()
    q.expect_many(
            EventPattern('dbus-signal', signal='StatusChanged', args=[1, 1]),
            EventPattern('irc-connected'))
    q.expect('dbus-signal', signal='SelfHandleChanged')
    q.expect('dbus-signal', signal='StatusChanged', args=[0, 1])

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

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

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

    # Meanwhile, in another application...

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

    sync_dbus(bus, q, conn)

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

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

    path, props = cc.value

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    romeo, juliet, duncan = conn.get_contact_handles_sync(
        ['*****@*****.**', '*****@*****.**', '*****@*****.**'])

    # receive some roster pushes for the "initial" state
    iq = IQ(stream, 'set')
    iq['id'] = 'roster-push'
    query = iq.addElement(('jabber:iq:roster', 'query'))
    item = query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    group = item.addElement('group', content='Still alive')
    group = item.addElement('group', content='Capulets')
    stream.send(iq)

    iq = IQ(stream, 'set')
    iq['id'] = 'roster-push'
    query = iq.addElement(('jabber:iq:roster', 'query'))
    item = query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    group = item.addElement('group', content='Still alive')
    stream.send(iq)

    iq = IQ(stream, 'set')
    iq['id'] = 'roster-push'
    query = iq.addElement(('jabber:iq:roster', 'query'))
    item = query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    stream.send(iq)

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

    # the XMPP prpl puts people into some sort of group, probably called
    # Buddies
    groups = conn.Properties.Get(cs.CONN_IFACE_CONTACT_GROUPS, 'Groups')
    default_group = None

    for group in groups:
        if group in ('Capulets', 'Still alive'):
            continue

        if default_group is not None:
            raise AssertionError('Two unexplained groups: %s, %s' %
                                 (group, default_group))

        default_group = group

    call_async(q, conn.ContactList, 'GetContactListAttributes',
               [cs.CONN_IFACE_CONTACT_GROUPS], False)
    r = q.expect('dbus-return', method='GetContactListAttributes')

    assertSameSets(['Still alive'], r.value[0][romeo][cs.ATTR_GROUPS])
    assertSameSets(['Still alive', 'Capulets'],
                   r.value[0][juliet][cs.ATTR_GROUPS])
    assertSameSets([default_group], r.value[0][duncan][cs.ATTR_GROUPS])

    # We can't remove Duncan from the default group, because it's his only
    # group
    call_async(q, conn.ContactGroups, 'RemoveFromGroup', default_group,
               [duncan])
    q.expect('dbus-error', method='RemoveFromGroup', name=cs.NOT_AVAILABLE)
    call_async(q, conn.ContactGroups, 'SetGroupMembers', default_group, [])
    q.expect('dbus-error', method='SetGroupMembers', name=cs.NOT_AVAILABLE)
    # SetContactGroups just doesn't do anything in this situation
    call_async(q, conn.ContactGroups, 'SetContactGroups', duncan, [])
    q.expect('dbus-return', method='SetContactGroups')

    call_async(q, conn.ContactList, 'GetContactListAttributes',
               [cs.CONN_IFACE_CONTACT_GROUPS], False)
    r = q.expect('dbus-return', method='GetContactListAttributes')
    assertSameSets([default_group], r.value[0][duncan][cs.ATTR_GROUPS])

    # Make a new group and add Duncan to it
    call_async(q, conn.ContactGroups, 'AddToGroup', 'Scots', [duncan])
    iq, _, _ = q.expect_many(
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[duncan], ['Scots'], []]),
        EventPattern('dbus-return', method='AddToGroup'),
    )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([
        str(x) for x in xpath.queryForNodes('/iq/query/item/group', iq.stanza)
    ])
    assertLength(2, groups)
    assertContains(default_group, groups)
    assertContains('Scots', groups)

    # Now we can remove him from the default group. Much rejoicing.
    call_async(q, conn.ContactGroups, 'RemoveFromGroup', default_group,
               [duncan])
    iq, _, _ = q.expect_many(
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[duncan], [], [default_group]]),
        EventPattern('dbus-return', method='RemoveFromGroup'),
    )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([
        str(x) for x in xpath.queryForNodes('/iq/query/item/group', iq.stanza)
    ])
    assertLength(1, groups)
    assertContains('Scots', groups)

    # Test SetContactGroups, which didn't previously have proper coverage
    call_async(q, conn.ContactGroups, 'SetContactGroups', duncan,
               ['Scottish former kings'])
    iq, _, _, _ = q.expect_many(
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[duncan], ['Scottish former kings'], []]),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[duncan], [], ['Scots']]),
        EventPattern('dbus-return', method='SetContactGroups'),
    )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([
        str(x) for x in xpath.queryForNodes('/iq/query/item/group', iq.stanza)
    ])
    assertLength(2, groups)
    assertContains('Scots', groups)
    assertContains('Scottish former kings', groups)
    iq, = q.expect_many(
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER), )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([
        str(x) for x in xpath.queryForNodes('/iq/query/item/group', iq.stanza)
    ])
    assertLength(1, groups)
    assertContains('Scottish former kings', groups)

    # Romeo dies. If he drops off the roster as a result, that would be
    # fd.o #21294. However, to fix that bug, Haze now puts him in the
    # default group.
    call_async(q, conn.ContactGroups, 'RemoveFromGroup', 'Still alive',
               [romeo])
    iq1, iq2, _, _, _ = q.expect_many(
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER),
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[romeo], [default_group], []]),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[romeo], [], ['Still alive']]),
        EventPattern('dbus-return', method='RemoveFromGroup'),
    )

    assertEquals('*****@*****.**', iq1.stanza.query.item['jid'])
    groups = set([
        str(x) for x in xpath.queryForNodes('/iq/query/item/group', iq1.stanza)
    ])
    assertLength(2, groups)
    assertContains('Still alive', groups)
    assertContains(default_group, groups)

    assertEquals('*****@*****.**', iq2.stanza.query.item['jid'])
    groups = set([
        str(x) for x in xpath.queryForNodes('/iq/query/item/group', iq2.stanza)
    ])
    assertLength(1, groups)
    assertContains(default_group, groups)

    # Juliet dies. She's in another group already, so the workaround for
    # fd.o #21294 is not active.
    call_async(q, conn.ContactGroups, 'SetGroupMembers', 'Still alive', [])
    iq, _, _ = q.expect_many(
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[juliet], [], ['Still alive']]),
        EventPattern('dbus-return', method='SetGroupMembers'),
    )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([
        str(x) for x in xpath.queryForNodes('/iq/query/item/group', iq.stanza)
    ])
    assertLength(1, groups)
    assertContains('Capulets', groups)

    # At the end of a tragedy, everyone dies, so there's no need for this
    # group.
    call_async(q, conn.ContactGroups, 'RemoveGroup', 'Still alive')
    q.expect('dbus-signal', signal='GroupsRemoved', args=[['Still alive']])

    # Deleting a non-empty group is allowed. (It removes everyone.)
    call_async(q, conn.ContactGroups, 'RemoveGroup', 'Capulets')
    q.expect_many(
        EventPattern('dbus-signal',
                     signal='GroupsRemoved',
                     args=[['Capulets']]),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[juliet], [default_group], []]),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[juliet], [], ['Capulets']]),
    )
Esempio n. 42
0
def test(q, bus, conn, stream, use_room=False):
    conn.Connect()
    q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged', args=[1, 1]),
        EventPattern('irc-connected'))
    q.expect('dbus-signal', signal='SelfHandleChanged')
    q.expect('dbus-signal', signal='StatusChanged', args=[0, 1])

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

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

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

    # Meanwhile, in another application...

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

    sync_dbus(bus, q, conn)

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

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

    path, props = cc.value

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    # MUC says yes!

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

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

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

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

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

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

    members = group_props['Members']

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

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

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

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

    event = q.expect('stream-presence', to=member_)
    assertEquals('unavailable', event.stanza['type'])
Esempio n. 44
0
def complete_search(q, bus, conn, stream, server):
    call_create(q, conn, server)

    # the channel is not yet in conn.Requests.Channels as it's not ready yet
    channels = conn.Get(cs.CONN_IFACE_REQUESTS, 'Channels',
        dbus_interface=cs.PROPERTIES_IFACE)
    for path, props in channels:
        assert props[cs.CHANNEL_TYPE] != cs.CHANNEL_TYPE_CONTACT_SEARCH

    ret, nc_sig = answer_field_query(q, stream, server)

    path, props = ret.value
    props = unwrap(props)

    expected_search_keys = ['email', 'nickname', 'x-n-family', 'x-n-given']

    assert props[cs.CONTACT_SEARCH_SERVER] == server, pformat(props)
    assert sorted(props[cs.CONTACT_SEARCH_ASK]) == expected_search_keys, \
        pformat(props)
    assert cs.CONTACT_SEARCH_STATE not in props, pformat(props)

    # check that channel is listed in conn.Requests.Channels
    channels = conn.Get(cs.CONN_IFACE_REQUESTS, 'Channels',
        dbus_interface=cs.PROPERTIES_IFACE)
    assert (path, props) in channels

    c = make_channel_proxy(conn, path, 'Channel')
    c_props = dbus.Interface(c, cs.PROPERTIES_IFACE)
    c_search = dbus.Interface(c, cs.CHANNEL_TYPE_CONTACT_SEARCH)

    state = c_props.Get(cs.CHANNEL_TYPE_CONTACT_SEARCH, 'SearchState')
    assert state == cs.SEARCH_NOT_STARTED, state

    # We make a search.
    iq = make_search(q, c_search, c_props, server, { 'x-n-family': 'Threepwood' })
    query = iq.firstChildElement()
    i = 0
    for field in query.elements():
        assert field.name == 'last', field.toXml()
        assert field.children[0] == u'Threepwood', field.children[0]
        i += 1
    assert i == 1, query

    # Server sends the results of the search.
    send_results(stream, iq, results.values())

    r = q.expect('dbus-signal', signal='SearchResultReceived')
    infos = r.args[0]

    assertSameSets(results.keys(), infos.keys())

    for id in results.keys():
        i = infos[id]
        r = results[id]
        i_ = pformat(unwrap(i))
        assert ("n", [], [r[2], r[1], "", "", ""])    in i, i_
        assert ("nickname", [], [r[3]])               in i, i_
        assert ("email", [], [r[0]])                  in i, i_
        assert ("x-n-family", [], [r[2]]) in i, i_
        assert ("x-n-given", [], [r[1]]) in i, i_

        assert len(i) == 5, i_

    ssc = q.expect('dbus-signal', signal='SearchStateChanged')
    assert ssc.args[0] == cs.SEARCH_COMPLETED, ssc.args

    # We call Stop after the search has completed; it should succeed, but leave
    # the channel in state Completed rather than changing it to Failed for
    # reason Cancelled.
    call_async(q, c_search, 'Stop')
    event = q.expect('dbus-return', method='Stop')
    state = c_props.Get(cs.CHANNEL_TYPE_CONTACT_SEARCH, 'SearchState')
    assert state == cs.SEARCH_COMPLETED, (state, cs.SEARCH_COMPLETED)

    c.Close()

    q.expect_many(
        EventPattern('dbus-signal', signal='Closed'),
        EventPattern('dbus-signal', signal='ChannelClosed'),
        )
def test_channel_reference_identity(q, bus, conn, stream):
    props = connect_and_get_tls_properties (q, bus, conn)

    reference_identities = props["ReferenceIdentities"]
    assertSameSets(reference_identities, [ "example.org", "localhost"])
    assertEquals(props["Hostname"], "example.org")
def test(q, bus, conn, stream, access_control):
    iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp',
            query_name='vCard')

    acknowledge_iq(stream, iq_event.stanza)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    tube_chan.Channel.Close()
    q.expect_many(
        EventPattern('dbus-signal', signal='Closed'),
        EventPattern('dbus-signal', signal='ChannelClosed'))
Esempio n. 47
0
def test_connection(q, bus, conn, stream):
    event = q.expect('stream-iq', query_ns=ns.ROSTER)
    event.stanza['type'] = 'result'

    normalized_buddies = ['*****@*****.**', '*****@*****.**', '*****@*****.**']
    buddies = ['*****@*****.**', '*****@*****.**', '[email protected]/resource']

    for buddy in normalized_buddies:
        item = event.query.addElement('item')
        item['jid'] = buddy
        item['subscription'] = 'both'

    stream.send(event.stanza)

    requested, attributes = conn.Addressing.GetContactsByVCardField(
        "X-JABBER", buddies[:2] + ['bad!jid'] + buddies[2:], [])

    addresses = []

    assertEquals(3, len(attributes))
    assertEquals(3, len(requested))

    for attr in attributes.values():
        assertContains(cs.CONN_IFACE_ADDRESSING + '/addresses', attr.keys())
        assertContains('x-jabber',
                       attr[cs.CONN_IFACE_ADDRESSING + '/addresses'].keys())
        addresses.append(attr[cs.CONN_IFACE_ADDRESSING +
                              '/addresses']['x-jabber'])

    assertSameSets(normalized_buddies, addresses)
    assertSameSets(buddies, requested.keys())

    normalized_buddies = ['12345', '54321']
    buddies = ['12345', '54321']
    bad_jid_buddies = ['-12345!CHAT.facebook.com', '*****@*****.**']

    for buddy in buddies:
        item = event.query.addElement('item')
        item['jid'] = buddy
        item['subscription'] = 'both'

    stream.send(event.stanza)

    requested, attributes = conn.Addressing.GetContactsByVCardField(
        "X-FACEBOOK-ID", buddies + bad_jid_buddies, [])

    addresses = []

    for attr in attributes.values():
        assertContains(cs.CONN_IFACE_ADDRESSING + '/addresses', attr.keys())
        assertContains('x-facebook-id',
                       attr[cs.CONN_IFACE_ADDRESSING + '/addresses'].keys())
        addr = attr[cs.CONN_IFACE_ADDRESSING + '/addresses']['x-facebook-id']
        addresses.append(addr)
        assertEquals(attr[cs.CONN + '/contact-id'],
                     "-" + addr + "@chat.facebook.com")

    assertSameSets(normalized_buddies, addresses)
    assertSameSets(buddies, requested.keys())

    normalized_buddies = ['*****@*****.**', '*****@*****.**', '*****@*****.**']
    buddies = ['[email protected]', '*****@*****.**', '[email protected]/resource']

    normalized_schemes = ["xmpp", "xmpp", "http"]
    schemes = ["xmpp", "XMPP", "http"]
    valid_schemes = ["xmpp", "XMPP"]

    request_uris = [a + ":" + b for a, b in zip(schemes, buddies)]
    valid_request_uris = [a + ":" + b for a, b in zip(valid_schemes, buddies)]
    normalized_request_uris = [
        a + ":" + b for a, b in zip(normalized_schemes, normalized_buddies)
    ]

    requested, attributes = conn.Addressing.GetContactsByURI(request_uris, [])

    assertEquals(2, len(attributes))
    assertEquals(2, len(requested))

    for attr in attributes.values():
        assertContains(attr[cs.CONN_IFACE_ADDRESSING + '/uris'][0],
                       normalized_request_uris)
        assertContains(cs.CONN_IFACE_ADDRESSING + '/uris', attr.keys())

    assertSameSets(valid_request_uris, requested.keys())
Esempio n. 48
0
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({})
Esempio n. 49
0
def test_complex_success(q, bus, conn, stream, with_extra_data=True,
        accept_early=False):
    chan, props = connect_and_get_sasl_channel(q, bus, conn)

    assertSameSets(MECHANISMS + ['X-TELEPATHY-PASSWORD'],
            props.get(cs.SASL_AVAILABLE_MECHANISMS))

    call_async(q, chan.SASLAuthentication, 'StartMechanismWithData',
            "FOO", "")
    q.expect('dbus-error', method='StartMechanismWithData',
            name=cs.NOT_IMPLEMENTED)

    if with_extra_data:
        chan.SASLAuthentication.StartMechanismWithData("SCOTTISH-PLAY",
                INITIAL_RESPONSE)
        e = q.expect('sasl-auth', initial_response=INITIAL_RESPONSE)
    else:
        chan.SASLAuthentication.StartMechanism("SCOTTISH-PLAY")
        e = q.expect('sasl-auth', has_initial_response=False)

    authenticator = e.authenticator

    q.expect('dbus-signal', signal='SASLStatusChanged',
             interface=cs.CHANNEL_IFACE_SASL_AUTH,
             args=[cs.SASL_STATUS_IN_PROGRESS, '', {}])

    if not with_extra_data:
        # send the stage directions in-band instead
        authenticator.challenge('')
        e = q.expect('dbus-signal', signal='NewChallenge',
                     interface=cs.CHANNEL_IFACE_SASL_AUTH)
        # this ought to be '' but dbus-python has fd.o #28131
        assert e.args in ([''], ['None'])
        chan.SASLAuthentication.Respond(INITIAL_RESPONSE)
        q.expect('sasl-response', response=INITIAL_RESPONSE)

    for challenge, response in CR_PAIRS:
        authenticator.challenge(challenge)
        q.expect('dbus-signal', signal='NewChallenge',
                     interface=cs.CHANNEL_IFACE_SASL_AUTH,
                     args=[challenge])
        chan.SASLAuthentication.Respond(response)
        q.expect('sasl-response', response=response)

    if with_extra_data:
        authenticator.success(SUCCESS_DATA)
    else:
        # The success data is sent in-band as a challenge
        authenticator.challenge(SUCCESS_DATA)

    q.expect('dbus-signal', signal='NewChallenge',
                 interface=cs.CHANNEL_IFACE_SASL_AUTH,
                 args=[SUCCESS_DATA])

    if accept_early:
        # the UI can tell that this challenge isn't actually a challenge,
        # it's a success in disguise
        chan.SASLAuthentication.AcceptSASL()
        q.expect('dbus-signal', signal='SASLStatusChanged',
                interface=cs.CHANNEL_IFACE_SASL_AUTH,
                args=[cs.SASL_STATUS_CLIENT_ACCEPTED, '', {}])
    else:
        chan.SASLAuthentication.Respond(dbus.ByteArray(''))

    if with_extra_data:
        # Wocky removes the distinction between a challenge containing
        # success data followed by a plain success, and a success
        # containing initial data, so we won't get to Server_Succeeded
        # til we "respond" to the "challenge". However, at the XMPP level,
        # we shouldn't get a response to a success.
        q.forbid_events([EventPattern('sasl-response')])
    else:
        q.expect('sasl-response', response='')
        authenticator.success(None)

    if not accept_early:
        # *now* we accept
        q.expect('dbus-signal', signal='SASLStatusChanged',
                interface=cs.CHANNEL_IFACE_SASL_AUTH,
                args=[cs.SASL_STATUS_SERVER_SUCCEEDED, '', {}])
        # We're willing to accept this SASL transaction
        chan.SASLAuthentication.AcceptSASL()

    q.expect('dbus-signal', signal='SASLStatusChanged',
            interface=cs.CHANNEL_IFACE_SASL_AUTH,
            args=[cs.SASL_STATUS_SUCCEEDED, '', {}])

    q.expect('dbus-signal', signal='StatusChanged',
             args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
    chan.Close()
    # ... and check that the Connection is still OK
    conn.Properties.Get(cs.CONN, "SelfHandle")
Esempio n. 50
0
def test(q, bus, conn, stream):
    client = 'http://telepathy.freedesktop.org/fake-client'
    contact = '[email protected]/Resource'
    files = [("file", "File.txt", 12345, False),
             ("file", "Image.txt", 54321, True),
             ("folder", "Folder", 123, False),
             ("folder", "Folder no size", None, True)]

    test_ft_caps_from_contact(q, bus, conn, stream, contact,
        2L, client)

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

    iq = IQ(stream, "set")
    iq['to'] = jid
    iq['from'] = contact
    session = iq.addElement("session", "http://www.google.com/session")
    session['type'] = "initiate"
    session['id'] = "2156517633"
    session['initiator'] = contact
    session.addElement("transport", "http://www.google.com/transport/p2p")
    description = session.addElement("description",
                                     "http://www.google.com/session/share")

    manifest = description.addElement("manifest")
    for f in files:
        type, name, size, image = f
        file = manifest.addElement(type)
        if size is not None:
            file['size'] = str(size)
        file.addElement("name", None, name)
        if image:
            image = file.addElement("image")
            image['width'] = '1200'
            image['height'] = '1024'

    protocol = description.addElement("protocol")
    http = protocol.addElement("http")
    url = http.addElement("url", None, "/temporary/ade15194140cf7b7bceafe/")
    url['name'] = 'source-path'
    url = http.addElement("url", None, "/temporary/578d715be25ddc28870d3f/")
    url['name'] = 'preview-path'

    stream.send(iq)

    patterns = []
    found = {}

    def get_predicate(name, found, i):
        # This needs to be a function so that name, found, i
        # are part of a closure.

        # /!\ This predicate has side-effects: it writes to 'found'
        def predicate(e):
            path, props = e.args[0][0]
            if props[cs.CHANNEL_TYPE] != cs.CHANNEL_TYPE_FILE_TRANSFER:
                return False

            if props[cs.FT_FILENAME] == name:
                found[i] = (path, props)
                return True
        return predicate

    for i, f in enumerate(files):
        type, name, size, image = f
        if type == "folder":
            name = "%s.tar" % name

            return False

        patterns.append(EventPattern('dbus-signal',
            signal='NewChannels',
            predicate=get_predicate(name, found, i)))

    # Make sure every file transfer has a channel associated with it
    file_collection = None
    q.expect_many(*patterns)
    assertLength(len(files), found)

    channels = []
    for i in found:
        assert found[i] is not None
        path, props = found[i]
        channels.append((path, props))

        # Get the FileCollection and make sure it exists
        if file_collection is None:
            file_collection = props[cs.FT_FILE_COLLECTION]
            assert file_collection != ''
        assert file_collection is not None

        # FileCollection must be the same for every channel
        assert props[cs.FT_FILE_COLLECTION] == file_collection, props

        type, name, size, image = files[i]
        if size is None:
            size = 0

        assertEquals(size, props[cs.FT_SIZE])

        assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER, props
        assertSameSets(
            [ cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA,
            ], props[cs.INTERFACES])
        assert props[cs.TARGET_HANDLE] == 2L, props
        assert props[cs.TARGET_ID] == contact.replace("/Resource", ""), props
        assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_CONTACT, props
        assert props[cs.REQUESTED] == False, props
        assert props[cs.INITIATOR_HANDLE] == 2L, props
        assert props[cs.INITIATOR_ID] == contact.replace("/Resource", ""), props
        assert props[cs.FT_STATE] == cs.FT_STATE_PENDING, props
        assert props[cs.FT_CONTENT_TYPE] == '', props
        # FT's protocol doesn't allow us the send the hash info
        assert props[cs.FT_CONTENT_HASH_TYPE] == cs.FILE_HASH_TYPE_NONE, props
        assert props[cs.FT_CONTENT_HASH] == '', props
        assert props[cs.FT_DESCRIPTION] == '', props
        assert props[cs.FT_DATE] == 0, props
        assert props[cs.FT_AVAILABLE_SOCKET_TYPES] == \
            {cs.SOCKET_ADDRESS_TYPE_UNIX: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST],
            cs.SOCKET_ADDRESS_TYPE_IPV4: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST],
            cs.SOCKET_ADDRESS_TYPE_IPV6: [cs.SOCKET_ACCESS_CONTROL_LOCALHOST]}, \
            props[cs.FT_AVAILABLE_SOCKET_TYPES]
        assert props[cs.FT_TRANSFERRED_BYTES] == 0, props
        assert props[cs.FT_INITIAL_OFFSET] == 0, props

    event = q.expect('stream-iq', to=contact,
                     iq_type='set', query_name='session')
    session_node = event.query
    assert session_node.attributes['type'] == 'transport-accept'

    # Close all but one of the channels, and make sure Gabble doesn't cancel
    # the multi-FT yet.
    terminate_pattern = EventPattern('stream-iq', to=contact, iq_type='set',
        query_name='session',
        predicate=lambda event: event.query['type'] == 'terminate')

    q.forbid_events([terminate_pattern])

    for path, props in channels[:-1]:
        ft_chan = bus.get_object(conn.object.bus_name, path)
        channel = dbus.Interface(ft_chan, cs.CHANNEL)
        channel.Close()
        q.expect('dbus-signal', signal='Closed', path=path)

    sync_stream(q, stream)
    q.unforbid_all()

    # Now close the final channel, and make sure Gabble terminates the session.
    last_path, props = channels[-1]

    ft_chan = bus.get_object(conn.object.bus_name, last_path)
    channel = dbus.Interface(ft_chan, cs.CHANNEL)
    channel.Close()

    q.expect_many(terminate_pattern)
Esempio n. 51
0
def test_connection(q, bus, conn, stream):
    event = q.expect("stream-iq", query_ns=ns.ROSTER)
    event.stanza["type"] = "result"

    normalized_buddies = ["*****@*****.**", "*****@*****.**", "*****@*****.**"]
    buddies = ["*****@*****.**", "*****@*****.**", "[email protected]/resource"]

    for buddy in normalized_buddies:
        item = event.query.addElement("item")
        item["jid"] = buddy
        item["subscription"] = "both"

    stream.send(event.stanza)

    requested, attributes = conn.Addressing.GetContactsByVCardField(
        "X-JABBER", buddies[:2] + ["bad!jid"] + buddies[2:], []
    )

    addresses = []

    assertEquals(3, len(attributes))
    assertEquals(3, len(requested))

    for attr in attributes.values():
        assertContains(cs.CONN_IFACE_ADDRESSING + "/addresses", attr.keys())
        assertContains("x-jabber", attr[cs.CONN_IFACE_ADDRESSING + "/addresses"].keys())
        addresses.append(attr[cs.CONN_IFACE_ADDRESSING + "/addresses"]["x-jabber"])

    assertSameSets(normalized_buddies, addresses)
    assertSameSets(buddies, requested.keys())

    normalized_buddies = ["12345", "54321"]
    buddies = ["12345", "54321"]
    bad_jid_buddies = ["-12345!CHAT.facebook.com", "*****@*****.**"]

    for buddy in buddies:
        item = event.query.addElement("item")
        item["jid"] = buddy
        item["subscription"] = "both"

    stream.send(event.stanza)

    requested, attributes = conn.Addressing.GetContactsByVCardField("X-FACEBOOK-ID", buddies + bad_jid_buddies, [])

    addresses = []

    for attr in attributes.values():
        assertContains(cs.CONN_IFACE_ADDRESSING + "/addresses", attr.keys())
        assertContains("x-facebook-id", attr[cs.CONN_IFACE_ADDRESSING + "/addresses"].keys())
        addr = attr[cs.CONN_IFACE_ADDRESSING + "/addresses"]["x-facebook-id"]
        addresses.append(addr)
        assertEquals(attr[cs.CONN + "/contact-id"], "-" + addr + "@chat.facebook.com")

    assertSameSets(normalized_buddies, addresses)
    assertSameSets(buddies, requested.keys())

    normalized_buddies = ["*****@*****.**", "*****@*****.**", "*****@*****.**"]
    buddies = ["[email protected]", "*****@*****.**", "[email protected]/resource"]

    normalized_schemes = ["xmpp", "xmpp", "http"]
    schemes = ["xmpp", "XMPP", "http"]
    valid_schemes = ["xmpp", "XMPP"]

    request_uris = [a + ":" + b for a, b in zip(schemes, buddies)]
    valid_request_uris = [a + ":" + b for a, b in zip(valid_schemes, buddies)]
    normalized_request_uris = [a + ":" + b for a, b in zip(normalized_schemes, normalized_buddies)]

    requested, attributes = conn.Addressing.GetContactsByURI(request_uris, [])

    assertEquals(2, len(attributes))
    assertEquals(2, len(requested))

    for attr in attributes.values():
        assertContains(attr[cs.CONN_IFACE_ADDRESSING + "/uris"][0], normalized_request_uris)
        assertContains(cs.CONN_IFACE_ADDRESSING + "/uris", attr.keys())

    assertSameSets(valid_request_uris, requested.keys())
def test(q, bus, conn):

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

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

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

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

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

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

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

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

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

    path, props = channels[0]

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

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

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

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

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

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

    tube_addr1 = e.value[0]

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

    check_dbus_names(contact1_tube, [conn1_self_handle])

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

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

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

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

    path, props = channels[0]

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

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

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

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

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

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

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

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

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

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

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

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

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

    obj1 = Test(tube_conn1, q)

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

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

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

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

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

    def my_method_error(e):
        assert False, e

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

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

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

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

    check_dbus_names(contact2_tube, [conn2_self_handle])

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

    conn.Disconnect()
    conn2.Disconnect()
def test(q, bus, conn, stream, access_control):
    iq_event = q.expect('stream-iq',
                        to=None,
                        query_ns='vcard-temp',
                        query_name='vCard')

    acknowledge_iq(stream, iq_event.stanza)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    tube_chan.Channel.Close()
    q.expect_many(EventPattern('dbus-signal', signal='Closed'),
                  EventPattern('dbus-signal', signal='ChannelClosed'))
def test(q, bus, conn, stream):
    conn.Connect()

    # This test can't be exactly like Gabble's because libpurple doesn't
    # signal that it's connected until it receives a roster; as a result,
    # the publish and subscribe channels already exist on startup.

    q.expect_many(
            EventPattern('dbus-signal', signal='StatusChanged',
                args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]),
            EventPattern('stream-authenticated'),
            )

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

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    group = item.addElement('group', content='3 letter names')

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'from'
    group = item.addElement('group', content='3 letter names')

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'to'

    stream.send(event.stanza)

    _, s, _ = q.expect_many(
            EventPattern('dbus-signal', signal='StatusChanged',
                args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]),
            EventPattern('dbus-signal', signal='ContactsChanged',
                interface=cs.CONN_IFACE_CONTACT_LIST, path=conn.object_path),
            EventPattern('dbus-signal', signal='ContactListStateChanged',
                args=[cs.CONTACT_LIST_STATE_SUCCESS]),
            )

    amy, bob, chris = conn.get_contact_handles_sync(
            ['*****@*****.**', '*****@*****.**', '*****@*****.**'])

    # Amy, Bob and Chris are all stored on our server-side roster.
    #
    # Everyone on our roster is (falsely!) alleged to have subscribe=YES
    # (in fact this ought to be just Amy and Chris, because we're publishing
    # presence to Bob without being subscribed to his presence, but libpurple
    # apparently can't represent this).
    #
    # The publish value is unknown, because libpurple doesn't have
    # state-recovery.
    assertEquals([{
        amy: (cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_UNKNOWN, ''),
        bob: (cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_UNKNOWN, ''),
        chris: (cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_UNKNOWN, ''),
        }, []], s.args)

    # the XMPP prpl puts people into some sort of group, probably called
    # Buddies
    groups = conn.Properties.Get(cs.CONN_IFACE_CONTACT_GROUPS, 'Groups')
    default_group = None

    for group in groups:
        if group == '3 letter names':
            continue

        if default_group is not None:
            raise AssertionError('Two unexplained groups: %s, %s' %
                    (group, default_group))

        default_group = group

    call_async(q, conn.ContactList, 'GetContactListAttributes',
            [cs.CONN_IFACE_CONTACT_GROUPS], False)
    r = q.expect('dbus-return', method='GetContactListAttributes')

    assertEquals(cs.SUBSCRIPTION_STATE_YES, r.value[0][amy][cs.ATTR_SUBSCRIBE])
    assertEquals(cs.SUBSCRIPTION_STATE_YES, r.value[0][bob][cs.ATTR_SUBSCRIBE])
    assertEquals(cs.SUBSCRIPTION_STATE_YES, r.value[0][chris][cs.ATTR_SUBSCRIBE])

    assertEquals(cs.SUBSCRIPTION_STATE_UNKNOWN, r.value[0][amy][cs.ATTR_PUBLISH])
    assertEquals(cs.SUBSCRIPTION_STATE_UNKNOWN, r.value[0][bob][cs.ATTR_PUBLISH])
    assertEquals(cs.SUBSCRIPTION_STATE_UNKNOWN, r.value[0][chris][cs.ATTR_PUBLISH])

    assertSameSets(['3 letter names'], r.value[0][amy][cs.ATTR_GROUPS])
    assertSameSets(['3 letter names'], r.value[0][bob][cs.ATTR_GROUPS])
    assertSameSets([default_group], r.value[0][chris][cs.ATTR_GROUPS])
Esempio n. 55
0
def test(q, bus, conn, stream):
    call_async(q, conn.ContactList, 'GetContactListAttributes',
            [cs.CONN_IFACE_CONTACT_GROUPS], False)
    r = q.expect('dbus-return', method='GetContactListAttributes')
    assertLength(0, r.value[0].keys())

    # receive a subscription request
    alice = conn.get_contact_handle_sync('*****@*****.**')

    presence = domish.Element(('jabber:client', 'presence'))
    presence['from'] = '*****@*****.**'
    presence['type'] = 'subscribe'
    presence.addElement('status', content='friend me')
    stream.send(presence)

    # it seems either libpurple or haze doesn't pass the message through
    q.expect_many(
            EventPattern('dbus-signal', signal='ContactsChangedWithID',
                args=[{
                    alice:
                        (cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_ASK,
                            ''),
                    },
                    {alice: '*****@*****.**'}, {}]),
            )

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

    # accept
    call_async(q, conn.ContactList, 'AuthorizePublication', [alice])

    q.expect_many(
            EventPattern('stream-presence', presence_type='subscribed',
                to='*****@*****.**'),
            EventPattern('dbus-signal', signal='ContactsChangedWithID',
                args=[{
                    alice:
                        (cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_YES,
                            ''),
                    },
                    {alice: '*****@*****.**'}, {}]),
            EventPattern('dbus-return', method='AuthorizePublication'),
            )

    # the server sends us a roster push
    iq = IQ(stream, 'set')
    iq['id'] = 'roster-push'
    query = iq.addElement(('jabber:iq:roster', 'query'))
    item = query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'from'

    stream.send(iq)

    q.expect_many(
            EventPattern('stream-iq', iq_type='result',
                predicate=lambda e: e.stanza['id'] == 'roster-push'),
            # She's not really on our subscribe list, but this is the closest
            # we can guess from libpurple
            EventPattern('dbus-signal', signal='ContactsChangedWithID',
                args=[{
                    alice:
                        (cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_YES,
                            ''),
                    },
                    {alice: '*****@*****.**'}, {}]),
            # the buddy needs a group, because libpurple
            EventPattern('dbus-signal', signal='GroupsChanged',
                predicate=lambda e: e.args[0] == [alice]),
            )

    call_async(q, conn.ContactList, 'GetContactListAttributes',
            [cs.CONN_IFACE_CONTACT_GROUPS], False)
    r = q.expect('dbus-return', method='GetContactListAttributes')
    assertSameSets([alice], r.value[0].keys())

    # receive another subscription request
    queen = conn.get_contact_handle_sync('*****@*****.**')

    presence = domish.Element(('jabber:client', 'presence'))
    presence['from'] = '*****@*****.**'
    presence['type'] = 'subscribe'
    presence.addElement('status', content='Off with her head!')
    stream.send(presence)

    # it seems either libpurple or haze doesn't pass the message through
    q.expect_many(
            EventPattern('dbus-signal', signal='ContactsChangedWithID',
                args=[{
                    queen:
                        (cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_ASK,
                            ''),
                    },
                    {queen: '*****@*****.**'}, {}]),
            )

    # the contact is temporarily on our roster
    call_async(q, conn.ContactList, 'GetContactListAttributes',
            [cs.CONN_IFACE_CONTACT_GROUPS], False)
    r = q.expect('dbus-return', method='GetContactListAttributes')
    assertSameSets([alice, queen], r.value[0].keys())

    # decline
    call_async(q, conn.ContactList, 'RemoveContacts', [queen])

    q.expect_many(
            EventPattern('stream-presence', presence_type='unsubscribed',
                to='*****@*****.**'),
            EventPattern('dbus-signal', signal='ContactsChangedWithID',
                args=[{
                    queen:
                        (cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_NO,
                            ''),
                    }, {queen: '*****@*****.**'}, {}]),
            EventPattern('dbus-return', method='RemoveContacts'),
            )

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

    # the declined contact isn't on our roster any more
    call_async(q, conn.ContactList, 'GetContactListAttributes',
            [cs.CONN_IFACE_CONTACT_GROUPS], False)
    r = q.expect('dbus-return', method='GetContactListAttributes')
    assertSameSets([alice], r.value[0].keys())

    # she's persistent
    presence = domish.Element(('jabber:client', 'presence'))
    presence['from'] = '*****@*****.**'
    presence['type'] = 'subscribe'
    presence.addElement('status', content='How dare you?')
    stream.send(presence)

    q.expect_many(
            EventPattern('dbus-signal', signal='ContactsChangedWithID',
                args=[{
                    queen:
                        (cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_ASK,
                            ''),
                        },
                        {queen: '*****@*****.**'}, {}]),
            )

    # disconnect with the request outstanding, to make sure we don't crash
    conn.Disconnect()
    q.expect('dbus-signal', signal='StatusChanged',
            args=[cs.CONN_STATUS_DISCONNECTED, cs.CSR_REQUESTED])
    # make sure Haze didn't crash
    sync_dbus(bus, q, conn)