def test_conflict(q, gateways_iface, stream): call_async(q, gateways_iface, 'Register', 'sip.example.com', '8675309', 'jenny') e = q.expect('stream-iq', iq_type='set', query_name='query', query_ns=ns.REGISTER, to='sip.example.com') assertEquals('8675309', xpath.queryForString('/query/username', e.query)) assertEquals('jenny', xpath.queryForString('/query/password', e.query)) error = domish.Element((None, 'error')) error['type'] = 'cancel' error['code'] = '409' error.addElement((ns.STANZA, 'conflict')) send_error_reply(stream, e.stanza, error) q.expect('dbus-error', method='Register', name=cs.REGISTRATION_EXISTS)
def test_not_acceptable(q, gateways_iface, stream): call_async(q, gateways_iface, 'Register', 'fully-captcha-enabled.example.com', 'lalala', 'stoats') e = q.expect('stream-iq', iq_type='set', query_name='query', query_ns=ns.REGISTER, to='fully-captcha-enabled.example.com') assertEquals('lalala', xpath.queryForString('/query/username', e.query)) assertEquals('stoats', xpath.queryForString('/query/password', e.query)) error = domish.Element((None, 'error')) error['type'] = 'modify' error['code'] = '406' error.addElement((ns.STANZA, 'not-acceptable')) send_error_reply(stream, e.stanza, error) q.expect('dbus-error', method='Register', name=cs.NOT_AVAILABLE)
def test_success(q, gateways_iface, stream): call_async(q, gateways_iface, 'Register', 'talkd.example.com', '1970', 's3kr1t') e = q.expect('stream-iq', iq_type='set', query_name='query', query_ns=ns.REGISTER, to='talkd.example.com') assertEquals('1970', xpath.queryForString('/query/username', e.query)) assertEquals('s3kr1t', xpath.queryForString('/query/password', e.query)) acknowledge_iq(stream, e.stanza) q.expect_many( EventPattern('dbus-return', method='Register'), EventPattern('stream-presence', presence_type='subscribe', to='talkd.example.com'), ) stream.send(make_presence('talkd.example.com', type='subscribed'))
def testStaticMethods(self): self.assertEquals(xpath.matches("/foo/bar", self.e), True) self.assertEquals(xpath.queryForNodes("/foo/bar", self.e), [self.bar1, self.bar2, self.bar4]) self.assertEquals(xpath.queryForString("/foo", self.e), "somecontent") self.assertEquals(xpath.queryForStringList("/foo", self.e), ["somecontent", "somemorecontent"])
def processMessagePC(self, elem): # log.msg("processMessagePC() called from %s...." % (elem['from'],)) _from = jid.JID(elem["from"]) if (elem["from"] == self.config['bot.xmppdomain']): log.msg("MESSAGE FROM SERVER?") return # Intercept private messages via a chatroom, can't do that :) if _from.host == self.config['bot.mucservice']: log.msg("ERROR: message is MUC private chat") return if _from.userhost() != "iembot_ingest@%s" % ( self.config['bot.xmppdomain']): log.msg("ERROR: message not from iembot_ingest") return # Go look for body to see routing info! # Get the body string bstring = xpath.queryForString('/message/body', elem) if not bstring: log.msg("Nothing found in body?") return if elem.x and elem.x.hasAttribute("channels"): channels = elem.x['channels'].split(",") else: # The body string contains channel = bstring.split(":", 1)[0] channels = [channel, ] # Send to chatroom, clip body of channel notation # elem.body.children[0] = meat # Always send to botstalk elem['to'] = "botstalk@%s" % (self.config['bot.mucservice'],) elem['type'] = "groupchat" self.send_groupchat_elem(elem) for channel in channels: for room in self.routingtable.get(channel, []): elem['to'] = "%s@%s" % (room, self.config['bot.mucservice']) self.send_groupchat_elem(elem) for page in self.tw_routingtable.get(channel, []): if page not in self.tw_access_tokens: log.msg(("Failed to tweet due to no access_tokens for %s" ) % (page,)) continue # Require the x.twitter attribute to be set to prevent # confusion with some ingestors still sending tweets themself if not elem.x.hasAttribute("twitter"): continue twtextra = {} if (elem.x and elem.x.hasAttribute("lat") and elem.x.hasAttribute("long")): twtextra['lat'] = elem.x['lat'] twtextra['long'] = elem.x['long'] log.msg("Sending tweet '%s' to page '%s'" % (elem.x['twitter'], page)) # Finally, actually tweet, this is in basicbot self.tweet(elem.x['twitter'], self.tw_access_tokens[page], twtextra=twtextra, twituser=page)
def check(vcard): assertEquals(mime_type, xpath.queryForString('/vCard/PHOTO/TYPE', vcard)) binval = xpath.queryForString('/vCard/PHOTO/BINVAL', vcard) # <http://xmpp.org/extensions/xep-0153.html#bizrules-image> says: # # 5. The image data MUST conform to the base64Binary datatype and thus # be encoded in accordance with Section 6.8 of RFC 2045, which # recommends that base64 data should have lines limited to at most # 76 characters in length. lines = binval.split('\n') for line in lines: assert len(line) <= 76, line assertEquals(image_data, base64.decodestring(binval))
def onMessage(self, msg): jidparts = jid.parse(msg['from']) userhost = "%s@%s" % (jidparts[0], jidparts[1]) if self.rooms.has_key(userhost): room_id = self.rooms[userhost][0] body = xpath.queryForString("/message/body", msg) return Message(speaker=jidparts[2], message=body, room_id=room_id, created_at=datetime.datetime.now()).save()
def _session_terminate_predicate(event, msg): reason = xpath.queryForNodes("/iq" "/jingle[@action='session-terminate']" "/reason/failed-application", event.stanza) reason_text = xpath.queryForString("/iq/jingle/reason/text", event.stanza) return reason is not None and reason_text == msg
def message_processor(stanza): """ Process a message stanza """ body = xpath.queryForString("/message/body", stanza) log.msg("Message from %s Body: %s" % (stanza["from"], body)) if body is None: return if body.lower().strip() == "shutdown": log.msg("I got shutdown message, shutting down...") reactor.callWhenRunning(reactor.stop) # @UndefinedVariable
def message_processor(self, stanza): """ Process a message stanza """ body = xpath.queryForString("/message/body", stanza) log.msg("Message from %s Body: %s" % (stanza['from'], body)) if body is None: return if body.lower().strip() == "shutdown": log.msg("I got shutdown message, shutting down...") reactor.callWhenRunning(reactor.stop)
def connect_and_send_form(q, conn, stream): conn.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]) event = q.expect('stream-iq', query_ns=ns.REGISTER) result = make_result_iq(stream, event.stanza) query = result.firstChildElement() query.addElement('username') query.addElement('password') stream.send(result) event = q.expect('stream-iq') iq = event.stanza assert xpath.queryForString('/iq/query/username', iq) == 'test' assert xpath.queryForString('/iq/query/password', iq) == 'pass' return iq
def test_staticMethods(self): """ Test basic operation of the static methods. """ self.assertEquals(xpath.matches("/foo/bar", self.e), True) self.assertEquals( xpath.queryForNodes("/foo/bar", self.e), [self.bar1, self.bar2, self.bar4, self.bar5, self.bar6, self.bar7] ) self.assertEquals(xpath.queryForString("/foo", self.e), "somecontent") self.assertEquals(xpath.queryForStringList("/foo", self.e), ["somecontent", "somemorecontent"])
def _session_terminate_predicate(event, reason, msg, jp): matches = jp.match_jingle_action(event.query, "session-terminate") if matches and jp.is_modern_jingle(): reason = xpath.queryForNodes("/iq" "/jingle[@action='session-terminate']" "/reason/%s" % reason, event.stanza) reason_text = xpath.queryForString("/iq/jingle/reason/text", event.stanza) return bool(reason) and reason_text == msg return matches
def processMessageGC(self, elem): """Process a stanza element that is from a chatroom""" # Ignore all messages that are x-stamp (delayed / room history) # <delay xmlns='urn:xmpp:delay' stamp='2016-05-06T20:04:17.513Z' # from='[email protected]/twisted_words'/> if xpath.queryForNodes("/message/delay[@xmlns='urn:xmpp:delay']", elem): return _from = jid.JID(elem["from"]) room = _from.user res = _from.resource body = xpath.queryForString('/message/body', elem) if body is not None and len(body) >= 4 and body[:4] == "ping": self.send_groupchat(room, "%s: %s" % (res, self.get_fortune())) # Look for bot commands if re.match(r"^%s:" % (self.name,), body): self.process_groupchat_cmd(room, res, body[7:].strip()) # In order for the message to be logged, it needs to be from iembot # and have a channels attribute if res is None or res != 'iembot': return a = xpath.queryForNodes("/message/x[@xmlns='nwschat:nwsbot']", elem) if a is None or len(a) == 0: return if room not in CHATLOG: CHATLOG[room] = {'seqnum': [-1]*40, 'timestamps': [0]*40, 'log': ['']*40, 'author': ['']*40, 'product_id': ['']*40, 'txtlog': ['']*40} ts = datetime.datetime.utcnow() product_id = '' if elem.x and elem.x.hasAttribute("product_id"): product_id = elem.x['product_id'] html = xpath.queryForNodes('/message/html/body', elem) logEntry = body if html is not None: logEntry = html[0].toXml() CHATLOG[room]['seqnum'] = (CHATLOG[room]['seqnum'][1:] + [self.next_seqnum(), ]) CHATLOG[room]['timestamps'] = (CHATLOG[room]['timestamps'][1:] + [ts.strftime("%Y%m%d%H%M%S"), ]) CHATLOG[room]['author'] = CHATLOG[room]['author'][1:] + [res, ] CHATLOG[room]['product_id'] = (CHATLOG[room]['product_id'][1:] + [product_id, ]) CHATLOG[room]['log'] = CHATLOG[room]['log'][1:] + [logEntry, ] CHATLOG[room]['txtlog'] = CHATLOG[room]['txtlog'][1:] + [body, ]
def test_staticMethods(self): """ Test basic operation of the static methods. """ self.assertEqual(xpath.matches("/foo/bar", self.e), True) self.assertEqual( xpath.queryForNodes("/foo/bar", self.e), [self.bar1, self.bar2, self.bar4, self.bar5, self.bar6, self.bar7]) self.assertEqual(xpath.queryForString("/foo", self.e), "somecontent") self.assertEqual(xpath.queryForStringList("/foo", self.e), ["somecontent", "somemorecontent"])
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_XMPP_BIND, 'bind')) jid = bind.addElement('jid', content=('test@localhost/%s' % resource)) self.xmlstream.send(result) self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT)
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 onPresence(self, pres): to = jid.JID(pres['to']) fr = jid.JID(pres['from']) account, roomname = self.parseCampfireName(to) def handleAuth(campfire): if campfire is None: self.sendErrorPresence(pres, "not-allowed", "cancel", NS_MUC) else: self.initializeRoom(campfire, roomname, to, jid.JID(pres['from'])) password = xpath.queryForString("/presence/x/password", pres) if pres.getAttribute('type') == "unavailable": self.smokey.putCampfireOut(account, to) elif password == "": self.sendErrorPresence(pres, "not-authorized") else: log.msg("attempting to auth %s for room %s on account %s" % (to.resource, roomname, account)) self.smokey.initCampfire(account, fr, to, password).addCallback(handleAuth)
def extract_hash_from_presence(stanza): return xpath.queryForString( '/presence/x[@xmlns="%s"]/photo' % ns.VCARD_TEMP_UPDATE, stanza)
def test(q, bus, conn, stream): # Initial vCard request. Respond only after we call SetAliases(). vcard_get_event = q.expect('stream-iq', iq_type='get', to=None, query_ns=ns.VCARD_TEMP, query_name='vCard') sync_stream(q, stream) handle = conn.GetSelfHandle() call_async(q, conn.Aliasing, 'SetAliases', {handle: 'Robert the Bruce'}) sync_dbus(bus, q, conn) acknowledge_iq(stream, vcard_get_event.stanza) # Gabble sets a new vCard with our nickname. vcard_set_event = q.expect('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard') assertEquals('Robert the Bruce', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/FN', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) # Before the server replies, the user sets their avatar call_async(q, conn.Avatars, 'SetAvatar', 'hello', 'image/png') sync_dbus(bus, q, conn) # This acknowledgement is for the nickname acknowledge_iq(stream, vcard_set_event.stanza) hello_binval = base64.b64encode('hello') # This sets the avatar vcard_set_event = q.expect('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard') assertEquals('Robert the Bruce', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertEquals('image/png', xpath.queryForString('/iq/vCard/PHOTO/TYPE', vcard_set_event.stanza)) assertEquals(hello_binval, xpath.queryForString('/iq/vCard/PHOTO/BINVAL', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/FN', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) # Before the server replies, the user sets their ContactInfo call_async(q, conn.ContactInfo, 'SetContactInfo', [(u'fn', [], [u'King Robert I']), (u'n', [], [u'de Brus', u'Robert', u'', u'King', u'']), (u'nickname', [], [u'Bob'])]) sync_dbus(bus, q, conn) # This acknowledgement is for the avatar; SetAvatar won't happen # until this has acknowledge_iq(stream, vcard_set_event.stanza) # This sets the ContactInfo vcard_set_event, _ = q.expect_many( EventPattern('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard'), EventPattern('dbus-return', method='SetAvatar')) assertEquals('Bob', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertEquals('image/png', xpath.queryForString('/iq/vCard/PHOTO/TYPE', vcard_set_event.stanza)) assertEquals(hello_binval, xpath.queryForString('/iq/vCard/PHOTO/BINVAL', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) assertEquals('Robert', xpath.queryForString('/iq/vCard/N/GIVEN', vcard_set_event.stanza)) assertEquals('de Brus', xpath.queryForString('/iq/vCard/N/FAMILY', vcard_set_event.stanza)) assertEquals('King', xpath.queryForString('/iq/vCard/N/PREFIX', vcard_set_event.stanza)) assertEquals('King Robert I', xpath.queryForString('/iq/vCard/FN', vcard_set_event.stanza)) # Before the server replies, the user unsets their avatar call_async(q, conn.Avatars, 'SetAvatar', '', '') sync_dbus(bus, q, conn) # This acknowledgement is for the ContactInfo; SetContactInfo won't happen # until this has acknowledge_iq(stream, vcard_set_event.stanza) vcard_set_event, _ = q.expect_many( EventPattern('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard'), EventPattern('dbus-return', method='SetContactInfo')) assertEquals('Bob', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) assertEquals('Robert', xpath.queryForString('/iq/vCard/N/GIVEN', vcard_set_event.stanza)) assertEquals('de Brus', xpath.queryForString('/iq/vCard/N/FAMILY', vcard_set_event.stanza)) assertEquals('King', xpath.queryForString('/iq/vCard/N/PREFIX', vcard_set_event.stanza)) assertEquals('King Robert I', xpath.queryForString('/iq/vCard/FN', vcard_set_event.stanza)) # This acknowledgement is for the avatar; SetAvatar won't finish # until this is received acknowledge_iq(stream, vcard_set_event.stanza) q.expect('dbus-return', method='SetAvatar') # Now Gabble gets disconnected. sync_stream(q, stream) conn.Disconnect() q.expect('dbus-signal', signal='StatusChanged', args=[2, 1])
def sendMsgRoom(room): if room is not None: room.say(xpath.queryForString("/message/body", msg))
def test(q, bus, conn, stream): event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') call_async( q, conn.ContactInfo, 'SetContactInfo', [(u'fn', [], [u'Wee Ninja']), (u'n', [], [u'Ninja', u'Wee', u'', u'', u'-san']), (u'org', [], ['Collabora, Ltd.']), (u'adr', ['type=work', 'type=postal', 'type=parcel'], [ '', '', '11 Kings Parade', 'Cambridge', 'Cambridgeshire', 'CB2 1SJ', 'UK' ]), (u'label', ['type=work'], [ '11 Kings Parade\n' 'Cambridge\n' 'Cambridgeshire\n' 'CB2 1SJ\n' 'UK\n' ]), (u'tel', ['type=voice', 'type=work'], ['+44 1223 362967']), (u'tel', ['type=voice', 'type=work'], ['+44 7700 900753']), (u'email', ['type=internet', 'type=pref' ], ['*****@*****.**']), (u'email', ['type=internet'], ['*****@*****.**']), (u'x-jabber', [], ['*****@*****.**']), (u'x-jabber', [], ['*****@*****.**']), (u'url', [], ['http://www.thinkgeek.com/geektoys/plush/8823/']), (u'nickname', [], [u'HR Ninja']), (u'nickname', [], [u'Enforcement Ninja'])]) # We don't acknowledge the initial vCard get until we're sure that Gabble's # received our call to SetContactInfo. This ensures that it will issue a # set when we send the reply, rather than issuing another get to ensure the # vCard is really, absolutely up to date before editing it. sync_dbus(bus, q, conn) acknowledge_iq(stream, event.stanza) vcard_set_event = q.expect('stream-iq', iq_type='set', query_ns='vcard-temp', query_name='vCard') assertLength( 2, xpath.queryForNodes('/iq/vCard/NICKNAME', vcard_set_event.stanza)) nicknames = [] for nickname in xpath.queryForNodes('/iq/vCard/NICKNAME', vcard_set_event.stanza): nicknames.append(str(nickname)) assertEquals(['HR Ninja', 'Enforcement Ninja'], nicknames) assertEquals( None, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) assertEquals( 'Wee', xpath.queryForString('/iq/vCard/N/GIVEN', vcard_set_event.stanza)) assertEquals( 'Ninja', xpath.queryForString('/iq/vCard/N/FAMILY', vcard_set_event.stanza)) assertEquals( '-san', xpath.queryForString('/iq/vCard/N/SUFFIX', vcard_set_event.stanza)) assertEquals('Wee Ninja', xpath.queryForString('/iq/vCard/FN', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/ORG', vcard_set_event.stanza)) assertEquals( 'Collabora, Ltd.', xpath.queryForString('/iq/vCard/ORG/ORGNAME', vcard_set_event.stanza)) assertEquals( None, xpath.queryForNodes('/iq/vCard/ORG/ORGUNIT', vcard_set_event.stanza)) assertLength( 1, xpath.queryForNodes('/iq/vCard/LABEL', vcard_set_event.stanza)) lines = xpath.queryForNodes('/iq/vCard/LABEL/LINE', vcard_set_event.stanza) assertLength(5, lines) for i, exp_line in enumerate( ['11 Kings Parade', 'Cambridge', 'Cambridgeshire', 'CB2 1SJ', 'UK']): assertEquals(exp_line, str(lines[i])) assertLength(2, xpath.queryForNodes('/iq/vCard/TEL', vcard_set_event.stanza)) for tel in xpath.queryForNodes('/iq/vCard/TEL', vcard_set_event.stanza): assertLength(1, xpath.queryForNodes('/TEL/NUMBER', tel)) assertContains(xpath.queryForString('/TEL/NUMBER', tel), ('+44 1223 362967', '+44 7700 900753')) assertLength(1, xpath.queryForNodes('/TEL/VOICE', tel)) assertLength(1, xpath.queryForNodes('/TEL/WORK', tel)) assertLength( 2, xpath.queryForNodes('/iq/vCard/EMAIL', vcard_set_event.stanza)) for email in xpath.queryForNodes('/iq/vCard/EMAIL', vcard_set_event.stanza): assertContains(xpath.queryForString('/EMAIL/USERID', email), ('*****@*****.**', '*****@*****.**')) assertLength(1, xpath.queryForNodes('/EMAIL/INTERNET', email)) if 'collabora' in xpath.queryForString('/EMAIL/USERID', email): assertLength(1, xpath.queryForNodes('/EMAIL/PREF', email)) else: assertEquals(None, xpath.queryForNodes('/EMAIL/PREF', email)) assertLength( 2, xpath.queryForNodes('/iq/vCard/JABBERID', vcard_set_event.stanza)) for jid in xpath.queryForNodes('/iq/vCard/JABBERID', vcard_set_event.stanza): assertContains(xpath.queryForString('/JABBERID', jid), ('*****@*****.**', '*****@*****.**')) acknowledge_iq(stream, vcard_set_event.stanza) q.expect_many( EventPattern('dbus-return', method='SetContactInfo'), EventPattern('dbus-signal', signal='AliasesChanged', predicate=lambda e: e.args[0][0][1] == 'HR Ninja'), EventPattern('dbus-signal', signal='ContactInfoChanged'), ) # Exercise various invalid SetContactInfo operations sync_stream(q, stream) sync_dbus(bus, q, conn) forbidden = [EventPattern('stream-iq', query_ns='vcard-temp')] q.forbid_events(forbidden) # unknown field call_async(q, conn.ContactInfo, 'SetContactInfo', [('x-salary', [], ['547 espressos per month'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # not enough values for a simple field call_async(q, conn.ContactInfo, 'SetContactInfo', [('fn', [], [])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # too many values for a simple field call_async(q, conn.ContactInfo, 'SetContactInfo', [('fn', [], ['Wee', 'Ninja'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # unsupported type-parameter for a simple field call_async(q, conn.ContactInfo, 'SetContactInfo', [('fn', ['language=ja'], ['Wee Ninja'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # unsupported type-parameter for a structured field call_async( q, conn.ContactInfo, 'SetContactInfo', [(u'n', ['language=ja'], [u'Ninja', u'Wee', u'', u'', u'-san'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # unsupported type-parameter for LABEL call_async( q, conn.ContactInfo, 'SetContactInfo', [('label', ['language=en'], ['Collabora Ltd.\n11 Kings Parade'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # not enough values for LABEL call_async(q, conn.ContactInfo, 'SetContactInfo', [('label', [], [])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # too many values for LABEL call_async(q, conn.ContactInfo, 'SetContactInfo', [('label', [], ['11 Kings Parade', 'Cambridge'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # unsupported type-parameter for ORG call_async(q, conn.ContactInfo, 'SetContactInfo', [('org', ['language=en'], ['Collabora Ltd.'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # empty ORG call_async(q, conn.ContactInfo, 'SetContactInfo', [('org', [], [])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # not enough values for N call_async(q, conn.ContactInfo, 'SetContactInfo', [('n', [], ['Ninja'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # too many values for N call_async( q, conn.ContactInfo, 'SetContactInfo', [('n', [], 'what could it mean if you have too many field values?'.split())]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) q.unforbid_events(forbidden) # Following a reshuffle, Company Policy Enforcement is declared to be # a sub-department within Human Resources, and the ninja no longer # qualifies for a company phone vcard_in = [ (u'fn', [], [u'Wee Ninja']), (u'n', [], [u'Ninja', u'Wee', u'', u'', u'-san']), (u'org', [], ['Collabora, Ltd.', 'Human Resources', 'Company Policy Enforcement']), (u'adr', ['type=work', 'type=postal', 'type=parcel'], [ '', '', '11 Kings Parade', 'Cambridge', 'Cambridgeshire', 'CB2 1SJ', 'UK' ]), (u'tel', ['type=voice', 'type=work'], ['+44 1223 362967']), (u'email', ['type=internet', 'type=pref'], ['*****@*****.**']), (u'email', ['type=internet'], ['*****@*****.**']), (u'url', [], ['http://www.thinkgeek.com/geektoys/plush/8823/']), (u'nickname', [], [u'HR Ninja']), (u'nickname', [], [u'Enforcement Ninja']) ] call_async(q, conn.ContactInfo, 'SetContactInfo', vcard_in) event = q.expect('stream-iq', iq_type='get', query_ns='vcard-temp', query_name='vCard') repeat_previous_vcard(stream, event.stanza, vcard_set_event.stanza) _, vcard_set_event = q.expect_many( EventPattern('dbus-signal', signal='ContactInfoChanged'), EventPattern('stream-iq', iq_type='set', query_ns='vcard-temp', query_name='vCard'), ) assertLength(1, xpath.queryForNodes('/iq/vCard/ORG', vcard_set_event.stanza)) assertEquals( 'Collabora, Ltd.', xpath.queryForString('/iq/vCard/ORG/ORGNAME', vcard_set_event.stanza)) units = xpath.queryForNodes('/iq/vCard/ORG/ORGUNIT', vcard_set_event.stanza) assertLength(2, units) for i, exp_unit in enumerate( ['Human Resources', 'Company Policy Enforcement']): assertEquals(exp_unit, str(units[i])) assertLength(1, xpath.queryForNodes('/iq/vCard/TEL', vcard_set_event.stanza)) for tel in xpath.queryForNodes('/iq/vCard/TEL', vcard_set_event.stanza): assertLength(1, xpath.queryForNodes('/TEL/NUMBER', tel)) assertEquals('+44 1223 362967', xpath.queryForString('/TEL/NUMBER', tel)) assertLength(1, xpath.queryForNodes('/TEL/VOICE', tel)) assertLength(1, xpath.queryForNodes('/TEL/WORK', tel)) acknowledge_iq(stream, vcard_set_event.stanza) _, event = q.expect_many( EventPattern('dbus-return', method='SetContactInfo'), EventPattern('dbus-signal', signal='ContactInfoChanged'), ) vcard_out = event.args[1][:] # the only change we expect to see is that perhaps the fields are # re-ordered, and perhaps the types on the 'tel' are re-ordered assertEquals(vcard_in[4][0], 'tel') vcard_in[4][1].sort() assertEquals(vcard_out[4][0], 'tel') vcard_out[4][1].sort() assertEquals(vcard_in, vcard_out) # Finally, the ninja decides that publishing his contact details is not # very ninja-like, and decides to be anonymous. The first (most important) # of his nicknames from the old vCard is kept, due to nickname's dual role # as ContactInfo and the alias. call_async(q, conn.ContactInfo, 'SetContactInfo', []) event = q.expect('stream-iq', iq_type='get', query_ns='vcard-temp', query_name='vCard') repeat_previous_vcard(stream, event.stanza, vcard_set_event.stanza) vcard_set_event = q.expect('stream-iq', iq_type='set', query_ns='vcard-temp', query_name='vCard') assertLength(1, xpath.queryForNodes('/iq/vCard/*', vcard_set_event.stanza)) assertEquals( 'HR Ninja', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) acknowledge_iq(stream, vcard_set_event.stanza) q.expect_many( EventPattern('dbus-return', method='SetContactInfo'), EventPattern('dbus-signal', signal='ContactInfoChanged'), )
def test(q, bus, conn, stream): event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') call_async(q, conn.ContactInfo, 'SetContactInfo', [(u'fn', [], [u'Wee Ninja']), (u'n', [], [u'Ninja', u'Wee', u'', u'', u'-san']), (u'org', [], ['Collabora, Ltd.']), (u'adr', ['type=work','type=postal','type=parcel'], ['', '', '11 Kings Parade', 'Cambridge', 'Cambridgeshire', 'CB2 1SJ', 'UK']), (u'label', ['type=work'], [ '11 Kings Parade\n' 'Cambridge\n' 'Cambridgeshire\n' 'CB2 1SJ\n' 'UK\n']), (u'tel', ['type=voice','type=work'], ['+44 1223 362967']), (u'tel', ['type=voice','type=work'], ['+44 7700 900753']), (u'email', ['type=internet','type=pref'], ['*****@*****.**']), (u'email', ['type=internet'], ['*****@*****.**']), (u'x-jabber', [], ['*****@*****.**']), (u'x-jabber', [], ['*****@*****.**']), (u'url', [], ['http://www.thinkgeek.com/geektoys/plush/8823/']), (u'nickname', [], [u'HR Ninja']), (u'nickname', [], [u'Enforcement Ninja'])]) # We don't acknowledge the initial vCard get until we're sure that Gabble's # received our call to SetContactInfo. This ensures that it will issue a # set when we send the reply, rather than issuing another get to ensure the # vCard is really, absolutely up to date before editing it. sync_dbus(bus, q, conn) acknowledge_iq(stream, event.stanza) vcard_set_event = q.expect('stream-iq', iq_type='set', query_ns='vcard-temp', query_name='vCard') assertLength(2, xpath.queryForNodes('/iq/vCard/NICKNAME', vcard_set_event.stanza)) nicknames = [] for nickname in xpath.queryForNodes('/iq/vCard/NICKNAME', vcard_set_event.stanza): nicknames.append(str(nickname)) assertEquals(['HR Ninja', 'Enforcement Ninja'], nicknames) assertEquals(None, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) assertEquals('Wee', xpath.queryForString('/iq/vCard/N/GIVEN', vcard_set_event.stanza)) assertEquals('Ninja', xpath.queryForString('/iq/vCard/N/FAMILY', vcard_set_event.stanza)) assertEquals('-san', xpath.queryForString('/iq/vCard/N/SUFFIX', vcard_set_event.stanza)) assertEquals('Wee Ninja', xpath.queryForString('/iq/vCard/FN', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/ORG', vcard_set_event.stanza)) assertEquals('Collabora, Ltd.', xpath.queryForString('/iq/vCard/ORG/ORGNAME', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/ORG/ORGUNIT', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/LABEL', vcard_set_event.stanza)) lines = xpath.queryForNodes('/iq/vCard/LABEL/LINE', vcard_set_event.stanza) assertLength(5, lines) for i, exp_line in enumerate(['11 Kings Parade', 'Cambridge', 'Cambridgeshire', 'CB2 1SJ', 'UK']): assertEquals(exp_line, str(lines[i])) assertLength(2, xpath.queryForNodes('/iq/vCard/TEL', vcard_set_event.stanza)) for tel in xpath.queryForNodes('/iq/vCard/TEL', vcard_set_event.stanza): assertLength(1, xpath.queryForNodes('/TEL/NUMBER', tel)) assertContains(xpath.queryForString('/TEL/NUMBER', tel), ('+44 1223 362967', '+44 7700 900753')) assertLength(1, xpath.queryForNodes('/TEL/VOICE', tel)) assertLength(1, xpath.queryForNodes('/TEL/WORK', tel)) assertLength(2, xpath.queryForNodes('/iq/vCard/EMAIL', vcard_set_event.stanza)) for email in xpath.queryForNodes('/iq/vCard/EMAIL', vcard_set_event.stanza): assertContains(xpath.queryForString('/EMAIL/USERID', email), ('*****@*****.**', '*****@*****.**')) assertLength(1, xpath.queryForNodes('/EMAIL/INTERNET', email)) if 'collabora' in xpath.queryForString('/EMAIL/USERID', email): assertLength(1, xpath.queryForNodes('/EMAIL/PREF', email)) else: assertEquals(None, xpath.queryForNodes('/EMAIL/PREF', email)) assertLength(2, xpath.queryForNodes('/iq/vCard/JABBERID', vcard_set_event.stanza)) for jid in xpath.queryForNodes('/iq/vCard/JABBERID', vcard_set_event.stanza): assertContains(xpath.queryForString('/JABBERID', jid), ('*****@*****.**', '*****@*****.**')) acknowledge_iq(stream, vcard_set_event.stanza) q.expect_many( EventPattern('dbus-return', method='SetContactInfo'), EventPattern('dbus-signal', signal='AliasesChanged', predicate=lambda e: e.args[0][0][1] == 'HR Ninja'), EventPattern('dbus-signal', signal='ContactInfoChanged'), ) # Exercise various invalid SetContactInfo operations sync_stream(q, stream) sync_dbus(bus, q, conn) forbidden = [EventPattern('stream-iq', query_ns='vcard-temp')] q.forbid_events(forbidden) # unknown field call_async(q, conn.ContactInfo, 'SetContactInfo', [('x-salary', [], ['547 espressos per month'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # not enough values for a simple field call_async(q, conn.ContactInfo, 'SetContactInfo', [('fn', [], [])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # too many values for a simple field call_async(q, conn.ContactInfo, 'SetContactInfo', [('fn', [], ['Wee', 'Ninja'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # unsupported type-parameter for a simple field call_async(q, conn.ContactInfo, 'SetContactInfo', [('fn', ['language=ja'], ['Wee Ninja'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # unsupported type-parameter for a structured field call_async(q, conn.ContactInfo, 'SetContactInfo', [(u'n', ['language=ja'], [u'Ninja', u'Wee', u'', u'', u'-san'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # unsupported type-parameter for LABEL call_async(q, conn.ContactInfo, 'SetContactInfo', [('label', ['language=en'], ['Collabora Ltd.\n11 Kings Parade'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # not enough values for LABEL call_async(q, conn.ContactInfo, 'SetContactInfo', [('label', [], [])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # too many values for LABEL call_async(q, conn.ContactInfo, 'SetContactInfo', [('label', [], ['11 Kings Parade', 'Cambridge'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # unsupported type-parameter for ORG call_async(q, conn.ContactInfo, 'SetContactInfo', [('org', ['language=en'], ['Collabora Ltd.'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # empty ORG call_async(q, conn.ContactInfo, 'SetContactInfo', [('org', [], [])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # not enough values for N call_async(q, conn.ContactInfo, 'SetContactInfo', [('n', [], ['Ninja'])]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) # too many values for N call_async(q, conn.ContactInfo, 'SetContactInfo', [('n', [], 'what could it mean if you have too many field values?'.split())]) q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT) q.unforbid_events(forbidden) # Following a reshuffle, Company Policy Enforcement is declared to be # a sub-department within Human Resources, and the ninja no longer # qualifies for a company phone vcard_in = [(u'fn', [], [u'Wee Ninja']), (u'n', [], [u'Ninja', u'Wee', u'', u'', u'-san']), (u'org', [], ['Collabora, Ltd.', 'Human Resources', 'Company Policy Enforcement']), (u'adr', ['type=work','type=postal','type=parcel'], ['', '', '11 Kings Parade', 'Cambridge', 'Cambridgeshire', 'CB2 1SJ', 'UK']), (u'tel', ['type=voice','type=work'], ['+44 1223 362967']), (u'email', ['type=internet','type=pref'], ['*****@*****.**']), (u'email', ['type=internet'], ['*****@*****.**']), (u'url', [], ['http://www.thinkgeek.com/geektoys/plush/8823/']), (u'nickname', [], [u'HR Ninja']), (u'nickname', [], [u'Enforcement Ninja'])] call_async(q, conn.ContactInfo, 'SetContactInfo', vcard_in) event = q.expect('stream-iq', iq_type='get', query_ns='vcard-temp', query_name='vCard') repeat_previous_vcard(stream, event.stanza, vcard_set_event.stanza) _, vcard_set_event = q.expect_many( EventPattern('dbus-signal', signal='ContactInfoChanged'), EventPattern('stream-iq', iq_type='set', query_ns='vcard-temp', query_name='vCard'), ) assertLength(1, xpath.queryForNodes('/iq/vCard/ORG', vcard_set_event.stanza)) assertEquals('Collabora, Ltd.', xpath.queryForString('/iq/vCard/ORG/ORGNAME', vcard_set_event.stanza)) units = xpath.queryForNodes('/iq/vCard/ORG/ORGUNIT', vcard_set_event.stanza) assertLength(2, units) for i, exp_unit in enumerate(['Human Resources', 'Company Policy Enforcement']): assertEquals(exp_unit, str(units[i])) assertLength(1, xpath.queryForNodes('/iq/vCard/TEL', vcard_set_event.stanza)) for tel in xpath.queryForNodes('/iq/vCard/TEL', vcard_set_event.stanza): assertLength(1, xpath.queryForNodes('/TEL/NUMBER', tel)) assertEquals('+44 1223 362967', xpath.queryForString('/TEL/NUMBER', tel)) assertLength(1, xpath.queryForNodes('/TEL/VOICE', tel)) assertLength(1, xpath.queryForNodes('/TEL/WORK', tel)) acknowledge_iq(stream, vcard_set_event.stanza) _, event = q.expect_many( EventPattern('dbus-return', method='SetContactInfo'), EventPattern('dbus-signal', signal='ContactInfoChanged'), ) vcard_out = event.args[1][:] # the only change we expect to see is that perhaps the fields are # re-ordered, and perhaps the types on the 'tel' are re-ordered assertEquals(vcard_in[4][0], 'tel') vcard_in[4][1].sort() assertEquals(vcard_out[4][0], 'tel') vcard_out[4][1].sort() assertEquals(vcard_in, vcard_out) # Finally, the ninja decides that publishing his contact details is not # very ninja-like, and decides to be anonymous. The first (most important) # of his nicknames from the old vCard is kept, due to nickname's dual role # as ContactInfo and the alias. call_async(q, conn.ContactInfo, 'SetContactInfo', []) event = q.expect('stream-iq', iq_type='get', query_ns='vcard-temp', query_name='vCard') repeat_previous_vcard(stream, event.stanza, vcard_set_event.stanza) vcard_set_event = q.expect('stream-iq', iq_type='set', query_ns='vcard-temp', query_name='vCard') assertLength(1, xpath.queryForNodes('/iq/vCard/*', vcard_set_event.stanza)) assertEquals('HR Ninja', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) acknowledge_iq(stream, vcard_set_event.stanza) q.expect_many( EventPattern('dbus-return', method='SetContactInfo'), EventPattern('dbus-signal', signal='ContactInfoChanged'), )
def test(q, bus, conn, stream): # Initial vCard request. Respond only after we call SetAliases(). vcard_get_event = q.expect('stream-iq', iq_type='get', to=None, query_ns=ns.VCARD_TEMP, query_name='vCard') sync_stream(q, stream) handle = conn.Properties.Get(cs.CONN, "SelfHandle") call_async(q, conn.Aliasing, 'SetAliases', {handle: 'Robert the Bruce'}) sync_dbus(bus, q, conn) acknowledge_iq(stream, vcard_get_event.stanza) # Gabble sets a new vCard with our nickname. vcard_set_event = q.expect('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard') assertEquals('Robert the Bruce', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/FN', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) # Before the server replies, the user sets their avatar call_async(q, conn.Avatars, 'SetAvatar', b'hello', 'image/png') sync_dbus(bus, q, conn) # This acknowledgement is for the nickname acknowledge_iq(stream, vcard_set_event.stanza) hello_binval = base64.b64encode(b'hello').decode() # This sets the avatar vcard_set_event = q.expect('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard') assertEquals('Robert the Bruce', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertEquals('image/png', xpath.queryForString('/iq/vCard/PHOTO/TYPE', vcard_set_event.stanza)) binval = xpath.queryForString('/iq/vCard/PHOTO/BINVAL', vcard_set_event.stanza) assertEquals(hello_binval, binval.strip()) assertEquals(None, xpath.queryForNodes('/iq/vCard/FN', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) # Before the server replies, the user sets their ContactInfo call_async(q, conn.ContactInfo, 'SetContactInfo', [(u'fn', [], [u'King Robert I']), (u'n', [], [u'de Brus', u'Robert', u'', u'King', u'']), (u'nickname', [], [u'Bob'])]) sync_dbus(bus, q, conn) # This acknowledgement is for the avatar; SetAvatar won't happen # until this has acknowledge_iq(stream, vcard_set_event.stanza) # This sets the ContactInfo vcard_set_event, _ = q.expect_many( EventPattern('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard'), EventPattern('dbus-return', method='SetAvatar')) assertEquals('Bob', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertEquals('image/png', xpath.queryForString('/iq/vCard/PHOTO/TYPE', vcard_set_event.stanza)) binval = xpath.queryForString('/iq/vCard/PHOTO/BINVAL', vcard_set_event.stanza) assertEquals(hello_binval, binval.strip()) assertLength(1, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) assertEquals('Robert', xpath.queryForString('/iq/vCard/N/GIVEN', vcard_set_event.stanza)) assertEquals('de Brus', xpath.queryForString('/iq/vCard/N/FAMILY', vcard_set_event.stanza)) assertEquals('King', xpath.queryForString('/iq/vCard/N/PREFIX', vcard_set_event.stanza)) assertEquals('King Robert I', xpath.queryForString('/iq/vCard/FN', vcard_set_event.stanza)) # Before the server replies, the user unsets their avatar call_async(q, conn.Avatars, 'SetAvatar', '', '') sync_dbus(bus, q, conn) # This acknowledgement is for the ContactInfo; SetContactInfo won't happen # until this has acknowledge_iq(stream, vcard_set_event.stanza) vcard_set_event, _ = q.expect_many( EventPattern('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard'), EventPattern('dbus-return', method='SetContactInfo')) assertEquals('Bob', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) assertEquals('Robert', xpath.queryForString('/iq/vCard/N/GIVEN', vcard_set_event.stanza)) assertEquals('de Brus', xpath.queryForString('/iq/vCard/N/FAMILY', vcard_set_event.stanza)) assertEquals('King', xpath.queryForString('/iq/vCard/N/PREFIX', vcard_set_event.stanza)) assertEquals('King Robert I', xpath.queryForString('/iq/vCard/FN', vcard_set_event.stanza)) # This acknowledgement is for the avatar; SetAvatar won't finish # until this is received acknowledge_iq(stream, vcard_set_event.stanza) q.expect('dbus-return', method='SetAvatar') # Now Gabble gets disconnected. sync_stream(q, stream) disconnect_conn(q, conn, stream)