def join(self, mucjid, nick, *,
             password=None, history=None, autorejoin=True):
        """
        Join a multi-user chat and create a conversation for it.

        :param mucjid: The bare JID of the room to join.
        :type mucjid: :class:`~aioxmpp.JID`.
        :param nick: The nickname to use in the room.
        :type nick: :class:`str`
        :param password: The password to join the room, if required.
        :type password: :class:`str`
        :param history: Specification for how much and which history to fetch.
        :type history: :class:`.xso.History`
        :param autorejoin: Flag to indicate that the MUC should be
            automatically rejoined after a disconnect.
        :type autorejoin: :class:`bool`
        :raises ValueError: if the MUC JID is invalid.
        :return: The :term:`Conversation` and a future on the join.
        :rtype: tuple of :class:`~.Room` and :class:`asyncio.Future`.

        Join a multi-user chat at `mucjid` with `nick`. Return a :class:`Room`
        instance which is used to track the MUC locally and a
        :class:`aioxmpp.Future` which becomes done when the join succeeded
        (with a :data:`None` value) or failed (with an exception).

        In addition, the :meth:`~.ConversationService.on_conversation_added`
        signal is emitted immediately with the new :class:`Room`.

        It is recommended to attach the desired signals to the :class:`Room`
        before yielding next (e.g. in a non-deferred event handler to the
        :meth:`~.ConversationService.on_conversation_added` signal), to avoid
        races with the server. It is guaranteed that no signals are emitted
        before the next yield, and thus, it is safe to attach the signals right
        after :meth:`join` returned. (This is also the reason why :meth:`join`
        is not a coroutine, but instead returns the room and a future to wait
        for.)

        Any other interaction with the room must go through the :class:`Room`
        instance.

        If the multi-user chat at `mucjid` is already or currently being
        joined, the existing :class:`Room` and future is returned. The `nick`
        and other options for the new join are ignored.

        If the `mucjid` is not a bare JID, :class:`ValueError` is raised.

        `password` may be a string used as password for the MUC. It will be
        remembered and stored at the returned :class:`Room` instance.

        `history` may be a :class:`History` instance to request a specific
        amount of history; otherwise, the server will return a default amount
        of history.

        If `autorejoin` is true, the MUC will be re-joined after the stream has
        been destroyed and re-established. In that case, the service will
        request history since the stream destruction and ignore the `history`
        object passed here.

        If the stream is currently not established, the join is deferred until
        the stream is established.
        """
        if history is not None and not isinstance(history, muc_xso.History):
            raise TypeError("history must be {!s}, got {!r}".format(
                muc_xso.History.__name__,
                history))

        if not mucjid.is_bare:
            raise ValueError("MUC JID must be bare")

        try:
            room, fut, *_ = self._pending_mucs[mucjid]
        except KeyError:
            pass
        else:
            return room, fut

        try:
            room = self._joined_mucs[mucjid]
        except KeyError:
            pass
        else:
            fut = asyncio.Future()
            fut.set_result(None)
            return room, fut

        room = Room(self, mucjid)
        room.muc_autorejoin = autorejoin
        room.muc_password = password
        room.on_exit.connect(
            functools.partial(
                self._muc_exited,
                room
            )
        )
        room.on_muc_enter.connect(
            self._pending_on_enter,
        )

        fut = asyncio.Future()
        fut.add_done_callback(functools.partial(
            self._pending_join_done,
            mucjid,
            room,
        ))
        self._pending_mucs[mucjid] = room, fut, nick, history

        if self.client.established:
            self._send_join_presence(mucjid, history, nick, password)

        self.on_conversation_new(room)
        self.dependencies[
            aioxmpp.im.service.ConversationService
        ]._add_conversation(room)

        return room, fut
Join a multi-user chat and create a conversation for it.

        :param mucjid: The bare JID of the room to join.
        :type mucjid: :class:`~aioxmpp.JID`.
        :param nick: The nickname to use in the room.
        :type nick: :class:`str`
        :param password: The password to join the room, if required.
        :type password: :class:`str`
        :param history: Specification for how much and which history to fetch.
        :type history: :class:`.xso.History`
        :param autorejoin: Flag to indicate that the MUC should be
            automatically rejoined after a disconnect.
        :type autorejoin: :class:`bool`
        :raises ValueError: if the MUC JID is invalid.
        :return: The :term:`Conversation` and a future on the join.
        :rtype: tuple of :class:`~.Room` and :class:`asyncio.Future`.

        Join a multi-user chat at `mucjid` with `nick`. Return a :class:`Room`
        instance which is used to track the MUC locally and a
        :class:`aioxmpp.Future` which becomes done when the join succeeded
        (with a :data:`None` value) or failed (with an exception).

        In addition, the :meth:`~.ConversationService.on_conversation_added`
        signal is emitted immediately with the new :class:`Room`.

        It is recommended to attach the desired signals to the :class:`Room`
        before yielding next (e.g. in a non-deferred event handler to the
        :meth:`~.ConversationService.on_conversation_added` signal), to avoid
        races with the server. It is guaranteed that no signals are emitted
        before the next yield, and thus, it is safe to attach the signals right
        after :meth:`join` returned. (This is also the reason why :meth:`join`
        is not a coroutine, but instead returns the room and a future to wait
        for.)

        Any other interaction with the room must go through the :class:`Room`
        instance.

        If the multi-user chat at `mucjid` is already or currently being
        joined, the existing :class:`Room` and future is returned. The `nick`
        and other options for the new join are ignored.

        If the `mucjid` is not a bare JID, :class:`ValueError` is raised.

        `password` may be a string used as password for the MUC. It will be
        remembered and stored at the returned :class:`Room` instance.

        `history` may be a :class:`History` instance to request a specific
        amount of history; otherwise, the server will return a default amount
        of history.

        If `autorejoin` is true, the MUC will be re-joined after the stream has
        been destroyed and re-established. In that case, the service will
        request history since the stream destruction and ignore the `history`
        object passed here.

        If the stream is currently not established, the join is deferred until
        the stream is established.