def complete_xml_element(self, xmlnode, _unused): """Complete the XML node with `self` content. Should be overriden in classes derived from `StanzaPayloadObject`. :Parameters: - `xmlnode`: XML node with the element being built. It has already right name and namespace, but no attributes or content. - `_unused`: document to which the element belongs. :Types: - `xmlnode`: `libxml2.xmlNode` - `_unused`: `libxml2.xmlDoc`""" if self.node: xmlnode.setProp("node", to_utf8(self.node)) if self.sid: xmlnode.setProp("sid", to_utf8(self.sid)) if self.mode and self.mode != 'tcp': xmlnode.setProp("mode", to_utf8(self.mode)) for host in self.hosts: try: host.as_xml(xmlnode, _unused) except: pprint(host) raise if self.activate: xmlnode.newChild(None, "activate", JID(self.activate).as_utf8()) if self.host_used: h = xmlnode.newChild(None, "streamhost-used", None) h.setProp("jid", JID(self.host_used).as_utf8())
def handle_message(self, stanza): ''' <message from='[email protected]/desktop' to='*****@*****.**'> <x xmlns='jabber:x:conference' jid='*****@*****.**' password='******' reason='Hey Hecate, this is the place for all good witches!'/> </message> ''' try: fromjid = stanza.get_from() x = stanza.xpath_eval('c:x', {'c': CONFERENCE_NS})[0] roomjid = JID(from_utf8(x.prop('jid'))) roomname = JID(roomjid).node password = x.prop('password') password = from_utf8(password) if password else None reason = x.prop('reason') reason = from_utf8(reason) if reason else None except Exception: traceback.print_exc() return False else: if not all((roomname, fromjid)): return False self.protocol.hub.on_invite( protocol=self.protocol, buddy=fromjid, room_name=roomname, message=reason, on_yes=lambda: self.protocol.join_chat_jid( roomjid, self.protocol.self_buddy.jid.node)) return True # don't let other message handlers do it
def check_presence_subscribe(self, p): self.failUnlessEqual(p.get_from(), JID("[email protected]/res")) self.failUnlessEqual(p.get_to(), JID("*****@*****.**")) self.failUnlessEqual(p.get_type(), "subscribe") self.failUnlessEqual(p.get_id(), None) self.failUnlessEqual(p.get_show(), None) self.failUnlessEqual(p.get_status(), None)
def from_xml(self, xmlnode): """Initialize Delay object from an XML node. :Parameters: - `xmlnode`: the jabber:x:delay XML element. :Types: - `xmlnode`: `libxml2.xmlNode`""" if xmlnode.type != "element": raise ValueError, "XML node is not a jabber:x:delay element (not an element)" ns = get_node_ns_uri(xmlnode) if ns and (ns != self.xml_element_namespace or xmlnode.name != self.xml_element_name): raise ValueError, "XML node is not a " + self.xml_element_namespace + " element" stamp = xmlnode.prop("stamp") tm = _parse_ts(stamp) tm = tm[0:8] + (0, ) self.timestamp = datetime.datetime.fromtimestamp(time.mktime(tm)) delay_from = from_utf8(xmlnode.prop("from")) if delay_from: try: self.delay_from = JID(delay_from) except JIDError: raise JIDMalformedProtocolError, "Bad JID in the " + self.xml_element_namespace + " 'from' attribute" else: self.delay_from = None self.reason = from_utf8(xmlnode.getContent())
def from_xml(self, xmlnode): """Initialize Delay object from an XML node. :Parameters: - `xmlnode`: the jabber:x:delay XML element. :Types: - `xmlnode`: `libxml2.xmlNode`""" if xmlnode.type != "element": raise ValueError, "XML node is not a jabber:x:delay element (not an element)" ns = get_node_ns_uri(xmlnode) if ns and ns != DELAY_NS or xmlnode.name != "x": raise ValueError, "XML node is not a jabber:x:delay element" stamp = xmlnode.prop("stamp") if stamp.endswith("Z"): stamp = stamp[:-1] if "-" in stamp: stamp = stamp.split("-", 1)[0] try: tm = time.strptime(stamp, "%Y%m%dT%H:%M:%S") except ValueError: raise BadRequestProtocolError, "Bad timestamp" tm = tm[0:8] + (0, ) self.timestamp = datetime.datetime.fromtimestamp(time.mktime(tm)) delay_from = from_utf8(xmlnode.prop("from")) if delay_from: try: self.delay_from = JID(delay_from) except JIDError: raise JIDMalformedProtocolError, "Bad JID in the jabber:x:delay 'from' attribute" else: self.delay_from = None self.reason = from_utf8(xmlnode.getContent())
def __init__(self, node_or_datetime, delay_from=None, reason=None, utc=True): """ Initialize the Delay object. :Parameters: - `node_or_datetime`: an XML node to parse or the timestamp. - `delay_from`: JID of the entity which adds the delay mark (when `node_or_datetime` is a timestamp). - `reason`: reason of the delay (when `node_or_datetime` is a timestamp). - `utc`: if `True` then the timestamp is assumed to be UTC, otherwise it is assumed to be local time. :Types: - `node_or_datetime`: `libxml2.xmlNode` or `datetime.datetime` - `delay_from`: `pyxmpp.JID` - `reason`: `unicode` - `utc`: `bool`""" if isinstance(node_or_datetime, libxml2.xmlNode): self.from_xml(node_or_datetime) else: if utc: self.timestamp = node_or_datetime else: self.timestamp = datetime_local_to_utc(node_or_datetime) self.delay_from = JID(delay_from) self.reason = unicode(reason)
def tls_is_certificate_valid(self, cert): """Default certificate verification callback for TLS connections. :Parameters: - `cert`: certificate information, as returned by `ssl.SSLSocket.getpeercert` :return: computed verification result.""" try: self.__logger.debug("tls_is_certificate_valid(cert = %r)" % (cert, )) if not cert: self.__logger.warning( "No TLS certificate information received.") return False valid_hostname_found = False if 'subject' in cert: for rdns in cert['subject']: for key, value in rdns: if key == 'commonName' and JID(value) == self.peer: self.__logger.debug( " good commonName: {0}".format(value)) valid_hostname_found = True if 'subjectAltName' in cert: for key, value in cert['subjectAltName']: if key == 'DNS' and JID(value) == self.peer: self.__logger.debug( " good subjectAltName({0}): {1}".format( key, value)) valid_hostname_found = True return valid_hostname_found except: self.__logger.exception("Exception caught") raise
def service_discovery_init(self): self.disco_init = jabber.disco.DiscoNode(self.cache, JID(self.jid.domain)) self.disco_init.fetch(self.disco_finished, depth=1, timeout_duration=1) self.disco_init2 = jabber.disco.DiscoNode(self.cache, JID("google.com")) self.disco_init2.fetch(super(GoogleTalk, self).disco_finished, depth=1, timeout_duration=1)
def test_field_jid_single(self): field = Field(field_type="jid-single", value=JID(u"*****@*****.**")) self.failUnlessEqual(field.value, JID(u"*****@*****.**")) self.failUnlessEqual(field.values, [u"*****@*****.**"]) field = Field(field_type="jid-single", values=[u"*****@*****.**"]) self.failUnlessEqual(field.value, JID(u"*****@*****.**")) self.failUnlessEqual(field.values, [u"*****@*****.**"]) field.value = JID(u"example.com") self.failUnlessEqual(field.value, JID(u"example.com")) self.failUnlessEqual(field.values, [u"example.com"])
def join(self, room, nick, handler, password=None, history_maxchars=None, history_maxstanzas=None, history_seconds=None, history_since=None): """ Create and return a new room state object and request joining to a MUC room. :Parameters: - `room`: the name of a room to be joined - `nick`: the nickname to be used in the room - `handler`: is an object to handle room events. - `password`: password for the room, if any - `history_maxchars`: limit of the total number of characters in history. - `history_maxstanzas`: limit of the total number of messages in history. - `history_seconds`: send only messages received in the last `history_seconds` seconds. - `history_since`: Send only the messages received since the dateTime specified (UTC). :Types: - `room`: `JID` - `nick`: `unicode` - `handler`: `MucRoomHandler` - `password`: `unicode` - `history_maxchars`: `int` - `history_maxstanzas`: `int` - `history_seconds`: `int` - `history_since`: `datetime.datetime` :return: the room state object created. :returntype: `MucRoomState` """ if not room.node or room.resource: raise ValueError, "Invalid room JID" room_jid = JID(room.node, room.domain, nick) cur_rs = self.rooms.get(room_jid.bare().as_unicode()) if cur_rs and cur_rs.joined: raise RuntimeError, "Room already joined" rs = MucRoomState(self, self.stream.me, room_jid, handler) self.rooms[room_jid.bare().as_unicode()] = rs rs.join(password, history_maxchars, history_maxstanzas, history_seconds, history_since) return rs
def _process_sasl_auth(self, mechanism, content): """Process incoming <sasl:auth/> element. [receiving entity only] :Parameters: - `mechanism`: mechanism choosen by the peer. - `content`: optional "initial response" included in the element. """ if self.authenticator: self.__logger.debug("Authentication already started") return False self.auth_method_used = "sasl:" + mechanism self.authenticator = sasl.server_authenticator_factory(mechanism, self) r = self.authenticator.start(base64.decodestring(content)) if isinstance(r, sasl.Success): el_name = "success" content = r.base64() elif isinstance(r, sasl.Challenge): el_name = "challenge" content = r.base64() else: el_name = "failure" content = None root = self.doc_out.getRootElement() xmlnode = root.newChild(None, el_name, None) ns = xmlnode.newNs(SASL_NS, None) xmlnode.setNs(ns) if content: xmlnode.setContent(content) if isinstance(r, sasl.Failure): xmlnode.newChild(None, r.reason, None) self._write_raw(xmlnode.serialize(encoding="UTF-8")) xmlnode.unlinkNode() xmlnode.freeNode() if isinstance(r, sasl.Success): if r.authzid: self.peer = JID(r.authzid) else: self.peer = JID(r.username, self.me.domain) self.peer_authenticated = 1 self.state_change("authenticated", self.peer) self._post_auth() if isinstance(r, sasl.Failure): raise SASLAuthenticationFailed, "SASL authentication failed" return True
def send(self, message, jabber_id, jabber_password, jabber_recpt): try: self.lock.acquire()#acquire lock subject = "Deluge Torrent completed" jid=JID(jabber_id) if not jid.resource: jid=JID(jid.node,jid.domain,"send_message") recpt=JID(jabber_recpt) send_message(jid, jabber_password, recpt, message, subject) finally: self.lock.release();#release lock
def send_msg(self, rid, msg): self.rid = JID(rid) if not self.sid.resource: self.sid = JID(self.sid.node, self.sid.domain, 'send_message') msg = Message(to_jid=self.rid, body=msg) def send(stream): stream.send(msg) self.xmpp_do(send)
def handle_message(self, stanza): ''' <message from='*****@*****.**' to='*****@*****.**'> <x xmlns='http://jabber.org/protocol/muc#user'> <invite from='[email protected]/desktop'> <reason> Hey Hecate, this is the place for all good witches! </reason> </invite> <password>cauldronburn</password> </x> </message> ''' self.stanza = stanza try: roomjid = JID(stanza.get_from()) roomname = roomjid.node except Exception: traceback.print_exc() return False else: if not roomname: return False for invite in stanza.xpath_eval('user:x/user:invite', {'user': MUC_USER_NS}): frm = invite.prop('from') if not frm: continue try: frm = JID(from_utf8(frm)) except Exception: continue else: break else: return False reason = None for rsn in xpath_eval(invite, 'user:reason/text()', {'user': MUC_USER_NS}): if rsn: reason = reason reason = reason or '' self.protocol.hub.on_invite( protocol=self.protocol, buddy=frm, room_name=roomname, message=reason, on_yes=lambda: self.protocol.join_chat_jid( roomjid, self.protocol.self_buddy.jid.node)) return True
def stream_start(self, doc): """Process <stream:stream> (stream start) tag received from peer. :Parameters: - `doc`: document created by the parser""" self.doc_in = doc log.debug("input document: %r" % (self.doc_in.serialize(), )) try: r = self.doc_in.getRootElement() if r.ns().getContent() != STREAM_NS: self._send_stream_error("invalid-namespace") raise FatalStreamError, "Invalid namespace." except libxml2.treeError: self._send_stream_error("invalid-namespace") raise FatalStreamError, "Couldn't get the namespace." self.version = r.prop("version") if self.version and self.version != "1.0": self._send_stream_error("unsupported-version") raise FatalStreamError, "Unsupported protocol version." # to_from_mismatch=0 assert self.initiator if self.initiator: self.stream_id = r.prop("id") peer = r.prop("from") if peer: peer = JID(peer) # if self.peer: # if peer and peer!=self.peer: # self.__logger.debug("peer hostname mismatch:" # " %r != %r" % (peer,self.peer)) # to_from_mismatch=1 # else: self.peer = peer else: to = r.prop("to") if to: to = self.check_to(to) if not to: self._send_stream_error("host-unknown") raise FatalStreamError, 'Bad "to"' self.me = JID(to) self._send_stream_start(self.generate_id()) self._send_stream_features() self.state_change("fully connected", self.peer) self._post_connect() if not self.version: self.state_change("fully connected", self.peer) self._post_connect()
def prefix_to_jid(self,prefix): if channel_re.match(prefix): node=channel_to_node(prefix,self.default_encoding) return JID(node,self.network.jid.domain,None) else: if "!" in prefix: nick,user=prefix.split("!",1) else: nick=prefix user="" node=nick_to_node(nick,self.default_encoding) resource=unicode(user,self.default_encoding,"replace") return JID(node,self.network.jid.domain,resource)
def _process_sasl_response(self, content): """Process incoming <sasl:response/> element. [receiving entity only] :Parameters: - `content`: the response data received (Base64-encoded). """ if not self.authenticator: self.__logger.debug("Unexpected SASL response") return 0 r = self.authenticator.response(base64.decodestring(content)) if isinstance(r, sasl.Success): el_name = "success" content = r.base64() elif isinstance(r, sasl.Challenge): el_name = "challenge" content = r.base64() else: el_name = "failure" content = None root = self.doc_out.getRootElement() xmlnode = root.newChild(None, el_name, None) ns = xmlnode.newNs(SASL_NS, None) xmlnode.setNs(ns) if content: xmlnode.setContent(content) if isinstance(r, sasl.Failure): xmlnode.newChild(None, r.reason, None) self._write_raw(xmlnode.serialize(encoding="UTF-8")) xmlnode.unlinkNode() xmlnode.freeNode() if isinstance(r, sasl.Success): authzid = r.authzid if authzid: self.peer = JID(r.authzid) else: self.peer = JID(r.username, self.me.domain) self.peer_authenticated = 1 self._restart_stream() self.state_change("authenticated", self.peer) self._post_auth() if isinstance(r, sasl.Failure): raise SASLAuthenticationFailed, "SASL authentication failed" return 1
def check_presence_full(self, p): self.failUnlessEqual(p.get_from(), JID("[email protected]/res")) self.failUnlessEqual(p.get_to(), JID("*****@*****.**")) self.failUnlessEqual(p.get_type(), None) self.failUnlessEqual(p.get_id(), "1") self.failUnlessEqual(p.get_show(), "away") self.failUnlessEqual(p.get_status(), "The Status") self.failUnlessEqual(p.get_priority(), 10) nodes = p.xpath_eval("t:payload", {"t": "http://pyxmpp.jajcus.net/xmlns/test"}) self.failUnless(nodes) self.failUnlessEqual(nodes[0].name, "payload") self.failUnless(nodes[0].children) self.failUnlessEqual(nodes[0].children.name, "abc")
def check_message_full(self, m): self.failUnlessEqual(m.get_from(), JID("[email protected]/res")) self.failUnlessEqual(m.get_to(), JID("*****@*****.**")) self.failUnlessEqual(m.get_type(), "normal") self.failUnlessEqual(m.get_id(), "1") self.failUnlessEqual(m.get_subject(), u"Subject") self.failUnlessEqual(m.get_body(), u"The body") self.failUnlessEqual(m.get_thread(), u"thread-id") nodes = m.xpath_eval("t:payload", {"t": "http://pyxmpp.jajcus.net/xmlns/test"}) self.failUnless(nodes) self.failUnlessEqual(nodes[0].name, "payload") self.failUnless(nodes[0].children) self.failUnlessEqual(nodes[0].children.name, "abc")
def join(self, room, nick, handler, password = None, history_maxchars = None, history_maxstanzas = None, history_seconds = None, history_since = None): """ Create and return a new room state object and request joining to a MUC room. :Parameters: - `room`: the name of a room to be joined - `nick`: the nickname to be used in the room - `handler`: is an object to handle room events. - `password`: password for the room, if any - `history_maxchars`: limit of the total number of characters in history. - `history_maxstanzas`: limit of the total number of messages in history. - `history_seconds`: send only messages received in the last `history_seconds` seconds. - `history_since`: Send only the messages received since the dateTime specified (UTC). :Types: - `room`: `JID` - `nick`: `unicode` - `handler`: `MucRoomHandler` - `password`: `unicode` - `history_maxchars`: `int` - `history_maxstanzas`: `int` - `history_seconds`: `int` - `history_since`: `datetime.datetime` :return: the room state object created. :returntype: `MucRoomState` """ if not room.node or room.resource: raise ValueError,"Invalid room JID" room_jid = JID(room.node, room.domain, nick) cur_rs = self.rooms.get(room_jid.bare().as_unicode()) if cur_rs and cur_rs.joined: raise RuntimeError,"Room already joined" rs=MucRoomState(self, self.stream.me, room_jid, handler) self.rooms[room_jid.bare().as_unicode()]=rs rs.join(password, history_maxchars, history_maxstanzas, history_seconds, history_since) return rs
def _sender_is_jid(sender, jid): cjc = Application.instance if not sender: return False if "@" in sender: try: sender_jid = JID(sender) if sender_jid.bare() == jid.bare(): return True except ValueError: pass if sender == cjc.get_user_info(jid, "nick"): return True if sender == cjc.get_user_info(jid, "rostername"): return True return sender == jid.node
def __init__(self,node_or_datetime,delay_from=None,reason=None,utc=True): """ Initialize the Delay object. :Parameters: - `node_or_datetime`: an XML node to parse or the timestamp. - `delay_from`: JID of the entity which adds the delay mark (when `node_or_datetime` is a timestamp). - `reason`: reason of the delay (when `node_or_datetime` is a timestamp). - `utc`: if `True` then the timestamp is assumed to be UTC, otherwise it is assumed to be local time. :Types: - `node_or_datetime`: `libxml2.xmlNode` or `datetime.datetime` - `delay_from`: `pyxmpp.JID` - `reason`: `unicode` - `utc`: `bool`""" if isinstance(node_or_datetime,libxml2.xmlNode): self.from_xml(node_or_datetime) else: if utc: self.timestamp=node_or_datetime else: self.timestamp=datetime_local_to_utc(node_or_datetime) self.delay_from=JID(delay_from) self.reason=unicode(reason)
def from_xml(self, node): #need jid, host, port, zeroconf """Initialize StreamHost from XML node.""" if node.type != "element": raise ValueError, "XML node is not a streamhost (not en element)" ns = get_node_ns_uri(node) if ns and ns != self.xml_element_namespace or node.name != self.xml_element_name: raise ValueError, "XML node is not a %s descriptor" % self.xml_element_name jid = JID(node.prop("jid").decode("utf-8")) self.jid = jid host = node.prop("host").decode("utf-8") self.host = host port = node.prop("port") #py2.5: self.port = int(port.decode("utf-8")) if port else None #py2.4: # if port: # self.port = int(port.decode("utf-8")) # else: # self.port = None zeroconf = node.prop("zeroconf") #py2.5: self.zeroconf = zeroconf.decode("utf-8") if zeroconf else None
def __init__(self, xmlnode_or_jid, host=None, port=None, zeroconf=None): """Initialize an `StreamHost` object. Wrap an existing streamhost XML element or create a new one. :Parameters: - `xmlnode_or_jid`: XML element describing the StreamHost or the JID of the StreamHost. - `host`: the hostname or IP address of the StreamHost. - `port`: the port of the StreamHost - `zeroconf`: the zeroconf identifier of the StreamHost. :Types: - `xmlnode_or_node`: `libxml2.xmlNode` or `unicode` - `host`: `unicode` - `port`: `int` - `zeroconf`: `unicode` """ if isinstance(xmlnode_or_jid, libxml2.xmlNode): self.from_xml(xmlnode_or_jid) else: self.jid = JID(xmlnode_or_jid) self.host = host self.port = port self.zeroconf = zeroconf if not (bool(self.port) ^ bool(self.zeroconf)): raise ValueError, 'StreamHost element requires one of [port, zeroconf]'
def from_xml(self,xmlnode): """Initialize Delay object from an XML node. :Parameters: - `xmlnode`: the jabber:x:delay XML element. :Types: - `xmlnode`: `libxml2.xmlNode`""" if xmlnode.type!="element": raise ValueError,"XML node is not a jabber:x:delay element (not an element)" ns=get_node_ns_uri(xmlnode) if ns and (ns != self.xml_element_namespace or xmlnode.name != self.xml_element_name): raise ValueError,"XML node is not a " + self.xml_element_namespace + " element" stamp=xmlnode.prop("stamp") tm = _parse_ts(stamp) tm=tm[0:8]+(0,) self.timestamp=datetime.datetime.fromtimestamp(time.mktime(tm)) delay_from=from_utf8(xmlnode.prop("from")) if delay_from: try: self.delay_from = JID(delay_from) except JIDError: raise JIDMalformedProtocolError, "Bad JID in the " + self.xml_element_namespace + " 'from' attribute" else: self.delay_from = None self.reason = from_utf8(xmlnode.getContent())
def _process_sasl_success(self, content): """Process incoming <sasl:success/> element. [initiating entity only] :Parameters: - `content`: the "additional data with success" received (Base64-encoded). """ if not self.authenticator: self.__logger.debug("Unexpected SASL response") return False r = self.authenticator.finish(base64.decodestring(content)) if isinstance(r, sasl.Success): self.__logger.debug("SASL authentication succeeded") if r.authzid: self.me = JID(r.authzid) else: self.me = self.me self.authenticated = 1 self._restart_stream() self.state_change("authenticated", self.me) self._post_auth() else: self.__logger.debug("SASL authentication failed") raise SASLAuthenticationFailed, "Additional success data procesing failed" return True
def _import(self, msg_type, directory, patterns): in_pattern, out_pattern = patterns same_pattern = (in_pattern == out_pattern) if same_pattern: pattern = in_pattern.replace("@@", "") else: in_pattern = in_pattern.replace("@@", "_in") out_pattern = out_pattern.replace("@@", "_out") pattern = "(?:{0}|{1})".format(in_pattern, out_pattern) pattern = re.compile(pattern) matches, unparseable, imported = 0, 0, 0 for filename in sorted(os.listdir(directory)): path = os.path.join(directory, filename) if not os.path.isfile(path) \ or not LOG_FILENAME_RE.match(filename): self.info(" skipping {0}".format(filename)) continue try: peer = JID(filename) except ValueError: self.info(" skipping {0} (bad jid)".format(filename)) continue self.info(" {0}...".format(filename)) with codecs.open(path, "r", "utf-8", "replace") as log_file: data = log_file.read() new_m, new_up, new_i = self._import_log(msg_type, peer, pattern, data) matches += new_m unparseable += new_up imported += new_i return matches, unparseable, imported
def check_authzid(self, authzid, extra_info=None): """Check authorization id provided by the client. [server only] :Parameters: - `authzid`: authorization id provided. - `extra_info`: additional information about the user from the authentication backend. This mapping will usually contain at least 'username' item. :Types: - `authzid`: unicode - `extra_info`: mapping :return: `True` if user is authorized to use that `authzid`. :returntype: `bool`""" if not extra_info: extra_info = {} if not authzid: return 1 if not self.initiator: jid = JID(authzid) if not extra_info.has_key("username"): ret = 0 elif jid.node != extra_info["username"]: ret = 0 elif jid.domain != self.my_jid.domain: ret = 0 elif not jid.resource: ret = 0 else: ret = 1 else: ret = 0 return ret
def pass_message_to_raw_channel(self, msg): fr = JID('#', self.network.jid.domain, None) m = Message(to_jid=self.jid, from_jid=fr, body=msg, stanza_type="groupchat") self.component.send(m)
def from_xml(self, xmlnode): """Initialize Delay object from an XML node. :Parameters: - `xmlnode`: the jabber:x:delay XML element. :Types: - `xmlnode`: `libxml2.xmlNode`""" if xmlnode.type != "element": raise ValueError, "XML node is not a jabber:x:delay element (not an element)" ns = get_node_ns_uri(xmlnode) if ns and ns != DELAY_NS or xmlnode.name != "x": raise ValueError, "XML node is not a jabber:x:delay element" stamp = xmlnode.prop("stamp") if stamp.endswith("Z"): stamp = stamp[:-1] if "-" in stamp: stamp = stamp.split("-", 1)[0] try: tm = time.strptime(stamp, "%Y%m%dT%H:%M:%S") except ValueError: raise BadRequestProtocolError, "Bad timestamp" tm = tm[0:8] + (0,) self.timestamp = datetime.datetime.fromtimestamp(time.mktime(tm)) delay_from = from_utf8(xmlnode.prop("from")) if delay_from: try: self.delay_from = JID(delay_from) except JIDError: raise JIDMalformedProtocolError, "Bad JID in the jabber:x:delay 'from' attribute" else: self.delay_from = None self.reason = from_utf8(xmlnode.getContent())
def from_xml(self, node): """Initialize RosterItem from XML node.""" if node.type != "element": raise ValueError, "XML node is not a roster item (not en element)" ns = get_node_ns_uri(node) if ns and ns != ROSTER_NS or node.name != "item": raise ValueError, "XML node is not a roster item" jid = JID(node.prop("jid").decode("utf-8")) subscription = node.prop("subscription") if subscription not in ("none", "from", "to", "both", "remove"): subscription = "none" ask = node.prop("ask") if ask not in ("subscribe", None): ask = None name = from_utf8(node.prop("name")) groups = [] n = node.children while n: if n.type != "element": n = n.next continue ns = get_node_ns_uri(n) if ns and ns != ROSTER_NS or n.name != "group": n = n.next continue group = n.getContent() if group: groups.append(from_utf8(group)) n = n.next self.jid = jid self.name = name self.groups = groups self.subscription = subscription self.ask = ask
def __init__(self, config_dir, data_dir): self.doc = None self.config_dir = config_dir self.data_dir = data_dir os.chdir(data_dir) libxml2.initializeCatalog() libxml2.loadCatalog(os.path.join(data_dir, "catalog.xml")) parser = libxml2.createFileParserCtxt( os.path.join(config_dir, "jjigw.xml")) parser.validate(1) parser.parseDocument() if not parser.isValid(): raise JJIGWFatalError, "Invalid configuration" self.doc = parser.doc() self.connect = ConnectConfig(self.doc.xpathEval("jjigw/connect")[0]) self.jid = None self.networks = {} for n in self.doc.xpathEval("jjigw/network"): network = NetworkConfig(n) if not self.jid: self.jid = network.jid self.networks[network.jid.domain] = network spidentd = self.doc.xpathEval("jjigw/spidentd") if spidentd: self.spidentd = SPIdentDConfig(spidentd[0]) else: self.spidentd = None self.admins = [] for n in self.doc.xpathEval("jjigw/admin"): self.admins.append(JID(n.getContent()))
def __init__(self, node_or_jid, subscription="none", name=None, groups=(), ask=None): """ Initialize a roster item from XML node or jid and optional attributes. :Parameters: - `node_or_jid`: XML node or JID - `subscription`: subscription type ("none", "to", "from" or "both" - `name`: item visible name - `groups`: sequence of groups the item is member of - `ask`: True if there was unreplied subsription or unsubscription request sent.""" if isinstance(node_or_jid, libxml2.xmlNode): self.from_xml(node_or_jid) else: node_or_jid = JID(node_or_jid) if subscription not in ("none", "from", "to", "both", "remove"): raise ValueError, "Bad subscription type: %r" % ( subscription, ) if ask not in ("subscribe", None): raise ValueError, "Bad ask type: %r" % (ask, ) self.jid = node_or_jid self.ask = ask self.subscription = subscription self.name = name self.groups = list(groups)
def get_jid(self): """Get the JID of the item. :return: the JID of the item. :returntype: `JID`""" jid = self.xmlnode.prop("jid") return JID(jid.decode("utf-8"))
def __init__(self, **args): self.isconnected = False # Create a unique jabber resource resource = args.get('resource') or 'python_client' resource += '_' + gethostname() + ':' + str(os.getpid()) + '_' + \ threading.currentThread().getName().lower() self.jid = JID(args['username'], args['host'], resource) osrf.log.log_debug("initializing network with JID %s and host=%s, " "port=%s, username=%s" % (self.jid.as_utf8(), args['host'], \ args['port'], args['username'])) #initialize the superclass JabberClient.__init__(self, self.jid, args['password'], args['host']) self.queue = [] self.receive_callback = None self.transport_error_msg = None
def __init(self,affiliation,role,jid=None,nick=None,actor=None,reason=None): """Initialize a `MucItem` object from a set of attributes. :Parameters: - `affiliation`: affiliation of the user. - `role`: role of the user. - `jid`: JID of the user. - `nick`: nickname of the user. - `actor`: actor modyfying the user data. - `reason`: reason of change of the user data. :Types: - `affiliation`: `str` - `role`: `str` - `jid`: `JID` - `nick`: `unicode` - `actor`: `JID` - `reason`: `unicode` """ if not affiliation: affiliation=None elif affiliation not in affiliations: raise ValueError,"Bad affiliation" self.affiliation=affiliation if not role: role=None elif role not in roles: raise ValueError,"Bad role" self.role=role if jid: self.jid=JID(jid) else: self.jid=None if actor: self.actor=JID(actor) else: self.actor=None self.nick=nick self.reason=reason
class MucItem(MucItemBase): """ MUC <item/> element -- describes a room occupant. :Ivariables: - `affiliation`: affiliation of the user. - `role`: role of the user. - `jid`: JID of the user. - `nick`: nickname of the user. - `actor`: actor modyfying the user data. - `reason`: reason of change of the user data. :Types: - `affiliation`: `str` - `role`: `str` - `jid`: `JID` - `nick`: `unicode` - `actor`: `JID` - `reason`: `unicode` """ def __init__(self,xmlnode_or_affiliation,role=None,jid=None,nick=None,actor=None,reason=None): """ Initialize a `MucItem` object. :Parameters: - `xmlnode_or_affiliation`: XML node to be pased or the affiliation of the user being described. - `role`: role of the user. - `jid`: JID of the user. - `nick`: nickname of the user. - `actor`: actor modyfying the user data. - `reason`: reason of change of the user data. :Types: - `xmlnode_or_affiliation`: `libxml2.xmlNode` or `str` - `role`: `str` - `jid`: `JID` - `nick`: `unicode` - `actor`: `JID` - `reason`: `unicode` """ self.jid,self.nick,self.actor,self.affiliation,self.reason,self.role=(None,)*6 MucItemBase.__init__(self) if isinstance(xmlnode_or_affiliation,libxml2.xmlNode): self.__from_xmlnode(xmlnode_or_affiliation) else: self.__init(xmlnode_or_affiliation,role,jid,nick,actor,reason) def __init(self,affiliation,role,jid=None,nick=None,actor=None,reason=None): """Initialize a `MucItem` object from a set of attributes. :Parameters: - `affiliation`: affiliation of the user. - `role`: role of the user. - `jid`: JID of the user. - `nick`: nickname of the user. - `actor`: actor modyfying the user data. - `reason`: reason of change of the user data. :Types: - `affiliation`: `str` - `role`: `str` - `jid`: `JID` - `nick`: `unicode` - `actor`: `JID` - `reason`: `unicode` """ if not affiliation: affiliation=None elif affiliation not in affiliations: raise ValueError,"Bad affiliation" self.affiliation=affiliation if not role: role=None elif role not in roles: raise ValueError,"Bad role" self.role=role if jid: self.jid=JID(jid) else: self.jid=None if actor: self.actor=JID(actor) else: self.actor=None self.nick=nick self.reason=reason def __from_xmlnode(self, xmlnode): """Initialize a `MucItem` object from an XML node. :Parameters: - `xmlnode`: the XML node. :Types: - `xmlnode`: `libxml2.xmlNode` """ actor=None reason=None n=xmlnode.children while n: ns=n.ns() if ns and ns.getContent()!=MUC_USER_NS: continue if n.name=="actor": actor=n.getContent() if n.name=="reason": reason=n.getContent() n=n.next self.__init( from_utf8(xmlnode.prop("affiliation")), from_utf8(xmlnode.prop("role")), from_utf8(xmlnode.prop("jid")), from_utf8(xmlnode.prop("nick")), from_utf8(actor), from_utf8(reason), ); def as_xml(self,parent): """ Create XML representation of `self`. :Parameters: - `parent`: the element to which the created node should be linked to. :Types: - `parent`: `libxml2.xmlNode` :return: an XML node. :returntype: `libxml2.xmlNode` """ n=parent.newChild(None,"item",None) if self.actor: n.newTextChild(None,"actor",to_utf8(self.actor)) if self.reason: n.newTextChild(None,"reason",to_utf8(self.reason)) n.setProp("affiliation",to_utf8(self.affiliation)) if self.role: n.setProp("role",to_utf8(self.role)) if self.jid: n.setProp("jid",to_utf8(self.jid.as_unicode())) if self.nick: n.setProp("nick",to_utf8(self.nick)) return n
def __init__(self, name_or_xmlnode, from_jid=None, to_jid=None, stanza_type=None, stanza_id=None, error=None, error_cond=None, stream = None): """Initialize a Stanza object. :Parameters: - `name_or_xmlnode`: XML node to be wrapped into the Stanza object or other Presence object to be copied. If not given then new presence stanza is created using following parameters. - `from_jid`: sender JID. - `to_jid`: recipient JID. - `stanza_type`: staza type: one of: "get", "set", "result" or "error". - `stanza_id`: stanza id -- value of stanza's "id" attribute. If not given, then unique for the session value is generated. - `error`: error object. Ignored if `stanza_type` is not "error". - `error_cond`: error condition name. Ignored if `stanza_type` is not "error" or `error` is not None. :Types: - `name_or_xmlnode`: `unicode` or `libxml2.xmlNode` or `Stanza` - `from_jid`: `JID` - `to_jid`: `JID` - `stanza_type`: `unicode` - `stanza_id`: `unicode` - `error`: `pyxmpp.error.StanzaErrorNode` - `error_cond`: `unicode`""" self._error=None self.xmlnode=None if isinstance(name_or_xmlnode,Stanza): self.xmlnode=name_or_xmlnode.xmlnode.copyNode(1) common_doc.addChild(self.xmlnode) elif isinstance(name_or_xmlnode,libxml2.xmlNode): self.xmlnode=name_or_xmlnode.docCopyNode(common_doc,1) common_doc.addChild(self.xmlnode) try: ns = self.xmlnode.ns() except libxml2.treeError: ns = None if not ns or not ns.name: xmlextra.replace_ns(self.xmlnode, ns, common_ns) else: self.xmlnode=common_doc.newChild(common_ns,name_or_xmlnode,None) if from_jid is not None: if not isinstance(from_jid,JID): from_jid=JID(from_jid) self.xmlnode.setProp("from",from_jid.as_utf8()) if to_jid is not None: if not isinstance(to_jid,JID): to_jid=JID(to_jid) self.xmlnode.setProp("to",to_jid.as_utf8()) if stanza_type: self.xmlnode.setProp("type",stanza_type) if stanza_id: self.xmlnode.setProp("id",stanza_id) if self.get_type()=="error": from pyxmpp.error import StanzaErrorNode if error: self._error=StanzaErrorNode(error,parent=self.xmlnode,copy=1) elif error_cond: self._error=StanzaErrorNode(error_cond,parent=self.xmlnode) self.stream = stream
class Delay(StanzaPayloadObject): """ Delayed delivery tag. Represents 'urn:xmpp:delay' (XEP-0203) element of a Jabber stanza. :Ivariables: - `delay_from`: the "from" value of the delay element - `reason`: the "reason" (content) of the delay element - `timestamp`: the UTC timestamp as naive datetime object """ xml_element_name = "delay" xml_element_namespace = DELAY_NS _sort_order = 1 _time_format = "%Y-%m-%dT%H:%M:%SZ" def __init__(self,node_or_datetime,delay_from=None,reason=None,utc=True): """ Initialize the Delay object. :Parameters: - `node_or_datetime`: an XML node to parse or the timestamp. - `delay_from`: JID of the entity which adds the delay mark (when `node_or_datetime` is a timestamp). - `reason`: reason of the delay (when `node_or_datetime` is a timestamp). - `utc`: if `True` then the timestamp is assumed to be UTC, otherwise it is assumed to be local time. :Types: - `node_or_datetime`: `libxml2.xmlNode` or `datetime.datetime` - `delay_from`: `pyxmpp.JID` - `reason`: `unicode` - `utc`: `bool`""" if isinstance(node_or_datetime,libxml2.xmlNode): self.from_xml(node_or_datetime) else: if utc: self.timestamp=node_or_datetime else: self.timestamp=datetime_local_to_utc(node_or_datetime) self.delay_from=JID(delay_from) self.reason=unicode(reason) def from_xml(self,xmlnode): """Initialize Delay object from an XML node. :Parameters: - `xmlnode`: the jabber:x:delay XML element. :Types: - `xmlnode`: `libxml2.xmlNode`""" if xmlnode.type!="element": raise ValueError,"XML node is not a jabber:x:delay element (not an element)" ns=get_node_ns_uri(xmlnode) if ns and (ns != self.xml_element_namespace or xmlnode.name != self.xml_element_name): raise ValueError,"XML node is not a " + self.xml_element_namespace + " element" stamp=xmlnode.prop("stamp") tm = _parse_ts(stamp) tm=tm[0:8]+(0,) self.timestamp=datetime.datetime.fromtimestamp(time.mktime(tm)) delay_from=from_utf8(xmlnode.prop("from")) if delay_from: try: self.delay_from = JID(delay_from) except JIDError: raise JIDMalformedProtocolError, "Bad JID in the " + self.xml_element_namespace + " 'from' attribute" else: self.delay_from = None self.reason = from_utf8(xmlnode.getContent()) def complete_xml_element(self, xmlnode, _unused): """Complete the XML node with `self` content. Should be overriden in classes derived from `StanzaPayloadObject`. :Parameters: - `xmlnode`: XML node with the element being built. It has already right name and namespace, but no attributes or content. - `_unused`: document to which the element belongs. :Types: - `xmlnode`: `libxml2.xmlNode` - `_unused`: `libxml2.xmlDoc`""" tm=self.timestamp.strftime(self._time_format) xmlnode.setProp("stamp",tm) if self.delay_from: xmlnode.setProp("from",self.delay_from.as_utf8()) if self.reason: xmlnode.setContent(to_utf8(self.reason)) def get_datetime_local(self): """Get the timestamp as a local time. :return: the timestamp of the delay element represented in the local timezone. :returntype: `datetime.datetime`""" r=datetime_utc_to_local(self.timestamp) return r def get_datetime_utc(self): """Get the timestamp as a UTC. :return: the timestamp of the delay element represented in UTC. :returntype: `datetime.datetime`""" return self.timestamp def __str__(self): n=self.as_xml() r=n.serialize() n.freeNode() return r def __cmp__(self, other): return cmp((self._sort_order, self.timestamp), (other._sort_order, other.timestamp))
class Network(JabberClient): def __init__(self, **args): self.isconnected = False # Create a unique jabber resource resource = args.get('resource') or 'python_client' resource += '_' + gethostname() + ':' + str(os.getpid()) + '_' + \ threading.currentThread().getName().lower() self.jid = JID(args['username'], args['host'], resource) osrf.log.log_debug("initializing network with JID %s and host=%s, " "port=%s, username=%s" % (self.jid.as_utf8(), args['host'], \ args['port'], args['username'])) #initialize the superclass JabberClient.__init__(self, self.jid, args['password'], args['host']) self.queue = [] self.receive_callback = None self.transport_error_msg = None def connect(self): JabberClient.connect(self) while not self.isconnected: stream = self.get_stream() act = stream.loop_iter(10) if not act: self.idle() def set_receive_callback(self, func): """The callback provided is called when a message is received. The only argument to the function is the received message. """ self.receive_callback = func def session_started(self): osrf.log.log_info("Successfully connected to the opensrf network") self.authenticated() self.stream.set_message_handler("normal", self.message_received) self.stream.set_message_handler("error", self.error_received) self.isconnected = True def send(self, message): """Sends the provided network message.""" osrf.log.log_internal("jabber sending to %s: %s" % (message.recipient, message.body)) message.sender = self.jid.as_utf8() msg = message.make_xmpp_msg() self.stream.send(msg) def error_received(self, stanza): self.transport_error_msg = NetworkMessage(stanza) osrf.log.log_error("XMPP error message received from %s" % self.transport_error_msg.sender) def message_received(self, stanza): """Handler for received messages.""" if stanza.get_type()=="headline": return True # check for errors osrf.log.log_internal("jabber received message from %s : %s" % (stanza.get_from().as_utf8(), stanza.get_body())) self.queue.append(NetworkMessage(stanza)) return True def stream_closed(self, stream): osrf.log.log_debug("XMPP Stream closing...") def stream_error(self, err): osrf.log.log_error("XMPP Stream error: condition: %s %r" % (err.get_condition().name,err.serialize())) def disconnected(self): osrf.log.log_internal('XMPP Disconnected') def recv(self, timeout=120): """Attempts to receive a message from the network. timeout - max number of seconds to wait for a message. If a message is received in 'timeout' seconds, the message is passed to the receive_callback is called and True is returned. Otherwise, false is returned. """ forever = False if timeout < 0: forever = True timeout = None if len(self.queue) == 0: while (forever or timeout >= 0) and len(self.queue) == 0: starttime = time.time() stream = self.get_stream() if not stream: raise XMPPNoConnection('We lost our server connection...') act = stream.loop_iter(timeout) endtime = time.time() - starttime if not forever: timeout -= endtime osrf.log.log_internal("exiting stream loop after %s seconds. " "act=%s, queue size=%d" % (str(endtime), act, len(self.queue))) if self.transport_error_msg: msg = self.transport_error_msg self.transport_error_msg = None raise XMPPNoRecipient(msg.sender) if not act: self.idle() # if we've acquired a message, handle it msg = None if len(self.queue) > 0: msg = self.queue.pop(0) if self.receive_callback: self.receive_callback(msg) return msg def flush_inbound_data(self): ''' Read all pending inbound messages from the socket and discard them ''' cb = self.receive_callback self.receive_callback = None while self.recv(0): pass self.receive_callback = cb