1
0
mirror of https://github.com/moparisthebest/xeps synced 2024-11-24 18:22:24 -05:00
xeps/inbox/muc-light.xml
2015-12-08 10:04:59 -07:00

1807 lines
78 KiB
XML

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM './xep.dtd' [
<!ENTITY % ents SYSTEM './xep.ent'>
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>Multi-User Chat Light</title>
<abstract>This specification provides a presence-less standard for Multi-User Chats. Its feature set is a response to mobile XMPP applications needs and specific environment.</abstract>
<legal>
<copyright>This XMPP Extension Protocol is copyright (c) 1999 - 2014 by the XMPP Standards Foundation (XSF).</copyright>
<permissions>Permission is hereby granted, free of charge, to any person obtaining a copy of this specification (the &quot;Specification&quot;), to make use of the Specification without restriction, including without limitation the rights to implement the Specification in a software program, deploy the Specification in a network service, and copy, modify, merge, publish, translate, distribute, sublicense, or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the condition that the foregoing copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. Unless separate permission is granted, modified works that are redistributed shall not contain misleading information regarding the authors, title, number, or publisher of the Specification, and shall not claim endorsement of the modified works by the authors, any organization or project to which the authors belong, or the XMPP Standards Foundation.</permissions>
<warranty>## NOTE WELL: This Specification is provided on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. In no event shall the XMPP Standards Foundation or the authors of this Specification be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Specification or the implementation, deployment, or other use of the Specification. ##</warranty>
<liability>In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall the XMPP Standards Foundation or any author of this Specification be liable for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising out of the use or inability to use the Specification (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if the XMPP Standards Foundation or such author has been advised of the possibility of such damages.</liability>
<conformance>This XMPP Extension Protocol has been contributed in full conformance with the XSF's Intellectual Property Rights Policy (a copy of which may be found at &lt;<link url='http://xmpp.org/extensions/ipr-policy.shtml'>http://xmpp.org/extensions/ipr-policy.shtml</link>&gt; or obtained by writing to XSF, P.O. Box 1641, Denver, CO 80201 USA).</conformance>
</legal>
<number>xxxx</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
<spec>XMPP IM</spec>
<spec>XEP-0004</spec>
<spec>XEP-0030</spec>
<spec>XEP-0045</spec>
<spec>XEP-0313</spec>
</dependencies>
<supersedes/>
<supersededby/>
<shortname>NOT_YET_ASSIGNED</shortname>
<author>
<firstname>Piotr</firstname>
<surname>Nosek</surname>
<email>piotr.nosek@erlang-solutions.com</email>
</author>
<revision>
<version>0.0.1</version>
<date>2015-10-29</date>
<initials>PN</initials>
<remark><p>First full version.</p></remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>Classic Multi-User chat, as described in XEP-0045, adds an IRC-like functionality to XMPP. It distinguishes between the affiliation list and the occupant list, where the latter is based on presences routed to the room from the client resource. While perfectly sufficient for desktop applications and relatively stable network connection, it does not exactly meet the challenges the mobile world is facing. Modern mobile applications do not rely on presence information, as it can frequently change. The expected user experience not only differs from IRC model, but also uses only a small subset of XEP-0045 features. The service described in this specification attempts to provide a complete solution for all common use cases of mobile groupchats.</p>
</section1>
<section1 topic='Requirements' anchor='reqs'>
<p>The list below contains the high-level features required from a new variant of MUC</p>
<ol>
<li>The service allows any user to create a room for group communication.</li>
<li>Users cannot join rooms on their own. They have to be added by the room owner or (if configured by service administrator) any other occupant.</li>
<li>Only the owner can remove other occupants from the room.</li>
<li>Every occupant can leave the room.</li>
<li>A user may block the attempts of being added to the specific room or by specific user.</li>
<li>The message sent in the room is always broadcasted to every occupant.</li>
<li>The full occupant list is always available to all occupants.</li>
<li>Occupant is always visible on the list, even if it does not have any resources online.</li>
<li>Occupants can only have two affiliations: owner and member.</li>
<li>There must be at most one owner in the room (the service can choose to treat all users equally).</li>
<li>If the room becomes empty, it is destroyed.</li>
<li>Occupants cannot hide behind nicks. Their real bare JID is always visible to everyone</li>
<li>No exchange of any &PRESENCE; stanza inside the room.</li>
<li>The user MUST be able to retrieve the list of rooms he or she occupies.</li>
<li>The owner can modify the room configuration at any time; members may also be allowed to set configuration.</li>
<li>All occupants can get the full room configuration at any time.</li>
<li>Room history is available only in Message Archive Management.</li>
</ol>
</section1>
<section1 topic='Entity Use Cases' anchor='entity-usecases'>
<section2 topic='Discovering a MUC Light Service' anchor='disco-service'>
<p>An entity often discovers a MUC service by sending a Service Discovery items ("disco#items") request to its own server.</p>
<example caption='Entity Queries the Server for Associated Services'><![CDATA[
<iq from='hag66@shakespeare.lit/pda'
id='h7ns81g'
to='shakespeare.lit'
type='get'>
<query xmlns='http://jabber.org/protocol/disco#items'/>
</iq>
]]></example>
<p>The server then returns the services that are associated with it.</p>
<example caption='Server Returns Disco Items Result'><![CDATA[
<iq from='shakespeare.lit'
id='h7ns81g'
to='hag66@shakespeare.lit/pda'
type='result'>
<query xmlns='http://jabber.org/protocol/disco#items'>
<item jid='muclight.shakespeare.lit' name='MUC Light Service'/>
</query>
</iq>
]]></example>
</section2>
<section2 topic='Discovering the Features Supported by a MUC Light Service' anchor='disco-service-features'>
<p>An entity may wish to discover if a service implements the Multi-User Chat protocol; in order to do so, it sends a service discovery information ("disco#info") query to the MUC service's JID.</p>
<example caption='Entity Queries Chat Service for MUC Light Support via Disco'><![CDATA[
<iq from='hag66@shakespeare.lit/pda'
id='lx09df27'
to='muclight.shakespeare.lit' type='get'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>
]]></example>
<p>The service MUST return its identity and the features it supports.</p>
<example caption='Service Returns Disco Info Result'><![CDATA[
<iq from='muclight.shakespeare.lit'
id='lx09df27'
to='hag66@shakespeare.lit/pda'
type='result'>
<query xmlns='http://jabber.org/protocol/disco#info'>
<identity category='conference' name='Shakespearean Chat Service' type='text'/>
<feature var='urn:xmpp:muclight:0'/>
</query>
</iq>
]]></example>
</section2>
<section2 topic='Discovering Occupied Rooms' anchor='disco-occupied-rooms'>
<p>The service discovery items ("disco#items") protocol enables an entity to query a service for a list of associated items, which in the case of a chat service would consist of the specific chat rooms the entity occupies.</p>
<example caption='Entity Queries Chat Service for Rooms'><![CDATA[
<iq from='hag66@shakespeare.lit/pda'
id='zb8q41f4'
to='muclight.shakespeare.lit'
type='get'>
<query xmlns='http://jabber.org/protocol/disco#items'/>
</iq>
]]></example>
<p>The service MUST return a full list of the rooms the entity occupies. The server SHOULD include room name and version in each item.</p>
<example caption='Service Returns Disco Items Result'><![CDATA[
<iq from='muclight.shakespeare.lit'
id='zb8q41f4'
to='hag66@shakespeare.lit/pda'
type='result'>
<query xmlns='http://jabber.org/protocol/disco#items'>
<item jid='heath@muclight.shakespeare.lit' name='A Lonely Heath' version='1'/>
<item jid='coven@muclight.shakespeare.lit' name='A Dark Cave' version='2'/>
<item jid='forres@muclight.shakespeare.lit' name='The Palace' version='3'/>
<item jid='inverness@muclight.shakespeare.lit'
name='Macbeth&apos;s Castle'
version='4'/>
</query>
</iq>
]]></example>
<p>If the full list of rooms is large (see <cite>XEP-0030</cite> for details), the service MAY return only a partial list of rooms. If it does so, it MUST include a &lt;set/&gt; element qualified by the 'http://jabber.org/protocol/rsm' namespace (as defined in &xep0059;) to indicate that the list is not the full result set.</p>
<example caption='Service Returns Limited List of Disco Items Result'><![CDATA[
<iq from='muclight.shakespeare.lit'
id='hx51v49s'
to='hag66@shakespeare.lit/pda'
type='result'>
<query xmlns='http://jabber.org/protocol/disco#items'>
<item jid='alls-well-that-ends-well@muclight.shakespeare.lit'
name='Everybody dies'
version='1'/>
<item jid='as-you-like-it@muclight.shakespeare.lit'
name='As you like it'
version='2'/>
<item jid='cleopatra@muclight.shakespeare.lit' name='Cleo fans' version='3'/>
<item jid='comedy-of-errors@muclight.shakespeare.lit'
name='404 Comedy not found'
version='4'/>
<item jid='coriolanus@muclight.shakespeare.lit'
name='What is Coriolanus?'
version='5'/>
<item jid='cymbeline@muclight.shakespeare.lit' name='Music room' version='6'/>
<item jid='hamlet@muclight.shakespeare.lit'
name='To chat or not to chat?'
version='7'/>
<item jid='henry-the-fourth-one@muclight.shakespeare.lit'
name='Royal Room 1'
version='8'/>
<item jid='henry-the-fourth-two@muclight.shakespeare.lit'
name='Royal Room 2'
version='9'/>
<item jid='henry-the-fifth@muclight.shakespeare.lit'
name='Royal Room Prime'
version='10'/>
<set xmlns='http://jabber.org/protocol/rsm'>
<first index='0'>alls-well-that-ends-well@muclight.shakespeare.lit</first>
<last>henry-the-fifth@muclight.shakespeare.lit</last>
<count>37</count>
</set>
</query>
</iq>
]]></example>
</section2>
</section1>
<section1 topic='Occupant Use Cases' anchor='occupant-usecases'>
<section2 topic='Sending a message to a room' anchor='sending-message'>
<p>Every occupant in the room MAY broadcast messages to other occupants. In order to do so, the client MUST send a groupchat message to the room bare JID.</p>
<p>The room automatically assumes that occupants' nicks are equal to their bare JIDs. MUC light is designed for applications where it is not important to hide behind nicknames. On the contrary - it is up to th client to replace pure JIDs with user-friendly names like phone numbers or full names if necessary.</p>
<p>Room MUST route all messages of type 'groupchat'.</p>
<example caption='Client sends a message to the room'><![CDATA[
<message from='hag66@shakespeare.lit/pda'
id='hysf1v37'
to='coven@muclight.shakespeare.lit'
type='groupchat'>
<body>Harpier cries: 'tis time, 'tis time.</body>
</message>
]]></example>
<example caption='Server broadcasts a groupchat message'><![CDATA[
<message id='msg111' type='groupchat'
from='coven@muclight.shakespeare.lit/hag66@shakespeare.lit'
to='crone1@shakespeare.lit'>
<body>Harpier cries: 'tis time, 'tis time.</body>
</message>
<message id='msg111' type='groupchat'
from='coven@muclight.shakespeare.lit/hag66@shakespeare.lit'
to='crone2@shakespeare.lit>
<body>Harpier cries: 'tis time, 'tis time.</body>
</message>
]]></example>
</section2>
<section2 topic='Changing room subject' anchor='changing-subject'>
<p>The service MAY allow room occupants to set the room subject by changing "subject" configuration field. A standard configuration stanza is used in this case. Subject change is announced like an ordinary configuration change.</p>
<example caption='Client sends a message to the room'><![CDATA[
<iq from='hag66@shakespeare.lit/pda'
id='subject1'
to='coven@muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#configuration'>
<subject>To be or not to be?</subject>
</query>
</iq>
<message from='coven@muclight.shakespeare.lit'
to='crone1@shakespeare.lit'
type='groupchat'
id='newsubject'>
<x xmlns='urn:xmpp:muclight:0#configuration'>
<prev-version>asdfghj000</prev-version>
<version>asdfghj</version>
<subject>To be or not to be?</subject>
</x>
<body />
</message>
<message from='coven@muclight.shakespeare.lit'
to='hag66@shakespeare.lit'
type='groupchat'
id='newsubject'>
<x xmlns='urn:xmpp:muclight:0#configuration'>
<prev-version>asdfghj000</prev-version>
<version>asdfghj</version>
<subject>To be or not to be?</subject>
</x>
<body />
</message>
<iq to='hag66@shakespeare.lit/pda'
id='subject1'
from='coven@muclight.shakespeare.lit'
type='result' />
]]></example>
</section2>
<section2 topic='Requesting room information' anchor='requesting-room-information'>
<p>Room occupant may request room information (configuration and/or occupants list) by information version. It is up to service to define the version string, the only requirement for it is to be unique per room. Please note there are no separate versions for configuration and occupant list alone.</p>
<p>If the server side version does not match the one provided by the client (or if the client does not provide one, i.e. 'version' element is empty), the service MUST respond with a current version string and full configuration and/or occupant list.</p>
<p>If the version strings match, server MUST reply with an empty result.</p>
<p>Only room occupants can get room information.</p>
<example caption='Matching versions'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='config0'
to='coven@muclight.shakespeare.lit'
type='get'>
<query xmlns='urn:xmpp:muclight:0#configuration'>
<version>abcdefg</version>
</query>
</iq>
<iq from='coven@muclight.shakespeare.lit'
id='config0'
to='crone1@shakespeare.lit/desktop'
type='result' />
]]></example>
<section3 topic='Getting the room configuration' anchor='get-room-config'>
<example caption='Client gets configuration from the server'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='getconfig1'
to='coven@muclight.shakespeare.lit'
type='get'>
<query xmlns='urn:xmpp:muclight:0#configuration'>
<version>abcdefg</version>
</query>
</iq>
<iq from='coven@muclight.shakespeare.lit'
id='getconfig1'
to='crone1@shakespeare.lit/desktop'
type='result'>
<query xmlns='urn:xmpp:muclight:0#configuration'>
<version>123456</version>
<roomname>A Dark Cave</roomname>
</query>
</iq>
]]></example>
</section3>
<section3 topic='Requesting a user list' anchor='requesting-user-list'>
<example caption='Client requests a user list'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='getmembers'
to='coven@muclight.shakespeare.lit'
type='get'>
<query xmlns='urn:xmpp:muclight:0#affiliations'>
<version>abcdefg</version>
</query>
</iq>
<iq from='coven@muclight.shakespeare.lit'
id='getmembers'
to='crone1@shakespeare.lit/desktop'
type='result'>
<query xmlns='urn:xmpp:muclight:0#affiliations'>
<version>123456</version>
<user affiliation='owner'>user1@shakespeare.lit</user>
<user affiliation='member'>user2@shakespeare.lit</user>
<user affiliation='member'>user3@shakespeare.lit</user>
</query>
</iq>
]]></example>
</section3>
<section3 topic='Requesting full room information' anchor='requesting-room-information'>
<p>Room occupants may request both lists (configuration + occupants) with a single request.</p>
<example caption='Client requests room information'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='getinfo1'
to='coven@muclight.shakespeare.lit'
type='get'>
<query xmlns='urn:xmpp:muclight:0#info'>
<version>abcdefg</version>
</query>
</iq>
<iq from='coven@muclight.shakespeare.lit'
id='getinfo1'
to='crone1@shakespeare.lit/desktop'
type='result'>
<query xmlns='urn:xmpp:muclight:0#info'>
<version>123456</version>
<configuration>
<roomname>A Dark Cave</roomname>
</configuration>
<occupants>
<user affiliation='owner'>user1@shakespeare.lit</user>
<user affiliation='member'>user2@shakespeare.lit</user>
<user affiliation='member'>user3@shakespeare.lit</user>
</occupants>
</query>
</iq>
]]></example>
</section3>
</section2>
<section2 topic='Leaving the room' anchor='leaving-the-room'>
<p>Every occupant is allowed to leave the room at any time. It is done by modifying own affiliation.</p>
<example caption='Occupant leaves the room'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='leave1'
to='coven@muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#affiliations'>
<user affiliation='none'>crone1@shakespeare.lit</user>
</query>
</iq>
<message from='coven@muclight.shakespeare.lit'
to='crone1@shakespeare.lit'
type='groupchat'
id='leave1'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<user affiliation='none'>crone1@shakespeare.lit</user>
</x>
<body />
</message>
<message from='coven@muclight.shakespeare.lit'
to='hag77@shakespeare.lit'
type='groupchat'
id='leave1'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<prev-version>1111111</prev-version>
<version>aaaaaaa</version>
<user affiliation='none'>crone1@shakespeare.lit</user>
</x>
<body />
</message>
<message from='coven@muclight.shakespeare.lit'
to='hag88@shakespeare.lit'
type='groupchat'
id='leave1'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<prev-version>1111111</prev-version>
<version>aaaaaaa</version>
<user affiliation='none'>crone1@shakespeare.lit</user>
</x>
<body />
</message>
<iq to='crone1@shakespeare.lit/desktop'
id='leave1'
from='coven@muclight.shakespeare.lit'
type='result' />
]]></example>
</section2>
<section2 topic='Blocking functionality' anchor='block-adding'>
<p>A user MAY choose to automatically deny being added to the room. All stanzas must be directed to MUC Light service. User MAY send more than one item in a single request and mix both 'user' and 'room' elements.</p>
<p>If the occupant tries to add another user to the room, and this user has set a blocking policy, the server MUST ignore the attempt. No error is returned, this user is simply skipped when processing affiliation change query.</p>
<example caption='Service denies adding blocking user'><![CDATA[
<iq from='crone2@shakespeare.lit/desktop'
id='blocked1'
to='coven@muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#affiliations'>
<user affiliation='member'>crone1@shakespeare.lit</user>
<user affiliation='member'>crone3@shakespeare.lit</user>
</query>
</iq>
<message from='coven@muclight.shakespeare.lit'
to='crone2@shakespeare.lit'
type='groupchat'
id='blockedadd1'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<user affiliation='member'>crone3@shakespeare.lit</user>
</x>
<body />
</message>
<message from='coven@muclight.shakespeare.lit'
to='hag88@@shakespeare.lit'
type='groupchat'
id='blockedadd1'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<user affiliation='member'>crone3@shakespeare.lit</user>
</x>
<body />
</message>
<iq to='crone2@shakespeare.lit/desktop'
id='blocked1'
from='coven@muclight.shakespeare.lit'
type='result' />
]]></example>
<section3 topic='Requesting a blocking list' anchor='block-get-list'>
<p>In order to get the current blocking list in MUC Light service, the client sends an empty IQ get query with a proper namespace.</p>
<p>The list includes only items with a 'deny' action, since the 'allow' behaviour is default for MUC Light and is only used for the list modification.</p>
<example caption='User retrieves a blocking list'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='getblock1'
to='muclight.shakespeare.lit'
type='get'>
<query xmlns='urn:xmpp:muclight:0#blocking'>
</query>
</iq>
<iq type='result'
id='getblock1'
to='crone1@shakespeare.lit/desktop'
from='muclight.shakespeare.lit'>
<query xmlns='urn:xmpp:muclight:0#blocking'>
<room action='deny'>coven@muclight.shakespeare.lit</room>
<user action='deny'>hag77@shakespeare.lit</room>
</query>
</iq>
]]></example>
</section3>
<section3 topic='Blocking a room' anchor='block-adding-room'>
<p>In order to block a room, a query must contain at least one 'room' item with a 'deny' action and room bare JID in the content.</p>
<example caption='User blocks a room'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='block1'
to='muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#blocking'>
<room action='deny'>coven@muclight.shakespeare.lit</room>
<room action='deny'>chapel@shakespeare.lit</room>
</query>
</iq>
<iq type='result'
id='block1'
to='crone1@shakespeare.lit/desktop'
from='muclight.shakespeare.lit' />
]]></example>
</section3>
<section3 topic='Blocking a user' anchor='blocking-adding-user'>
<p>In order to block a room, a query must contain at least one 'user' item with a 'deny' action and user bare JID in the content.</p>
<example caption='User blocks another user'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='block2'
to='muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#blocking'>
<user action='deny'>hag66@shakespeare.lit</room>
<user action='deny'>hag77@shakespeare.lit</room>
</query>
</iq>
<iq type='result'
id='block2'
to='crone1@shakespeare.lit/desktop'
from='muclight.shakespeare.lit' />
]]></example>
</section3>
<section3 topic='Unblocking' anchor='unblocking-adding'>
<p>In order to cancel a blocking, a query must contain at least one 'room' or 'user' item with an 'allow' action and an appriopriate bare JID in the content.</p>
<p>Unblocking a JID that is not blocked does not trigger any error. The server MUST return empty IQ result in such case.</p>
<example caption='User cancels blocking'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='unblock1'
to='muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#blocking'>
<room action='allow'>coven@muclight.shakespeare.lit</room>
<user action='allow'>hag66@shakespeare.lit</room>
</query>
</iq>
<iq type='result'
id='unblock1'
to='crone1@shakespeare.lit/desktop'
from='muclight.shakespeare.lit' />
]]></example>
</section3>
</section2>
</section1>
<section1 topic='Owner Use Cases' anchor='owner-usecases'>
<section2 topic='Creating a new room' anchor='creating-a-room'>
<p>A room is created by submitting a dedicated stanza. The client application should pick random room node name, since human-readable room name is in configuration.</p>
<p>For rules that apply to the configuration options, please see "Setting room configuration" chapter.</p>
<p>The client MAY include initial configuration and occupant list (the list MUST NOT include the creator). The server MAY allow sending incomplete configuration form. In such case the server MUST use default values for missing fields. The server MAY enforce a minimal occupant list length.</p>
<p>The service MAY either give the creator the 'owner' or 'member' status. In the latter case all users are equal.</p>
<p>Upon room creation success, the service MUST reply with an empty IQ result.</p>
<p>The following rules (similar to the ones relevant to the affiliation change request) apply to the occupant list:
<ul>
<li>'none' affiliation cannot be used.</li>
<li>All user bare JIDs must be unique</li>
<li>At most one owner can be chosen. In such case the room creator will become "just" a 'member'.</li>
</ul>
</p>
<p>After the room is created (but before receiving IQ result), new occupants (including creator) receive &MESSAGE; from the room with their affiliations (stanza MUST include only recipient's affiliation) and initial room version. &lt;prev-version /&gt; element MUST NOT be included.</p>
<example caption='Client requests room creation'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='create1'
to='coven@muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#create'>
<configuration>
<roomname>A Dark Cave</roomname>
</configuration>
<occupants>
<user affiliation='member'>user1@shakespeare.lit</user>
<user affiliation='member'>user2@shakespeare.lit</user>
</occupants>
</query>
</iq>
<message from='coven@muclight.shakespeare.lit'
to='crone1@shakespeare.lit'
type='groupchat'
id='createnotif'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<version>aaaaaaa</version>
<user affiliation='owner'>crone1@shakespeare.lit</user>
</x>
<body />
</message>
<message from='coven@muclight.shakespeare.lit'
to='user1@shakespeare.lit'
type='groupchat'
id='createnotif'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<version>aaaaaaa</version>
<user affiliation='member'>user1@shakespeare.lit</user>
</x>
<body />
</message>
<message from='coven@muclight.shakespeare.lit'
to='user2@shakespeare.lit'
type='groupchat'
id='createnotif'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<version>aaaaaaa</version>
<user affiliation='member'>user2@shakespeare.lit</user>
</x>
<body />
</message>
<iq to='crone1@shakespeare.lit/desktop'
id='create1'
from='coven@muclight.shakespeare.lit'
type='result' />
]]></example>
<section3 topic='Requesting a new room with a unique name' anchor='unique-room-name'>
<p>If a client would like to avoid a room JID conflict, it MAY request creating a new room with a server-side generated name, that is verfied to be unique. In order to do so, the client MUST send a creation request to service JID, not room bare JID. The IQ result will originate from the new room bare JID</p>
<p>The messages with affiliation change notifications MUST have the same ID as IQ set and result.</p>
<example caption='Client requests room creation'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='createrandom'
to='muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#create'>
<configuration>
<roomname>Random Cave</roomname>
</configuration>
</query>
</iq>
<message from='randomcave@muclight.shakespeare.lit'
to='crone1@shakespeare.lit'
type='groupchat'
id='createrandom'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<version>aaaaaaa</version>
<user affiliation='owner'>crone1@shakespeare.lit</user>
</x>
<body />
</message>
<iq to='crone1@shakespeare.lit/desktop'
id='createrandom'
from='muclight.shakespeare.lit'
type='result' />
]]></example>
</section3>
<section3 topic='Room already exists' anchor='room-exists'>
<p>If the chosen room name already exists, the service MUST return 'conflict' error.</p>
<example caption='Client requests room creation with existing name'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='conflict1'
to='castle@muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#create'>
<configuration>
<roomname>A Dark Cave</roomname>
</configuration>
</query>
</iq>
<iq to='crone1@shakespeare.lit/desktop'
id='conflict1'
from='castle@muclight.shakespeare.lit'
type='error'>
<error type='cancel'>
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
]]></example>
</section3>
</section2>
<section2 topic='Destroying a room' anchor='destroying-a-room'>
<p>A room is automatically destroyed when its occupant list becomes empty or the room owner explicitly sends IQ with a room destroy request.</p>
<p>Before sending an IQ result, every occupant is notified that its affiliation has changed to 'none'. These notifications include &X; element qualified with "urn:xmpp:muclight:0#destroy" namespace.</p>
<p>Only the room owner is allowed to destroy it.</p>
<p>Room destruction notification SHOULD NOT contain version (or "prev-version" information).</p>
<example caption='Client requests room destruction'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='destroy1'
to='coven@muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#destroy' />
</iq>
<message from='coven@muclight.shakespeare.lit'
to='crone1@shakespeare.lit'
type='groupchat'
id='destroynotif'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<user affiliation='none'>crone1@shakespeare.lit</user>
</x>
<x xmlns='urn:xmpp:muclight:0#destroy' />
<body />
</message>
<message from='coven@muclight.shakespeare.lit'
to='hag77@shakespeare.lit'
type='groupchat'
id='destroynotif'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<user affiliation='none'>hag77@shakespeare.lit</user>
</x>
<x xmlns='urn:xmpp:muclight:0#destroy' />
<body />
</message>
<message from='coven@muclight.shakespeare.lit'
to='hag88@shakespeare.lit'
type='groupchat'
id='destroynotif'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<user affiliation='none'>hag88@shakespeare.lit</user>
</x>
<x xmlns='urn:xmpp:muclight:0#destroy' />
<body />
</message>
<iq to='crone1@shakespeare.lit/desktop'
id='create1'
from='coven@muclight.shakespeare.lit'
type='result' />
]]></example>
</section2>
<section2 topic='Setting room configuration' anchor='set-room-config'>
<p>Only room owners can modify room configuration but the service MAY allow members to change it too.</p>
<p>All room occupants MUST be notified about a configuration change and both the new and old room version string (&lt;version /&gt; and &lt;prev-version /&gt; respectively).</p>
<p>"version" and "prev-version" configuration field names are NOT ALLOWED - they are reserved for room versioning.</p>
<p>The service MAY allow the client to set the configuration fields with any name but it is NOT RECOMMENDED.</p>
<p>The Data Forms are not used for the configuration. Instead, the config fields are encoded in XML elements with names equal to the key and content equal to the value.</p>
<example caption='Client configuration request to the server'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='conf2'
to='coven@muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#configuration'>
<roomname>A Darker Cave</roomname>
</query>
</iq>
<message from='coven@muclight.shakespeare.lit'
to='crone1@shakespeare.lit'
type='groupchat'
id='configchange'>
<x xmlns='urn:xmpp:muclight:0#configuration'>
<prev-version>zaqwsx</prev-version>
<version>zxcvbnm</version>
<roomname>A Darker Cave</roomname>
</x>
<body />
</message>
<message from='coven@muclight.shakespeare.lit'
to='hag66@shakespeare.lit'
type='groupchat'
id='configchange'>
<x xmlns='urn:xmpp:muclight:0#configuration'>
<prev-version>zaqwsx</prev-version>
<version>zxcvbnm</version>
<roomname>A Darker Cave</roomname>
</x>
<body />
</message>
<iq to='crone1@shakespeare.lit/desktop'
id='conf2'
from='coven@muclight.shakespeare.lit'
type='result' />
]]></example>
<p>The server SHOULD accept incomplete (i.e. delta) configuration forms. In such case, values of the missing fields SHOULD be preserved.</p>
</section2>
<section2 topic='Changing the occupant list' anchor='changing-occupant-list'>
<p>The occupant list is modified by a direct affiliation change. Following rules apply:</p>
<ol>
<li>There are only 3 affiliations.
<ul>
<li>owner - can do everything in the room</li>
<li>member - can send messages to the room and if the service allows it, can also change configuration or change others' affiliations</li>
<li>none - not in the room; it's a keyword for marking a user for removal from room</li>
</ul></li>
<li>Every occupant can change its own affiliation to none in order to leave the room.</li>
<li>The only way to join the room is being added by other occupant.</li>
<li>The owner can change affiliations at will.</li>
<li>If the owner leaves, the server MAY use any strategy to choose a new one.</li>
<li>The room can have at most one owner. Giving someone else the 'owner' status effectively causes the current one to lose it.</li>
<li>Owner can choose a new owner when leaving by including both 'none' and 'owner' items in affiliation change request.</li>
<li>Every user JID can be used in the request at most once.</li>
<li>A single request MAY change multiple affiliations.</li>
<li>All changes must be meaningful, e.g. setting member's affiliation to 'member' is considered a bad request.</li>
<li>Server MAY allow members to add new members but they still cannot make anyone an 'owner' or remove other users from the room.</li>
</ol>
<p>On success the server will reply with result IQ with all changed items. <b>BEFORE</b> returning the IQ result, the service MUST route a message with affiliation change to all relevant users.</p>
<p>Newcomers, i.e. users that were not occupants before the change, SHOULD receive only their own affiliation and SHOULD NOT receive &lt;prev-version /&gt; element.</p>
<p>The notifications must include both the new and old room version (&lt;version /&gt; and &lt;prev-version /&gt; respectively) string (except for the ones directed to users that have been removed from the room).</p>
<p>The notifications contain a list of items. The item list may be different from the list in IQ set, because some of the changes may require additional operations, e.g. choosing new owner when the old one leaves. Users, that are still in the room after change, will receive full change list. Users, that have been removed from the room with the request, will get only one item: themselves with affiliation 'none'.</p>
<example caption='Affiliations change request'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='member1'
to='coven@muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#affiliations'>
<user affiliation='member'>hag66@shakespeare.lit</user>
<user affiliation='owner'>hag77@shakespeare.lit</user>
<user affiliation='none'>hag88@shakespeare.lit</user>
</query>
</iq>
<message from='coven@muclight.shakespeare.lit'
to='crone1@shakespeare.lit'
type='groupchat'
id='memberchange'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<prev-version>njiokm</prev-version>
<version>qwerty</version>
<user affiliation='member'>crone1@shakespeare.lit</user>
<user affiliation='member'>hag66@shakespeare.lit</user>
<user affiliation='owner'>hag77@shakespeare.lit</user>
<user affiliation='none'>hag88@shakespeare.lit</user>
</x>
<body></body>
</message>
<message from='coven@muclight.shakespeare.lit'
to='hag66@shakespeare.lit'
type='groupchat'
id='memberchange'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<version>qwerty</version>
<user affiliation='member'>hag66@shakespeare.lit</user>
</x>
<body></body>
</message>
<message from='coven@muclight.shakespeare.lit'
to='hag77@shakespeare.lit'
type='groupchat'
id='memberchange'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<prev-version>njiokm</prev-version>
<version>qwerty</version>
<user affiliation='member'>crone1@shakespeare.lit</user>
<user affiliation='member'>hag66@shakespeare.lit</user>
<user affiliation='owner'>hag77@shakespeare.lit</user>
<user affiliation='none'>hag88@shakespeare.lit</user>
</x>
<body></body>
</message>
<message from='coven@muclight.shakespeare.lit'
to='hag88@shakespeare.lit'
type='groupchat'
id='memberchange'>
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<user affiliation='none'>hag88@shakespeare.lit</user>
</x>
<body></body>
</message>
<iq to='crone1@shakespeare.lit/desktop'
id='member1'
from='coven@muclight.shakespeare.lit'
type='result' />
]]></example>
</section2>
</section1>
<section1 topic='Interactions with RFCs and other XEPs' anchor='rfc-xep-interactions'>
<section2 topic='User rosters' anchor='user-rosters'>
<p>The service MAY add user's rooms to its roster. It allows the client to skip separate Disco request to the service. Roster items with rooms MUST belong to the group "urn:xmpp:muclight:0" (MUC Light namespace) and include &lt;version&gt; element. Their subscription type MUST be 'to'.</p>
<example caption='Entity requests the roster and receives reply that includes room item'><![CDATA[
<iq type='get' id='roster1' to='shakespeare.lit'>
<query xmlns='jabber:iq:roster'/>
</iq>
<iq id='roster1' to='hag66@shakespeare.lit/tablet' type='result'>
<query xmlns='jabber:iq:roster' ver='ver7'>
<item jid='hag77@shakespeare.lit' subscription='both'/>
<item jid='hag88@shakespeare.lit' subscription='both'/>
<item jid='coven@muclight.shakespeare.lit' name='The Coven' subscription='to'>
<group>urn:xmpp:muclight:0</group>
<version>1234345</version>
</item>
</query>
</iq>
]]></example>
</section2>
<section2 topic='XEP-0313 Message Archive Management' anchor='mam'>
<p>This section defines the rules for archiving MUC Light events and messages. Stanzas described in the subsections below MUST be archived by the server. The stanzas not included here MUST NOT be archived.</p>
<p>The &MESSAGE; element inside &lt;forwarded&gt; MUST include "from" attribute and MUST NOT include "to" attribute. "id" SHOULD be archived as well.</p>
<p>In case of regular groupchat messages, "from" attribute MUST consist of a room full JID with sender bare JID in the resource part. As for room notification, e.g. create event, "from" MUST be equal to room bare JID.</p>
<p>Examples below use MAM v0.4 protocol. Archive can be fetched only from a specific room, the client MUST NOT query MUC Light service directly.</p>
<section3 topic='Groupchat message from occupant' anchor='mam-message-occupant'>
<p>Message from a user MUST be archived with all child elements.</p>
<example caption='Occupant queries MAM and receives regular groupchat message'><![CDATA[
<iq type='set' id='mamget1' to='coven@muclight.shakespeare.lit'>
<query xmlns='urn:xmpp:mam:1' queryid='f27' />
</iq>
<message id='aeb213' to='hag66@shakespeare.lit/pda'>
<result xmlns='urn:xmpp:mam:1' queryid='f27' id='28482-98726-73623'>
<forwarded xmlns='urn:xmpp:forward:0'>
<delay xmlns='urn:xmpp:delay' stamp='2010-07-10T23:08:25Z'/>
<message from="coven@muclight.shakespeare.lit/hag77@shakespeare.lit"
id="msgid11">
<body>Welcome!</body>
<x xmlns="elixir:ingredient">bat-wing</x>
</message>
</forwarded>
</result>
</message>
<iq type='result' id='mamget1' from='coven@muclight.shakespeare.lit'/>
]]></example>
</section3>
<section3 topic='Affiliation change' anchor='mam-aff-change'>
<p>Every archived affiliation change notification MUST include &lt;version&gt; element and MUST NOT contain &lt;prev-version&gt; element.</p>
<example caption='Occupant queries MAM and receives affiliation change notification'><![CDATA[
<iq type='set' id='mamget2' to='muclight.shakespeare.lit'>
<query xmlns='urn:xmpp:mam:1' queryid='f37' />
</iq>
<message id='aef2133' to='hag66@shakespeare.lit/pda'>
<result xmlns='urn:xmpp:mam:1' queryid='f37' id='21482-98726-71623'>
<forwarded xmlns='urn:xmpp:forward:0'>
<delay xmlns='urn:xmpp:delay' stamp='2013-07-10T21:08:25Z'/>
<message from="coven@muclight.shakespeare.lit" id="notifid11">
<x xmlns='urn:xmpp:muclight:0#affiliations'>
<version>b9uf13h98f13</version>
<user affiliation='owner'>hag66@shakespeare.lit</user>
<user affiliation='member'>user1@shakespeare.lit</user>
<user affiliation='member'>user2@shakespeare.lit</user>
</x>
</message>
</forwarded>
</result>
</message>
<iq type='result' id='mamget12'/>
]]></example>
</section3>
<section3 topic='Room creation' anchor='mam-room-create'>
<p>Room creation is archived as an affiliation change that includes ALL initial occupants (including the room creator).</p>
</section3>
</section2>
</section1>
<section1 topic='General Error Cases' anchor='general-errors'>
<section2 topic='Client sends an unauthorized stanza to a room' anchor='unauthorized-stanza-to-room'>
<p>If a client sends a stanza to the room, that it does not occupy, the service MUST reply with the 'item-not-found' error.</p>
<example caption='Unauthorized IQ'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='member1'
to='coven@muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#affiliations'>
<user affiliation='member'>hag66@shakespeare.lit</user>
</query>
</iq>
<iq to='crone1@shakespeare.lit/desktop'
id='member1'
from='coven@muclight.shakespeare.lit'
type='error'>
<error type='cancel'>
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
]]></example>
<example caption='Unauthorized message'><![CDATA[
<message from='hag66@shakespeare.lit/pda'
id='unauth2'
to='coven@muclight.shakespeare.lit'
type='groupchat'>
<body>Harpier cries: 'tis time, 'tis time.</body>
</message>
<message to='hag66@shakespeare.lit/pda'
id='unauth2'
from='coven@muclight.shakespeare.lit'
type='error'>
<error type='cancel'>
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</message>
]]></example>
</section2>
<section2 topic='Client sends a &PRESENCE; stanza to the service' anchor='presence-to-service'>
<p>The service MUST ignore all &PRESENCE; stanzas sent by the client.</p>
</section2>
<section2 topic='Client sends an invalid stanza to the service' anchor='invalid-to-service'>
<p>If service receives a stanza with invalid syntax, it MUST reply with a 'bad-request' error.</p>
<example caption='Invalid IQ'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='bad1'
to='coven@muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#affiliations'>
<item role='participant'>hag66@shakespeare.lit</item>
</query>
</iq>
<iq to='crone1@shakespeare.lit/desktop'
id='bad1'
from='coven@muclight.shakespeare.lit'
type='error'>
<error type='modify'>
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
]]></example>
<example caption='Invalid message'><![CDATA[
<message from='hag66@shakespeare.lit/pda'
id='bad2'
to='coven@muclight.shakespeare.lit'
type='chat'>
<body>Harpier cries: 'tis time, 'tis time.</body>
</message>
<message to='hag66@shakespeare.lit/pda'
id='bad2'
from='coven@muclight.shakespeare.lit'
type='error'>
<error type='modify'>
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</message>
]]></example>
</section2>
<section2 topic='Request sender has insufficient privileges' anchor='insufficient-privileges'>
<p>If the request sender does not have sufficient privileges (but is a room occupant), the service MUST reply with a 'not-allowed' error.</p>
<p>It occurs in the following cases:
<ul>
<li>A member tries to change the configuration but the service is not configured to allow it. It does not apply to the subject change, although it has to be performed by sending &MESSAGE; with &SUBJECT;, not configuration &IQ;.</li>
<li>A member tries to change anyone's affiliation to 'none' or 'owner'.</li>
<li>A member tries to change someone's affiliation to 'member' but the service is not configured to allow it.</li>
</ul>
</p>
<example caption='Prohibited IQ'><![CDATA[
<iq from='minion@shakespeare.lit/desktop'
id='privileges1'
to='coven@muclight.shakespeare.lit'
type='set'>
<query xmlns='urn:xmpp:muclight:0#affiliations'>
<user role='owner'>minion@shakespeare.lit</user>
</query>
</iq>
<iq to='minion@shakespeare.lit/desktop'
id='privileges1'
from='coven@muclight.shakespeare.lit'
type='error'>
<error type='cancel'>
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
]]></example>
</section2>
</section1>
<section1 topic='Implementation Notes' anchor='impl'>
<section2 topic='XEP-0045 mappings' anchor='xep0045'>
<p>Some client-side developers might choose to use existing XEP-0045 Multi-User Chat implementations to interface with the new MUC Light. There may be various reasons to do so: using familiar protocol, avoiding additional implementation, quick prototyping etc. This section provides suggestions of mappings between XEP-0045 stanzas and the new ones described in this document.</p>
<p>Operations not described here SHOULD remain unmodified.</p>
<section3 topic='Discovering the Features Supported by a MUC Service' anchor='comp-features'>
<p>A Disco result MAY either include new &lt;feature /&gt; element with an "http://jabber.org/protocol/muc" namespace next to MUC Light one, or completely replace it, which is RECOMMENDED behaviour.</p>
<example caption='Returning MUC namespace in Disco'><![CDATA[
<iq from='hag66@shakespeare.lit/pda'
id='lx09df27'
to='muclight.shakespeare.lit'
type='get'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>
<iq from='muclight.shakespeare.lit'
id='lx09df27'
to='hag66@shakespeare.lit/pda'
type='result'>
<query xmlns='http://jabber.org/protocol/disco#info'>
<identity category='conference'
name='Shakespearean Chat Service'
type='text'/>
<feature var='http://jabber.org/protocol/muc'/>
</query>
</iq>
]]></example>
</section3>
<section3 topic='Discovering Occupied Rooms' anchor='comp-disco-rooms'>
<p>The room list MUST not include room versions.</p>
<example caption='Service Returns Disco Items Result'><![CDATA[
<iq from='muclight.shakespeare.lit'
id='zb8q41f4'
to='hag66@shakespeare.lit/pda'
type='result'>
<query xmlns='http://jabber.org/protocol/disco#items'>
<item jid='heath@muclight.shakespeare.lit'
name='A Lonely Heath'/>
<item jid='coven@muclight.shakespeare.lit'
name='A Dark Cave'/>
<item jid='forres@muclight.shakespeare.lit'
name='The Palace'/>
<item jid='inverness@muclight.shakespeare.lit'
name='Macbeth&apos;s Castle'/>
</query>
</iq>
]]></example>
</section3>
<section3 topic='Changing a room subject' anchor='comp-change-subject'>
<p>Instead of distributing the configuration change notifications, the room MUST route &MESSAGE; with &SUBJECT; like a classic MUC would. The client MUST send classic message &SUBJECT; as well. The room SHOULD save new subject in the room configuration.</p>
<example caption='New subject is routed as ordinary message'><![CDATA[
<message from='hag66@shakespeare.lit/pda'
id='compsubject'
to='coven@muclight.shakespeare.lit'
type='groupchat'>
<subject>To be or not to be?</subject>
</message>
<message from='coven@muclight.shakespeare.lit'
to='crone1@shakespeare.lit'
type='groupchat'
id='compsubject'>
<subject>To be or not to be?</subject>
</message>
<message from='coven@muclight.shakespeare.lit'
to='hag66@shakespeare.lit'
type='groupchat'
id='compsubject'>
<subject>To be or not to be?</subject>
</message>
]]></example>
</section3>
<section3 topic='Getting room configuration' anchor='comp-get-config'>
<p>Room configuration is encoded in Data Form, that simulates XEP-0045 config form.</p>
<p>Getting room configuration does not benefit from room versioning.</p>
<example caption='Requesting room configuration'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='comp-config'
to='coven@muclight.shakespeare.lit'
type='get'>
<query xmlns='http://jabber.org/protocol/muc#owner'/>
</iq>
<iq from='coven@muclight.shakespeare.lit'
id='comp-config'
to='crone1@shakespeare.lit/desktop'
type='result'>
<query xmlns='http://jabber.org/protocol/muc#owner'>
<x xmlns='jabber:x:data' type='form'>
<title>Configuration for "coven" Room</title>
<field type='hidden' var='FORM_TYPE'>
<value>http://jabber.org/protocol/muc#roomconfig</value>
</field>
<field label='Natural-Language Room Name'
type='text-single'
var='muc#roomconfig_roomname'>
<value>A Dark Cave</value>
</field>
<field label='Room subject'
type='text-single'
var='muc#roomconfig_subject'>
<value>To be or not to be?</value>
</field>
</x>
</query>
</iq>
]]></example>
</section3>
<section3 topic='Requesting user list' anchor='comp-get-user-list'>
<p>User list is retrieved with affiliation IQ get.</p>
<example caption='Requesting affiliation list'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='comp-getaff'
to='coven@muclight.shakespeare.lit' type='get'>
<query xmlns='http://jabber.org/protocol/muc#admin'>
<item affiliation='owner'/>
<item affiliation='member'/>
</query>
</iq>
<iq from='coven@muclight.shakespeare.lit'
id='comp-getaff'
to='crone1@shakespeare.lit/desktop'
type='result'>
<query xmlns='http://jabber.org/protocol/muc#admin'>
<item affiliation='owner'
jid='crone1@shakespeare.lit'
nick='crone1@shakespeare.lit'
role='moderator'/>
<item affiliation='member'
jid='hag66@shakespeare.lit'
nick='hag66@shakespeare.lit'
role='participant'/>
</query>
</iq>
]]></example>
</section3>
<section3 topic='Requesting room information' anchor='requesting-room-information'>
<p>There is no XEP-0045 equivalent for getting full room information</p>
</section3>
<section3 topic='Leaving the room' anchor='comp-leaving'>
<p>Leaving the room is performed by setting own affiliation to 'none'. The service uses &PRESENCE; to notify all occupants (and former occupant) about the change. &PRESENCE; to the leaving occupant MUST be of type "unavailable" and MUST include status code 321 (i.e. user leaving due to affiliation change).</p>
<example caption='Requesting affiliation list'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='comp-leave'
to='coven@muclight.shakespeare.lit'
type='set'>
<query xmlns='http://jabber.org/protocol/muc#admin'>
<item affiliation='none' jid='crone1@shakespeare.lit'/>
</query>
</iq>
<presence from='coven@muclight.shakespeare.lit/crone1@shakespeare.lit'
to='crone1@shakespeare.lit'
type='unavailable'>
<x xmlns='http://jabber.org/protocol/muc#user'>
<item affiliation='none' jid='crone1@shakespeare.lit/pda' role='none'/>
<status code='321'/>
</x>
</presence>
<presence from='coven@muclight.shakespeare.lit/crone1@shakespeare.lit'
to='hag66@shakespeare.lit/desktop'>
<x xmlns='http://jabber.org/protocol/muc#user'>
<item affiliation='none' jid='crone1@shakespeare.lit/pda' role='none'/>
<status code='321'/>
</x>
</presence>
<iq from='coven@muclight.shakespeare.lit'
id='comp-leave'
to='crone1@shakespeare.lit/desktop'
type='result'/>
]]></example>
</section3>
<section3 topic='Blocking functionality' anchor='comp-blocking'>
<p>Blocking functionality uses small subset of Privacy Lists protocol. Stanzas MUST be addressed to the server JID and.</p>
<p>The privacy list name MUST be equal to "urn:xmpp:muclight:0"</p>
<p>Obviously, this method won't work properly in XMPP Server Federation.</p>
<p>As opposed to XEP-0016, it is allowed to send "delta" privacy lists.</p>
<section4 topic='Request blocking list' anchor='comp-get-blocking'>
<example caption='Retrieving blocking list'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop' type='get' id='comp-getlist'>
<query xmlns='jabber:iq:privacy'>
<list name='urn:xmpp:muclight:0'/>
</query>
</iq>
<iq type='result' id='comp-getlist' to='crone1@shakespeare.lit/desktop'>
<query xmlns='jabber:iq:privacy'>
<list name='urn:xmpp:muclight:0'>
<item type='jid'
value='coven@muclight.shakespeare.lit'
action='deny'
order='1'/>
<item type='jid'
value='muclight.shakespeare.lit/hag66@shakespeare.lit'
action='deny'
order='1'/>
</list>
</query>
</iq>
]]></example>
</section4>
<section4 topic='Blocking a room' anchor='comp-blocking-room'>
<p>In order to block a room, the client MUST deny room bare JID in privacy list.</p>
<example caption='Blocking a room'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop' type='set' id='comp-blockroom'>
<query xmlns='jabber:iq:privacy'>
<list name='urn:xmpp:muclight:0'>
<item type='jid'
value='coven@muclight.shakespeare.lit'
action='deny'
order='1'/>
</list>
</query>
</iq>
<iq type='result' id='comp-blockroom' to='crone1@shakespeare.lit/desktop' />
]]></example>
</section4>
<section4 topic='Blocking a user' anchor='comp-blocking-user'>
<p>In order to block a room, the client MUST deny service JID with user's bare JID in resource.</p>
<example caption='Blocking a user'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop' type='set' id='comp-blockuser'>
<query xmlns='jabber:iq:privacy'>
<list name='urn:xmpp:muclight:0'>
<item type='jid'
value='muclight.shakespeare.lit/hag66@shakespeare.lit'
action='deny'
order='1'/>
</list>
</query>
</iq>
<iq type='result' id='comp-blockuser' to='crone1@shakespeare.lit/desktop' />
]]></example>
</section4>
<section4 topic='Unblocking' anchor='comp-unblocking'>
<example caption='Unblocking'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop' type='get' id='comp-getlist'>
<query xmlns='jabber:iq:privacy'>
<list name='urn:xmpp:muclight:0'>
<item type='jid'
value='coven@muclight.shakespeare.lit'
action='allow'
order='1'/>
<item type='jid'
value='muclight.shakespeare.lit/hag66@shakespeare.lit'
action='allow'
order='1'/>
</list>
</query>
</iq>
<iq type='result' id='comp-getlist' to='crone1@shakespeare.lit/desktop' />
]]></example>
</section4>
</section3>
<section3 topic='Creating a room' anchor='comp-create-room'>
<p>Room is created in standard XEP-0045 way. Client MUST use nick equal to own bare JID.</p>
<p>Compatibility mode MUST NOT support unique room name generation.</p>
<example caption='Creating a room'><![CDATA[
<presence from='crone1@shakespeare.lit/desktop'
to='coven@muclight.shakespeare.lit/crone1@shakespeare.lit'>
<x xmlns='http://jabber.org/protocol/muc'/>
</presence>
<presence from='coven@chat.shakespeare.lit/crone1@shakespeare.lit'
to='crone1@shakespeare.lit/desktop'>
<x xmlns='http://jabber.org/protocol/muc#user'>
<item affiliation='owner' role='moderator'/>
<status code='110'/>
<status code='201'/>
</x>
</presence>
]]></example>
<section4 topic='Room already exists' anchor='comp-room-exists'>
<p>If the client attempts to create a room that is already used, it will receive error &PRESENCE; informing that registration is required (like in case of members-only rooms in XEP-0045)</p>
<example caption='Creating a room'><![CDATA[
<presence from='coven@muclight.shakespeare.lit/crone1@shakespeare.lit'
to='crone1@shakespeare.lit/desktop'
type='error'>
<x xmlns='http://jabber.org/protocol/muc'/>
<error by='coven@muclight.shakespeare.lit' type='auth'>
<registration-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</presence>
]]></example>
</section4>
</section3>
<section3 topic='Destroying the room' anchor='comp-room-destroy'>
<p>Classic XEP-0045 method is used but the service SHOULD NOT forward reason and alternate venue JID.</p>
<example caption='Destroying the room'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='begone'
to='heath@muclight.shakespeare.lit'
type='set'>
<query xmlns='http://jabber.org/protocol/muc#owner'>
<destroy jid='coven@muclight.shakespare.lit'>
<reason>Some reason.</reason>
</destroy>
</query>
</iq>
<presence from='heath@chat.shakespeare.lit/crone1@shakespeare.lit'
to='crone1@shakespeare.lit/desktop' type='unavailable'>
<x xmlns='http://jabber.org/protocol/muc#user'>
<item affiliation='none' role='none'/>
<destroy />
</x>
</presence>
<presence
from='heath@chat.shakespeare.lit/wiccarocks@shakespeare.lit'
to='wiccarocks@shakespeare.lit/laptop' type='unavailable'>
<x xmlns='http://jabber.org/protocol/muc#user'>
<item affiliation='none' role='none'/>
<destroy />
</x>
</presence>
<presence
from='heath@chat.shakespeare.lit/hag66@shakespeare.lit'
to='hag66@shakespeare.lit/pda'
type='unavailable'>
<x xmlns='http://jabber.org/protocol/muc#user'>
<item affiliation='none' role='none'/>
<destroy />
</x>
</presence>
<iq from='heath@chat.shakespeare.lit'
id='begone'
to='crone1@shakespeare.lit/desktop'
type='result'/>
]]></example>
</section3>
<section3 topic='Setting room configuration' anchor='comp-set-config'>
<p>Room occupants can use standard XEP-0045 configuration modification method. The service MUST broadcast only the notification about configuration change with status code 104, so every occupant can retrieve new room configuration in separate request. The client is allowed to send config delta in a form.</p>
<example caption='Setting room configuration'><![CDATA[
<iq to='coven@muclight.shakespeare.lit'
id='comp-setconfig'
from='crone1@shakespeare.lit/desktop'
type='set'>
<query xmlns='http://jabber.org/protocol/muc#owner'>
<x xmlns='jabber:x:data' type='form'>
<field type='hidden' var='FORM_TYPE'>
<value>http://jabber.org/protocol/muc#roomconfig</value>
</field>
<field label='Natural-Language Room Name'
type='text-single'
var='muc#roomconfig_roomname'>
<value>A Darker Cave</value>
</field>
<field label='Room subject'
type='text-single'
var='muc#roomconfig_subject'>
<value>To be!</value>
</field>
</x>
</query>
</iq>
<message from='coven@muclight.shakespeare.lit'
id='comp-confchange'
to='crone1@shakespeare.lit/desktop'
type='groupchat'>
<x xmlns='http://jabber.org/protocol/muc#user'>
<status code='104'/>
</x>
</message>
<message from='coven@muclight.shakespeare.lit'
id='comp-confchange'
to='crone2@shakespeare.lit/desktop'
type='groupchat'>
<x xmlns='http://jabber.org/protocol/muc#user'>
<status code='104'/>
</x>
</message>
<iq from='coven@muclight.shakespeare.lit'
id='comp-setconfig'
to='crone1@shakespeare.lit/desktop'
type='result'/>
]]></example>
</section3>
<section3 topic='Changing occupant list' anchor='comp-change-aff'>
<p>The service MUST send affiliation change notification to all participants. Leaving users MUST NOT receive any information except for their own "none" affiliation. New users MUST receive invitation message.</p>
<example caption='Changing occupant list'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='comp-setaff'
to='coven@muclight.shakespeare.lit'
type='set'>
<query xmlns='http://jabber.org/protocol/muc#admin'>
<item affiliation='none' jid='hag66@shakespeare.lit'/>
<item affiliation='member' jid='hecate@shakespeare.lit'/>
</query>
</iq>
<presence from='coven@chat.shakespeare.lit/hag66@shakespeare.lit'
to='hag66@shakespeare.lit'
type='unavailable'>
<x xmlns='http://jabber.org/protocol/muc#user'>
<item affiliation='none' jid='hag66@shakespeare.lit' role='none'/>
<status code='321'/>
</x>
</presence>
<message from='coven@muclight.shakespeare.lit'
id='comp-invite0'
to='hecate@shakespeare.lit'>
<x xmlns='http://jabber.org/protocol/muc#user'>
<invite from='crone1@shakespeare.lit'/>
</x>
</message>
<presence from='coven@chat.shakespeare.lit/hag66@shakespeare.lit'
to='crone1@shakespeare.lit'
type='unavailable'>
<x xmlns='http://jabber.org/protocol/muc#user'>
<item affiliation='none' jid='hag66@shakespeare.lit' role='none'/>
<status code='321'/>
</x>
</presence>
<presence from='coven@chat.shakespeare.lit/hecate@shakespeare.lit'
to='crone1@shakespeare.lit'>
<x xmlns='http://jabber.org/protocol/muc#user'>
<item affiliation='member'
jid='hecate@shakespeare.lit'
role='participant'
nick='hecate@shakespeare.lit'/>
</x>
</presence>
<iq from='coven@muclight.shakespeare.lit'
id='comp-setaff'
to='crone1@shakespeare.lit/desktop'
type='result'/>
]]></example>
</section3>
</section2>
<section2 topic='Service limits and configuration' anchor='limits-and-config'>
<p>MUC Light service may be abused by malicious users, e.g. due to replicating single message for every room occupant. The list below contains suggested configurable limits that SHOULD be implemented.</p>
<p>The service features that might vary depending on specific application are included as well.</p>
<p>
<ul>
<li>Maximal count of rooms the user occupies.</li>
<li>Blocking feature enabled/disabled.</li>
<li>XEP-0045 compatibility mode enabled/disabled.</li>
<li>Room creator's initial affiliation: owner/member.</li>
<li>Room configuration may be changed by owner/occupants.</li>
<li>New members can be invited by owner/occupants.</li>
<li>Maximal room size.</li>
</ul>
</p>
</section2>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<section2 topic='Denial of Service' anchor='dos'>
<p>Since every user is allowed to create rooms in MUC Light, it is possible to achieve high ratio of messages delivered to the clients to messages sent by the clients with little effort. To mitigate or avoid this issue, the service MAY implement additional rules like limiting per-user room count or message rate in a room. Heuristic algorithms for analysing user behaviours MAY be used as well to monitor and detect potential attacks.</p>
</section2>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>This document requires no interaction with &IANA;.</p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>None.</p>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<section2 topic='urn:xmpp:muclight:0#configuration' anchor='schema-configuration'>
<code><![CDATA[
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema
xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='urn:xmpp:muclight:0#configuration'
xmlns='urn:xmpp:muclight:0#configuration'
elementFormDefault='qualified'>
<xs:element name='x'>
<xs:complexType>
<xs:sequence>
<xs:element name='version'
type='xs:string'
minOccurs='1'
maxOccurs='1'/>
<xs:element name='prev-version'
type='xs:string'
minOccurs='1'
maxOccurs='1'/>
<xs:any processContents="lax"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='query'>
<xs:complexType>
<xs:sequence>
<xs:element name='version'
type='xs:string'
minOccurs='0'
maxOccurs='1'/>
<xs:any processContents="lax"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
]]></code>
</section2>
<section2 topic='urn:xmpp:muclight:0#affiliations' anchor='schema-affiliations'>
<code><![CDATA[
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema
xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='urn:xmpp:muclight:0#affiliations'
xmlns='urn:xmpp:muclight:0#affiliations'
elementFormDefault='qualified'>
<xs:element name='x'>
<xs:complexType>
<xs:sequence>
<xs:element name='version'
type='xs:string'
minOccurs='0'
maxOccurs='1'/>
<xs:element name='prev-version'
type='xs:string'
minOccurs='0'
maxOccurs='1'/>
<xs:element ref='user' minOccurs='0' maxOccurs='unbounded'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='query'>
<xs:complexType>
<xs:sequence>
<xs:element name='version'
type='xs:string'
minOccurs='0'
maxOccurs='1'/>
<xs:element ref='user' minOccurs='0' maxOccurs='unbounded'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='user'>
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xsd:string">
<xs:attribute name='affiliation' use='required'>
<xs:simpleType>
<xs:restriction base='xs:NCName'>
<xs:enumeration value='member'/>
<xs:enumeration value='none'/>
<xs:enumeration value='owner'/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>
]]></code>
</section2>
<section2 topic='urn:xmpp:muclight:0#info' anchor='schema-info'>
<code><![CDATA[
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema
xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='urn:xmpp:muclight:0#info'
xmlns='urn:xmpp:muclight:0#info'
elementFormDefault='qualified'>
<xs:element name='query'>
<xs:complexType>
<xs:sequence>
<xs:element name='version'
type='xs:string'
minOccurs='1'
maxOccurs='1'/>
<xs:element ref='configuration' minOccurs='1' maxOccurs='1'/>
<xs:element ref='occupants' minOccurs='1' maxOccurs='1'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='configuration'>
<xs:complexType>
<xs:sequence>
<xs:any processContents="lax"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='occupants'>
<xs:complexType>
<xs:sequence>
<xs:element ref='user' minOccurs='0' maxOccurs='unbounded'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='user'>
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xsd:string">
<xs:attribute name='affiliation' use='required'>
<xs:simpleType>
<xs:restriction base='xs:NCName'>
<xs:enumeration value='member'/>
<xs:enumeration value='owner'/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>
]]></code>
</section2>
<section2 topic='urn:xmpp:muclight:0#blocking' anchor='schema-blocking'>
<code><![CDATA[
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema
xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='urn:xmpp:muclight:0#blocking'
xmlns='urn:xmpp:muclight:0#blocking'
elementFormDefault='qualified'>
<xs:element name='query'>
<xs:complexType>
<xs:sequence>
<xs:element ref='user' minOccurs='0' maxOccurs='unbounded'/>
<xs:element ref='room' minOccurs='0' maxOccurs='unbounded'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='user'>
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xsd:string">
<xs:attribute name='action' use='required'>
<xs:simpleType>
<xs:restriction base='xs:NCName'>
<xs:enumeration value='allow'/>
<xs:enumeration value='deny'/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name='room'>
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xsd:string">
<xs:attribute name='action' use='required'>
<xs:simpleType>
<xs:restriction base='xs:NCName'>
<xs:enumeration value='allow'/>
<xs:enumeration value='deny'/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>
]]></code>
</section2>
<section2 topic='urn:xmpp:muclight:0#create' anchor='schema-create'>
<code><![CDATA[
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema
xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='urn:xmpp:muclight:0#create'
xmlns='urn:xmpp:muclight:0#create'
elementFormDefault='qualified'>
<xs:element name='query'>
<xs:complexType>
<xs:sequence>
<xs:element ref='configuration' minOccurs='0' maxOccurs='1'/>
<xs:element ref='occupants' minOccurs='0' maxOccurs='1'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='configuration'>
<xs:complexType>
<xs:sequence>
<xs:any processContents="lax"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='occupants'>
<xs:complexType>
<xs:sequence>
<xs:element ref='user' minOccurs='0' maxOccurs='unbounded'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='user'>
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xsd:string">
<xs:attribute name='affiliation' use='required'>
<xs:simpleType>
<xs:restriction base='xs:NCName'>
<xs:enumeration value='member'/>
<xs:enumeration value='owner'/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>
]]></code>
</section2>
<section2 topic='urn:xmpp:muclight:0#destroy' anchor='schema-destroy'>
<code><![CDATA[
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema
xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='urn:xmpp:muclight:0#configuration'
xmlns='urn:xmpp:muclight:0#configuration'
elementFormDefault='qualified'>
<xs:element name='x'>
<xs:complexType />
</xs:element>
<xs:element name='query'>
<xs:complexType />
</xs:element>
</xs:schema>
]]></code>
</section2>
</section1>
<section1 topic='Acknowledgements' anchor='acknowledgements'>
<p>Many thanks to Stefan Strigler for the long, initial brainstorm before creating MUC Light extension. I am also very grateful to ESL MongooseIM team for their input and sharing stories that helped in improving this specification.</p>
</section1>
</xep>