def join(self, password=None, history_maxchars=None, history_maxstanzas=None, history_seconds=None, history_since=None): """ Send a join request for the room. :Parameters: - `password`: password to the room. - `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: - `password`: `unicode` - `history_maxchars`: `int` - `history_maxstanzas`: `int` - `history_seconds`: `int` - `history_since`: `datetime.datetime` """ if self.joined: raise RuntimeError, "Room is already joined" p = MucPresence(to_jid=self.room_jid) p.make_join_request(password, history_maxchars, history_maxstanzas, history_seconds, history_since) self.manager.stream.send(p)
def join(self, password=None, history_maxchars = None, history_maxstanzas = None, history_seconds = None, history_since = None): """ Send a join request for the room. :Parameters: - `password`: password to the room. - `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: - `password`: `unicode` - `history_maxchars`: `int` - `history_maxstanzas`: `int` - `history_seconds`: `int` - `history_since`: `datetime.datetime` """ if self.joined: raise RuntimeError,"Room is already joined" p=MucPresence(to_jid=self.room_jid) p.make_join_request(password, history_maxchars, history_maxstanzas, history_seconds, history_since) self.manager.stream.send(p)
def update_presence(self, presence): """ Update user information. :Parameters: - `presence`: a presence stanza with user information update. :Types: - `presence`: `MucPresence` """ self.presence = MucPresence(presence) t = presence.get_type() if t == "unavailable": self.role = "none" self.affiliation = "none" self.room_jid = self.presence.get_from() self.nick = self.room_jid.resource mc = self.presence.get_muc_child() if isinstance(mc, MucUserX): items = mc.get_items() for item in items: if not isinstance(item, MucItem): continue if item.role: self.role = item.role if item.affiliation: self.affiliation = item.affiliation if item.jid: self.real_jid = item.jid if item.nick: self.new_nick = item.nick break
def update_presence(self,presence): """ Update user information. :Parameters: - `presence`: a presence stanza with user information update. :Types: - `presence`: `MucPresence` """ self.presence=MucPresence(presence) t=presence.get_type() if t=="unavailable": self.role="none" self.affiliation="none" self.room_jid=self.presence.get_from() self.nick=self.room_jid.resource mc=self.presence.get_muc_child() if isinstance(mc,MucUserX): items=mc.get_items() for item in items: if not isinstance(item,MucItem): continue if item.role: self.role=item.role if item.affiliation: self.affiliation=item.affiliation if item.jid: self.real_jid=item.jid if item.nick: self.new_nick=item.nick break
def leave(self): """ Send a leave request for the room. """ if self.joined: p = MucPresence(to_jid=self.room_jid, stanza_type="unavailable") self.manager.stream.send(p)
def __presence_unavailable(self, stanza): """Process an unavailable presence from a MUC room. :Parameters: - `stanza`: the stanza received. :Types: - `stanza`: `Presence` :return: `True` if the stanza was properly recognized as generated by one of the managed rooms, `False` otherwise. :returntype: `bool`""" fr = stanza.get_from() key = fr.bare().as_unicode() rs = self.rooms.get(key) if not rs: return False rs.process_unavailable_presence(MucPresence(stanza)) return True
class MucRoomUser: """ Describes a user of a MUC room. The attributes of this object should not be changed directly. :Ivariables: - `presence`: last presence stanza received for the user. - `role`: user's role. - `affiliation`: user's affiliation. - `room_jid`: user's room jid. - `real_jid`: user's real jid or None if not available. - `nick`: user's nick (resource part of `room_jid`) :Types: - `presence`: `MucPresence` - `role`: `str` - `affiliation`: `str` - `room_jid`: `JID` - `real_jid`: `JID` - `nick`: `unicode` """ def __init__(self,presence_or_user_or_jid): """ Initialize a `MucRoomUser` object. :Parameters: - `presence_or_user_or_jid`: a MUC presence stanza with user information, a user object to copy or a room JID of a user. :Types: - `presence_or_user_or_jid`: `MucPresence` or `MucRoomUser` or `JID` When `presence_or_user_or_jid` is a JID user's role and affiliation are set to "none". """ if isinstance(presence_or_user_or_jid,MucRoomUser): self.presence=presence_or_user_or_jid.presence self.role=presence_or_user_or_jid.role self.affiliation=presence_or_user_or_jid.affiliation self.room_jid=presence_or_user_or_jid.room_jid self.real_jid=presence_or_user_or_jid.real_jid self.nick=presence_or_user_or_jid.nick self.new_nick=None else: self.affiliation="none" self.presence=None self.real_jid=None self.new_nick=None if isinstance(presence_or_user_or_jid,JID): self.nick=presence_or_user_or_jid.resource self.room_jid=presence_or_user_or_jid self.role="none" elif isinstance(presence_or_user_or_jid,Presence): self.nick=None self.room_jid=None self.role="participant" self.update_presence(presence_or_user_or_jid) else: raise TypeError,"Bad argument type for MucRoomUser constructor" def update_presence(self,presence): """ Update user information. :Parameters: - `presence`: a presence stanza with user information update. :Types: - `presence`: `MucPresence` """ self.presence=MucPresence(presence) t=presence.get_type() if t=="unavailable": self.role="none" self.affiliation="none" self.room_jid=self.presence.get_from() self.nick=self.room_jid.resource mc=self.presence.get_muc_child() if isinstance(mc,MucUserX): items=mc.get_items() for item in items: if not isinstance(item,MucItem): continue if item.role: self.role=item.role if item.affiliation: self.affiliation=item.affiliation if item.jid: self.real_jid=item.jid if item.nick: self.new_nick=item.nick break def same_as(self,other): """Check if two `MucRoomUser` objects describe the same user in the same room. :Parameters: - `other`: the user object to compare `self` with. :Types: - `other`: `MucRoomUser` :return: `True` if the two object describe the same user. :returntype: `bool`""" return self.room_jid==other.room_jid
class MucRoomUser: """ Describes a user of a MUC room. The attributes of this object should not be changed directly. :Ivariables: - `presence`: last presence stanza received for the user. - `role`: user's role. - `affiliation`: user's affiliation. - `room_jid`: user's room jid. - `real_jid`: user's real jid or None if not available. - `nick`: user's nick (resource part of `room_jid`) :Types: - `presence`: `MucPresence` - `role`: `str` - `affiliation`: `str` - `room_jid`: `JID` - `real_jid`: `JID` - `nick`: `unicode` """ def __init__(self, presence_or_user_or_jid): """ Initialize a `MucRoomUser` object. :Parameters: - `presence_or_user_or_jid`: a MUC presence stanza with user information, a user object to copy or a room JID of a user. :Types: - `presence_or_user_or_jid`: `MucPresence` or `MucRoomUser` or `JID` When `presence_or_user_or_jid` is a JID user's role and affiliation are set to "none". """ if isinstance(presence_or_user_or_jid, MucRoomUser): self.presence = presence_or_user_or_jid.presence self.role = presence_or_user_or_jid.role self.affiliation = presence_or_user_or_jid.affiliation self.room_jid = presence_or_user_or_jid.room_jid self.real_jid = presence_or_user_or_jid.real_jid self.nick = presence_or_user_or_jid.nick self.new_nick = None else: self.affiliation = "none" self.presence = None self.real_jid = None self.new_nick = None if isinstance(presence_or_user_or_jid, JID): self.nick = presence_or_user_or_jid.resource self.room_jid = presence_or_user_or_jid self.role = "none" elif isinstance(presence_or_user_or_jid, Presence): self.nick = None self.room_jid = None self.role = "participant" self.update_presence(presence_or_user_or_jid) else: raise TypeError, "Bad argument type for MucRoomUser constructor" def update_presence(self, presence): """ Update user information. :Parameters: - `presence`: a presence stanza with user information update. :Types: - `presence`: `MucPresence` """ self.presence = MucPresence(presence) t = presence.get_type() if t == "unavailable": self.role = "none" self.affiliation = "none" self.room_jid = self.presence.get_from() self.nick = self.room_jid.resource mc = self.presence.get_muc_child() if isinstance(mc, MucUserX): items = mc.get_items() for item in items: if not isinstance(item, MucItem): continue if item.role: self.role = item.role if item.affiliation: self.affiliation = item.affiliation if item.jid: self.real_jid = item.jid if item.nick: self.new_nick = item.nick break def same_as(self, other): """Check if two `MucRoomUser` objects describe the same user in the same room. :Parameters: - `other`: the user object to compare `self` with. :Types: - `other`: `MucRoomUser` :return: `True` if the two object describe the same user. :returntype: `bool`""" return self.room_jid == other.room_jid
class Component(pyxmpp.jabberd.component.Component): def __init__(self, config, profile=False): pyxmpp.jabberd.component.Component.__init__( self, config.jid, config.connect.secret, config.connect.host, config.connect.port, disco_name="JJIGW IRC gateway", disco_category="conference", disco_type="irc") self.__logger = logging.getLogger("jjigw.Component") self.profile = profile self.shutdown = 0 signal.signal(signal.SIGINT, self.signal_handler) signal.signal(signal.SIGPIPE, self.signal_handler) signal.signal(signal.SIGHUP, self.signal_handler) signal.signal(signal.SIGTERM, self.signal_handler) self.irc_sessions = {} self.config = config if config.spidentd: self.ident_handler = SPIdentD(self, config.spidentd) else: self.ident_handler = None self.disco_info.add_identity("JJIGW IRC gateway", "conference", "text") # MUC compliance self.disco_info.add_identity( "JJIGW IRC gateway", "gateway", "x-irc") # non-conference gateway services def get_session(self, user_jid, component_jid): return self.irc_sessions.get( (user_jid.as_unicode(), component_jid.domain)) def register_session(self, sess): user_jid = sess.jid component_jid = sess.network.jid self.__logger.debug("Registering session: %r on %r for %r" % (sess, component_jid, user_jid)) self.irc_sessions[user_jid.as_unicode(), component_jid.domain] = sess def unregister_session(self, sess): user_jid = sess.jid component_jid = sess.network.jid self.__logger.debug("Unregistering session: %r on %r for %r" % (sess, component_jid, user_jid)) try: del self.irc_sessions[user_jid.as_unicode(), component_jid.domain] except KeyError: self.__logger.debug("Session not found!") def signal_handler(self, signum, frame): self.__logger.debug("Signal %i received, shutting down..." % (signum, )) self.shutdown = 1 def run(self, timeout): self.connect() try: while (not self.shutdown and self.stream and not self.stream.eof and self.stream.socket is not None): try: self.stream.loop_iter(timeout) except (KeyboardInterrupt, SystemExit, FatalStreamError, StreamError): raise except: self.__logger.exception("Exception cought:") finally: if self.shutdown: for sess in self.irc_sessions.values(): sess.disconnect("JJIGW shutdown") threads = threading.enumerate() for th in threads: try: th.join(10 * timeout) except: pass for th in threads: try: th.join(timeout) except: pass self.disconnect() self.__logger.debug("Exitting normally") def send(self, stanza): self.get_stream().send(stanza) def stream_state_changed(self, state, arg): print "*** State changed: %s %r ***" % (state, arg) def authenticated(self): pyxmpp.jabberd.component.Component.authenticated(self) self.stream.set_iq_get_handler("query", "jabber:iq:version", self.get_version) self.stream.set_iq_get_handler("query", "jabber:iq:register", self.get_register) self.stream.set_iq_set_handler("query", "jabber:iq:register", self.set_register) self.stream.set_iq_set_handler("query", MUC_ADMIN_NS, self.set_muc_admin) self.stream.set_presence_handler("available", self.presence_available) self.stream.set_presence_handler("unavailable", self.presence_unavailable) self.stream.set_presence_handler("subscribe", self.presence_control) self.stream.set_message_handler("groupchat", self.groupchat_message) self.stream.set_message_handler("normal", self.message) def set_muc_admin(self, iq): to = iq.get_to() fr = iq.get_from() if not to.node: self.__logger.debug("admin request sent to JID without a node") iq = iq.make_error_response("feature-not-implemented") self.stream.send(iq) return 1 if to.resource or not (to.node[0] in "#+!" or to.node.startswith(",amp,")): self.__logger.debug("admin request sent not to a channel") iq = iq.make_error_response("not-acceptable") self.stream.send(iq) return 1 iq = MucIq(iq) sess = self.get_session(fr, to) if not sess: self.__logger.debug("User session not found") iq = iq.make_error_response("recipient-unavailable") self.stream.send(iq) return 1 channel = sess.get_channel(to) if not channel: self.__logger.debug("Channel not found") iq = iq.make_error_response("recipient-unavailable") self.stream.send(iq) return 1 query = iq.get_muc_child() if not isinstance(query, MucAdminQuery): self.__logger.debug("Bad query content") iq = iq.make_error_response("bad-request") self.stream.send(iq) return 1 items = query.get_items() if not items: self.__logger.debug("No items in query") iq = iq.make_error_response("bad-request") self.stream.send(iq) return 1 item = items[0] if item.role == "none": channel.kick_user(item.nick, item.reason, iq) elif item.role == "visitor": channel.devoice_user(item.nick, iq) elif item.role == "participant": channel.voice_user(item.nick, iq) elif item.role == "moderator": channel.op_user(item.nick, iq) else: self.__logger.debug("Unknown admin action") iq = iq.make_error_response("feature-not-implemented") self.stream.send(iq) return 1 def get_version(self, iq): iq = iq.make_result_response() q = iq.new_query("jabber:iq:version") q.newTextChild(q.ns(), "name", "Jajcus' Jabber-IRC Gateway") q.newTextChild(q.ns(), "version", "0.2.2") self.stream.send(iq) return 1 def get_register(self, iq): to = iq.get_to() if to and to != self.jid: iq = iq.make_error_response("feature-not-implemented") self.stream.send(iq) return 1 iq = iq.make_result_response() q = iq.new_query("jabber:iq:register") q.newTextChild(q.ns(), "instructions", "Enter nickname and network password.") q.newChild(q.ns(), "username", None) q.newChild(q.ns(), "password", None) self.stream.send(iq) return 1 def set_register(self, iq): to = iq.get_to() if to and to != self.jid: iq = iq.make_error_response("feature-not-implemented") self.stream.send(iq) return 1 remove = iq.xpath_eval("r:query/r:remove", {"r": "jabber:iq:register"}) if remove: m = Message(from_jid=iq.get_to(), to_jid=iq.get_from(), stanza_type="chat", body=u"Unregistered") self.stream.send(m) p = Presence(from_jid=iq.get_to(), to_jid=iq.get_from(), stanza_type="unsubscribe") self.stream.send(p) p = Presence(from_jid=iq.get_to(), to_jid=iq.get_from(), stanza_type="unsubscribed") self.stream.send(p) return 1 username = iq.xpath_eval("r:query/r:username", {"r": "jabber:iq:register"}) if username: username = username[0].getContent() else: username = u"" password = iq.xpath_eval("r:query/r:password", {"r": "jabber:iq:register"}) if password: password = password[0].getContent() else: password = u"" try: with open("regs/%s" % iq.get_from().bare(), "w") as f: f.write("%s\n%s" % (username, password)) except Exception as ex: m = Message(from_jid=iq.get_to(), to_jid=iq.get_from(), stanza_type="chat", body=u"Exception registering with username '%s': %s" % (username, ex)) self.stream.send(m) return 1 m = Message(from_jid=iq.get_to(), to_jid=iq.get_from(), stanza_type="chat", body=u"Registered with username '%s' and password '%s'" % (username, password)) self.stream.send(m) p = Presence(from_jid=iq.get_to(), to_jid=iq.get_from(), stanza_type="subscribe") self.stream.send(p) iq = iq.make_result_response() self.stream.send(iq) return 1 def message(self, stanza): to = stanza.get_to() fr = stanza.get_from() typ = stanza.get_type() if typ not in (None, "chat"): typ = None sess = self.get_session(fr, to) if not to.node: if sess: m = Message(to_jid=fr, from_jid=to, body="Connected to: %s" % (sess.server, ), stanza_type=typ) else: m = Message(to_jid=fr, from_jid=to, body="Not connected", stanza_type=typ) return 1 if not to.resource and (to.node[0] in "#+!" or to.node.startswith(",amp,")): self.groupchat_message(stanza) if sess: sess.message_to_user(stanza) else: m = stanza.make_error_response("recipient-unavailable") self.send(m) return 1 def groupchat_message(self, stanza): to = stanza.get_to() if not to.node: self.__logger.debug("No node in groupchat message target") return 0 if to.node[0] not in "#+!" and not to.node.startswith(",amp,"): self.__logger.debug("Groupchat message target is not a channel") return self.message(stanza) if to.resource: self.__logger.debug("Groupchat message target is not bare JID") return 0 fr = stanza.get_from() sess = self.get_session(fr, to) if sess: sess.message_to_channel(stanza) else: m = stanza.make_error_response("recipient-unavailable") self.send(m) return 1 def presence_available(self, stanza): nick = None to = stanza.get_to() fr = stanza.get_from() status = stanza.get_status() show = stanza.get_show() if not status: if not show: status = "Unknown" else: status = show if to.node and not to.resource: p = stanza.make_error_response("bad-request") self.send(p) return 1 sess = self.get_session(fr, to) if sess: if to.node and not sess.check_nick(to.resource): p = stanza.make_error_response("conflict") self.send(p) return 1 if show in ("away", "xa", "dnd"): sess.set_away(status) else: sess.set_back() else: nick = to.resource if not nick: nick = fr.node try: sess = IRCSession(self, self.config, to, fr, nick) except ValueError, e: print ` e ` e = stanza.make_error_response("bad-request") self.send(e) return self.register_session(sess) if to.node: sess.join(MucPresence(stanza)) else: sess.login(stanza) return 1