def deleteNode(self, node, server=None): """ Deletes the selected node. @type node: string @param node: id of the node to delete @type server: string @param server: PubSub server @rtype: (string , list[string]) @return: A tuple with the type of answer ('ok','error') and information about the answer. In case of 'error', a list with the errors. In case of 'ok' an empty list. """ #TODO: A method to redirect the subscriptions to the node to another one COULD be implemented if server is None: server = self._server iq = Iq( typ='set', queryNS=None, attrs={}, frm=self._client, to=server, ) pubsub_node = Node(tag='pubsub', attrs={'xmlns': NS_PUBSUB_OWNER}) pubsub_node.addChild(name='delete', attrs={'node': node}) iq.addChild(node=pubsub_node) return self._sendAndReceive(iq, lambda msg: [])
def handle_starttag(self, tag, attr): """XML Parser callback. Used internally""" attrs={} #attlist=attrs.keys() # #for attr in attlist: # FIXME: Crude hack. And it also slows down the whole library considerably. # sp=attr.rfind(" ") # # if sp==-1: continue # # ns=attr[:sp] # # attrs[self.namespaces[ns]+attr[sp+1:]]=attrs[attr] # del attrs[attr] # for each in attr: attrs[each[0]]=each[1] self.__depth += 1 self.DEBUG(DBG_NODEBUILDER, "DEPTH -> %i , tag -> %s, attrs -> %s" % (self.__depth, tag, `attrs`), 'down') if self.__depth == self._dispatch_depth: if not self._mini_dom : self._mini_dom = Node(tag=tag, attrs=attrs) else: Node.__init__(self._mini_dom,tag=tag, attrs=attrs) self._ptr = self._mini_dom elif self.__depth > self._dispatch_depth: self._ptr.kids.append(Node(tag=tag,parent=self._ptr,attrs=attrs)) self._ptr = self._ptr.kids[-1] if self.__depth == 1: self._document_attrs = attrs ns, name = (['']+tag.split())[-2:] self.stream_header_received(ns, name, attrs) if not self.last_is_data and self._ptr.parent: self._ptr.parent.data.append('') self.last_is_data = 0
def handle_starttag(self, tag, attr): """XML Parser callback. Used internally""" attrs = {} #attlist=attrs.keys() # #for attr in attlist: # FIXME: Crude hack. And it also slows down the whole library considerably. # sp=attr.rfind(" ") # # if sp==-1: continue # # ns=attr[:sp] # # attrs[self.namespaces[ns]+attr[sp+1:]]=attrs[attr] # del attrs[attr] # for each in attr: attrs[each[0]] = each[1] self.__depth += 1 self.DEBUG( DBG_NODEBUILDER, "DEPTH -> %i , tag -> %s, attrs -> %s" % (self.__depth, tag, ` attrs `), 'down') if self.__depth == self._dispatch_depth: if not self._mini_dom: self._mini_dom = Node(tag=tag, attrs=attrs) else: Node.__init__(self._mini_dom, tag=tag, attrs=attrs) self._ptr = self._mini_dom elif self.__depth > self._dispatch_depth: self._ptr.kids.append(Node(tag=tag, parent=self._ptr, attrs=attrs)) self._ptr = self._ptr.kids[-1] if self.__depth == 1: self._document_attrs = attrs ns, name = ([''] + tag.split())[-2:] self.stream_header_received(ns, name, attrs) if not self.last_is_data and self._ptr.parent: self._ptr.parent.data.append('') self.last_is_data = 0
def unsubscribe(self, node, server=None, jid=None): """ Unsubscribe from the selected node @type node: string @param node: id of the node to unsubscribe @type server: string @param server: PubSub server @rtype: (string , list[string]) @return: A tuple with the type of answer ('ok','error') and information about the answer. In case of 'error', a list with the errors. In case of 'ok' an empty list. """ if server is None: server = self._server if jid is None: jid = self._client iq = Iq( typ='set', queryNS=None, attrs={}, frm=self._client, to=server ) pubsub_node = Node(tag='pubsub', attrs={'xmlns': NS_PUBSUB_OWNER}) unsubscribe_node = Node(tag='unsubscribe', attrs={'node': node, 'jid': jid}) pubsub_node.addChild(node=unsubscribe_node) iq.addChild(node=pubsub_node) return self._sendAndReceive(iq, lambda msg: [])
def __init__(self, status=None, nick=None, jid=None, affiliation=None, role=None, reason=None, actor=None, node=None): Node.__init__(self, 'x', node=node) if not node: self.setNamespace(NS_MUC_USER) if jid != None: self.setJid(jid) if affiliation != None: self.setAffiliation(affiliation) if role != None: self.setRole(role) if nick != None: self.setNick(nick) if reason != None: self.setReason(reason) if status != None: self.setStatus(status) if actor != None: self.setActor(actor)
def unsubscribe(self, node, server=None, jid=None): """ Unsubscribe from the selected node @type node: string @param node: id of the node to unsubscribe @type server: string @param server: PubSub server @rtype: (string , list[string]) @return: A tuple with the type of answer ('ok','error') and information about the answer. In case of 'error', a list with the errors. In case of 'ok' an empty list. """ if server is None: server = self._server if jid is None: jid = self._client iq = Iq(typ='set', queryNS=None, attrs={}, frm=self._client, to=server) pubsub_node = Node(tag='pubsub', attrs={'xmlns': NS_PUBSUB_OWNER}) unsubscribe_node = Node(tag='unsubscribe', attrs={ 'node': node, 'jid': jid }) pubsub_node.addChild(node=unsubscribe_node) iq.addChild(node=pubsub_node) return self._sendAndReceive(iq, lambda msg: [])
def mshtmlformat(text): """Converts a MySpace formatted message into a (text,html) tuple""" html = Node('html') html.setNamespace('http://jabber.org/protocol/xhtml-im') xhtml = html.addChild('body',namespace='http://www.w3.org/1999/xhtml') tree = ET.XML('<body>' + text + '</body>') text = convert_node_myspace_to_text_xhtml(tree, xhtml) return text,html
def __init__(self, id=None, mimetype=None, profile=None, node=None): Node.__init__(self, 'si', node=node) if not node: self.setNamespace(NS_SI) if id != None: self.setID(id) if mime - type: self.setMimeType(mime - type) if profile: self.setProfile(profile)
def __init__(self, id = None, mimetype = None, profile = None, node = None): Node.__init__(self,'si',node=node) if not node: self.setNamespace(NS_SI) if id != None: self.setID(id) if mime-type: self.setMimeType(mime-type) if profile: self.setProfile(profile)
def __init__(self, id = None, composing = False, delivered = False, offline = False, displayed = False, node = None): Node.__init__(self, 'x', node = node) if not node: self.setNamespace(NS_EVENT) if id != None: self.setEventID(id) if composing: self.setComposing() if delivered: self.setDelivered() if offline: self.setOffline() if displayed: self.setDisplayed()
def __init__(self, name = None, size = None, hash = None, date = None, offset = None, length = None, node = None): Node.__init__(self,'file',node=node) if not node: self.setNamespace(NS_SI_FILE) if name: self.setName(name) if size: self.setSize(size) if hash: self.setHash(hash) if date: self.setDate(date) if offset: self.setOffset(offset) if length: self.setLength(length)
def testPublishEvent(self): result = self.a.createEvent("ExistsNode") self.assertEqual(result, ('ok', ['ExistsNode'])) result = self.b.subscribeToEvent("ExistsNode", SubscribeBehaviour()) self.assertEqual(result, ('ok', [])) #TODO: Check that the last published item is sent after subscription. self.b.eventmsg = None self.a.publishEvent('ExistsNode', Node(tag='foo')) import time time.sleep(3) # wait for the event #Check that the event is received in the callback self.assertNotEqual(self.b.eventmsg, None) n = self.b.eventmsg.T.event.T.items.T.item self.assertNotEqual(n.getTag("foo"), None) if not "puba@" + host in n.getAttr("publisher"): self.fail("Wrong publisher") #TODO: Check that the new item published by 'a' is received too. self.b.unsubscribeFromEvent("ExistsNode") self.a.deleteEvent("ExistsNode")
def testPublishNotExistEvent(self): result = self.a.publishEvent('NENode', Node(tag='foo')) self.assertEqual(result[0], 'ok') self.assertEqual(len(result[1]), 2) self.assertEqual(result[1][0], 'NENode') self.assertEqual(type(result[1][1]), unicode) self.a.deleteEvent("NENode")
def __init__(self,status = None, nick = None, jid = None, affiliation = None, role = None, reason = None, actor = None, node = None): Node.__init__(self, 'x', node = node) if not node: self.setNamespace(NS_MUC_USER) if jid != None: self.setJid(jid) if affiliation != None: self.setAffiliation(affiliation) if role != None: self.setRole(role) if nick != None: self.setNick(nick) if reason != None: self.setReason(reason) if status != None: self.setStatus(status) if actor != None: self.setActor(actor)
def createNode(self, node, server=None, type='leaf', parent=None, access=None): """ Creates a node with the specified parameters. @type node: string @param node: The ID of the node to create @type server: string @param server: PubSub server @type type: string @param type: Type of the node: 'leaf' or 'collection' @type parent: string @param parent: id of the parent node. None if parent is root @type access: string @param acccess: Access model of the node @rtype: (string , list[string]) @return: A tuple with the type of answer ('ok','error') and information about the answer. In case of 'error', a list with the errors. In case of 'ok' the name of the created node. """ #TODO: Add suport for node configuration (RECOMMENDED in XEP-60) if server is None: server = self._server iq = Iq( typ='set', queryNS=None, attrs={}, frm=self._client, to=server ) pubsub_node = Node(tag='pubsub', attrs={'xmlns':NS_PUBSUB}) create_node = Node(tag='create', attrs={} if node is None else {'node':node}) pubsub_node.addChild(node=create_node) iq.addChild(node=pubsub_node) if parent is not None or type=='collection' or access is not None: field_nodes=[] configure_node = Node(tag='configure') field_nodes.append(DataField('FORM_TYPE', NS_PUBSUB+'#node_config','hidden')) if parent is not None: field_nodes.append(DataField('pubsub#collection',parent)) # <field var='pubsub#collection'><value>announcements</value></field> if type == 'collection': field_nodes.append(DataField('pubsub#node_type','collection')) if access is not None: field_nodes.append(DataField('pubsub#access_model',access)) x_node = DataForm(typ='submit',data=field_nodes) configure_node.addChild(x_node) pubsub_node.addChild(configure_node) return self._sendAndReceive(iq, lambda msg:[msg.getTag('pubsub').getTag('create')['node']])
def _process(self): #pubsub = PubSub(self.myAgent, self) try: while self.myAgent.subscribeToEvent('ExistsNode') == ( 'error', ['item-not-found']): time.sleep(1) asserteq(self.myAgent.subscribeToEvent('ExistsNode'), ('error', [ 'not-authorized', 'presence-subscription-required' ])) asserteq( self.myAgent.unsubscribeFromEvent('ExistsNode'), ('error', ['unexpected-request', 'not-subscribeToEventd'])) asserteq(self.myAgent.deleteEvent('ExistsNode'), ('error', ['forbidden'])) asserteq(self.myAgent.createEvent('ExistsNode'), ('error', ['conflict'])) asserteq( self.myAgent.publishEvent('ExistsNode', Node(tag='foo')), ('error', ['forbidden'])) self.myAgent.setSocialItem('romeo@' + self.myAgent.server) self.myAgent._socialnetwork['romeo@' + self.myAgent.server].subscribe() time.sleep(10) print 'Sleeping 10 seconds...' asserteq(self.myAgent.subscribeToEvent('ExistsNode'), ('ok', [])) #TODO: Check that the last published item is sent after subscription. #TODO: Check that the new item published by Romeo is received too. time.sleep(5) print 'Sleeping 5 seconds...' asserteq(self.myAgent.unsubscribeFromEvent('ExistsNode'), ('ok', [])) asserteq(self.myAgent.subscribeToEvent('ExistsNode'), ('ok', [])) # OK #TODO: Check that the last published item is sent after subscription. asserteq( self.myAgent.subscribeToEvent('ExistsNode', jid='romeo@' + self.myAgent.server), ('error', ['bad-request', 'invalid-jid'])) #TODO: Check that the notification of node deletion is received. except Exception, e: print e
def __init__(self, id=None, composing=False, delivered=False, offline=False, displayed=False, node=None): Node.__init__(self, 'x', node=node) if not node: self.setNamespace(NS_EVENT) if id != None: self.setEventID(id) if composing: self.setComposing() if delivered: self.setDelivered() if offline: self.setOffline() if displayed: self.setDisplayed()
def _process(self): #self.myAgent.setSocialItem('sandra@'+self.myAgent.server) #self.myAgent._socialnetwork['sandra@'+self.myAgent.server].subscribe() #frm = self.myAgent.getAID().getName() #to = self.myAgent.getSpadePlatformJID() #pubsub = PubSub(self.myAgent, self) try: asserteq(self.myAgent.subscribeToEvent('NENode'), ('error', ['item-not-found'])) asserteq(self.myAgent.unsubscribeFromEvent('NENode'), ('error', ['item-not-found'])) asserteq(self.myAgent.deleteEvent('NENode'), ('error', ['item-not-found'])) res = self.myAgent.publishEvent('NENode', Node(tag='foo')) asserteq(res[0], 'ok') asserteq(len(res[1]), 2) asserteq(res[1][0], 'NENode') asserteq(type(res[1][1]), unicode) asserteq(self.myAgent.createEvent('ExistsNode'), ('ok', ['ExistsNode'])) self.myAgent.setSocialItem('juliet@'+self.myAgent.server) self.myAgent._socialnetwork['juliet@'+self.myAgent.server].subscribe() time.sleep(15) print 'Sleeping 15 seconds...' self.myAgent.publishEvent('ExistsNode', Node(tag='foo')) #OK asserteq(self.myAgent.unsubscribeFromEvent('ExistsNode', jid='juliet@'+self.myAgent.server), ('error', ['bad-request', 'invalid-jid'])) time.sleep(5) print 'Sleeping 5 seconds...' asserteq(self.myAgent.deleteEvent('ExistsNode'), ('ok', [])) except Exception,e: print 'Exception' print e
def __init__(self, name=None, size=None, hash=None, date=None, offset=None, length=None, node=None): Node.__init__(self, 'file', node=node) if not node: self.setNamespace(NS_SI_FILE) if name: self.setName(name) if size: self.setSize(size) if hash: self.setHash(hash) if date: self.setDate(date) if offset: self.setOffset(offset) if length: self.setLength(length)
def publish(self, node, event=None): """ Publishes an item to a given node. XXX: 'node' here is not an XML node, but the attribute for <publish> @type node: string @param node: The ID of the pubsub node to publish @type event: Event @param event: Content to publish @rtype: (string , list[string]) @return: A tuple with the type of answer ('ok','error') and information about the answer. In case of 'error', a list with the errors. In case of 'ok' the name of the created node. """ iq = Iq( typ='set', queryNS=None, attrs={}, frm=self._client ) pubsub_node = Node(tag='pubsub', attrs={'xmlns': NS_PUBSUB}) publish_node = Node(tag='publish', attrs={'node': node}) item_node = Node(tag='item') if event is not None: item_node.addChild(node=event) publish_node.addChild(node=item_node) pubsub_node.addChild(node=publish_node) iq.addChild(node=pubsub_node) def getContents(msg): node_publish = msg.getTag('pubsub').getTag('publish') #XXX: Server implementation always returns the item id, but XEP-60 does # vim snot require it return [node_publish['node'], node_publish.getTag('item')['id']] return self._sendAndReceive(iq, getContents)
def iqReceived(self, cnx, iq): '''Default handler for IQ stanzas.''' typ = iq.getType() ns = iq.getQueryNS() if (NS_VERSION == ns) and ('get' == typ): name = Node('name') name.setData(LIB_NAME) version = Node('version') version.setData(LIB_VERSION) reply = iq.buildReply('result') query = reply.getQuery() query.addChild(node=name) query.addChild(node=version) cnx.send(reply) raise NodeProcessed elif (NS_LAST == ns) and ('get' == typ): if self.last is not None: reply = iq.buildReply('result') query = reply.getQuery() query.setAttr('seconds', (datetime.now() - self.last).seconds) cnx.send(reply) raise NodeProcessed else: debug("Unhandled IQ namespace '%s'." % ns)
def publish(self, node, event=None): """ Publishes an item to a given node. XXX: 'node' here is not an XML node, but the attribute for <publish> @type node: string @param node: The ID of the pubsub node to publish @type event: Event @param event: Content to publish @rtype: (string , list[string]) @return: A tuple with the type of answer ('ok','error') and information about the answer. In case of 'error', a list with the errors. In case of 'ok' the name of the created node. """ iq = Iq(typ='set', queryNS=None, attrs={}, frm=self._client) pubsub_node = Node(tag='pubsub', attrs={'xmlns': NS_PUBSUB}) publish_node = Node(tag='publish', attrs={'node': node}) item_node = Node(tag='item') if event is not None: item_node.addChild(node=event) publish_node.addChild(node=item_node) pubsub_node.addChild(node=publish_node) iq.addChild(node=pubsub_node) def getContents(msg): node_publish = msg.getTag('pubsub').getTag('publish') #XXX: Server implementation always returns the item id, but XEP-60 does # vim snot require it return [node_publish['node'], node_publish.getTag('item')['id']] return self._sendAndReceive(iq, getContents)
def join(self, channel, password=None, nick=None): """ join conference. """ if '#' in channel: return try: if not nick: nick = channel.split('/')[1] except IndexError: nick = self.nick channel = channel.split('/')[0] if not self.channels.has_key(channel): # init channel data self.channels.setdefault(channel, {}) # setup error wait q = Queue.Queue() self.errorwait.register("409", q, 3) self.errorwait.register("401", q, 3) self.errorwait.register("400", q, 3) # do the actual join presence = xmpp.Presence(to=channel + '/' + nick) #presence.setFrom(self.me) if password: passnode = Node('password') passnode.addData(password) presence.addChild(name='x', namespace='http://jabber.org/protocol/muc', \ payload=[passnode, ]) self.send(presence) errorobj = waitforqueue(q, 3) if errorobj: err = errorobj[0].error rlog(10, self.name, 'error joining %s: %s' % (channel, err)) if err == '409': if channel not in self.channels409: self.channels409.append(channel) return err self.timejoined[channel] = time.time() chan = self.channels[channel] # if password is provided set it chan['nick'] = nick if password: chan['key'] = password # check for control char .. if its not there init to ! if not chan.has_key('cc'): chan['cc'] = config['defaultcc'] or '!' if not chan.has_key('perms'): chan['perms'] = [] self.channels.save() if channel not in self.state['joinedchannels']: self.state['joinedchannels'].append(channel) if channel in self.channels409: self.channels409.remove(channel) self.state.save() return 1
def createNode(self, node, server=None, type='leaf', parent=None, access=None): """ Creates a node with the specified parameters. @type node: string @param node: The ID of the node to create @type server: string @param server: PubSub server @type type: string @param type: Type of the node: 'leaf' or 'collection' @type parent: string @param parent: id of the parent node. None if parent is root @type access: string @param acccess: Access model of the node @rtype: (string , list[string]) @return: A tuple with the type of answer ('ok','error') and information about the answer. In case of 'error', a list with the errors. In case of 'ok' the name of the created node. """ #TODO: Add suport for node configuration (RECOMMENDED in XEP-60) if server is None: server = self._server iq = Iq(typ='set', queryNS=None, attrs={}, frm=self._client, to=server) pubsub_node = Node(tag='pubsub', attrs={'xmlns': NS_PUBSUB}) create_node = Node(tag='create', attrs={} if node is None else {'node': node}) pubsub_node.addChild(node=create_node) iq.addChild(node=pubsub_node) if parent is not None or type == 'collection' or access is not None: field_nodes = [] configure_node = Node(tag='configure') field_nodes.append( DataField('FORM_TYPE', NS_PUBSUB + '#node_config', 'hidden')) if parent is not None: field_nodes.append(DataField('pubsub#collection', parent)) # <field var='pubsub#collection'><value>announcements</value></field> if type == 'collection': field_nodes.append(DataField('pubsub#node_type', 'collection')) if access is not None: field_nodes.append(DataField('pubsub#access_model', access)) x_node = DataForm(typ='submit', data=field_nodes) configure_node.addChild(x_node) pubsub_node.addChild(configure_node) return self._sendAndReceive( iq, lambda msg: [msg.getTag('pubsub').getTag('create')['node']])
def __init__(self, form=None, node=None): Node.__init__(self, 'feature', node=node) if not node: self.setNamespace(NS_FEATURE) if form: self.addChild(form)
def __init__(self, form = None, node = None): Node.__init__(self,'feature',node=node) if not node: self.setNamespace(NS_FEATURE) if form: self.addChild(form)
def iqReceived(self, cnx, iq): '''IQ handler for the component''' typ = iq.getType() queries = iq.getChildren() # there should be only one if 0 == len(queries): return ns = queries[0].getNamespace() debug("OK we're handling IQ %s, ns=%s" % (typ, ns)) if NS_REGISTER == ns: if 'set' == typ: children = iq.getQueryChildren() if (0 != len(children)) and ('remove' == children[0].getName()): self.unregistrationRequested(iq) else: self.registrationRequested(iq) raise NodeProcessed elif 'get' == typ: instructions = Node('instructions') username = Node('username') user = UserAccount(iq.getFrom()) registered = user.isRegistered() if registered: instructions.setData(_(REGISTRATION, 'set_username')) username.setData(user.username) else: debug("A new user is preparing a registration") instructions.setData(_(REGISTRATION, 'introduction')) reply = iq.buildReply('result') query = reply.getQuery() if registered: query.addChild('registered') query.addChild(node=instructions) query.addChild(node=username) cnx.send(reply) raise NodeProcessed else: # Unkown namespace and type. The default handler will take care of it if we don't raise NodeProcessed. debug("Unknown IQ with ns '%s' and type '%s'." % (ns, typ)) elif NS_GATEWAY == ns: if 'get' == typ: reply = iq.buildReply('result') query = reply.getQuery() query.addChild('desc', payload=[_(ROSTER, 'address2jid_description')]) query.addChild('prompt', payload=[_(ROSTER, 'address2jid_prompt')]) cnx.send(reply) raise NodeProcessed elif 'set' == typ: children = iq.getQueryChildren() if (0 != len(children)) and ('prompt' == children[0].getName()): prompt = children[0].getData() debug("Someone wants to convert %s into a JID" % prompt) jid = Node('jid') try: jid.setData(Address(prompt).jid) except InvalidBitcoinAddressError: try: jid.setData(UserAccount(prompt).getLocalJID()) except UnknownUserError: reply = iq.buildReply(typ='error') reply.addChild(node=ErrorNode('item-not-found', 404, 'cancel', _(ROSTER, 'address2jid_invalid'))) cnx.send(reply) raise NodeProcessed reply = iq.buildReply('result') query = reply.getQuery() query.addChild(node=jid) cnx.send(reply) raise NodeProcessed elif NS_VCARD == ns: if 'get' == typ: reply = iq.buildReply('result') query = reply.getQuery() query.addChild('FN', payload=["%s v%s" % (LIB_NAME, LIB_VERSION)]) query.addChild('DESC', payload=[LIB_DESCRIPTION]) cnx.send(reply) raise NodeProcessed Addressable.iqReceived(self, cnx, iq)
def command(self, adhoc_state, vars): """ Send an ad-hoc command. The parameter vars is a list of tupels each defining name, type, and value. So if you pass the following tuple as vars:: [("var-name", "text-single", "example")] ... a field with the following XML will be send:: <field var="var-name" type="text-single"> <value>example</value> </field> The adhoc_state parameter is special to spectrumctl and identifies the command being executed. @param adhoc_state: The command identifier. @type adhoc_state: str @param vars: A list of tuples defining the fields to send. See above for more information. @todo: return str instead of None with the payload of the note stanza in case of a non-error note. @todo: use send_iq instead of doing our own wrapping/casting. @raises RuntimeError: If communicating with the socket fails or the command itself fails. """ from xmpp.simplexml import Node from xmpp.protocol import Iq, NS_DATA, NS_COMMANDS # build adhoc_state field: state_value = Node(tag='value', payload=[adhoc_state]) state = Node(tag='field', payload=[state_value], attrs={ 'type': 'hidden', 'var': 'adhoc_state' }) # build variable fields: fields = [state] for var in vars: name, typ, val = var # build payload for field: var_payload = [] if typ == 'text-multi': for line in val.splitlines(): var_payload.append(Node(tag='value', payload=[line])) else: var_payload.append(Node(tag='value', payload=[val])) # build field stanza: var_node = Node(tag='field', payload=var_payload, attrs={ 'type': typ, 'var': name }) fields.append(var_node) # build x stanza x = Node(tag='x', payload=fields, attrs={ 'xmlns': NS_DATA, 'type': 'submit' }) # build command node cmd_attrs = { 'node': 'transport_admin', 'sessionid': 'WHATEVER', 'xmlns': NS_COMMANDS } cmd = Node(tag='command', attrs=cmd_attrs, payload=[x]) # build IQ node iq = Iq(typ='set', xmlns=None) iq.addChild(node=cmd) answer = self.send_iq(iq) print("Answer: " + str(answer)) cmd = answer.kids[0] if len(cmd.kids) == 0: return note = cmd.kids[0] if note.getAttr('type') == 'error': raise RuntimeError(note.getPayload()[0])