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 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 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 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 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 _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 _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 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])
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