Ejemplo n.º 1
0
def xmppBrute0x00(ip, usernames, passwords, port, delay):
    #client = Client(str(ip))
    #client.connect(server=(str(ip), port))
    found = False
    for username in usernames:
        for password in passwords:
            try:
                client = Client(username, password)
                client.connect((str(ip), port))
                if client.auth(username, password):
                    client.sendInitPresence()
                    found = True
                    data = username + " : " + password
                    save_data(database, module, lvl1, lvl2, lvl3, name, data)
                    print(G + ' [+] Username: %s | Password found: %s\n' %
                          (username, password))
                    client.disconnect()
            except Exception as e:
                print(R + " [-] Error caught! Name: " + str(e))
            except KeyboardInterrupt:
                client.disconnect()
                if not found:
                    data = "Nothing found."
                    save_data(database, module, lvl1, lvl2, lvl3, name, data)
                sys.exit(1)
            except Exception:
                print(GR + " [*] Checking : " + C +
                      "Username: {} | ".format(username) + B +
                      "Password: {} ".format(password) + R + "| Incorrect!\n")
                sleep(delay)
    if not found:
        data = "Nothing found."
        save_data(database, module, lvl1, lvl2, lvl3, name, data)
Ejemplo n.º 2
0
 def __init__(self):
     ClientXMPP.__init__(self, FCM_JID, FCM_SERVER_KEY, sasl_mech="PLAIN")
     self.add_event_handler("session_start", self.start)
     self.auto_reconnect = False
     self.connect((FCM_SERVER_IP, FCM_SERVER_PORT),
                  use_tls=True,
                  reattempt=True)
     print("Connected!!")
     self.process(block=True)
     print("Process Done!!")
Ejemplo n.º 3
0
    def __init__(self, *args):
        ConfigurableComponent.__init__(self, "XMPPBOT", *args)
        if self.config.get('password', None) is None:
            self.config.password = std_uuid()
            self.config.save()

        ClientXMPP.__init__(self, self.config.jid, self.config.password)

        self.add_event_handler("session_start", self.session_start)
        self.add_event_handler("message", self.message)
        # Discard SSL Error
        self.add_event_handler("ssl_invalid_cert", self.discard)

        # If you wanted more functionality, here's how to register plugins:
        # self.register_plugin('xep_0030') # Service Discovery
        # self.register_plugin('xep_0199') # XMPP Ping

        # Here's how to access plugins once you've registered them:
        # self['xep_0030'].add_feature('echo_demo')

        # If you are working with an OpenFire server, you will
        # need to use a different SSL version:
        # import ssl
        # self.ssl_version = ssl.PROTOCOL_SSLv3

        import ssl
        self.ssl_version = ssl.PROTOCOL_SSLv23

        self.log('Connecting bot to ejabberd')
        self.connect(use_tls=True)
        self.log('Processing ejabberd connection')
        self.process(block=False)

        self.auto_authorize = True
        self.auto_subscribe = True
        self.send_presence(pfrom='claptrap@localhost',
                           pstatus='Curiouser and curiouser!',
                           pshow='xa')

        self.fireEvent(cli_register_event('test_xmpp_send',
                                          cli_test_xmpp_send))
        self.log("Started")
Ejemplo n.º 4
0
	def __init__(self, active_alerter, alerter_model):
		'''
		Constructor
		
		:param active_alerter: The parent alerter for the chat
		:param alerter_model: 
			The database alerter model associated with the bot
		'''
		# Initialises the connection
		ClientXMPP.__init__(self,
						'{}@{}/{}'.format(alerter_model.username,
							Constants.CHAT_SERVER, Constants.CHAT_RESOURCE),
						'AIR_{}'.format(alerter_model.password))

		# Automatically add new friends?
		self.auto_authorize = None
		
		self.auto_subscribe = True
		self.auto_reconnect = True
		self.ssl_version = ssl.PROTOCOL_SSLv3

		# Add the event handlers
		self.add_event_handler('session_start', self.session_start)
		self.add_event_handler('message', self.got_message)
		self.add_event_handler('got_online', self.got_online)
		self.add_event_handler('got_offline', self.got_offline)
		self.add_event_handler('presence_subscribe', self.presence_subscribe)
		self.add_event_handler('presence_unsubscribe',
							self.presence_unsubscribe)
		self.add_event_handler('disconnected', self.disconnected)
		self.add_event_handler('failed_auth', self.failed_auth)

		# Presence change events
		self.add_event_handler('presence_available', self.handle_presence)
		self.add_event_handler('presence_dnd', self.handle_presence)
		self.add_event_handler('presence_xa', self.handle_presence)
		self.add_event_handler('presence_chat', self.handle_presence)
		self.add_event_handler('presence_away', self.handle_presence)

		self.alerter = active_alerter
		self.model = alerter_model
Ejemplo n.º 5
0
    def connect(self):
        """Perform a connection to the server.

        This function is designed to work internally, but calls to connect
        handlers when connection is sucessful.

        """
        if self.client:
            return self.client

        self.client = ClientXMPP(self.jid, self.password)

        # Install event handlers
        self.client.add_event_handler("groupchat_message", self.handle_muc_message)
        self.client.add_event_handler("session_start", self.handle_session_start)
        self.client.add_event_handler("message", self.handle_message)
        self.client.add_event_handler("changed_status", self.handle_changed_status)

        if self.ignore_ssl_cert:
            self.client.add_event_handler("ssl_invalid_cert", self.handle_invalid_cert)

        # Add plug-ins
        self.client.register_plugin("xep_0030") # Service Discovery
        self.client.register_plugin("xep_0004") # Data Forms
        self.client.register_plugin("xep_0060") # PubSub
        self.client.register_plugin("xep_0199") # XMPP Ping
        self.client.register_plugin("xep_0045") # Multi-User Chat

        if self.client.connect(self.server or ()):
            if self.use_tls:
                self.log.info("starting TLS...")
                self.client.start_tls()
            self.log.info("connected to %s, port %d" % self.server)
        else:
            raise WhistlerConnectionError("Unable to connect to %s:%d"
                    % self.server)

        self.run_handler(EVENT_CONNECT)

        return self.client
Ejemplo n.º 6
0
    def _handle_stream_features(self, features):
        if 'starttls' in features['features']:  # Reset stream features after starttls
            self._stream_features = {
                'starttls': features['starttls'],
            }
        else:  # New stream features encountered
            self._stream_features.update(features.get_features())

        found_tags = set([re.match('{.*}(.*)', n.tag).groups(1)[0]
                         for n in features.xml.getchildren()])
        unhandled = found_tags - set(features.get_features().keys())
        if unhandled:
            log.error("Unhandled stream features: %s", sorted(unhandled))
        return ClientXMPP._handle_stream_features(self, features)
Ejemplo n.º 7
0
    def _handle_stream_features(self, features):
        if 'starttls' in features[
                'features']:  # Reset stream features after starttls
            self._stream_features = {
                'starttls': features['starttls'],
            }
        else:  # New stream features encountered
            self._stream_features.update(features.get_features())

        found_tags = set([
            re.match('{.*}(.*)', n.tag).groups(1)[0]
            for n in features.xml.getchildren()
        ])
        unhandled = found_tags - set(features.get_features().keys())
        if unhandled:
            log.error("Unhandled stream features: %s", sorted(unhandled))
        return ClientXMPP._handle_stream_features(self, features)
Ejemplo n.º 8
0
    def connect(self):
        """Perform a connection to the server.

        This function is designed to work internally, but calls to connect
        handlers when connection is sucessful.

        """
        if self.client:
            return self.client

        self.client = ClientXMPP(self.jid, self.password)

        # Install event handlers
        self.client.add_event_handler("groupchat_message", self.handle_muc_message)
        self.client.add_event_handler("session_start", self.handle_session_start)
        self.client.add_event_handler("message", self.handle_message)
        self.client.add_event_handler("changed_status", self.handle_changed_status)

        if self.ignore_ssl_cert:
            self.client.add_event_handler("ssl_invalid_cert", self.handle_invalid_cert)

        # Add plug-ins
        self.client.register_plugin("xep_0030") # Service Discovery
        self.client.register_plugin("xep_0004") # Data Forms
        self.client.register_plugin("xep_0060") # PubSub
        self.client.register_plugin("xep_0199") # XMPP Ping
        self.client.register_plugin("xep_0045") # Multi-User Chat

        if len(self.server) == 2:
            domain, port = self.server
            self.client._expected_server_name = domain

        if self.client.connect(self.server or ()):
            if self.use_tls:
                self.log.info("starting TLS...")
                self.client.start_tls()
            self.log.info("connected to %s, port %d" % self.server)
        else:
            raise WhistlerConnectionError("Unable to connect to %s:%d"
                    % self.server)

        self.run_handler(EVENT_CONNECT)

        return self.client
Ejemplo n.º 9
0
 def connect_soc(self):
     ClientXMPP.connect(self, address=(self.host, self.port), reattempt=True,
                                        use_tls=True, use_ssl=False)
Ejemplo n.º 10
0
    def __init__(self, jid, password, room, nick, mq):
        self.nick = nick
        self.room = room
        self.jid = JID(jid)

        bot = ClientXMPP(jid, password)

        # disable ipv6 for now since we're getting errors using it
        bot.use_ipv6 = False

        bot.add_event_handler('session_start', self.on_start)
        bot.add_event_handler('message', self.on_message)

        bot.register_plugin('xep_0045')
        self._muc = bot.plugin['xep_0045']
        bot.register_plugin('xep_0199')
        bot.plugin['xep_0199'].enable_keepalive(30, 30)
        resource = 'sweetiewatch' + self.randomstr()

        self.mq = mq

        if not bot.connect(): raise 'could not connect'
        bot.process()

        self._bot = bot
Ejemplo n.º 11
0
class WhistlerBot(object):
    """Main Whistler bot class.

    The main WhistlerBot class handle the bot behaviour and perform subcall
    to specific command handler when a command is received in a configured
    MUC channel.

    """

    def __init__(self, jid, password, server=None, rooms=None,
            resource=None, mention=None, log=None, users=[], use_tls=False, ignore_ssl_cert=True):
        """Initialize a Whistler bot.

        Create a new :class:`WhistlerBot` object, the :func:`__init__`
        receive the following parameters:

        :param `jid`: a valid JID atom to identify the bot user.
        :param `password`: a plaintext password to identify the bot user.
        :param `server`: a tuple in the form *server*, *port* which sepcify
            the host to connect to, if not provided the server then use the
            JID domain instead.
        :param `rooms`: a :class:`list` of rooms to be autojoin in.
        :param `resource`: the XMPP resource string, or autogenerated one if
            not provided.
        :param `log`: a :class:`WhistlerLog` to log bot messages to, or
            *stdout* if none is provided.
        :param `users`: a :class:`set` of valid JID as strings which
            identify master users.
        :param use_tls: if set to true, try to use TLS where available
        :param ignore_ssl_cert: if set to false raise an exception when
            certificate do not match with hostname or any other kind of
            invalid certificate.
        """
        self.user = jid
        self.jid = jid
        self.password = password
        self.server = server
        self.log = log or WhistlerLog()
        self.use_tls = use_tls
        self.ignore_ssl_cert = ignore_ssl_cert
        self._initial_users = users
        self.handlers = { EVENT_CONNECT:  [], EVENT_DISCONNECT:  [],
                          EVENT_REGISTER: [], EVENT_JOIN:        [],
                          EVENT_LEAVE:    [], EVENT_UNREGISTER:  [],
                          EVENT_MESSAGE:  [], EVENT_MUC_MESSAGE: [],
                          EVENT_MUC_COMMAND: [], EVENT_CHANGE_STATUS: []}

        self.client = None

        self.resource = resource or self.__class__.__name__.lower() + \
                                    str(random.getrandbits(32))
        self.mention = mention or self.resource

        self.jid += "/" + self.resource
        self._rooms = set(rooms or [])

    @property
    def users(self):
        """Users in the bot roster (administrators)

        A property which return an iterator over users in bot roster, that is
        administrative users or valid users to admin the bot.

        """
        return filter(lambda x:x not in self._rooms,
                self.client.roster[self.user].keys())

    @property
    def roster(self):
        """Bot roster"""
        return self.client.roster

    @property
    def rooms(self):
        """Return a list of rooms where bot are joined in."""
        return self.client["xep_0045"].rooms.keys()

    def run_handler(self, event, *args, **kwargs):
        """Performs the handler actions related with specified event."""

        for handler in self.handlers[event]:
            handler(*args, **kwargs)

    def register_handler(self, typ, fun):
        """Register a new handler to whistler. The handler is a function
        which will be executed on certain actions.

        :param `typ`: The type of the handler, can be one of following:
            * connect: *on connect* handler,
            * disconnect: *on disconnect* handler,
            * register: *on register user* handler.
        :param `fun`: a function to be executed, which receive almost
            an instance of class :class:`WhistlerBot` as parameter. The
            register type also receive a JID in string notation of the
            registered user.
        """
        self.handlers[typ].append(fun)

    def unregister_handler(self, typ, fun):
        """Unregister a previously registerd handler."""
        self.handlers[typ].remove(fun)

    def set_subject(self, room, subject):
        """Set a new subject on specified room."""

        if room in self._rooms:
            mesg = "Whistler set subject to: %s" % subject
            self.client.send_message(room, mesg, subject, "groupchat")

    def send(self, to, mesg, typ="chat", subject=None):
        self.client.send_message(to, mesg, subject, typ)

    def register_plugin(self, plugin_name):
        """Register a new SleekXMPP plugin."""

        if not self.client:
            raise WhistlerError("No client connected")

        self.client.register_plugin(plugin_name)

    def handle_invalid_cert(self, pem_cert):
        """Handle a invalid certification request."""
        self.log.warning("Invalid certificated found, but continue anyway.")

    def connect(self):
        """Perform a connection to the server.

        This function is designed to work internally, but calls to connect
        handlers when connection is sucessful.

        """
        if self.client:
            return self.client

        self.client = ClientXMPP(self.jid, self.password)

        # Install event handlers
        self.client.add_event_handler("groupchat_message", self.handle_muc_message)
        self.client.add_event_handler("session_start", self.handle_session_start)
        self.client.add_event_handler("message", self.handle_message)
        self.client.add_event_handler("changed_status", self.handle_changed_status)

        if self.ignore_ssl_cert:
            self.client.add_event_handler("ssl_invalid_cert", self.handle_invalid_cert)

        # Add plug-ins
        self.client.register_plugin("xep_0030") # Service Discovery
        self.client.register_plugin("xep_0004") # Data Forms
        self.client.register_plugin("xep_0060") # PubSub
        self.client.register_plugin("xep_0199") # XMPP Ping
        self.client.register_plugin("xep_0045") # Multi-User Chat

        if len(self.server) == 2:
            domain, port = self.server
            self.client._expected_server_name = domain

        if self.client.connect(self.server or ()):
            if self.use_tls:
                self.log.info("starting TLS...")
                self.client.start_tls()
            self.log.info("connected to %s, port %d" % self.server)
        else:
            raise WhistlerConnectionError("Unable to connect to %s:%d"
                    % self.server)

        self.run_handler(EVENT_CONNECT)

        return self.client

    def handle_changed_status(self, presence):
        self.run_handler(EVENT_CHANGE_STATUS, presence)

    def handle_session_start(self, event):
        self.client.get_roster()
        self.client.send_presence()
        [self.join_room(room) for room in self._rooms]
        for user in self._initial_users:
            self.register_user(user)

    def register_command(self, cmdname, cmdfun):
        """Register a new command.

        This function in intended to provide a way to add commands
        on-the-fly, when :class:`WhistlerBot` is alreay instanced.

        :param `cmdname`: a name to this command.
        :param `cmdfun`: a callback which can accept three arguments, which
            will be usd when command called.

        """
        setattr(self, "cmd_%s" % cmdname, cmdfun)

    def start(self):
        """Start bot operation.

        Connect to the XMPP server and start the bot, it will be serving
        requests until the stopping is requested, using :func:`stop`
        function.

        """
        if not self.connect():
            raise WhistlerConnectionError("unknown error")

        self.client.process(threaded=False)

    def stop(self):
        """Stop bot operation.

        Stop serving requests. This function also destroys the current
        connection, if existed.

        """
        self.disconnect()

    def is_validuser(self, jid):
        """Check for whether an user is valid.

        Check whether the specified user is registered as valid user in the
        bot, according to :func:`register_user` and :func:`unregister_user`
        functions.

        """
        return (jid not in self._rooms and
                jid in self.client.roster[self.user].keys()) or \
               (jid in self._initial_users)

    def register_user(self, jid, subscription="both"):
        """Register an user as valid user for the bot."""

        self.client.update_roster(jid, subscription=subscription)
        self.run_handler(EVENT_REGISTER, jid)

    def unregister_user(self, jid, subscription="remove"):
        """Unregister an user as valid user for the bot."""

        self.client.update_roster(jid, subscription=subscription)
        self.run_handler(EVENT_UNREGISTER, jid)

    def reply(self, to, message):
        """Send a reply to an specified message, using a new message one.

        :param `to`: a message to be replied
        :param `message`: a string with the reply.

        """
        to.reply(message).send()

    def get_room_nicks(self, room):
        """Return a dict with the nicks in room as keys. Values contains
        data about these nicks."""
        return self.client.plugin["xep_0045"].rooms[room]

    def handle_muc_message(self, message):
        """Handle any received group chat message.

        :param message: Message received from the MUC room.

        """
        body = message["body"]

        self.run_handler(EVENT_MUC_MESSAGE, message, None)

        if not body or (body[0] != COMMAND_CHAR \
                and not body.startswith(self.mention + ", ") \
                and not body.startswith(self.mention + ": ") \
                and not body.startswith("@" + self.mention)):
            # None to handle
            return

        if body[0] == COMMAND_CHAR:
            command_n = body.split()[0][1:]
            arguments = body.split()[1:]
        else:
            command_n = body.split()[1]
            arguments = body.split()[2:]

        command = getattr(self, "cmd_%s" % command_n, None)
        message.command = command

        if command:
            self.log.info("muc command %s %r" % (command_n, arguments))
            result = command(message, arguments)
            if result is not None:
                if isinstance(result, list):
                    for r in result:
                        self.reply(message, r)
                elif isinstance(result, basestring):
                    self.reply(message, result)
        self.run_handler(EVENT_MUC_COMMAND, message, arguments)

    def handle_message(self, message):
        """Handle a direct chat message.

        :param message: Message received from some user.

        """
        if not message["body"]:
            return

        self.run_handler(EVENT_MESSAGE, message, None)

        if message["type"] == "groupchat":
            # discard muc messages here.
            return

        body = message["body"].split()

        command_n = body[0]
        arguments = body[1:]

        command = getattr(self, "cmd_%s" % command_n, None)

        if command:
            self.log.info("chat command %s %r" % (command_n, arguments))
            result = command(message, arguments)
            if result is not None:
                if isinstance(result, list):
                    for r in result:
                        self.reply(message, r)
                elif isinstance(result, basestring):
                    self.reply(message, result)


    def join(self, rooms, resource=None):
        """Join several rooms at once.

        :param rooms: Iterable with room JIDs as strings.
        :param resource: If given, nickname (resource) used in rooms.

        """
        [self.join_room(room, resource) for room in rooms]


    def leave(self, rooms, resource=None):
        """Leave several rooms at once.

        :param rooms: Iterable with rooms JIDs as strings.
        :param resource: If given, nickname (resource) used in rooms.

        """
        [self.leave_room(room, resource) for room in rooms]


    def join_room(self, room, resource=None):
        """Join a Multi-User Chat (MUC) room.

        Make the bot join a MUC room. If a nick different from the resource
        name is to be used, it can be specified. This allows for several
        bots to be in the same room.

        :param `room`: The room name.
        :param `resource`: A resource name for the bot in the room.
        """
        self.client.plugin["xep_0045"].joinMUC(room, resource or self.resource, maxhistory="1")
        self.run_handler(EVENT_JOIN, room)


    def disconnect(self):
        """Disconnect from the server.

        Leave all rooms, sets bot presence to unavailable, and closes the
        connection to the server.

        """
        self.log.info("Shutting down the bot...")
        self.run_handler(EVENT_DISCONNECT)

        self.client.disconnect()


    def leave_room(self, room, resource=None):
        """Leaves a Multi-User Chat (MUC) room.

        :param `room`: the room name to leave.
        :param `resource`: the resource which leaves.

        """
        self.client.plugin["xep_0045"].leaveMUC(room, resource or self.resource)
        self.run_handler(EVENT_LEAVE, room)
Ejemplo n.º 12
0
    def __init__(self, jid, password, room, nick, mq):
        self.nick = nick
        self.room = room
        self.jid = JID(jid)

        bot = ClientXMPP(jid, password)

        bot.add_event_handler('session_start', self.on_start)
        bot.add_event_handler('message', self.on_message)

        bot.register_plugin('xep_0045')
        self._muc = bot.plugin['xep_0045']
        bot.register_plugin('xep_0199')
        bot.plugin['xep_0199'].enable_keepalive(30, 30)
        resource = 'sweetiewatch' + self.randomstr()

        self.mq = mq

        if not bot.connect(): raise 'could not connect'
        bot.process()

        self._bot = bot
Ejemplo n.º 13
0
class WhistlerBot(object):
    """Main Whistler bot class.

    The main WhistlerBot class handle the bot behaviour and perform subcall
    to specific command handler when a command is received in a configured
    MUC channel.

    """

    def __init__(self, jid, password, server=None, rooms=None,
            resource=None, mention=None, log=None, users=[], use_tls=False, ignore_ssl_cert=True):
        """Initialize a Whistler bot.

        Create a new :class:`WhistlerBot` object, the :func:`__init__`
        receive the following parameters:

        :param `jid`: a valid JID atom to identify the bot user.
        :param `password`: a plaintext password to identify the bot user.
        :param `server`: a tuple in the form *server*, *port* which sepcify
            the host to connect to, if not provided the server then use the
            JID domain instead.
        :param `rooms`: a :class:`list` of rooms to be autojoin in.
        :param `resource`: the XMPP resource string, or autogenerated one if
            not provided.
        :param `log`: a :class:`WhistlerLog` to log bot messages to, or
            *stdout* if none is provided.
        :param `users`: a :class:`set` of valid JID as strings which
            identify master users.
        :param use_tls: if set to true, try to use TLS where available
        :param ignore_ssl_cert: if set to false raise an exception when
            certificate do not match with hostname or any other kind of
            invalid certificate.
        """
        self.user = jid
        self.jid = jid
        self.password = password
        self.server = server
        self.log = log or WhistlerLog()
        self.use_tls = use_tls
        self.ignore_ssl_cert = ignore_ssl_cert
        self._initial_users = users
        self.handlers = { EVENT_CONNECT:  [], EVENT_DISCONNECT:  [],
                          EVENT_REGISTER: [], EVENT_JOIN:        [],
                          EVENT_LEAVE:    [], EVENT_UNREGISTER:  [],
                          EVENT_MESSAGE:  [], EVENT_MUC_MESSAGE: [],
                          EVENT_MUC_COMMAND: [], EVENT_CHANGE_STATUS: []}

        self.client = None

        self.resource = resource or self.__class__.__name__.lower() + \
                                    str(random.getrandbits(32))
        self.mention = mention or self.resource

        self.jid += "/" + self.resource
        self._rooms = set(rooms or [])

    @property
    def users(self):
        """Users in the bot roster (administrators)

        A property which return an iterator over users in bot roster, that is
        administrative users or valid users to admin the bot.

        """
        return filter(lambda x:x not in self._rooms,
                self.client.roster[self.user].keys())

    @property
    def roster(self):
        """Bot roster"""
        return self.client.roster

    @property
    def rooms(self):
        """Return a list of rooms where bot are joined in."""
        return self.client["xep_0045"].rooms.keys()

    def run_handler(self, event, *args, **kwargs):
        """Performs the handler actions related with specified event."""

        for handler in self.handlers[event]:
            handler(*args, **kwargs)

    def register_handler(self, typ, fun):
        """Register a new handler to whistler. The handler is a function
        which will be executed on certain actions.

        :param `typ`: The type of the handler, can be one of following:
            * connect: *on connect* handler,
            * disconnect: *on disconnect* handler,
            * register: *on register user* handler.
        :param `fun`: a function to be executed, which receive almost
            an instance of class :class:`WhistlerBot` as parameter. The
            register type also receive a JID in string notation of the
            registered user.
        """
        self.handlers[typ].append(fun)

    def unregister_handler(self, typ, fun):
        """Unregister a previously registerd handler."""
        self.handlers[typ].remove(fun)

    def set_subject(self, room, subject):
        """Set a new subject on specified room."""

        if room in self._rooms:
            mesg = "Whistler set subject to: %s" % subject
            self.client.send_message(room, mesg, subject, "groupchat")

    def send(self, to, mesg, typ="chat", subject=None):
        self.client.send_message(to, mesg, subject, typ)

    def register_plugin(self, plugin_name):
        """Register a new SleekXMPP plugin."""

        if not self.client:
            raise WhistlerError("No client connected")

        self.client.register_plugin(plugin_name)

    def handle_invalid_cert(self, pem_cert):
        """Handle a invalid certification request."""
        self.log.warning("Invalid certificated found, but continue anyway.")

    def connect(self):
        """Perform a connection to the server.

        This function is designed to work internally, but calls to connect
        handlers when connection is sucessful.

        """
        if self.client:
            return self.client

        self.client = ClientXMPP(self.jid, self.password)

        # Install event handlers
        self.client.add_event_handler("groupchat_message", self.handle_muc_message)
        self.client.add_event_handler("session_start", self.handle_session_start)
        self.client.add_event_handler("message", self.handle_message)
        self.client.add_event_handler("changed_status", self.handle_changed_status)

        if self.ignore_ssl_cert:
            self.client.add_event_handler("ssl_invalid_cert", self.handle_invalid_cert)

        # Add plug-ins
        self.client.register_plugin("xep_0030") # Service Discovery
        self.client.register_plugin("xep_0004") # Data Forms
        self.client.register_plugin("xep_0060") # PubSub
        self.client.register_plugin("xep_0199") # XMPP Ping
        self.client.register_plugin("xep_0045") # Multi-User Chat

        if self.client.connect(self.server or ()):
            if self.use_tls:
                self.log.info("starting TLS...")
                self.client.start_tls()
            self.log.info("connected to %s, port %d" % self.server)
        else:
            raise WhistlerConnectionError("Unable to connect to %s:%d"
                    % self.server)

        self.run_handler(EVENT_CONNECT)

        return self.client

    def handle_changed_status(self, presence):
        self.run_handler(EVENT_CHANGE_STATUS, presence)

    def handle_session_start(self, event):
        self.client.get_roster()
        self.client.send_presence()
        [self.join_room(room) for room in self._rooms]
        for user in self._initial_users:
            self.register_user(user)

    def register_command(self, cmdname, cmdfun):
        """Register a new command.

        This function in intended to provide a way to add commands
        on-the-fly, when :class:`WhistlerBot` is alreay instanced.

        :param `cmdname`: a name to this command.
        :param `cmdfun`: a callback which can accept three arguments, which
            will be usd when command called.

        """
        setattr(self, "cmd_%s" % cmdname, cmdfun)

    def start(self):
        """Start bot operation.

        Connect to the XMPP server and start the bot, it will be serving
        requests until the stopping is requested, using :func:`stop`
        function.

        """
        if not self.connect():
            raise WhistlerConnectionError("unknown error")

        self.client.process(threaded=False)

    def stop(self):
        """Stop bot operation.

        Stop serving requests. This function also destroys the current
        connection, if existed.

        """
        self.disconnect()

    def is_validuser(self, jid):
        """Check for whether an user is valid.

        Check whether the specified user is registered as valid user in the
        bot, according to :func:`register_user` and :func:`unregister_user`
        functions.

        """
        return (jid not in self._rooms and
                jid in self.client.roster[self.user].keys()) or \
               (jid in self._initial_users)

    def register_user(self, jid, subscription="both"):
        """Register an user as valid user for the bot."""

        self.client.update_roster(jid, subscription=subscription)
        self.run_handler(EVENT_REGISTER, jid)

    def unregister_user(self, jid, subscription="remove"):
        """Unregister an user as valid user for the bot."""

        self.client.update_roster(jid, subscription=subscription)
        self.run_handler(EVENT_UNREGISTER, jid)

    def reply(self, to, message):
        """Send a reply to an specified message, using a new message one.

        :param `to`: a message to be replied
        :param `message`: a string with the reply.

        """
        to.reply(message).send()

    def get_room_nicks(self, room):
        """Return a dict with the nicks in room as keys. Values contains
        data about these nicks."""
        return self.client.plugin["xep_0045"].rooms[room]

    def handle_muc_message(self, message):
        """Handle any received group chat message.

        :param message: Message received from the MUC room.

        """
        body = message["body"]

        self.run_handler(EVENT_MUC_MESSAGE, message, None)

        if not body or (body[0] != COMMAND_CHAR \
                and not body.startswith(self.mention + ", ") \
                and not body.startswith(self.mention + ": ") \
                and not body.startswith("@" + self.mention)):
            # None to handle
            return

        if body[0] == COMMAND_CHAR:
            command_n = body.split()[0][1:]
            arguments = body.split()[1:]
        else:
            command_n = body.split()[1]
            arguments = body.split()[2:]

        command = getattr(self, "cmd_%s" % command_n, None)
        message.command = command

        if command:
            self.log.info("muc command %s %r" % (command_n, arguments))
            result = command(message, arguments)
            if result is not None:
                if isinstance(result, list):
                    for r in result:
                        self.reply(message, r)
                elif isinstance(result, basestring):
                    self.reply(message, result)
        self.run_handler(EVENT_MUC_COMMAND, message, arguments)

    def handle_message(self, message):
        """Handle a direct chat message.

        :param message: Message received from some user.

        """
        if not message["body"]:
            return

        self.run_handler(EVENT_MESSAGE, message, None)

        if message["type"] == "groupchat":
            # discard muc messages here.
            return

        body = message["body"].split()

        command_n = body[0]
        arguments = body[1:]

        command = getattr(self, "cmd_%s" % command_n, None)

        if command:
            self.log.info("chat command %s %r" % (command_n, arguments))
            result = command(message, arguments)
            if result is not None:
                if isinstance(result, list):
                    for r in result:
                        self.reply(message, r)
                elif isinstance(result, basestring):
                    self.reply(message, result)


    def join(self, rooms, resource=None):
        """Join several rooms at once.

        :param rooms: Iterable with room JIDs as strings.
        :param resource: If given, nickname (resource) used in rooms.

        """
        [self.join_room(room, resource) for room in rooms]


    def leave(self, rooms, resource=None):
        """Leave several rooms at once.

        :param rooms: Iterable with rooms JIDs as strings.
        :param resource: If given, nickname (resource) used in rooms.

        """
        [self.leave_room(room, resource) for room in rooms]


    def join_room(self, room, resource=None):
        """Join a Multi-User Chat (MUC) room.

        Make the bot join a MUC room. If a nick different from the resource
        name is to be used, it can be specified. This allows for several
        bots to be in the same room.

        :param `room`: The room name.
        :param `resource`: A resource name for the bot in the room.
        """
        self.client.plugin["xep_0045"].joinMUC(room, resource or self.resource, maxhistory="1")
        self.run_handler(EVENT_JOIN, room)


    def disconnect(self):
        """Disconnect from the server.

        Leave all rooms, sets bot presence to unavailable, and closes the
        connection to the server.

        """
        self.log.info("Shutting down the bot...")
        self.run_handler(EVENT_DISCONNECT)

        self.client.disconnect()


    def leave_room(self, room, resource=None):
        """Leaves a Multi-User Chat (MUC) room.

        :param `room`: the room name to leave.
        :param `resource`: the resource which leaves.

        """
        self.client.plugin["xep_0045"].leaveMUC(room, resource or self.resource)
        self.run_handler(EVENT_LEAVE, room)