# `muc` — Multi-User-Chat support (XEP-0045)

This subpackage provides client-side support for XEP-0045.

New in version 0.5.

Changed in version 0.9: Nearly the whole public interface of this module has been re-written in 0.9 to make it coherent with the Modern IM interface defined by `aioxmpp.im`.

## Using Multi-User-Chats

To start using MUCs in your application, you have to load the `Service` into the client, using `summon()`.

class aioxmpp.MUCClient(client, **kwargs)

  Conversation Implementation for Multi-User Chats (XEP-0045).

  See also

  `AbstractConversationService`

    for useful common signals

  This service provides access to Multi-User Chats using the conversation interface defined by `aioxmpp.im`.

  Client service implementing the a Multi-User Chat client. By loading it into a client, it is possible to join multi-user chats and implement interaction with them.

  Private Messages into the MUC are not handled by this service. They are handled by the normal `p2p.Service`.

  join(mucjid, nick, *, password=None, history=None, autorejoin=True)

    Join a multi-user chat and create a conversation for it.

    Parameters

      - mucjid (`JID`.) – The bare JID of the room to join.

      - nick (`str`) – The nickname to use in the room.

      - password (`str`) – The password to join the room, if required.

      - history (`xso.History`) – Specification for how much and which history to fetch.

      - autorejoin (`bool`) – Flag to indicate that the MUC should be automatically rejoined after a disconnect.

    Raises

      ValueError – if the MUC JID is invalid.

    Returns

      The Conversation and a future on the join.

    Return type

      tuple of `Room` and `asyncio.Future`.

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

    In addition, the `on_conversation_added()` signal is emitted immediately with the new `Room`.

    It is recommended to attach the desired signals to the `Room` before yielding next (e.g. in a non-deferred event handler to the `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 `join()` returned. (This is also the reason why `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 `Room` instance.

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

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

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

    history may be a `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.

  Manage rooms:

  async get_room_config(mucjid)

    Query and return the room configuration form for the given MUC.

    Parameters

      mucjid (bare `JID`) – JID of the room to query

    Returns

      data form template for the room configuration

    Return type

      `aioxmpp.forms.Data`

    See also

    `ConfigurationForm`

      for a form template to work with the returned form

    New in version 0.7.

  async set_room_config(mucjid, data)

    Set the room configuration using a XEP-0004 data form.

    Parameters

      - mucjid (bare `JID`) – JID of the room to query

      - data (`aioxmpp.forms.Data`) – Filled-out configuration form

    See also

    `ConfigurationForm`

      for a form template to generate the required form

    A sensible workflow to, for example, set a room to be moderated, could be this:

        form = aioxmpp.muc.ConfigurationForm.from_xso(
            (await muc_service.get_room_config(mucjid))
        )
        form.moderatedroom = True
        await muc_service.set_rooom_config(mucjid, form.render_reply())

    New in version 0.7.

  async get_affiliated(mucjid, affiliation)

    Retrieve the list of JIDs with the given affiliation with a MUC.

    Parameters

      - mucjid (`JID`) – The bare JID identifying the MUC.

      - affiliation (`str`) – The affiliation level to query.

    Raises

      `aioxmpp.errors.XMPPAuthError` if the client does not have sufficient privileges to query affiliations of the given level.

    Returns

      Collection of JIDs with the given affiliation.

  async set_affiliation(mucjid, jid, affiliation, *, reason=None)

    Change the affiliation of an entity with a MUC.

    Parameters

      - mucjid (`JID`) – The bare JID identifying the MUC.

      - jid (`JID`) – The bare JID of the entity whose affiliation shall be changed.

      - affiliation (`str`) – The new affiliation for the entity.

      - reason (`str` or `None`) – Optional reason for the affiliation change.

    Change the affiliation of the given jid with the MUC identified by the bare mucjid to the given new affiliation. Optionally, a reason can be given.

    If you are joined in the MUC, `Room.muc_set_affiliation()` may be more convenient, but it is possible to modify the affiliations of a MUC without being joined, given sufficient privilegues.

    Setting the different affiliations require different privilegues of the local user. The details can be checked in XEP-0045 and are enforced solely by the server, not local code.

    The coroutine returns when the change in affiliation has been acknowledged by the server. If the server returns an error, an appropriate `aioxmpp.errors.XMPPError` subclass is raised.

  Global events:

  signal on_muc_invitation(stanza, muc_address, inviter_address, mode, *, password=None, reason=None, **kwargs)

    Emits when a MUC invitation has been received.

    New in version 0.10.

    Parameters

      - stanza (`aioxmpp.Message`) – The stanza containing the invitation.

      - muc_address (`aioxmpp.JID`) – The address of the MUC to which the invitation points.

      - inviter_address (`aioxmpp.JID` or `None`) – The address of the inviter.

      - mode (`im.InviteMode`) – The type of the invitation.

      - password (`str` or `None`) – Password for the MUC.

      - reason (`str` or `None`) – Text accompanying the invitation.

    The format of the inviter_address depends on the mode:

    `DIRECT`

      For direct invitations, the inviter_address is the full or bare JID of the entity which sent the invitation. Usually, this will be a full JID of a users client.

    `MEDIATED`

      For mediated invitations, the inviter_address is either the occupant JID of the inviting occupant or the real bare or full JID of the occupant (XEP-0045 leaves it up to the service to decide). May also be `None`.

    Warning

    Neither invitation type is perfect and has issues. Mediated invites can easily be spoofed by MUCs (both their intent and the inviter address) and might be used by spam rooms to trick users into joining. Direct invites may not reach the recipient due to local policy, but they allow proper sender attribution.

    inviter_address values which are not an occupant JID should not be trusted for mediated invites!

    How to deal with this is a policy decision which `aioxmpp` can not make for your application.

  Changed in version 0.8: This class was formerly known as `aioxmpp.muc.Service`. It is still available under that name, but the alias will be removed in 1.0.

  Changed in version 0.9: This class was completely remodeled in 0.9 to conform with the `aioxmpp.im` interface.

  Changed in version 0.10: This class now conforms to the `AbstractConversationService` interface.

class aioxmpp.muc.Service

  Alias of `MUCClient`.

  Deprecated since version 0.8: The alias will be removed in 1.0.

The service returns `Room` objects which are used to track joined MUCs:

class aioxmpp.muc.Room(service, mucjid)

  Conversation representing a single XEP-0045 Multi-User Chat.

  Note

  This is an implementation of `AbstractConversation`. The members which do not carry the `muc_` prefix usually have more extensive documentation there. This documentation here only provides a short synopsis for those members plus the changes with respect to the base interface.

  Changed in version 0.9: In 0.9, the `Room` interface was re-designed to match `AbstractConversation`.

  The following properties are provided:

  features

    The set of features supported by this MUC. This may vary depending on features exported by the MUC service, so be sure to check this for each individual MUC.

  jid

    The (bare) `aioxmpp.JID` of the MUC which this `Room` tracks.

  me

    A `Occupant` instance which tracks the local user. This is `None` until `on_enter()` is emitted; it is never set to `None` again, but the identity of the object changes on each `on_enter()`.

  members

    A copy of the list of occupants. The local user is always the first item in the list, unless the `on_enter()` has not fired yet.

  service_member

    A `ServiceMember` object which represents the MUC service itself.

    This is used when messages from the MUC service are received.

    See also

    `service_member`

      For more documentation on the semantics of `service_member`.

    New in version 0.10.

  These properties are specific to MUC:

  muc_active

    A boolean attribute indicating whether the connection to the MUC is currently live.

    This becomes true when `joined` first becomes true. It becomes false whenever the connection to the MUC is interrupted in a way which requires re-joining the MUC (this implies that if stream management is being used, active does not become false on temporary connection interruptions).

  muc_joined

    This attribute becomes true when `on_enter()` is first emitted and stays true until `on_exit()` is emitted.

    When it becomes false, the `Room` is removed from the bookkeeping of the `MUCClient` to which it belongs and is thus dead.

  muc_state

    The state the MUC is in. This is one of the `RoomState` enumeration values. See there for documentation on the meaning.

    This state is more detailed than `muc_active`.

  muc_subject

    The current subject of the MUC, as `LanguageMap`.

  muc_subject_setter

    The nick name of the entity who set the subject.

  muc_autorejoin

    A boolean flag indicating whether this MUC is supposed to be automatically rejoined when the stream it is used gets destroyed and re-estabished.

  muc_password

    The password to use when (re-)joining. If `autorejoin` is `None`, this can be cleared after `on_enter()` has been emitted.

  The following methods and properties provide interaction with the MUC itself:

  async ban(member, reason=None, *, request_kick=True)

    Ban an occupant from re-joining the MUC.

    Parameters

      - member (`Occupant`) – The occupant to ban.

      - reason (`str`) – A reason to show to the members of the conversation including the banned member.

      - request_kick (`bool`) – A flag indicating that the member should be removed from the conversation immediately, too.

    request_kick is supported by MUC, but setting it to false has no effect: banned members are always immediately kicked.

    See also

    `AbstractConversation.ban()` for the full interface specification.

  async kick(member, reason=None)

    Kick an occupant from the MUC.

    Parameters

      - member (`Occupant`) – The member to kick.

      - reason (`str`) – A reason to show to the members of the conversation including the kicked member.

    Raises

      aioxmpp.errors.XMPPError – if the server returned an error for the kick command.

    See also

    `AbstractConversation.kick()` for the full interface specification.

  async leave()

    Leave the MUC.

  send_message(msg)

    Send a message to the MUC.

    Parameters

      msg (`aioxmpp.Message`) – The message to send.

    Returns

      The stanza token of the message.

    Return type

      `StanzaToken`

    There is no need to set the address attributes or the type of the message correctly; those will be overridden by this method to conform to the requirements of a message to the MUC. Other attributes are left untouched (except that `autoset_id()` is called) and can be used as desired for the message.

    See also

    `AbstractConversation.send_message()` for the full interface specification.

  send_message_tracked(msg)

    Send a message to the MUC with tracking.

    Parameters

      msg (`aioxmpp.Message`) – The message to send.

    Warning

    Please read General Remarks about Tracking and Memory Consumption. This is especially relevant for MUCs because tracking is not guaranteed to work due to how XEP-0045 is written. It will work in many cases, probably in all cases you test during development, but it may fail to work for some individual messages and it may fail to work consistently for some services. See the implementation details below for reasons.

    The message is tracked and is considered `DELIVERED_TO_RECIPIENT` when it is reflected back to us by the MUC service. The reflected message is then available in the `response` attribute.

    Note

    Two things:

    1. The MUC service may change the contents of the message. An example of this is the Prosody developer MUC which replaces messages with more than a few lines with a pastebin link.

    2. Reflected messages which are caught by tracking are not emitted through `on_message()`.

    There is no need to set the address attributes or the type of the message correctly; those will be overridden by this method to conform to the requirements of a message to the MUC. Other attributes are left untouched (except that `autoset_id()` is called) and can be used as desired for the message.

    Warning

    Using `send_message_tracked()` before `on_join()` has emitted will cause the member object in the resulting `on_message()` event to be `None` (the message will be delivered just fine).

    Using `send_message_tracked()` before history replay is over will cause the `on_message()` event to be emitted during history replay, even though everyone else in the MUC will – of course – only see the message after the history.

    `send_message()` is not affected by these quirks.

    See also

    `AbstractConversation.send_message_tracked()` for the full interface specification.

    Implementation details: Currently, we try to detect reflected messages using two different criteria. First, if we see a message with the same message ID (note that message IDs contain 120 bits of entropy) as the message we sent, we consider it as the reflection. As some MUC services re-write the message ID in the reflection, as a fallback, we also consider messages which originate from the correct sender and have the correct body a reflection.

    Obviously, this fails consistently in MUCs which re-write the body and re-write the ID and randomly if the MUC always re-writes the ID but only sometimes the body.

  async set_nick(new_nick)

    Change the nick name of the occupant.

    Parameters

      new_nick (`str`) – New nickname to use

    This sends the request to change the nickname and waits for the request to be sent over the stream.

    The nick change may or may not happen, or the service may modify the nickname; observe the `on_nick_change()` event.

    See also

    `AbstractConversation.set_nick()` for the full interface specification.

  async set_topic(new_topic)

    Change the (possibly publicly) visible topic of the conversation.

    Parameters

      new_topic (`str`) – The new topic for the conversation.

    Request to set the subject to new_topic. new_topic must be a mapping which maps `LanguageTag` tags to strings; `None` is a valid key.

  async muc_request_voice()

    Request voice (participant role) in the room and wait for the request to be sent.

    The participant role allows occupants to send messages while the room is in moderated mode.

    There is no guarantee that the request will be granted. To detect that voice has been granted, observe the `on_role_change()` signal.

    New in version 0.8.

  async muc_set_role(nick, role, *, reason=None)

    Change the role of an occupant.

    Parameters

      - nick (`str`) – The nickname of the occupant whose role shall be changed.

      - role (`str`) – The new role for the occupant.

      - reason – An optional reason to show to the occupant (and all others).

    Change the role of an occupant, identified by their nick, to the given new role. Optionally, a reason for the role change can be provided.

    Setting the different roles require different privilegues of the local user. The details can be checked in XEP-0045 and are enforced solely by the server, not local code.

    The coroutine returns when the role change has been acknowledged by the server. If the server returns an error, an appropriate `aioxmpp.errors.XMPPError` subclass is raised.

  async muc_set_affiliation(jid, affiliation, *, reason=None)

    Convenience wrapper around `MUCClient.set_affiliation()`. See there for details, and consider its mucjid argument to be set to `mucjid`.

  The interface provides signals for most of the rooms events. The following keyword arguments are used at several signal handlers (which is also noted at their respective documentation):

  muc_actor = `None`

    The `UserActor` instance of the corresponding `UserExt`, describing which other occupant caused the event.

    Note that the muc_actor is in fact not a `Occupant`.

  muc_reason = `None`

    The reason text in the corresponding `UserExt`, which gives more information on why an action was triggered.

  Note

  Signal handlers attached to any of the signals below must accept arbitrary keyword arguments for forward compatibility. For details see the documentation on `AbstractConversation`.

  signal on_enter(**kwargs)

    Emits when the initial room `Presence` stanza for the local JID is received. This means that the join to the room is complete; the message history and subject are not transferred yet though.

    See also

    `on_muc_enter()`

      is an extended version of this signal which contains additional MUC-specific information.

    Changed in version 0.10: The `on_enter()` signal does not receive any arguments anymore to make MUC comply with the `AbstractConversation` spec.

  signal on_muc_enter(presence, occupant, *, muc_status_codes=set(), **kwargs)

    This is an extended version of `on_enter()` which adds MUC-specific arguments.

    Parameters

      - presence – The initial presence stanza.

      - occupant – The `Occupant` which will be used to track the local user.

      - muc_status_codes (`Set` of `int` or `StatusCode`) – The set of status codes received in the initial join.

    New in version 0.10.

  signal on_message(msg, member, source, **kwargs)

    A message occurred in the conversation.

    Parameters

      - msg (`aioxmpp.Message`) – Message which was received.

      - member (`Occupant`) – The member object of the sender.

      - source (`MessageSource`) – How the message was acquired

    The notable specialities about MUCs compared to the base specification at `AbstractConversation.on_message()` are:

    - Carbons do not happen for MUC messages.

    - MUC Private Messages are not handled here; see `MUCClient` for MUC PM details.

    - MUCs reflect messages; to make this as easy to handle as possible, reflected messages are not emitted via the `on_message()` event if and only if they were sent with tracking (see `send_message_tracked()`) and they were detected as reflection.

      See `send_message_tracked()` for details and caveats on the tracking implementation.

    When history replay happens, since joins and leaves are not part of the history, it is not always possible to reason about the identity of the sender of a history message. To avoid possible spoofing attacks, the following caveats apply to the `Occupant` objects handed as member during history replay:

    - Two identical `Occupant` objects are only used iff the nickname and the actual address of the entity are equal. This implies that unless this client has the permission to see JIDs of occupants of the MUC, all `Occupant` objects during history replay will be different instances.

    - If the nickname and the actual address of a message from history match, the current `Occupant` object for the respective occupant is used.

    - `Occupant` objects which are created for history replay are never part of `members`. They are only used to convey the information passed in the messages from the history replay, which would otherwise be inaccessible.

    See also

    `AbstractConversation.on_message()` for the full specification.

  signal on_presence_changed(member, resource, presence, **kwargs)

    The presence state of an occupant has changed.

    Parameters

      - member (`Occupant`) – The member object of the affected member.

      - resource (`str` or `None`) – The resource of the member which changed presence.

      - presence (`aioxmpp.Presence`) – The presence stanza

    resource is always `None` for MUCs and unavailable presence implies that the occupant left the room. In this case, only `on_leave()` is emitted.

    See also

    `AbstractConversation.on_presence_changed()` for the full specification.

  signal on_nick_changed(member, old_nick, new_nick, *, muc_status_codes=set(), **kwargs)

    The nickname of an occupant has changed

    Parameters

      - member (`Occupant`) – The occupant whose nick has changed.

      - old_nick (`str` or `None`) – The old nickname of the member.

      - new_nick (`str`) – The new nickname of the member.

      - muc_status_codes (`Set` of `int` or `StatusCode`) – The set of status codes received in the leave notification.

    The new nickname is already set in the member object. Both old_nick and new_nick are not `None`.

    See also

    `AbstractConversation.on_nick_changed()` for the full specification.

    Changed in version 0.10: The muc_status_codes argument was added.

  signal on_topic_changed(member, new_topic, *, muc_nick=None, **kwargs)

    The topic of the conversation has changed.

    Parameters

      - member (`Occupant` or `None`) – The member object who changed the topic.

      - new_topic (`LanguageMap`) – The new topic of the conversation.

      - muc_nick (`str`) – The nickname of the occupant who changed the topic.

    The member is matched by nickname. It is possible that the member is not in the room at the time the topic change is received (for example on a join).

    muc_nick is always the nickname of the entity who changed the topic. If the entity is currently not joined or has changed nick since the topic was set, member will be `None`, but muc_nick is still the nickname of the actor.

    Note

    `on_topic_changed()` is emitted during join, iff a topic is set in the MUC.

  signal on_join(member, **kwargs)

    A new occupant has joined the MUC.

    Parameters

      member (`Occupant`) – The member object of the new member.

    When this signal is called, the member is already included in the `members`.

  signal on_leave(member, *, muc_leave_mode=None, muc_actor=None, muc_reason=None, **kwargs)

    An occupant has left the conversation.

    Parameters

      - member (`Occupant`) – The member object of the previous occupant.

      - muc_leave_mode (`LeaveMode` member) – The cause of the removal.

      - muc_actor (`UserActor`) – The actor object if available.

      - muc_reason (`str`) – The reason for the cause, as given by the actor.

      - muc_status_codes (`Set` of `int` or `StatusCode`) – The set of status codes received in the leave notification.

    When this signal is called, the member has already been removed from the `members`.

    Changed in version 0.10: The muc_status_codes argument was added.

  signal on_muc_suspend()

    Emits when the stream used by this MUC gets destroyed (see `on_stream_destroyed()`) and the MUC is configured to automatically rejoin the user when the stream is re-established.

  signal on_muc_resume()

    Emits when the MUC is about to be rejoined on a new stream. This can be used by implementations to clear their MUC state, as it is emitted before any events like presence are emitted.

    The internal state of `Room` is cleared before `on_resume()` is emitted, which implies that presence events will be emitted for all occupants on re-join, independent on their presence before the connection was lost.

    Note that on a rejoin, all presence is re-emitted.

  signal on_muc_role_request(form, submission_future)

    Emits when an unprivileged occupant requests a role change and the MUC service wants this occupant to approve or deny it.

    Parameters

      - form (`VoiceRequestForm`) – The approval form as presented by the service.

      - submission_future (`asyncio.Future`) – A future to which the form to submit must be sent.

    To decide on a role change request, a handler of this signal must fill in the form and set the form as a result of the submission_future.

    Once the result is set, the reply is sent by the MUC service automatically.

    It is required for signal handlers to check whether the submission_future is already done before processing the form (as it is possible that multiple handlers are connected to this signal).

  signal on_exit(*, muc_leave_mode=None, muc_actor=None, muc_reason=None, muc_status_codes=set(), **kwargs)

    Emits when the unavailable `Presence` stanza for the local JID is received.

    Parameters

      - muc_leave_mode (`LeaveMode` member) – The cause of the removal.

      - muc_actor (`UserActor`) – The actor object if available.

      - muc_reason (`str`) – The reason for the cause, as given by the actor.

      - muc_status_codes (`Set` of `int` or `StatusCode`) – The set of status codes received in the leave notification.

    Note

    The keyword arguments muc_actor, muc_reason and muc_status_codes are not always given. Be sure to default them accordingly.

    Changed in version 0.10: The muc_status_codes argument was added.

  signal on_muc_stale(**kwargs)

    Emits when the `muc_hard_timeout` expires.

    This signal is emitted only up to once for each pause in data reception. As long as data is received often enough, the timeout will not trigger. When the timeout triggers due to silence, the signal is emitted once, and not again until after data has been received for the next time.

    This signal is only informational. It does not imply that the MUC is unreachable or that the local occupant has been removed from the MUC, but it is very likely that no messages can currently be sent or received.

    It is not clear whether messages are being lost.

    A prominent example on when this condition can occur is highlighted in the specification for the feature this is built on (XEP-0410). Often, the MUC service is on a remote domain, which means that there are at least two network connections involved, sometimes three (c2s, s2s, and from the remote server to the MUC component).

    When the s2s connection (for example) fails in certain ways, it is possible that no error replies are generated by any party; stanzas are essentially blackholed. When the network connection resumes, it depends on the exact failure mode whether the occupant is still in the room and which messages (if any) which were sent in the meantime will have been delivered to any participant.

    After `on_muc_stale()` emits, exactly one of the following will happen, given infinite time:

    - `on_muc_fresh()` is emitted, which means that connectivity to the MUC has been re-confirmed.

    - `on_muc_suspend()` is emitted, which means that the local client has disconnected (but autorejoin is enabled).

    - `on_exit()` is emitted, which means that the client has been removed from the MUC or the local client has disconnected (and autorejoin is disabled).

    The aliveness checks are only enabled after presence synchronisation has begun.

  signal on_muc_fresh(**kwargs)

    Emits after `on_muc_stale()` when connectivity is re-confirmed.

    See `on_muc_stale()` for details.

  The following signals inform users about state changes related to other occupants in the chat room. Note that different events may fire for the same presence stanza. A common example is a ban, which triggers `on_affiliation_change()` (as the occupants affiliation is set to `"outcast"`) and then `on_leave()` (with `LeaveMode.BANNED` mode).

  signal on_muc_affiliation_changed(member, *, actor=None, reason=None, status_codes=set(), **kwargs)

    Emits when the affiliation of a member with the room changes.

    Parameters

      - occupant (`Occupant`) – The member of the room.

      - actor (`UserActor`) – The actor object if available.

      - reason (`str`) – The reason for the change, as given by the actor.

      - status_codes (`Set` of `int` or `StatusCode`) – The set of status codes received in the change notification.

    occupant is the `Occupant` instance tracking the occupant whose affiliation changed.

    Changed in version 0.10: The status_codes argument was added.

  signal on_muc_role_changed(member, *, actor=None, reason=None, status_codes=set(), **kwargs)

    Emits when the role of an occupant in the room changes.

    Parameters

      - occupant (`Occupant`) – The member of the room.

      - actor (`UserActor`) – The actor object if available.

      - reason (`str`) – The reason for the change, as given by the actor.

      - status_codes (`Set` of `int` or `StatusCode`) – The set of status codes received in the change notification.

    occupant is the `Occupant` instance tracking the occupant whose role changed.

    Changed in version 0.10: The status_codes argument was added.

  Timeout control:

  See also

  Self-Ping Implementation and Logic

  muc_soft_timeout

    The soft timeout of the MUC aliveness timeout logic as `datetime.timedelta`.

    New in version 0.11.

  muc_hard_timeout

    The hard timeout of the MUC aliveness timeout logic as `datetime.timedelta`.

    New in version 0.11.

  muc_ping_interval

    The interval at which pings are sent after the soft timeout expires as `datetime.timedelta`.

    Warning

    Please see the notes on `muc_ping_timeout` when changing the value of `muc_ping_timeout` or `muc_ping_interval`.

    New in version 0.11.

  muc_ping_timeout

    The maximum time to wait for a ping reply for each individual ping as `datetime.timedelta`.

    Warning

    Pings are continued to be sent even when other pings are already in-flight. This means that up to `math.ceil(muc_ping_timeout / muc_ping_interval)` pings are in-flight at the same time. Each ping which is in-flight unfortunately requires a small amount of memory and an entry in a map which associates the stanza ID with the handler/future for the reply.

    New in version 0.11.

  See also

  Self-Ping Implementation and Logic

class aioxmpp.muc.RoomState(value)

  Enumeration which describes the state a `Room` is in.

  JOIN_PRESENCE

    The room is in the process of being joined and the presence state transfer is going on.

  HISTORY

    Presence state transfer has happened, but the room subject has not been received yet. This is where history replay messages are received.

    When entering this state, `muc_active` becomes true.

  ACTIVE

    The join has completed, including history replay and receiving the subject.

  DISCONNECTED

    The MUC is suspended or disconnected. If the MUC is disconnected, `muc_joined` will be false, too.

class aioxmpp.muc.LeaveMode(value)

  The different reasons for a user to leave or be removed from MUC.

  DISCONNECTED

    The local client disconnected. This only occurs in events referring to the local entity.

  SYSTEM_SHUTDOWN

    The remote server shut down.

  NORMAL

    The leave was initiated by the occupant themselves and was not a kick or ban.

  KICKED

    The user was kicked from the room.

  AFFILIATION_CHANGE

    Changes in the affiliation of the user caused them to be removed.

  MODERATION_CHANGE

    Changes in the moderation settings of the room caused the user to be removed.

  BANNED

    The user was banned from the room.

  ERROR

    The user was removed due to an error when communicating with the client or the users server.

    Not all servers support this. If not supported by the server, one will typically see a `KICKED` status code with an appropriate `status` message.

    New in version 0.10.

Inside rooms, there are occupants:

class aioxmpp.muc.Occupant(occupantjid, is_self, presence_state=<PresenceState available>, presence_status={}, affiliation=None, role=None, jid=None)

  A tracking object to track a single occupant in a `Room`.

  See also

  `AbstractConversationMember`

    for additional notes on some of the pre-defined attributes.

  direct_jid

    The real `JID` of the occupant.

    If the MUC is anonymous and we do not have the permission to see the real JIDs of occupants, this is `None`.

  conversation_jid

    The `JID` of the conversation member relative to the conversation.

  uid

    This is either a random identifier if the real JID of the occupant is not known, or an identifier derived from the real JID of the occupant.

    Note that as per the semantics of the `uid`, users must treat it as opaque.

    See also

    `uid`

      Documentation of the attribute on the base class, with additional information on semantics.

  nick

    The nickname of the occupant.

  presence_state

    The `PresenceState` of the occupant.

  presence_status

    The `LanguageMap` holding the presence status text of the occupant.

  affiliation

    The affiliation of the occupant with the room. This may be `None` with faulty MUC implementations.

  role

    The current role of the occupant within the room. This may be `None` with faulty MUC implementations.

class aioxmpp.muc.ServiceMember(muc_address)

  A `AbstractConversationMember` which represents a MUC service.

  New in version 0.10.

  Objects of this instance are used for the `Room.service_member` property of rooms.

  Aside from the mandatory conversation member attributes, the following attributes for compatibility with `Occupant` are provided:

  nick
  presence_state aioxmpp.structs.PresenceState(False)

    The presence state of the service. Always unavailable.

  presence_status {}

    The presence status of the service as `LanguageMap`. Always empty.

  affiliation None

    The affiliation of the service. Always `None`.

  role None

    The role of the service. Always `None`.

### Timeout controls / XEP-0410 (MUC Self-Ping) support

New in version 0.11: XEP-0410 support and aliveness detection.

#### Motivation

In XMPP, multi-user chat services may reside on a server different than the one the user is at. This may either be due to the service running on a remote domain, or due to the service being connected via the network to the users server as component (see e.g. XEP-0114).

When the connection between the MUC service and the user’s server is broken when stanzas need to be delivered, stanzas can be lost. This can lead to the MUC getting “out of sync”, in the sense that different participants have different views of what happens and who even is in the MUC; this uncertainty can go as far as a client assuming that they’re still joined, while they were long removed from the MUC.

These types of breakages are hard to detect, unless the user tries to send a message through the MUC (in which case the lack of reflection or an error reply will give a clue that something is wrong). In the worst case, with an always-on client, it may appear that the MUC has been silent for days, while in fact everyone has been chatting away happily.

#### Solution

The underlying problem (networks get split) cannot be solved. While Stream Management on the s2s links could mitigate the issue to some extent, there will always be limits and circumstances at play which can still cause the out-of-sync situation.

While loss of messages can be compensated for by fetching the messages from the archive (doing this automatically on an interruption is out of scope for aioxmpp), there is no way for an application to detect that the client has been removed from the MUC except by explicitly pinging or sending messages.

To codify the complex rules which are needed to silently (i.e. invisible to other participants) check whether a client is still joined, XEP-0410 was written. It specifies the use of XEP-0199 pings through the MUC to the clients occupant (i.e. pinging oneself). MUC services explicitly reject the ping request if the sending client is not an occupant.

#### Self-Ping Implementation and Logic

The XEP-0410 implementation in aioxmpp is controlled with several attributes and lines of defense. In the first line of defense, there is a `AlivenessMonitor` instance (this class is also used to manage pinging the main XML stream). It is configured through `aioxmpp.muc.Room.muc_soft_timeout` and `muc_hard_timeout`.

The two timers run concurrently. When the soft timeout expires, the pinger (see below) task is started. When the hard timeout expires, the MUC is marked stale (this means, the `on_muc_stale()` event fires). The timers for both timeouts are reset whenever a presence or message stanza is received from the MUC, preventing unnecessary pinging.

The pinger task emits pings in a defined interval (`muc_ping_interval`). The pings have a timeout of `muc_ping_timeout`. If a ping is replied to, the result is interpreted according to XEP-0410. If the result is positive (= user still joined), the soft and hard timeout timers mentioned above are reset (the pinger, thus, ideally prevents the hard timeout from being triggered if the connection to the MUC is fine after the soft timeout expired). If the result is inconclusive, pinging continues. If the result is negative (= user is not joined anymore), the MUC room is marked as exited (with the reason `DISCONNECTED`), except if it is set to autorejoin, in which case a re-join (just as if the XML stream had been disconnected) is attempted.

The default timeouts are set reasonably high to work reliably even on mobile links.

Warning

Please see the notes on `muc_ping_timeout` when changing the value of `muc_ping_timeout` or `muc_ping_interval`.

## Forms

class aioxmpp.muc.ConfigurationForm(*args, **kwargs)

  This is a XEP-0004 form template (see `aioxmpp.forms`) for MUC configuration forms.

  The attribute documentation is auto-generated from XEP-0045; see there for details on the semantics of each field.

  New in version 0.7.

  allowinvites

    `boolean` field `muc#roomconfig_allowinvites`

    Whether to Allow Occupants to Invite Others

  allowpm

    `list-single` field `muc#roomconfig_allowpm`

    Roles that May Send Private Messages

  changesubject

    `boolean` field `muc#roomconfig_changesubject`

    Whether to Allow Occupants to Change Subject

  enablelogging

    `boolean` field `muc#roomconfig_enablelogging`

    Whether to Enable Public Logging of Room Conversations

  getmemberlist

    `list-multi` field `muc#roomconfig_getmemberlist`

    Roles and Affiliations that May Retrieve Member List

  lang

    `text-single` field `muc#roomconfig_lang`

    Natural Language for Room Discussions

  maxhistoryfetch

    `text-single` field `muc#maxhistoryfetch`

    Maximum Number of History Messages Returned by Room

  maxusers

    `list-single` field `muc#roomconfig_maxusers`

    Maximum Number of Room Occupants

  membersonly

    `boolean` field `muc#roomconfig_membersonly`

    Whether to Make Room Members-Only

  moderatedroom

    `boolean` field `muc#roomconfig_moderatedroom`

    Whether to Make Room Moderated

  passwordprotectedroom

    `boolean` field `muc#roomconfig_passwordprotectedroom`

    Whether a Password is Required to Enter

  persistentroom

    `boolean` field `muc#roomconfig_persistentroom`

    Whether to Make Room Persistent

  presencebroadcast

    `list-multi` field `muc#roomconfig_presencebroadcast`

    Roles for which Presence is Broadcasted

  publicroom

    `boolean` field `muc#roomconfig_publicroom`

    Whether to Allow Public Searching for Room

  pubsub

    `text-single` field `muc#roomconfig_pubsub`

    XMPP URI of Associated Publish-Subscribe Node

  roomadmins

    `jid-multi` field `muc#roomconfig_roomadmins`

    Full List of Room Admins

  roomdesc

    `text-single` field `muc#roomconfig_roomdesc`

    Short Description of Room

  roomname

    `text-single` field `muc#roomconfig_roomname`

    Natural-Language Room Name

  roomowners

    `jid-multi` field `muc#roomconfig_roomowners`

    Full List of Room Owners

  roomsecret

    `text-private` field `muc#roomconfig_roomsecret`

    The Room Password

  whois

    `list-single` field `muc#roomconfig_whois`

    Affiliations that May Discover Real JIDs of Occupants

class aioxmpp.muc.InfoForm(*args, **kwargs)
  contactjid

    `jid-multi` field `muc#roominfo_contactjid`

    Contact Addresses (normally, room owner or owners)

  description

    `text-single` field `muc#roominfo_description`

    Short Description of Room

  lang

    `text-single` field `muc#roominfo_lang`

    Natural Language for Room Discussions

  ldapgroup

    `text-single` field `muc#roominfo_ldapgroup`

    An associated LDAP group that defines room membership; this should be an LDAP Distinguished Name according to an implementation-specific or deployment-specific definition of a group.

  logs

    `text-single` field `muc#roominfo_logs`

    URL for Archived Discussion Logs

  maxhistoryfetch

    `text-single` field `muc#maxhistoryfetch`

    Maximum Number of History Messages Returned by Room

  occupants

    `text-single` field `muc#roominfo_occupants`

    Current Number of Occupants in Room

  subject

    `text-single` field `muc#roominfo_subject`

    Current Discussion Topic

  subjectmod

    `boolean` field `muc#roominfo_subjectmod`

    The room subject can be modified by participants

class aioxmpp.muc.VoiceRequestForm(*args, **kwargs)
  jid

    `jid-single` field `muc#jid`

    User ID

  request_allow

    `boolean` field `muc#request_allow`

    Whether to grant voice

  role

    `list-single` field `muc#role`

    Requested role

  roomnick

    `text-single` field `muc#roomnick`

    Room Nickname

## XSOs

class aioxmpp.muc.StatusCode(value)

  This integer enumeration (see `enum.IntEnum`) is used for the status codes defined in XEP-0045.

  Note that members of this enumeration are equal to their respective integer values, making it ideal for backward- and forward-compatible code and a replacement for magic numbers.

  New in version 0.10: Before version 0.10, this enum did not exist and the numeric codes were used bare. Since this is an `IntEnum`, it is possible to use the named enum members and their numeric codes interchangeably.

  NON_ANONYMOUS = 100

    Included when entering a room where every user can see every users real JID.

  AFFILIATION_CHANGE = 101

    Included in out-of-band messages informing about affiliation changes.

  SHOWING_UNAVAILABLE = 102

    Inform occupants that room now shows unavailable members.

  NOT_SHOWING_UNAVAILABLE = 103

    Inform occupants that room now does not show unavailable members.

  CONFIG_NON_PRIVACY_RELATED = 104

    Inform occupants that a non-privacy related configuration change has occurred.

  SELF = 110

    Inform that the stanza refers to the addressee themselves.

  CONFIG_ROOM_LOGGING = 170

    Inform that the room is now logged.

  CONFIG_NO_ROOM_LOGGING = 171

    Inform that the room is not logged anymore.

  CONFIG_NON_ANONYMOUS = 172

    Inform that the room is now not anonymous.

  CONFIG_SEMI_ANONYMOUS = 173

    Inform that the room is now semi-anonymous.

  CREATED = 201

    Inform that the room was created during the join operation.

  REMOVED_BANNED = 301

    Inform that the user was banned from the room.

  NICKNAME_CHANGE = 303

    Inform about new nickname.

  REMOVED_KICKED = 307

    Inform that the occupant was kicked.

  REMOVED_AFFILIATION_CHANGE = 321

    Inform that the occupant was removed from the room due to a change in affiliation.

  REMOVED_NONMEMBER_IN_MEMBERS_ONLY = 322

    Inform that the occupant was removed from the room because the room was changed to members-only and the occupant was not a member.

  REMOVED_SERVICE_SHUTDOWN = 332

    Inform that the occupant is being removed because the MUC service is being shut down.

  REMOVED_ERROR = 333

    Inform that the occupant is being removed because there was an error while communicating with them or their server.

### Attributes added to existing XSOs

aioxmpp.Message.xep0045_muc

  A `GenericExt` object or `None`.

aioxmpp.Message.xep0045_muc_user

  A `UserExt` object or `None`.

aioxmpp.Presence.xep0045_muc

  A `GenericExt` object or `None`.

aioxmpp.Presence.xep0045_muc_user

  A `UserExt` object or `None`.

aioxmpp.Message.xep0249_direct_invite

  A `DirectInvite` object or `None`.

### Generic namespace

class aioxmpp.muc.xso.GenericExt(*args, **kwargs)

class aioxmpp.muc.xso.History(*args, **kwargs)

### User namespace

class aioxmpp.muc.xso.UserExt(*args, **kwargs)

class aioxmpp.muc.xso.Status(*args, **kwargs)

class aioxmpp.muc.xso.DestroyNotification(*args, **kwargs)

class aioxmpp.muc.xso.Decline(*args, **kwargs)

class aioxmpp.muc.xso.Invite(*args, **kwargs)

class aioxmpp.muc.xso.UserItem(*args, **kwargs)

class aioxmpp.muc.xso.UserActor(*args, **kwargs)

class aioxmpp.muc.xso.Continue(*args, **kwargs)

### Admin namespace

class aioxmpp.muc.xso.AdminQuery(*args, **kwargs)

class aioxmpp.muc.xso.AdminItem(*args, **kwargs)

class aioxmpp.muc.xso.AdminActor(*args, **kwargs)

### Owner namespace

class aioxmpp.muc.xso.OwnerQuery(*args, **kwargs)

class aioxmpp.muc.xso.DestroyRequest(*args, **kwargs)

### XEP-0249 Direct Invitations

class aioxmpp.muc.xso.DirectInvite(*args, **kwargs)