Beispiel #1
0
    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)
Beispiel #2
0
    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)
Beispiel #3
0
    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
Beispiel #4
0
    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
Beispiel #5
0
 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)
Beispiel #6
0
    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
Beispiel #7
0
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
Beispiel #8
0
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
Beispiel #9
0
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