Channels are identified with a bare JID where the domain part is the service on which the channel resides and the localpart is an opaque identifier for the channel, generated by the service at creation time. The name of the channel is returned in disco#items responses on the service, and in the channel's configuration. This allows channels to have their presented name changed without breaking addressing, as would happen in MUC. e.g. [email protected]
.
Occupants have a stable identifier, much as XEP-0421. The occupant is identified by the JID of the channel, plus the occupant's identifier as the resource giving a full JID. This is similar to MUC, except that the user identifier is not their nickname. e.g. [email protected]/VGhpcyBpcyBLZXYK
- this is called the "Participant JID".
A client can (optionally, but suggested) request the join configuration form before trying to join the room by sending an iq get
<iq
from='[email protected]/pda'
id='ia324fih'
to='[email protected]'
type='get'>
<join-form xmlns="urn:xmpp:gc3:0"/>
</iq>
The server responds with a form with fields, some of which may be mandatory.
<iq
to='[email protected]/pda'
id='ia324fih'
from='[email protected]'
type='result'>
<join-form xmlns="urn:xmpp:gc3:0">
<x xmlns='jabber:x:data' type='form'>
<title>Join options</title>
<instructions>Fill out this form to configure your join</instructions>
<field type='hidden'
var='FORM_TYPE'>
<value>urn:xmpp:gc3:join-form</value>
</field>
<field type='text-single'
label='Nickname'
var='urn:xmpp:gc3:fields:nickname'>
<required/>
</field>
</join>
</iq>
A field whose var is urn:xmpp:gc3:fields:nickname
is always the user's nickname in the room, and clients might wish to special-case presentation of this field.
Client sends an iq set, optionally including the form. Not including the form is the same as including the form with no fields. Not including a field is an instruction to use the default value for that field. Not including a mandatory field is an error (TODO: Define error case so client knows that it needs to re-request the form to submit mandatory fields).
<iq
from='[email protected]/pda'
id='39dhs'
to='[email protected]'
type='set'>
<join xmlns="urn:xmpp:gc3:0">
<x xmlns='jabber:x:data' type='form'>
<field type='hidden'
var='FORM_TYPE'>
<value>urn:xmpp:gc3:join-form</value>
</field>
<field type='text-single'
var='urn:xmpp:gc3:fields:nickname'>
<value>Haggish</value>
</field>
</join>
</iq>
This includes the subscription-jid (occupant JID), and also the membership configuration (which could contain fields not part of the join and is in the member-form rather than join-form (QUESTION: do we want to merge these?))
<iq
to='[email protected]/pda'
id='39dhs'
from='[email protected]'
type='result'>
<joined xmlns="urn:xmpp:gc3:0">
<subscription-jid>[email protected]</subscription-jid>
<x xmlns='jabber:x:data' type='form'>
<field type='hidden'
var='FORM_TYPE'>
<value>urn:xmpp:gc3:member-form</value>
</field>
<field type='text-single'
var='urn:xmpp:gc3:fields:nickname'>
<value>Haggish</value>
</field>
</x>
</joined>
</iq>
The channel responds telling the user what room JID they should expect the presence subscription request from. This allows for room aliases (e.g. [email protected]
being a friendly alias that a user can join for the channel whose opaque JID is really [email protected]
).
At this point the rest of the join process varies based on whether the user's server supports gc3pam.
If the user's server supports gc3pam, advertised with urn:xmpp:gc3:pam:0
, the client doesn't need to take further action, as the server will have made the necessary changes to the 'joined channels' node, and the client also doesn't need to exchange presence with the channel as the server will do this. Where the server advertises support for gc3pam the client MUST NOT perform the fallback mechanism.
A description of the server behaviour is given in #gc3pam.
Clients MAY implement this fallback mechanism, to be used when their server doesn't support gc3pam. This allows bootstrapping on the network while servers don't support gc3pam, and it is expected that all clients' gc3 support written in the near future will need to implement this, but if in the future gc3pam is widespread, or a client knows it will only need to support gc3pam servers, it is able to skip this.
The client then adds the channel to the private 'joined channels' node. (TODO: Basically bookmarks2, but for tracking joined GC3 rooms).
As part of the fallback, the client will also need to share presence with the channel every session, see 'Sending presence to a channel'.
Creating a channel follows the same flow as joining, but with a create-form
and create
instead of join-form
and join
. The subscription flow follows the same.
A participant entity is not subscribed to messages, presence, or other data for channels they're in by default. Instead the entity selects which data it wants to receive.
A participant entity advertises that they want to receive messages for all channels by advertising the urn:xmpp:gc3:0:default-receive:message
feature in their disco+caps of their initial broadcast presence. If a channel receives initial presence from a participant's full JID containing this feature, the participant should be subscribed to messages on the channel until either the channel receives an unavailable at the end of the presence session, or the participant explicitly unsubscribes from messages (see below). A client that always advertises this feature could avoid implementing the explicit subscription flow and will get behaviour very much like MUC.
An entity SHOULD NOT add or remove this value during a presence session, and channels are not expected to reevaluate a participant's presence after their initial presence broadcast for a session.
Presence works as messages, but with an advertised feature of urn:xmpp:gc3:0:default-receive:presence
.
GC3 splits the MUC concepts of occupancy and presence. To receive updates to the participant list, do the same but with urn:xmpp:gc3:0:default-receive:participants
.
A participant can subscribe to messages, presence or participant changes by sending an iq
<iq
from='[email protected]/pda'
id='ia324fih'
to='[email protected]'
type='set'>
<subscribe xmlns="urn:xmpp:gc3:0" type="message"/>
</iq>
where the type
is message
, presence
or participant
respectively.
Similarly:
<iq
from='[email protected]/pda'
id='2iardh3'
to='[email protected]'
type='set'>
<unsubscribe xmlns="urn:xmpp:gc3:0" type="message"/>
</iq>
Note that explicit subscription and unsubscription override the default-receive
, but a full JID is always unsubscribed when the channel receives an unavailable
presence.
This happens as it did in MUC.
<message
from='[email protected]/pda'
id='hysf1v37'
to='[email protected]'
type='groupchat'>
<body>Harpier cries: 'tis time, 'tis time.</body>
</message>
The channel then checks if the participant is allowed to send a message to the channel, and if so it distributes it to those participants allowed to see messages in the channel who are currently subscribed to messages). If the user is not authorised to send a message to the channel, an error is returned.
When the channel distributes a received message it sends it from the participant's Participant JID. As channels are required to implement MAM, it'll always contain a stanza-id.
<message
from='[email protected]/414ff9c3-c5d4-4d4a-bce9-085b9ab08979'
id='hysf1v37'
to='[email protected]/desktop'
type='groupchat'>
<body>Harpier cries: 'tis time, 'tis time.</body>
<stanza-id xmlns='urn:xmpp:sid:0'
by='[email protected]'
id='28482-98726-73623' />
</message>
<message
from='[email protected]/414ff9c3-c5d4-4d4a-bce9-085b9ab08979'
id='hysf1v37'
to='[email protected]/laptop'
type='groupchat'>
<body>Harpier cries: 'tis time, 'tis time.</body>
<stanza-id xmlns='urn:xmpp:sid:0'
by='[email protected]'
id='28482-98726-73623' />
</message>
<message
from='[email protected]/414ff9c3-c5d4-4d4a-bce9-085b9ab08979'
id='hysf1v37'
to='[email protected]/pda'
type='groupchat'>
<body>Harpier cries: 'tis time, 'tis time.</body>
<stanza-id xmlns='urn:xmpp:sid:0'
by='[email protected]'
id='28482-98726-73623' />
</message>
As a presence subscription is established during join of a channel, a GC3 client SHOULD NOT send directed presence to a channel if their server supports gc3pam. A user's presence will be distributed by their server as part of the usual presence broadcast.
If a user's server does not support gc3pam, a client supporting the fallback mechanism from "Join when user's server doesn't support gc3pam" SHOULD send a presence stanza to every channel in the 'joined channels' node on login. This stanza does not need any gc3-specific elements, and the contents SHOULD match those of the client's broadcast presence.
GC3 uses ACL.md for access control, and hats for roles. Perform Hats/ACL queries against the channel JID.
When dual-stacking with MUC (which it's assumed almost all implementations will), Hats of Owner, Admin, Member should exist to map onto the MUC affiliations.
Users can configure their membership of a room (particularly their nickname, but also whatever else the service exposes).
A client can the membership configuration form from a channel they're in by sending an iq get
<iq
from='[email protected]/pda'
id='ia324fih'
to='[email protected]'
type='get'>
<member-form xmlns="urn:xmpp:gc3:0"/>
</iq>
The server responds with a form with fields, some of which may be mandatory.
<iq
to='[email protected]/pda'
id='ia324fih'
from='[email protected]'
type='result'>
<member-form xmlns="urn:xmpp:gc3:0">
<x xmlns='jabber:x:data' type='form'>
<title>Member options</title>
<instructions>Fill out this form to configure your membership</instructions>
<field type='hidden'
var='FORM_TYPE'>
<value>urn:xmpp:gc3:member-form</value>
</field>
<field type='text-single'
label='Nickname'
var='urn:xmpp:gc3:fields:nickname'>
<required/>
</field>
</member-form>
</iq>
A field whose var is urn:xmpp:gc3:fields:nickname
is always the user's nickname in the room, and clients might wish to special-case presentation of this field.
Client sends an iq set, including the form. Not including a field is an instruction to use the existing value for that field.
<iq
from='[email protected]/pda'
id='39dhs'
to='[email protected]'
type='set'>
<member-form xmlns="urn:xmpp:gc3:0">
<x xmlns='jabber:x:data' type='form'>
<field type='hidden'
var='FORM_TYPE'>
<value>urn:xmpp:gc3:member-form</value>
</field>
<field type='text-single'
var='urn:xmpp:gc3:fields:nickname'>
<value>Haggish</value>
</field>
</x>
</member-form>
</iq>
Like the join response.
<iq
to='[email protected]/pda'
id='39dhs'
from='[email protected]'
type='result'>
<member-form xmlns="urn:xmpp:gc3:0">
<subscription-jid>[email protected]</subscription-jid>
<x xmlns='jabber:x:data' type='form'>
<field type='hidden'
var='FORM_TYPE'>
<value>urn:xmpp:gc3:member-form</value>
</field>
<field type='text-single'
var='urn:xmpp:gc3:fields:nickname'>
<value>Haggish</value>
</field>
</x>
</member-form>
</iq>
- Watches outbound GC3 joins
- On receiving join result (for an outstanding join), add it to the user's 'joined channels' pubsub node
- When a session comes online, include all channels in 'joined channels' in the presence distribution as if they were in the roster (but don't treat them as whitelisted for 'roster' PEP nodes).
- Channel naming/addressing is split
- Occupant naming/addressing is split
- Channel creation is explicit IQ to service
- Channel join is explicit IQ to service
- User's server is involved in create/join/part to track channel occupancy