def getStats(self, jid = "icq.netlab.cz"): iq = IQ(self.xmlstream, "get") iq['to'] = jid iq.addElement(("http://jabber.org/protocol/stats", "query")) iq.addCallback(self._statsReceived) iq.send()
def sync_stream(q, xmpp_connection): """Used to ensure that Salut has processed all stanzas sent to it on this xmpp_connection.""" iq = IQ(None, "get") iq.addElement(('http://jabber.org/protocol/disco#info', 'query')) xmpp_connection.send(iq) q.expect('stream-iq', query_ns='http://jabber.org/protocol/disco#info')
def invalid_user(self, xs): iq = IQ(self.xmlstream, "set") iq.addElement(("jabber:iq:register", "query")) iq.query.addElement("username", content = self.jid.user) iq.query.addElement("password", content = self.password) iq.addCallback(self._registerResultEvent) iq.send()
def make_result_iq(iq): result = IQ(None, "result") result["id"] = iq["id"] query = iq.firstChildElement() if query: result.addElement((query.uri, query.name)) return result
def sync_stream(q, stream): """Used to ensure that Gabble has processed all stanzas sent to it.""" iq = IQ(stream, "get") id = iq['id'] iq.addElement(('http://jabber.org/protocol/disco#info', 'query')) stream.send(iq) q.expect('stream-iq', query_ns='http://jabber.org/protocol/disco#info', predicate=(lambda event: event.stanza['id'] == id and event.iq_type == 'result'))
def make_result_iq(stream, iq, add_query_node=True): result = IQ(stream, "result") result["id"] = iq["id"] to = iq.getAttribute('to') if to is not None: result["from"] = to query = iq.firstChildElement() if query and add_query_node: result.addElement((query.uri, query.name)) return result
def authenticated(self, xs): presence = domish.Element((None, 'presence')) xs.send(presence) iq = IQ(self.xmlstream, "set") iq.addElement(("jabber:iq:register", "query")) iq.query.addElement("remove") iq.addCallback(self._result) iq.send()
def registerAccount(self, username=None, password=None): if username: self.jid.user = username if password: self.password = password iq = IQ(self.xmlstream, "set") iq.addElement(("jabber:iq:register", "query")) iq.query.addElement("username", content=self.jid.user) iq.query.addElement("password", content=self.password) iq.addCallback(self._registerResultEvent) iq.send()
def _result2(self, iq): if iq['type'] != 'result': self.failed() query = iq.firstChildElement() if query.name != "query": self.failed() iq = IQ(self.xmlstream, "get") iq['to'] = transport iq.addElement(("jabber:iq:register", "query")) iq.addCallback(self._result3) iq.send()
def authenticated(self, xs): self.log.debug('Cloud Authenticated') presence = domish.Element((None, 'presence')) xs.send(presence) xs.addObserver('/presence', self.on_presence) xs.addObserver('/iq', self.on_iq) xs.addObserver('/message', self.on_event) disco = IQ(xs, 'get') disco.addElement(('http://jabber.org/protocol/disco#items', 'query')) disco.addCallback(self.cloud_discovered) disco.send() # self.reactor.callLater(120, xs.sendFooter) self.reactor.callLater(5, self.check_users)
def authenticated(self, xs): self.xmlstream.addObserver("/presence[@type='subscribe']", self.onSubscribe, 1) self.xmlstream.addObserver("/presence[@type='subscribed']", self.onSubscribed, 1) presence = domish.Element((None, 'presence')) xs.send(presence) iq = IQ(self.xmlstream, "get") iq['to'] = transport iq.addElement(("jabber:iq:register", "query")) iq.addCallback(self._result) iq.send()
def send_error_reply(stream, iq, error_stanza=None): result = IQ(stream, "error") result["id"] = iq["id"] query = iq.firstChildElement() to = iq.getAttribute('to') if to is not None: result["from"] = to if query: result.addElement((query.uri, query.name)) if error_stanza: result.addChild(error_stanza) stream.send(result)
def test(q, bus, conn, stream): # This sidecar sends a stanza, and waits for a reply, before being # created. pattern = EventPattern('stream-iq', to='sidecar.example.com', query_ns='http://example.com/sidecar') call_async(q, conn.Sidecars1, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".IQ") e = q.expect_many(pattern)[0] # The server said yes, so we should get a sidecar back! acknowledge_iq(stream, e.stanza) q.expect('dbus-return', method='EnsureSidecar') identities = ["test/app-list//Test"] features = ["com.example.test1", "com.example.test2"] ver = compute_caps_hash(identities, features, {}) iq = IQ(stream, "get") query = iq.addElement((ns.DISCO_INFO, 'query')) query['node'] = ns.GABBLE_CAPS + '#' + ver stream.send(iq) e = q.expect('stream-iq', query_ns='http://jabber.org/protocol/disco#info') returned_features = [feature['var'] for feature in xpath.queryForNodes('/iq/query/feature', e.stanza)] assertEquals(features, returned_features) returned_identities = [identity['category'] + "/" + identity['type']+"//" + identity['name'] for identity in xpath.queryForNodes('/iq/query/identity', e.stanza)] assertEquals(identities, returned_identities) new_ver = compute_caps_hash(returned_identities, returned_features, {}) assertEquals(new_ver, ver)
def __init__(self, iq: IQ): self.iq = iq # Create form element self.form = iq.addElement("x") self.form.attributes["xmlns"] = "jabber:x:data" self.form.attributes["type"] = "form"
def answer_error_to_pubsub_request(stream, request): # look for node's name in the request items = xpath.queryForNodes('/iq/pubsub/items', request)[0] node = items['node'] reply = IQ(stream, "error") reply['id'] = request['id'] reply['from'] = request['to'] pubsub = reply.addElement((ns.PUBSUB, 'pubsub')) items = pubsub.addElement((None, 'items')) items['node'] = node error = reply.addElement((None, 'error')) error['type'] = 'auth' error.addElement((ns.STANZA, 'not-authorized')) error.addElement(("%s#errors" % ns.PUBSUB, 'presence-subscription-required')) stream.send(reply)
def answer_error_to_pubsub_request(stream, request): # look for node's name in the request items = xpath.queryForNodes('/iq/pubsub/items', request)[0] node = items['node'] reply = IQ(stream, "error") reply['id'] = request['id'] reply['from'] = request['to'] pubsub = reply.addElement((ns.PUBSUB, 'pubsub')) items = pubsub.addElement((None, 'items')) items['node'] = node error = reply.addElement((None, 'error')) error['type'] = 'auth' error.addElement((ns.STANZA, 'not-authorized')) error.addElement( ("%s#errors" % ns.PUBSUB, 'presence-subscription-required')) stream.send(reply)
def send_not_found(self, id): iq = IQ(self.stream, 'error') iq['to'] = self.initiator iq['from'] = self.target iq['id'] = id error = iq.addElement(('', 'error')) error['type'] = 'cancel' error['code'] = '404' self.stream.send(iq)
def _result(self, iq): #<iq from='icq.localhost' to='t3@localhost/test' id='H_24' type='result'><query xmlns='jabber:iq:register'><instructions>Enter your Jabber ID and password:</instructions><username/><password/><x xmlns='jabber:x:data' type='form'><title>Registration</title><instructions>Enter your Jabber ID and password:</instructions><field type='hidden' var='FORM_TYPE'><value>jabber:iq:register</value></field><field type='text-single' var='username' label='Network username'><required/></field><field type='text-private' var='password' label='Password'><required/></field><field type='list-single' var='language' label='Language'><value>en</value><option label='Cesky'><value>cs</value></option><option label='English'><value>en</value></option></field></x></query></iq> # TODO: more tests if iq['type'] != 'result': self.failed() query = iq.firstChildElement() if query.name != "query": self.failed() iq = IQ(self.xmlstream, "set") iq['to'] = transport iq.addElement(("jabber:iq:register", "query")) iq.query.addElement("username", content = client_jid1.userhost()) iq.query.addElement("password", content = secret1) iq.addCallback(self._result2) iq.send()
def _send_socks5_reply(self, id, stream_used): result = IQ(self.stream, 'result') result['id'] = id result['from'] = self.target result['to'] = self.initiator query = result.addElement((ns.BYTESTREAMS, 'query')) streamhost_used = query.addElement((None, 'streamhost-used')) streamhost_used['jid'] = stream_used result.send()
def send_roster_push(stream, jid, groups): iq = IQ(stream, 'set') query = iq.addElement((ns.ROSTER, 'query')) item = query.addElement('item') item['jid'] = jid item['subscription'] = 'both' for group in groups: item.addElement('group', content=group) stream.send(iq)
def send_roster_iq(stream, jid, subscription): iq = IQ(stream, "set") iq['id'] = 'push' query = iq.addElement('query') query['xmlns'] = ns.ROSTER item = query.addElement('item') item['jid'] = jid item['subscription'] = subscription stream.send(iq)
def test(q, bus, conn, stream): self_presence = q.expect('stream-presence') c = xpath.queryForNodes('/presence/c', self_presence.stanza)[0] jid = '[email protected]/omg' # Gabble shouldn't send any disco requests to our contact during this test. q.forbid_events([ EventPattern('stream-iq', to=jid, iq_type='get', query_ns=ns.DISCO_INFO), ]) # Check that Gabble doesn't disco other clients with the same caps hash. p = make_presence(jid, caps={'node': c['node'], 'hash': c['hash'], 'ver': c['ver'], }) stream.send(p) sync_stream(q, stream) # Check that Gabble doesn't disco its own ext='' bundles (well, its own # bundles as advertised by Gabbles that don't do hashed caps) p = make_presence(jid, caps={'node': c['node'], 'ver': c['ver'], # omitting hash='' so Gabble doesn't ignore ext='' 'ext': 'voice-v1 video-v1', }) stream.send(p) sync_stream(q, stream) # Advertise some different capabilities, to change our own caps hash. add = [(cs.CHANNEL_TYPE_STREAMED_MEDIA, 2L**32-1), (cs.CHANNEL_TYPE_STREAM_TUBE, 2L**32-1), (cs.CHANNEL_TYPE_STREAM_TUBE, 2L**32-1)] remove = [] caps = conn.Capabilities.AdvertiseCapabilities(add, remove) self_presence = q.expect('stream-presence') c_ = xpath.queryForNodes('/presence/c', self_presence.stanza)[0] assertNotEquals(c['ver'], c_['ver']) # But then someone asks us for our old caps iq = IQ(stream, 'get') iq['from'] = jid query = iq.addElement((ns.DISCO_INFO, 'query')) query['node'] = c['node'] + '#' + c['ver'] stream.send(iq) # Gabble should still know what they are, and reply. This is actually quite # important: there's a bug in iChat where if you return an error to a disco # query, it just asks again, and again, and again... reply = q.expect('stream-iq', to=jid) assertEquals('result', reply.iq_type)
def _cb_bare_jid_disco_iq(self, iq): # Additionally, Prosody 0.6.1 doesn't like us discoing our own bare # JID, and responds with an error which doesn't have the 'from' # attribute. Wocky used to discard this, but now tolerates it. result = IQ(self, 'error') result['id'] = iq['id'] error = result.addElement((None, 'error')) error['type'] = 'cancel' error.addElement((ns.STANZA, 'service-unavailable')) self.send(result)
def respondToInitialIq(self, iq): result = IQ(self.xmlstream, "result") result["id"] = iq["id"] query = result.addElement('query') query["xmlns"] = "jabber:iq:auth" query.addElement('username', content='test') query.addElement('password') query.addElement('digest') query.addElement('resource') self.xmlstream.send(result)
def initialIq(self, iq): result = IQ(self.xmlstream, "result") result["id"] = iq["id"] query = result.addElement('query') query["xmlns"] = "jabber:iq:auth" query.addElement('username', content='test') query.addElement('password') query.addElement('digest') query.addElement('resource') self.xmlstream.addOnetimeObserver('/iq/query/username', self.secondIq) self.xmlstream.send(result)
def authenticated(self, xs): # print "Authenticated." xs.addObserver('/presence', self.on_presence) xs.addObserver('/iq', self.on_iq) presence = domish.Element((None, 'presence')) uc = domish.Element( ('urn:schemas-upnp-org:cloud-1-0', 'ConfigIdCloud')) uc['hash'] = 'uda' uc.addContent('1.0') # print(uc.toXml()) presence.addChild(uc) # print(presence.toXml()) xs.send(presence) disco = IQ(xs, 'get') disco.addElement(('http://jabber.org/protocol/disco#info', 'query')) disco.addCallback(self.check_server) disco.send(to='pubsub.xmpp.bertrandverdu.me') self.check_ps_nodes() self.reactor.callLater(30, self.ping)
def _statsReceived(self, el): iq = IQ(self.xmlstream, "get") iq['to'] = el['from'] q = iq.addElement(("http://jabber.org/protocol/stats", "query")) query = el.firstChildElement() for child in query.children: s = q.addElement('stat') s['name'] = child['name'] iq.addCallback(self._statsDataReceived) iq.send()
def authenticated(self, xs): print "Authenticated." # bind = IQ(xs, 'set') # # res = domish.Element((None, 'resource'), content=self.resource) # res = domish.Element(('urn:ietf:params:xml:ns:xmpp-bind', 'bind')) # res.addElement('resource', content=self.resource) # bind.addChild(res) # # bind['from'] = self._jid # # bind['to'] = self.jid.host # xs.send(bind) presence = domish.Element((None, 'presence')) xs.send(presence) xs.addObserver('/presence', self.on_presence) xs.addObserver('/iq', self.on_iq) disco = IQ(xs, 'get') # disco['to'] = '[email protected]/urn:schemas-upnp-org:device:MediaRenderer:1:uuid:e70e9d0e-d9eb-4748-b163-636a323e7950' # search = domish.Element(('http://jabber.org/protocol/disco#items', 'query')) disco.addElement(('http://jabber.org/protocol/disco#items', 'query')) disco.addCallback(self.discovered) disco.send() self.reactor.callLater(120, xs.sendFooter) self.reactor.callLater(5, self.check_users)
def ping(self): def pong(res): if res['type'] == 'result': # log.debug('pong !') self.timeout = False self.reactor.callLater(30, self.ping) else: self.log.error('ping error: %s' % res.toXml()) self.timeout = False # self.startService() def check_timeout(): if self.timeout: self.log.error('ping timeout !') # self.connector.connect() iq = IQ(self.xmlstream, 'get') iq.addElement('ping', 'urn:xmpp:ping') self.reactor.callLater(10, check_timeout) iq.addCallback(pong) self.timeout = True iq.send(to=self.jid.host)
def _send_socks5_init(self, port): iq = IQ(self.stream, 'set') iq['to'] = self.target iq['from'] = self.initiator query = iq.addElement((ns.BYTESTREAMS, 'query')) query['sid'] = self.stream_id query['mode'] = 'tcp' for jid, host in self.hosts: streamhost = query.addElement('streamhost') streamhost['jid'] = jid streamhost['host'] = host streamhost['port'] = str(port) self.stream.send(iq)
def moderate(self, jn, jid_nick, ra, set_to, reason=None): if not reason: reason = self.bot.nick packet = IQ(self.globalbot.wrapper.x, 'set') query = packet.addElement('query', 'http://jabber.org/protocol/muc#admin') i = query.addElement('item') i[jn] = jid_nick i[ra] = set_to i.addElement('reason').addContent(reason) d = Deferred() packet.addCallback(d.callback) #print packet.toXml() callFromThread(packet.send, self.jid) return d
def test_configureResponse(self): def _getChild(element, name): for child in element.elements(): if child.name == name: return child return None response = IQ(self.xmlStream, type="result") pubsubElement = response.addElement("pubsub") configElement = pubsubElement.addElement("configure") formElement = configElement.addElement("x") formElement["type"] = "form" fields = [ ( "unknown", "don't edit me", "text-single" ), ( "pubsub#deliver_payloads", "0", "boolean" ), ( "pubsub#persist_items", "0", "boolean" ), ] expectedFields = { "unknown" : "don't edit me", "pubsub#deliver_payloads" : "1", "pubsub#persist_items" : "1", } for field in fields: fieldElement = formElement.addElement("field") fieldElement["var"] = field[0] fieldElement["type"] = field[2] fieldElement.addElement("value", content=field[1]) self.assertEquals(len(self.xmlStream.elements), 1) self.notifier.requestConfigurationFormSuccess(response, "testNodeName", False) self.assertEquals(len(self.xmlStream.elements), 2) iq = self.xmlStream.elements[1] self.assertEquals(iq.name, "iq") self.assertEquals(iq["type"], "set") pubsubElement = list(iq.elements())[0] self.assertEquals(pubsubElement.name, "pubsub") configElement = list(pubsubElement.elements())[0] self.assertEquals(configElement.name, "configure") self.assertEquals(configElement["node"], "testNodeName") formElement = list(configElement.elements())[0] self.assertEquals(formElement["type"], "submit") for field in formElement.elements(): valueElement = _getChild(field, "value") if valueElement is not None: self.assertEquals(expectedFields[field["var"]], str(valueElement))
def authenticated(self, xs): print "Authenticated." xs.addObserver('/presence', self.on_presence) xs.addObserver('/iq', self.on_iq) presence = domish.Element((None, 'presence')) uc = domish.Element( ('urn:schemas-upnp-org:cloud-1-0', 'ConfigIdCloud')) uc['hash'] = 'uda' uc.addContent('1.0') # print(uc.toXml()) presence.addChild(uc) # print(presence.toXml()) xs.send(presence) disco = IQ(xs, 'get') # disco['to'] = 'pubsub.xmpp.bertrandverdu.me' # search = domish.Element(('http://jabber.org/protocol/disco#items', 'query')) disco.addElement(('http://jabber.org/protocol/disco#info', 'query')) disco.addCallback(self.check_server) disco.send(to='pubsub.xmpp.bertrandverdu.me') self.reactor.callLater(120, xs.sendFooter)
def returns_bees_from_search(q, stream, conn): server = 'hivemind.localhost' iq = call_create(q, conn, server) result = make_result_iq(stream, iq) query = result.firstChildElement() query.addElement("nick") stream.send(result) event = q.expect('dbus-return', method='CreateChannel') c = make_channel_proxy(conn, event.value[0], 'Channel') c_search = dbus.Interface(c, cs.CHANNEL_TYPE_CONTACT_SEARCH) call_async(q, c_search, 'Search', {'nickname': 'Buzzy'}) iq_event, _ = q.expect_many( EventPattern('stream-iq', to=server, query_ns=ns.SEARCH), EventPattern('dbus-signal', signal='SearchStateChanged'), ) iq = iq_event.stanza result = IQ(stream, 'result') result['id'] = iq['id'] result['from'] = iq['to'] result.addElement((ns.SEARCH, 'bees')).addElement('bzzzzzzz') stream.send(result) ssc = q.expect('dbus-signal', signal='SearchStateChanged') new_state, reason, details = ssc.args assert new_state == cs.SEARCH_FAILED, new_state assert reason == cs.NOT_AVAILABLE, reason # We call stop after the search has failed; it should succeed and do nothing. call_async(q, c_search, 'Stop') event = q.expect('dbus-return', method='Stop') c.Close()
def moderate(self, jn, jid_nick, ra, set_to, reason=None): if not reason: try: reason = self.bot.nick except: reason = 'freQ' packet = IQ(self.globalbot.wrapper.x, 'set') query = packet.addElement('query', 'http://jabber.org/protocol/muc#admin') i = query.addElement('item') i[jn] = jid_nick i[ra] = set_to i.addElement('reason').addContent(reason) d = Deferred() packet.addCallback(d.callback) #print packet.toXml() callFromThread(packet.send, self.jid) return d
def test(q, bus, conn, stream): amy_handle = conn.get_contact_handle_sync('*****@*****.**') # Divergence from Gabble: hazetest responds to all roster gets with an # empty roster, so we need to push the roster. iq = IQ(stream, 'set') query = iq.addElement(('jabber:iq:roster', 'query')) item = query.addElement('item') item['jid'] = '*****@*****.**' item['subscription'] = 'both' stream.send(iq) presence = domish.Element((None, 'presence')) presence['from'] = '*****@*****.**' show = presence.addElement((None, 'show')) show.addContent('away') status = presence.addElement((None, 'status')) status.addContent('At the pub') stream.send(presence) event = q.expect('dbus-signal', signal='PresencesChanged') assert event.args[0] == { amy_handle: (3, 'away', 'At the pub') } presence = domish.Element((None, 'presence')) presence['from'] = '*****@*****.**' show = presence.addElement((None, 'show')) show.addContent('chat') status = presence.addElement((None, 'status')) status.addContent('I may have been drinking') stream.send(presence) event = q.expect('dbus-signal', signal='PresencesChanged') # FIXME: 'chat' gets lost somewhere between the XMPP stream and what Haze # produces. assert event.args[0] == { amy_handle: (2, 'available', 'I may have been drinking') } amy_handle, asv = conn.Contacts.GetContactByID('*****@*****.**', [cs.CONN_IFACE_SIMPLE_PRESENCE]) assertEquals(event.args[0][amy_handle], asv.get(cs.ATTR_PRESENCE)) bob_handle, asv = conn.Contacts.GetContactByID('*****@*****.**', [cs.CONN_IFACE_SIMPLE_PRESENCE]) assertEquals((cs.PRESENCE_UNKNOWN, 'unknown', ''), asv.get(cs.ATTR_PRESENCE)) conn.Disconnect() q.expect('dbus-signal', signal='StatusChanged', args=[2, 1])
def bindIq(self, iq): resource = xpath.queryForString('/iq/bind/resource', iq) if self.resource is not None: assertEquals(self.resource, resource) else: assert resource is not None result = IQ(self.xmlstream, "result") result["id"] = iq["id"] bind = result.addElement((ns.NS_XMPP_BIND, 'bind')) self.bare_jid = '%s@%s' % (self.username, self.xmlstream.domain) self.full_jid = '%s/%s' % (self.bare_jid, resource) jid = bind.addElement('jid', content=self.full_jid) self.xmlstream.send(result) self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT)
def open_bytestream(self, expected_before=[], expected_after=[]): # open IBB bytestream iq = IQ(self.stream, 'set') iq['to'] = self.target iq['from'] = self.initiator open = iq.addElement((ns.IBB, 'open')) open['sid'] = self.stream_id # set a ridiculously small block size to stress test IBB buffering open['block-size'] = '1' assert self.checked events_before = self.q.expect_many(*expected_before) self.stream.send(iq) events_after = self.q.expect_many(*expected_after) return events_before, events_after
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 make_roster_push(stream, jid, subscription, ask_subscribe=False, name=None): iq = IQ(stream, "set") iq['id'] = 'push' query = iq.addElement('query') query['xmlns'] = ns.ROSTER item = query.addElement('item') item['jid'] = jid item['subscription'] = subscription if name is not None: item['name'] = name if ask_subscribe: item['ask'] = 'subscribe' return iq
def _create_si_offer(self, profile, to=None): assert self.initiated iq = IQ(self.stream, 'set') iq['from'] = self.initiator if to is None: iq['to'] = self.target else: iq['to'] = to si = iq.addElement((ns.SI, 'si')) si['id'] = self.stream_id si['profile'] = profile feature = si.addElement((ns.FEATURE_NEG, 'feature')) x = feature.addElement((ns.X_DATA, 'x')) x['type'] = 'form' field = x.addElement((None, 'field')) field['var'] = 'stream-method' field['type'] = 'list-single' return iq, si, field
def outgoing_fail(q, bus, conn): path, incoming, stanza = setup_outgoing_tests(q, bus, conn) # construct a nice error reply reply = IQ(None, 'error') reply['id'] = stanza['id'] error = reply.addElement('error') error['type'] = 'cancel' error['code'] = '409' error.addElement((ns.STANZA, 'conflict')) error.addElement((ycs.MESSAGE_NS, 'yodawg')) text = error.addElement((ns.STANZA, 'text'), content='imma let you finish') incoming.send(reply) e = q.expect('dbus-signal', signal='Failed', path=path) error_type, stanza_error_name, yst_error_name, text = e.args assertEquals(ycs.ERROR_TYPE_CANCEL, error_type) assertEquals('conflict', stanza_error_name) assertEquals('yodawg', yst_error_name) assertEquals('imma let you finish', text)
def test(q, bus, conn, stream, remove, local): h = conn.get_contact_handle_sync(jid) # Another client logged into our account (Gajim, say) wants to subscribe to # Marco's presence. First, per RFC 3921 it 'SHOULD perform a "roster set" # for the new roster item': # # <iq type='set'> # <query xmlns='jabber:iq:roster'> # <item jid='*****@*****.**'/> # </query> # </iq> # # 'As a result, the user's server (1) MUST initiate a roster push for the # new roster item to all available resources associated with this user that # have requested the roster, setting the 'subscription' attribute to a # value of "none"': iq = IQ(stream, "set") item = iq.addElement((ns.ROSTER, 'query')).addElement('item') item['jid'] = jid item['subscription'] = 'none' stream.send(iq) # In response, Haze adds Marco to the roster, which we guess (wrongly, # in this case) also means subscribe q.expect('dbus-signal', signal='ContactsChangedWithID', args=[{ h: (cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_UNKNOWN, ''), }, { h: jid }, {}]) # Gajim sends a <presence type='subscribe'/> to Marco. 'As a result, the # user's server MUST initiate a second roster push to all of the user's # available resources that have requested the roster, setting [...] # ask='subscribe' attribute in the roster item [for Marco]: iq = IQ(stream, "set") item = iq.addElement((ns.ROSTER, 'query')).addElement('item') item['jid'] = jid item['subscription'] = 'none' item['ask'] = 'subscribe' stream.send(iq) # In response, Haze should add Marco to subscribe:remote-pending, # but libpurple has no such concept, so nothing much happens. # The user decides that they don't care what Marco's baking after all # (maybe they read his blog instead?) and: if remove: # ...removes him from the roster... if local: # ...by telling Haze to remove him from the roster conn.ContactList.RemoveContacts([h]) event = q.expect('stream-iq', iq_type='set', query_ns=ns.ROSTER) item = event.query.firstChildElement() assertEquals(jid, item['jid']) assertEquals('remove', item['subscription']) else: # ...using the other client. pass # The server must 'inform all of the user's available resources that # have requested the roster of the roster item removal': iq = IQ(stream, "set") item = iq.addElement((ns.ROSTER, 'query')).addElement('item') item['jid'] = jid item['subscription'] = 'remove' # When Marco found this bug, this roster update included: item['ask'] = 'subscribe' # which is a bit weird: I don't think the server should send that when # the contact's being removed. I think CMs should ignore it, so I'm # including it in the test. stream.send(iq) # In response, Haze should announce that Marco has been removed from # the roster q.expect('dbus-signal', signal='ContactsChangedWithID', args=[{}, {}, { h: jid }]) else: # ...rescinds the subscription request... if local: raise AssertionError("Haze can't do this ") else: # ...in the other client. pass # In response, the server sends a roster update: iq = IQ(stream, "set") item = iq.addElement((ns.ROSTER, 'query')).addElement('item') item['jid'] = jid item['subscription'] = 'none' # no ask='subscribe' any more. stream.send(iq)
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)