RFC 6121
Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence
RFC 6121: Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence ๐
okay bestie, this one is the IETF doc (Internet Engineering Task Force ๐ฆ) and it's giving official standards energy โจ. It's an RFC numbered 6121, dated March 2011, and it's on the Standards Track ๐. The main author is P. Saint-Andre from Cisco ๐ .
It also obsoletes RFC 3921, which means this one replaces the older version. It doesn't update anything else. The ISSN is 2070-1721 ๐ฅ.
Abstract โจ
okay so the abstract is literally the TL;DR ๐. This doc defines extensions to the core features of XMPP (Extensible Messaging and Presence Protocol ๐) that give you basic instant messaging (IM) and presence functionality. It does that while following the requirements in RFC 2779 ๐ธ. And yep, this one obsoletes RFC 3921 ๐.
Status of This Memo ๐
this is an Internet Standards Track document, so it's not just vibes, it's the real deal ๐ญ.
It's a product of the Internet Engineering Task Force (IETF) ๐ฆ, and it represents the consensus of the IETF community. It got public review and was approved for publication by the Internet Engineering Steering Group (IESG) ๐. If you want more on Internet Standards, check Section 2 of RFC 5741 ๐ง.
For the current status, any errata, and how to give feedback, go to http://www.rfc-editor.org/info/rfc6121 ๐.
Copyright Notice ๐
Copyright (c) 2011 IETF Trust and the persons identified as the document authors. All rights reserved. ๐
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) as they're in effect on the date of publication ๐. Read these carefully, bestie, because they explain your rights and restrictions for this document ๐ซถ.
Code Components pulled out of this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they come without warranty as described in the Simplified BSD License ๐.
Table of Contents ๐
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1. Overview . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2. History . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3. Requirements . . . . . . . . . . . . . . . . . . . . . . 5
1.4. Functional Summary . . . . . . . . . . . . . . . . . . . 7
1.5. Terminology . . . . . . . . . . . . . . . . . . . . . . . 8
2. Managing the Roster . . . . . . . . . . . . . . . . . . . . . 9
2.1. Syntax and Semantics . . . . . . . . . . . . . . . . . . 9
2.1.1. Ver Attribute . . . . . . . . . . . . . . . . . . . . 10
2.1.2. Roster Items . . . . . . . . . . . . . . . . . . . . 10
2.1.2.1. Approved Attribute . . . . . . . . . . . . . . . 10
2.1.2.2. Ask Attribute . . . . . . . . . . . . . . . . . . 10
2.1.2.3. JID Attribute . . . . . . . . . . . . . . . . . . 11
2.1.2.4. Name Attribute . . . . . . . . . . . . . . . . . 11
2.1.2.5. Subscription Attribute . . . . . . . . . . . . . 11
2.1.2.6. Group Element . . . . . . . . . . . . . . . . . . 12
2.1.3. Roster Get . . . . . . . . . . . . . . . . . . . . . 12
2.1.4. Roster Result . . . . . . . . . . . . . . . . . . . . 13
2.1.5. Roster Set . . . . . . . . . . . . . . . . . . . . . 14
2.1.6. Roster Push . . . . . . . . . . . . . . . . . . . . . 14
2.2. Retrieving the Roster on Login . . . . . . . . . . . . . 16
2.3. Adding a Roster Item . . . . . . . . . . . . . . . . . . 17
2.3.1. Request . . . . . . . . . . . . . . . . . . . . . . . 17
2.3.2. Success Case . . . . . . . . . . . . . . . . . . . . 17
2.3.3. Error Cases . . . . . . . . . . . . . . . . . . . . . 18
2.4. Updating a Roster Item . . . . . . . . . . . . . . . . . 22
2.4.1. Request . . . . . . . . . . . . . . . . . . . . . . . 22
2.4.2. Success Case . . . . . . . . . . . . . . . . . . . . 24
2.4.3. Error Cases . . . . . . . . . . . . . . . . . . . . . 24
2.5. Deleting a Roster Item . . . . . . . . . . . . . . . . . 24
2.5.1. Request . . . . . . . . . . . . . . . . . . . . . . . 24
2.5.2. Success Case . . . . . . . . . . . . . . . . . . . . 25
2.5.3. Error Cases . . . . . . . . . . . . . . . . . . . . . 26
2.6. Roster Versioning . . . . . . . . . . . . . . . . . . . . 26
2.6.1. Stream Feature . . . . . . . . . . . . . . . . . . . 26
2.6.2. Request . . . . . . . . . . . . . . . . . . . . . . . 26
2.6.3. Success Case . . . . . . . . . . . . . . . . . . . . 27
3. Managing Presence Subscriptions . . . . . . . . . . . . . . . 30
3.1. Requesting a Subscription . . . . . . . . . . . . . . . . 30
3.1.1. Client Generation of Outbound Subscription Request . 31
3.1.2. Server Processing of Outbound Subscription Request . 32
3.1.3. Server Processing of Inbound Subscription Request . . 34
3.1.4. Client Processing of Inbound Subscription Request . . 35
3.1.5. Server Processing of Outbound Subscription Approval . 36
3.1.6. Server Processing of Inbound Subscription Approval . 38
3.2. Canceling a Subscription . . . . . . . . . . . . . . . . 40
3.2.1. Client Generation of Subscription Cancellation . . . 40
3.2.2. Server Processing of Outbound Subscription
Cancellation . . . . . . . . . . . . . . . . . . . . 40
3.2.3. Server Processing of Inbound Subscription
Cancellation . . . . . . . . . . . . . . . . . . . . 41
3.3. Unsubscribing . . . . . . . . . . . . . . . . . . . . . . 43
3.3.1. Client Generation of Unsubscribe . . . . . . . . . . 43
3.3.2. Server Processing of Outbound Unsubscribe . . . . . . 43
3.3.3. Server Processing of Inbound Unsubscribe . . . . . . 44
3.4. Pre-Approving a Subscription Request . . . . . . . . . . 46
3.4.1. Client Generation of Subscription Pre-Approval . . . 46
3.4.2. Server Processing of Subscription Pre-Approval . . . 47
4. Exchanging Presence Information . . . . . . . . . . . . . . . 48
4.1. Presence Fundamentals . . . . . . . . . . . . . . . . . . 48
4.2. Initial Presence . . . . . . . . . . . . . . . . . . . . 49
4.2.1. Client Generation of Initial Presence . . . . . . . . 49
4.2.2. Server Processing of Outbound Initial Presence . . . 50
4.2.3. Server Processing of Inbound Initial Presence . . . . 50
4.2.4. Client Processing of Initial Presence . . . . . . . . 51
4.3. Presence Probes . . . . . . . . . . . . . . . . . . . . . 51
4.3.1. Server Generation of Outbound Presence Probe . . . . 52
4.3.2. Server Processing of Inbound Presence Probe . . . . . 53
4.3.2.1. Handling of the 'id' Attribute . . . . . . . . . 55
4.4. Subsequent Presence Broadcast . . . . . . . . . . . . . . 57
4.4.1. Client Generation of Subsequent Presence Broadcast . 57
4.4.2. Server Processing of Subsequent Outbound Presence . . 57
4.4.3. Server Processing of Subsequent Inbound Presence . . 58
4.4.4. Client Processing of Subsequent Presence . . . . . . 59
4.5. Unavailable Presence . . . . . . . . . . . . . . . . . . 59
4.5.1. Client Generation of Unavailable Presence . . . . . . 59
4.5.2. Server Processing of Outbound Unavailable Presence . 59
4.5.3. Server Processing of Inbound Unavailable Presence . . 61
4.5.4. Client Processing of Unavailable Presence . . . . . . 62
4.6. Directed Presence . . . . . . . . . . . . . . . . . . . . 62
4.6.1. General Considerations . . . . . . . . . . . . . . . 62
4.6.2. Client Generation of Directed Presence . . . . . . . 63
4.6.3. Server Processing of Outbound Directed Presence . . . 63
4.6.4. Server Processing of Inbound Directed Presence . . . 64
4.6.5. Client Processing of Inbound Directed Presence . . . 64
4.6.6. Server Processing of Presence Probes . . . . . . . . 64
4.7. Presence Syntax . . . . . . . . . . . . . . . . . . . . . 65
4.7.1. Type Attribute . . . . . . . . . . . . . . . . . . . 65
4.7.2. Child Elements . . . . . . . . . . . . . . . . . . . 66
4.7.2.1. Show Element . . . . . . . . . . . . . . . . . . 66
4.7.2.2. Status Element . . . . . . . . . . . . . . . . . 67
4.7.2.3. Priority Element . . . . . . . . . . . . . . . . 68
4.7.3. Extended Content . . . . . . . . . . . . . . . . . . 69
5. Exchanging Messages . . . . . . . . . . . . . . . . . . . . . 69
5.1. One-to-One Chat Sessions . . . . . . . . . . . . . . . . 69
5.2. Message Syntax . . . . . . . . . . . . . . . . . . . . . 70
5.2.1. To Attribute . . . . . . . . . . . . . . . . . . . . 70
5.2.2. Type Attribute . . . . . . . . . . . . . . . . . . . 71
5.2.3. Body Element . . . . . . . . . . . . . . . . . . . . 73
5.2.4. Subject Element . . . . . . . . . . . . . . . . . . . 74
5.2.5. Thread Element . . . . . . . . . . . . . . . . . . . 75
5.3. Extended Content . . . . . . . . . . . . . . . . . . . . 77
6. Exchanging IQ Stanzas . . . . . . . . . . . . . . . . . . . . 77
7. A Sample Session . . . . . . . . . . . . . . . . . . . . . . 78
8. Server Rules for Processing XML Stanzas . . . . . . . . . . . 84
8.1. General Considerations . . . . . . . . . . . . . . . . . 85
8.2. No 'to' Address . . . . . . . . . . . . . . . . . . . . . 85
8.3. Remote Domain . . . . . . . . . . . . . . . . . . . . . . 85
8.4. Local Domain . . . . . . . . . . . . . . . . . . . . . . 86
8.5. Local User . . . . . . . . . . . . . . . . . . . . . . . 86
8.5.1. No Such User . . . . . . . . . . . . . . . . . . . . 86
8.5.2. localpart@domainpart . . . . . . . . . . . . . . . . 86
8.5.2.1. Available or Connected Resources . . . . . . . . 87
8.5.2.2. No Available or Connected Resources . . . . . . . 89
8.5.3. localpart@domainpart/resourcepart . . . . . . . . . . 90
8.5.3.1. Resource Matches . . . . . . . . . . . . . . . . 90
8.5.3.2. No Resource Matches . . . . . . . . . . . . . . . 90
8.5.4. Summary of Message Delivery Rules . . . . . . . . . . 92
9. Handling of URIs . . . . . . . . . . . . . . . . . . . . . . 93
10. Internationalization Considerations . . . . . . . . . . . . . 94
11. Security Considerations . . . . . . . . . . . . . . . . . . . 94
12. Conformance Requirements . . . . . . . . . . . . . . . . . . 95
13. References . . . . . . . . . . . . . . . . . . . . . . . . . 99
13.1. Normative References . . . . . . . . . . . . . . . . . . 99
13.2. Informative References . . . . . . . . . . . . . . . . . 99
Appendix A. Subscription States . . . . . . . . . . . . . . . . 103
A.1. Defined States . . . . . . . . . . . . . . . . . . . . . 103
A.2. Server Processing of Outbound Presence Subscription
Stanzas . . . . . . . . . . . . . . . . . . . . . . . . . 104
A.2.1. Subscribe . . . . . . . . . . . . . . . . . . . . . . 105
A.2.2. Unsubscribe . . . . . . . . . . . . . . . . . . . . . 105
A.2.3. Subscribed . . . . . . . . . . . . . . . . . . . . . 106
A.2.4. Unsubscribed . . . . . . . . . . . . . . . . . . . . 106
A.3. Server Processing of Inbound Presence Subscription
Stanzas . . . . . . . . . . . . . . . . . . . . . . . . . 106
A.3.1. Subscribe . . . . . . . . . . . . . . . . . . . . . . 107
A.3.2. Unsubscribe . . . . . . . . . . . . . . . . . . . . . 107
A.3.3. Subscribed . . . . . . . . . . . . . . . . . . . . . 108
A.3.4. Unsubscribed . . . . . . . . . . . . . . . . . . . . 109
Appendix B. Blocking Communication . . . . . . . . . . . . . . . 110
Appendix C. vCards . . . . . . . . . . . . . . . . . . . . . . . 110
Appendix D. XML Schema for jabber:iq:roster . . . . . . . . . . 110
Appendix E. Differences From RFC 3921 . . . . . . . . . . . . . 112
Appendix F. Acknowledgements . . . . . . . . . . . . . . . . . . 113
1. Introduction โจ
1.1. Overview
okay so XMPP (that's the Extensible Messaging and Presence Protocol ๐) is an application profile of the Extensible Markup Language [XML], and it's giving near-real-time exchange of structured but still extensible data between any two or more network entities ๐ฆ the core features in [XMPP-CORE] are the building blocks for a whole bunch of near-real-time apps, and you can layer those apps on top by sending app-specific data inside particular XML namespaces (refer to [XML-NAMES]) ๐ง this document then defines the XMPP extensions that give you the basic functionality you'd expect from an instant messaging (IM) and presence app, as described in [IMP-REQS] ๐ โจ
1.2. History ๐ฐ๏ธโจ
Okay so the basic syntax and semantics of XMPP were first cooked up in the Jabber open-source community, mainly in 1999. ๐ง Then in late 2002 the XMPP Working Group got chartered to adapt the core Jabber protocol into an IETF IM and presence technology, following [IMP-REQS]. Iconic glow-up ๐ In October 2004, [RFC3920] and [RFC3921] were published, and they were the most complete definition of XMPP at that time ๐
Since 2004 the Internet community has gotten a LOT of real implementation and deployment experience with XMPP, including formal interoperability testing run under the XMPP Standards Foundation (XSF) ๐งช This document folds in comprehensive feedback from software developers and service providers, including a bunch of backward-compatible modifications summarized under Appendix E ๐ซถ So this document reflects the rough consensus of the Internet community on the IM and presence features of XMPP 1.0, and that's how it ends up obsoleting RFC 3921 ๐ฆ
1.3. Requirements ๐
Traditionally, IM apps have combined the following factors:
- The central point of focus is a list of one's contacts or "buddies" (in XMPP this list is called a "roster") ๐ธ
- The whole point of using the app is to swap relatively brief text messages with particular contacts in close to real time ๐ฌ Often that means lots of messages in rapid succession, in the form of a one-to-one "chat session" as described under Section 5.1 โจ
- The catalyst for exchanging messages is "presence", i.e., information about the network availability of particular contacts (so you know who is online and available for a one-to-one chat session) ๐ข
- Presence information is only given to contacts you've authorized through an explicit agreement called a "presence subscription" ๐
Thus, at a high level, this document assumes that a user needs to be able to complete the following use cases:
- Manage items in one's contact list
- Exchange messages with one's contacts
- Exchange presence information with one's contacts
- Manage presence subscriptions to and from one's contacts
The detailed definitions of these functionality areas are in RFC 2779 [IMP-REQS], and if you want the in-depth requirements, go check that doc ๐ The XMPP IM and presence extensions specified here do meet the requirements of RFC 2779, but they weren't designed explicitly with that spec in mind ๐ The base protocol evolved through an open development process in the Jabber community before RFC 2779 was written, so it's giving accidental main character energy ๐ญ Also, XMPP protocol extensions for lots of other functionality areas exist in the XMPP Standards Foundation's XEP series (for example, multi-user text chat as specified in [XEP-0045]). They aren't specified in this document, though, because RFC 2779 doesn't mandate them ๐ง
Implementation Note: RFC 2779 stipulates that presence services must be separable from IM services and vice-versa; i.e., it must be possible to use the protocol to provide a presence service, a messaging service, or both. Although the text of this document assumes that implementations and deployments will want to offer a unified IM and presence service, it is not mandatory for an XMPP service to offer both a presence service and a messaging service, and the protocol makes it possible to offer separate and distinct services for presence and for messaging. (For example, a presence-only service could return a<service-unavailable/>stanza error if a client attempts to send a<message/>stanza.) ๐
1.4. Functional Summary ๐
This non-normative section gives a developer-friendly, functional summary of XMPP-based IM and presence features. For the normative definitions, check the sections that follow ๐
[XMPP-CORE] explains how an XMPP client connects to an XMPP server ๐ In particular, it lays out the preconditions that must be met before a client is allowed to send XML stanzas (the basic unit of meaning in XMPP) to other entities on an XMPP network. Those preconditions cover negotiating the XML stream, which includes exchanging XML stream headers, optional channel encryption via Transport Layer Security [TLS], mandatory authentication via Simple Authentication and Security Layer [SASL], and binding a resource to the stream for client addressing โจ Refer to [XMPP-CORE] for the details, because knowledge of it is assumed in this doc ๐ค
Interoperability Note: [RFC3921] specified one additional precondition: formal establishment of an instant messaging and presence session. Implementation and deployment experience has shown that this additional step is unnecessary. However, for backward compatibility an implementation MAY still offer that feature. This enables older software to connect while letting newer software save a round trip. ๐
Once the preconditions in [XMPP-CORE] are fulfilled, an XMPP client has a long-lived XML stream with an XMPP server ๐ That lets the user controlling the client send and receive a potentially unlimited number of XML stanzas over the stream. The stream can be used to exchange messages, share presence information, and do structured request-response interactions in close to real time โก After the XML stream is negotiated, the typical flow for an IM and presence session goes like this:
- Retrieve one's roster. (See Section 2.2.) ๐
- Send initial presence to the server for broadcast to all subscribed contacts, which is how you "go online" from the XMPP communication perspective. (See Section 4.2.) ๐ข
- Exchange messages, manage presence subscriptions, perform roster updates, and in general process and generate other XML stanzas with particular semantics throughout the life of the session. (See Sections 5, 3, 2, and 6.) ๐
- Terminate the session when you want by sending unavailable presence and closing the underlying XML stream. (See Section 4.5.) ๐
1.5. Terminology ๐
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 [KEYWORDS] ๐
This document inherits the terminology defined in [XMPP-CORE] ๐ง
The terms "automated client" and "interactive client" are to be understood in the sense defined in [TLS-CERTS] ๐ค
For convenience, this document uses the term "user" to refer to the owner of an XMPP account. Account owners don't have to be humans, though. They can be bots, devices, or other automated applications ๐ฆพ
Several other terms, such as "interested resource", are defined within the body of this document ๐
Following the "XML Notation" used in [IRI] to represent characters that can't be rendered in ASCII-only documents, some examples in this document use the form &#x.... as a notational device to represent [UNICODE] characters (e.g., the string ř stands for the Unicode character LATIN SMALL LETTER R WITH CARON). This form is definitely NOT to be sent over the wire in XMPP systems ๐ซ
In examples, lines have been wrapped for readability, [...] means elision, and the following prepended strings are used (these prepended strings are not to be sent over the wire) ๐
C:= clientCC:= contact's clientCS:= contact's serverS:= serverUC:= user's clientUS:= user's server
Readers need to be aware that the examples aren't exhaustive, and that in examples for some protocol flows, the alternate steps shown would not necessarily be triggered by the exact data sent in the previous step. In all cases, the protocol definitions in this document or in normatively referenced documents rule over any examples here ๐ All examples are fictional, and the info exchanged (like usernames and passwords) doesn't represent any existing users or servers ๐ซง
2. Managing the Roster ๐๐
In XMPP, a user's roster contains any number of specific contacts. A user's roster is stored by the user's server on the user's behalf, so the user can access roster info from any device ๐ฑ When the user adds items to the roster or modifies existing items, if an error does not occur then the server SHOULD store that data unmodified if at all possible, and it MUST return the data it has stored when an authorized client requests the roster ๐๏ธ
Security Warning: Because the user's roster can contain confidential data, the server MUST restrict access to this data so that only authorized entities (typically limited to the account owner) are able to retrieve, modify, or delete it. ๐จ๐ญ
RFC 3921 assumed that the only place a user stores their roster is the server where the user's account is registered and where the user authenticates for access to the XMPP network. This specification breaks that strict coupling of roster storage to account registration and network authentication, so a user could store their roster at another location, or could have multiple rosters stored in multiple locations ๐ However, since there isn't implementation and deployment experience with a more flexible roster storage model yet, this specification keeps the terminology of RFC 3921 by using the terms "client" and "server" (and "the roster" instead of "a roster"), rather than coining a new term for "a place where a user stores a roster" ๐งฉ Future documents might provide normative rules for non-server roster storage or for managing multiple rosters, but those rules are out of scope for this document ๐ฎ
2.1. Syntax and Semantics ๐ง
Rosters are managed using <iq/> stanzas (see Section 8.2.3 of [XMPP-CORE]), specifically by means of a <query/> child element qualified by the 'jabber:iq:roster' namespace. The detailed syntax and semantics are defined in the following sections ๐
2.1.1. Ver Attribute ๐ข
The 'ver' attribute is a string that identifies a particular version of the roster information. The value MUST be generated only by the server and MUST be treated by the client as opaque. The server can use any appropriate method for generating the version ID, such as a hash of the roster data or a strictly increasing sequence number ๐งฎ
Inclusion of the 'ver' attribute is RECOMMENDED. โจ
Use of the 'ver' attribute is described more fully under Section 2.6 ๐
Interoperability Note: The'ver'attribute of the<query/>element was not defined in RFC 3921 and is newly defined in this specification. ๐
2.1.2. Roster Items ๐ฆ
The <query/> element inside a roster set (Section 2.1.5) contains one <item/> child, and a roster result (Section 2.1.4) typically contains multiple <item/> children. Each <item/> element describes a unique "roster item" (sometimes also called a "contact") ๐ซถ
The syntax of the <item/> element is described in the following sections ๐
2.1.2.1. Approved Attribute โจ
Okay so the boolean approved attribute set to "true" is how we flag subscription pre-approval, which we dig into in Section 3.4 ๐ฆ The default is "false", following [XML-DATATYPES], so if you don't include it, you're not pre-approved, no drama.
A server SHOULD include the approved attribute so the client knows about pre-approvals ๐ซถ But a client MUST NOT include approved in the roster sets it sends to the server. Instead it MUST use presence stanzas of type "subscribed" and "unsubscribed" to manage pre-approvals, as described in Section 3.4 ๐
๐ง Interoperability Note: Theapprovedattribute of the<item/>element was not defined in RFC 3921 and is newly defined in this specification.
2.1.2.2. Ask Attribute ๐
The ask attribute of the <item/> element with a value of "subscribe" is how we signal the different subscription sub-states that have a "Pending Out" aspect, as described in Section 3.1.2 ๐ธ
A server SHOULD include the ask attribute to tell the client about those "Pending Out" sub-states ๐ A client MUST NOT include the ask attribute in the roster sets it sends to the server. Instead it MUST use presence stanzas of type "subscribe" and "unsubscribe" to manage those sub-states, as described in Section 3.1.2 โจ
2.1.2.3. JID Attribute ๐
The jid attribute of the <item/> element specifies the Jabber Identifier (JID) that uniquely identifies the roster item. It's basically the item's ID card ๐ชช
The jid attribute is REQUIRED whenever a client or server adds, updates, deletes, or returns a roster item. No jid, no party ๐
2.1.2.4. Name Attribute ๐
The name attribute of the <item/> element specifies the "handle" to be associated with the JID. The user decides this, not the contact, so you get to pick the nickname ๐ซถ Even though the value of the name attribute MAY have meaning to a human user, the server treats it as opaque. However, the server MAY use the name attribute for matching purposes within the context of various XMPP extensions. One possible comparison method is the one described for XMPP resourceparts in [XMPP-ADDR] ๐ง
It is OPTIONAL for a client to include the name attribute when adding or updating a roster item ๐
2.1.2.5. Subscription Attribute ๐
The state of the presence subscription lives in the subscription attribute of the <item/> element. These are the subscription-related values we've got:
none: the user doesn't have a subscription to the contact's presence, and the contact doesn't have a subscription to the user's presence. This is the default value, so if thesubscriptionattribute isn't included, the state is understood to be "none" ๐to: the user has a subscription to the contact's presence, but the contact doesn't have a subscription to the user's presence ๐from: the contact has a subscription to the user's presence, but the user doesn't have a subscription to the contact's presence ๐both: the user and the contact have subscriptions to each other's presence (also called a "mutual subscription") ๐
In a roster result (Section 2.1.4), the client MUST ignore values of the subscription attribute other than "none", "to", "from", or "both". Anything else gets ignored, no cap ๐
โโ๏ธ
In a roster push (Section 2.1.6), the client MUST ignore values of the subscription attribute other than "none", "to", "from", "both", or "remove" ๐ซ
In a roster set (Section 2.1.5), the subscription attribute MAY be included with a value of "remove", which means the item should be removed from the roster ๐๏ธ In a roster set, the server MUST ignore all values of the subscription attribute other than "remove" โจ
Including the subscription attribute is OPTIONAL ๐
2.1.2.6. Group Element ๐งบ
The <group/> child element specifies a category or "bucket" that a client uses to group the roster item. An <item/> element MAY contain more than one <group/> element, which means roster groups are not exclusive. You can be in as many buckets as you want, bestie ๐ซง The XML character data of the <group/> element MAY have meaning to a human user, but the server treats it as opaque. However, the server MAY use the <group/> element for matching purposes within the context of various XMPP extensions. One possible comparison method is the one described for XMPP resourceparts in [XMPP-ADDR] ๐ฆ
It is OPTIONAL for a client to include the <group/> element when adding or updating a roster item. If a roster set (Section 2.1.5) includes no <group/> element, then the item is interpreted as being affiliated with no group ๐ธ
2.1.3. Roster Get ๐ฅ
A "roster get" is a client's request for the server to return the roster. Syntactically it's an IQ stanza of type "get" sent from client to server, containing a <query/> element qualified by the jabber:iq:roster namespace. The <query/> element MUST NOT contain any <item/> child elements, so keep it empty ๐ซถ
C: <iq from='juliet@example.com/balcony'
id='bv1bs71f'
type='get'>
<query xmlns='jabber:iq:roster'/>
</iq>
The expected outcome of sending a roster get is for the server to return a roster result ๐
2.1.4. Roster Result ๐ค
A "roster result" is the server's response to a roster get. Syntactically it's an IQ stanza of type "result" sent from server to client, containing a <query/> element qualified by the jabber:iq:roster namespace ๐
The <query/> element in a roster result contains one <item/> element for each contact, so it can hold more than one <item/> element ๐
S: <iq id='bv1bs71f'
to='juliet@example.com/chamber'
type='result'>
<query xmlns='jabber:iq:roster' ver='ver7'>
<item jid='nurse@example.com'/>
<item jid='romeo@example.net'/>
</query>
</iq>
If the roster exists but there are no contacts in it, then the server MUST return an IQ-result containing a child <query/> element that contains no <item/> children. In other words, the server MUST NOT return an empty <iq/> stanza of type "error" ๐
S: <iq id='bv1bs71f'
to='juliet@example.com/chamber'
type='result'>
<query xmlns='jabber:iq:roster' ver='ver9'/>
</iq>
If the roster does not exist, then the server MUST return a stanza error with a condition of <item-not-found/> ๐
S: <iq id='bv1bs71f'
to='juliet@example.com/chamber'
type='error'>
<error type='cancel'>
<item-not-found
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
2.1.5. Roster Set ๐ ๏ธ
A "roster set" is a client's request for the server to modify a roster item, which means create, update, or delete it. Syntactically it's an IQ stanza of type "set" sent from client to server, containing a <query/> element qualified by the jabber:iq:roster namespace ๐ง
The following rules apply to roster sets:
- The
<query/>element MUST contain one and only one<item/>element ๐ฏ - The server MUST ignore any value of the
subscriptionattribute other than "remove" (see Section 2.1.2.5) ๐ โโ๏ธ
๐จ Security Warning: Traditionally, the IQ stanza of the roster set included no 'to' address, so every roster set was sent from an authenticated resource (full JID) of the account whose roster was being updated. RFC 3921 also required a server to do special-case checking of roster sets to ignore the 'to' address. This specification removes that special-casing, which means a roster set might include a 'to' address other than the sender's. So the entity that processes a roster set MUST verify that the sender is authorized to update the roster, and if not, return a <forbidden/> error. Don't skip this one, it's serious ๐ญ
C: <iq from='juliet@example.com/balcony'
id='rs1'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='nurse@example.com'/>
</query>
</iq>
2.1.6. Roster Push ๐ฃ
A "roster push" is a newly created, updated, or deleted roster item that the server sends to the client. Syntactically it's an IQ stanza of type "set" sent from server to client, containing a <query/> element qualified by the jabber:iq:roster namespace ๐ฌ
The following rules apply to roster pushes:
- The
<query/>element in a roster push MUST contain one and only one<item/>element ๐ - A receiving client MUST ignore the stanza unless it has no 'from' attribute (meaning it's implicitly from the bare JID of the user's account), or it has a 'from' attribute whose value matches the user's bare JID
<user@domainpart>๐ซถ
S: <iq id='a78b4q6ha463'
to='juliet@example.com/chamber'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='nurse@example.com'/>
</query>
</iq>
As mandated by the semantics of the IQ stanza defined in [XMPP-CORE], each resource that receives a roster push from the server is supposed to reply with an IQ stanza of type "result" or "error". However, it's known that many existing clients don't reply to roster pushes ๐
C: <iq from='juliet@example.com/balcony'
id='a78b4q6ha463'
type='result'/>
C: <iq from='juliet@example.com/chamber'
id='a78b4q6ha463'
type='result'/>
๐จ Security Warning: Traditionally, a roster push included no 'from' address, so every roster push was sent implicitly from the bare JID of the account itself. This specification, however, allows entities other than the user's server to maintain roster information, which means a roster push might include a 'from' address other than the bare JID of the user's account. So the client MUST check the 'from' address to verify that the sender is authorized to update the roster. If the client receives a roster push from an unauthorized entity, it MUST NOT process the pushed data. In addition, the client can either return a stanza error of <service-unavailable/> or refuse to return a stanza error at all. The latter behavior overrides a MUST-level requirement from [XMPP-CORE], for the purpose of preventing a presence leak ๐ต๏ธโโ๏ธ
๐ง Implementation Note: There is no error case for client processing of roster pushes. If the server receives an IQ of type "error" in response to a roster push, then it SHOULD ignore the error ๐
2.2. Retrieving the Roster on Login ๐
Okay so once you've authenticated with a server and bound a resource (which makes you a connected resource, per [XMPP-CORE]) โจ, a client SHOULD request the roster before sending initial presence ๐ . Receiving the roster isn't necessarily desirable for every resource, like a connection with limited bandwidth, so the client's request for the roster is not mandatory ๐ธ. After a connected resource sends initial presence (see Section 4.2), it's called an "available resource" ๐ฆ. If a connected resource or available resource requests the roster, it's called an "interested resource" ๐. The server MUST send roster pushes to all interested resources.
Implementation Note: Presence subscription requests go to available resources, but the roster pushes linked to subscription state changes go to interested resources ๐ง. So if a resource wants to receive both subscription requests and roster pushes, it MUST both send initial presence and request the roster ๐ฅ.
A client requests the roster by sending a roster get over its stream with the server ๐ซถ.
C: <iq from='juliet@example.com/balcony'
id='hu2bac18'
type='get'>
<query xmlns='jabber:iq:roster'/>
</iq>
S: <iq id='hu2bac18'
to='juliet@example.com/balcony'
type='result'>
<query xmlns='jabber:iq:roster' ver='ver11'>
<item jid='romeo@example.net'
name='Romeo'
subscription='both'>
<group>Friends</group>
</item>
<item jid='mercutio@example.com'
name='Mercutio'
subscription='from'/>
<item jid='benvolio@example.net'
name='Benvolio'
subscription='both'/>
</query>
</iq>
If the server can't process the roster get, it MUST return an appropriate stanza error as described in [XMPP-CORE] ๐ญ. For example, that could be <service-unavailable/> if the roster namespace isn't supported, or <internal-server-error/> if the server is having trouble processing or returning the roster ๐.
2.3. Adding a Roster Item ๐
2.3.1. Request
At any time, a client can add an item to the roster โจ. To do that, it sends a roster set containing a new item ๐.
C: <iq from='juliet@example.com/balcony'
id='ph1xaz53'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='nurse@example.com'
name='Nurse'>
<group>Servants</group>
</item>
</query>
</iq>
2.3.2. Success Case
If the server can successfully process the roster set for the new item (meaning no error occurs), it MUST create the item in the user's roster and carry on as follows ๐.
The server MUST return an IQ stanza of type "result" to the connected resource that sent the roster set ๐ฉท.
S: <iq id='ph1xaz53'
to='juliet@example.com/balcony'
type='result'/>
The server MUST also send a roster push containing the new roster item to all of the user's interested resources, including the resource that generated the roster set ๐ฃ.
S: <iq to='juliet@example.com/balcony'
id='a78b4q6ha463'
type='set'>
<query xmlns='jabber:iq:roster' ver='ver13'>
<item jid='nurse@example.com'
name='Nurse'
subscription='none'>
<group>Servants</group>
</item>
</query>
</iq>
S: <iq to='juliet@example.com/chamber'
id='x81g3bdy4n19'
type='set'>
<query xmlns='jabber:iq:roster' ver='ver13'>
<item jid='nurse@example.com'
name='Nurse'
subscription='none'>
<group>Servants</group>
</item>
</query>
</iq>
As the semantics of the IQ stanza defined in [XMPP-CORE] require, each resource that receives a roster push from the server is supposed to reply with an IQ stanza of type "result" or "error" ๐. Honestly though, it's known that a lot of existing clients don't reply to roster pushes ๐ .
C: <iq from='juliet@example.com/balcony'
id='a78b4q6ha463'
type='result'/>
C: <iq from='juliet@example.com/chamber'
id='x81g3bdy4n19'
type='result'/>
2.3.3. Error Cases
If the server can't successfully process the roster set, it MUST return a stanza error. Here are the error cases that are defined ๐จ. Other stanza errors can also happen, obviously ๐. For example, <internal-server-error/> if the server has an internal problem processing the roster set, or even <not-allowed/> if the server only lets you modify the roster through a non-XMPP method, like a web interface ๐.
The server MUST return a <forbidden/> stanza error to the client if the sender of the roster set isn't authorized to update the roster (usually only an authenticated resource of the account itself is authorized) ๐.
The server MUST return a <bad-request/> stanza error to the client if the roster set has any of the following violations ๐
โโ๏ธ:
- The
<query/>element contains more than one<item/>child element. - The
<item/>element contains more than one<group/>element, but there are duplicate groups (one possible way to check for duplicates is the one described for XMPP resourceparts in [XMPP-ADDR]).
The server MUST return a <not-acceptable/> stanza error to the client if the roster set has any of the following violations ๐:
- The length of the 'name' attribute is greater than a server-configured limit.
- The XML character data of the
<group/>element has zero length. (To remove an item from all groups, the client needs to leave out any<group/>element from the roster set instead.) - The XML character data of the
<group/>element is larger than a server-configured limit.
Error: Roster set initiated by unauthorized entity ๐ซ
C: <iq from='juliet@example.com/balcony'
id='ix7s53v2'
to='romeo@example.net'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='nurse@example.com'/>
</query>
</iq>
S: <iq id='ix7s53v2'
to='juliet@example.com/balcony'
type='error'>
<error type='auth'>
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
Error: Roster set contains more than one item ๐ฏ
C: <iq from='juliet@example.com/balcony'
id='nw83vcj4'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='nurse@example.com'
name='Nurse'>
<group>Servants</group>
</item>
<item jid='mother@example.com'
name='Mom'>
<group>Family</group>
</item>
</query>
</iq>
S: <iq id='nw83vcj4'
to='juliet@example.com/balcony'
type='error'>
<error type='modify'>
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
Error: Roster set contains item with oversized handle ๐
C: <iq from='juliet@example.com/balcony'
id='yl491b3d'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='nurse@example.com'
name='[ ... some-very-long-handle ... ]'>
<group>Servants</group>
</item>
</query>
</iq>
S: <iq id='yl491b3d'
to='juliet@example.com/balcony'
type='error'>
<error type='modify'>
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
Error: Roster set contains duplicate groups ๐ฏโโ๏ธ
C: <iq from='juliet@example.com/balcony'
id='tk3va749'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='nurse@example.com'
name='Nurse'>
<group>Servants</group>
<group>Servants</group>
</item>
</query>
</iq>
S: <iq id='tk3va749'
to='juliet@example.com/balcony'
type='error'>
<error type='modify'>
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
Error: Roster set contains empty group ๐ซฅ
C: <iq from='juliet@example.com/balcony'
id='fl3b486u'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='nurse@example.com'
name='Nurse'>
<group></group>
</item>
</query>
</iq>
S: <iq id='fl3b486u'
to='juliet@example.com/balcony'
type='error'>
<error type='modify'>
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
Error: Roster set contains oversized group name ๐
C: <iq from='juliet@example.com/balcony'
id='qh3b4v19'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='nurse@example.com'
name='Nurse'>
<group>[ ... some-very-long-group-name ... ]</group>
</item>
</query>
</iq>
S: <iq id='qh3b4v19'
to='juliet@example.com/balcony'
type='error'>
<error type='modify'>
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
Interoperability Note: Some servers return a<not-allowed/>stanza error to the client if the value of the<item/>element's 'jid' attribute matches the bare JID <localpart@domainpart> of the user's account ๐ง.
2.4. Updating a Roster Item ๐ฆ
2.4.1. Request
okay so updating an existing roster item is basically the same move as adding one ๐ you just send a roster set to the server again. and bestie, a roster item is atomic, so the server MUST update it exactly as you sent it in the roster set ๐ซถ
there are a few reasons a client might wanna update a roster item:
- Adding a group
- Deleting a group
- Changing the handle
- Deleting the handle
ok picture this ๐ Romeo is on Juliet's roster like this:
<item jid='romeo@example.net'
name='Romeo'>
<group>Friends</group>
</item>
Juliet, who has him on her roster, wants to add him to another group ๐ธ
C: <iq from='juliet@example.com/balcony'
id='di43b2x9'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='romeo@example.net'
name='Romeo'>
<group>Friends</group>
<group>Lovers</group>
</item>
</query>
</iq>
Later on, she decides she wants him out of the original group ๐
C: <iq from='juliet@example.com/balcony'
id='lf72v157'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='romeo@example.net'
name='Romeo'>
<group>Lovers</group>
</item>
</query>
</iq>
Or maybe she wants him out of all groups ๐
C: <iq from='juliet@example.com/balcony'
id='ju4b62a5'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='romeo@example.net'/>
</query>
</iq>
She can also change the handle for the item โจ
C: <iq from='juliet@example.com/balcony'
id='gb3sv487'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='romeo@example.net'
name='MyRomeo'/>
</query>
</iq>
And then, if she's over it, she can remove the handle altogether ๐ฆ
C: <iq from='juliet@example.com/balcony'
id='o3bx66s5'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='romeo@example.net'
name=''/>
</query>
</iq>
Implementation Note: including an emptynameattribute is equivalent to including nonameattribute. Both actions set the name to the empty string. ๐ง
2.4.2. Success Case
same energy as adding a roster item, bestie ๐ซถ if the roster item can be successfully processed, then the server MUST update the item in the user's roster, send a roster push to all of the user's interested resources, and send an IQ result to the initiating resource. the details are under Section 2.3. โจ
2.4.3. Error Cases
the error cases from Section 2.3.3 also apply to updating a roster item, so no new drama here ๐
2.5. Deleting a Roster Item
2.5.1. Request
anytime, a client can delete an item from their roster ๐ฅ they just send a roster set and set the subscription attribute to "remove". bye bye, Nurse ๐
C: <iq from='juliet@example.com/balcony'
id='hm4hs97y'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='nurse@example.com'
subscription='remove'/>
</query>
</iq>
2.5.2. Success Case
same as adding a roster item again ๐ if the server can successfully process the roster set, then it MUST update the item in the user's roster, send a roster push to all of the user's interested resources (with the subscription attribute set to "remove"), and send an IQ result to the initiating resource. details are under Section 2.3.
but wait, there's more ๐ the user's server might also need to generate one or more subscription-related presence stanzas:
- If the user has a presence subscription to the contact, then the user's server MUST send a presence stanza of type "unsubscribe" to the contact (to unsubscribe from the contact's presence).
- If the contact has a presence subscription to the user, then the user's server MUST send a presence stanza of type "unsubscribed" to the contact (to cancel the contact's subscription to the user).
- If the presence subscription is mutual, then the user's server MUST send both a presence stanza of type "unsubscribe" and a presence stanza of type "unsubscribed" to the contact.
so the server would send stuff like this ๐
S: <presence from='juliet@example.com'
id='lm3ba81g'
to='nurse@example.com'
type='unsubscribe'/>
S: <presence from='juliet@example.com'
id='xb2c1v4k'
to='nurse@example.com'
type='unsubscribed'/>
2.5.3. Error Cases
if the jid attribute points at an item that isn't in the roster, the server MUST return an <item-not-found/> stanza error ๐ญ
Error: Roster item not found
C: <iq from='juliet@example.com/balcony'
id='uj4b1ca8'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='[ ... non-existent-jid ... ]'
subscription='remove'/>
</query>
</iq>
S: <iq id='uj4b1ca8'
to='juliet@example.com/balcony'
type='error'>
<error type='modify'>
<item-not-found
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
2.6. Roster Versioning
2.6.1. Stream Feature
if a server supports roster versioning, it MUST advertise the following stream feature during stream negotiation ๐
<ver xmlns='urn:xmpp:features:rosterver'/>
the roster versioning stream feature is merely informative, so it is never mandatory-to-negotiate. very chill feature, no pressure ๐ธ
2.6.2. Request
if a client supports roster versioning AND the server it's connected to advertises support for it (like we just covered), then the client SHOULD include the ver element in its request for the roster. if the server does NOT advertise support for roster versioning, the client MUST NOT include the ver attribute. if the client does include the ver attribute in its roster get, it sets the attribute's value to the version ID tied to its last cache of the roster ๐ง
C: <iq from='romeo@example.net/home'
id='r1h3vzp7'
to='romeo@example.net'
type='get'>
<query xmlns='jabber:iq:roster' ver='ver14'/>
</iq>
if the client hasn't cached the roster yet, or the cache got lost or corrupted, but it still wants to bootstrap roster versioning, it MUST set the ver attribute to the empty string (i.e., ver="") ๐ซถ
naturally, if the client doesn't support roster versioning or doesn't wanna bootstrap it, it just won't include the ver attribute at all ๐
2.6.3. Success Case โจ
Okay bestie, here's the vibe ๐ Whether or not the roster changed since the version ID the client sent, the server MUST either hand back the whole roster (the way we described in Section 2.1.4, including a 'ver' attribute that shows the newest version) OR send an empty IQ-result ๐ซถ. That empty result basically means "any roster changes are coming to you as roster pushes, fr." In general, unless (1) sending the full roster would use less bandwidth than individual roster pushes (like if the roster only has a few items) or (2) the server can't match the version ID to any previous version it has on file, the server SHOULD send the empty IQ-result and then send any modifications through roster pushes ๐ฆ
S: <iq from='romeo@example.net'
id='r1h3vzp7'
to='romeo@example.net/home'
type='result'/>
๐ธ Implementation Note: This empty IQ-result is different from an empty <query/> element, so it's easy to tell this usage apart from an empty roster. Iconic.
If roster versioning is enabled and the roster hasn't changed since the version ID the client sent, the server will simply not send any roster pushes to the client. It stays quiet unless and until some relevant event triggers a roster push during the client's session ๐ง
If the roster HAS been modified since the version ID the client sent, the server MUST then send one roster push to the client for each roster item that changed since that version ID. (We call a roster push sent for roster version synchronization an "interim roster push" ๐)
๐ก Definition: A "roster modification" is any change to the roster data that would result in a roster push to a connected client. So internal roster-processing states in the server that wouldn't cause a roster push to a connected client don't need to change the version. Not me, but the logic is so clean ๐ญ
S: <iq from='romeo@example.net'
id='ah382g67'
to='romeo@example.net/home'
type='set'>
<query xmlns='jabber:iq:roster' ver='ver34'>
<item jid='tybalt@example.org' subscription='remove'/>
</query>
</iq>
S: <iq from='romeo@example.net'
id='b2gs90j5'
to='romeo@example.net/home'
type='set'>
<query xmlns='jabber:iq:roster' ver='ver42'>
<item jid='bill@example.org' subscription='both'/>
</query>
</iq>
S: <iq from='romeo@example.net'
id='c73gs419'
to='romeo@example.net/home'
type='set'>
<query xmlns='jabber:iq:roster' ver='ver72'>
<item jid='nurse@example.org'
name='Nurse'
subscription='to'>
<group>Servants</group>
</item>
</query>
</iq>
S: <iq from='romeo@example.net'
id='dh361f35'
to='romeo@example.net/home'
type='set'>
<query xmlns='jabber:iq:roster' ver='ver96'>
<item jid='juliet@example.org'
name='Juliet'
subscription='both'>
<group>VIPs</group>
</item>
</query>
</iq>
So how do these "interim roster pushes" work? Picture it like this ๐
- Imagine the client had an active presence session the whole time between its cached roster version (say, "ver14") and the new roster version (say, "ver96").
- During that time, the client might have gotten roster pushes for different roster versions (maybe "ver51" and "ver79"). Some of those pushes might have included intermediate updates to the same roster item, like the subscription state for bill@example.org changing from "none" to "to" and then from "to" to "both" ๐ณ
- The interim roster pushes skip all those in-between steps and only send the final result of every modification applied to each item while the client was offline (which might have been, say, "ver34", "ver42", "ver72", and "ver96") ๐
The client MUST handle an "interim roster push" the same way it handles any roster push. Honestly, from the client's side it can't tell an "interim" roster push apart from a "live" one, so it has no way of knowing when it has received all of the interim roster pushes ๐ When requesting the roster after reconnecting, the client SHOULD request the version tied to the last roster push it received during its previous session, NOT the version tied to the roster result it got at the start of that session. (Careful with that one, bestie!)
When roster versioning is enabled, the server MUST include the updated roster version with each roster push. Roster pushes MUST occur in order of modification, and the version in a roster push MUST be unique ๐ฅ Even if the client didn't include the 'ver' attribute in its roster gets or sets, the server SHOULD include the 'ver' attribute on all roster pushes and results it sends to the client.
๐ฆ Implementation Note: Guidelines and more detailed examples for roster versioning are provided in [XEP-0237].
3. Managing Presence Subscriptions ๐
Okay so privacy is everything in XMPP โจ Presence info only gets shared with other entities that a user has approved. When a user agrees that another entity can view its presence, that entity is said to have a "subscription" to the user's presence. An entity that has a subscription to a user's presence, or that the user has a presence subscription to, is called a "contact." (In this document, "contact" is also used more loosely to mean a potential contact or any item in a user's roster. Sneaky, I know ๐ )
In XMPP, a subscription lasts across presence sessions. It sticks around until the contact unsubscribes or the user cancels the subscription they gave out. (This is different from how presence subscriptions work in the Session Initiation Protocol (SIP), as defined in [SIP-PRES]. Not the same vibe at all ๐ง)
Subscriptions are handled in XMPP by sending presence stanzas with special attributes: "subscribe", "unsubscribe", "subscribed", and "unsubscribed" ๐
๐ธ Implementation Note: When a server processes or generates an outbound presence stanza of type "subscribe", "subscribed", "unsubscribe", or "unsubscribed", the server MUST stamp the outgoing presence stanza with the bare JID<localpart@domainpart>of the sending entity, NOT the full JID<localpart@domainpart/resourcepart>. Enforcing this keeps the presence subscription model simple and helps prevent presence leaks ๐ For info about presence leaks, check the security considerations of [XMPP-CORE]. Serious stuff, bestie!
Subscription states show up in the rosters of both the user and the contact. This section doesn't cover every possible case related to presence subscriptions. It mostly walks through the protocol flows for setting up a mutual subscription between a user and a contact. The full details on subscription states are in Appendix A ๐
3.1. Requesting a Subscription ๐
A "subscription request" is a request from a user for permission to permanently subscribe to a contact's presence information. Syntactically, it's a presence stanza whose 'type' attribute has the value "subscribe". The user's client generates the subscription request, the (potential) contact's server processes it, and the contact acts on it through the contact's client. The workflow is in the sections below โจ
๐ Implementation Note: Presence subscription requests get sent to available resources, while the roster pushes tied to subscription state changes go to interested resources. So if a resource wants to receive BOTH subscription requests AND roster pushes, it MUST both send initial presence and request the roster.
3.1.1. Client Generation of Outbound Subscription Request ๐ฆ
A user's client generates a subscription request by sending a presence stanza of type "subscribe", with a 'to' address of the potential contact's bare JID <contact@domainpart>.
UC: <presence id='xk3h1v69'
to='juliet@example.com'
type='subscribe'/>
When a user sends a presence subscription request to a potential instant messaging and presence contact, the value of the 'to' attribute MUST be a bare JID <contact@domainpart>, NOT a full JID <contact@domainpart/resourcepart>. The reason? The user wants to receive presence from ALL of the contact's resources, not just the one in the 'to' attribute. Bare JIDs also keep subscription processing, presence probes, and presence notifications simpler for the user's server and the contact's server ๐
For tracking purposes, a client SHOULD include an 'id' attribute in a presence subscription request ๐
๐ Implementation Note: Lots of XMPP clients ask the user for info about the potential contact (like a "handle" and a desired roster group) when they generate an outbound presence subscription request. Because of that, they often send a roster set before the outbound presence subscription request. This behavior is OPTIONAL, because a client MAY instead wait until it receives the initial roster push from the server before uploading the user-provided info about the contact. A server MUST process a roster set and an outbound presence subscription request in either order (in whatever order the client generated them) โจ
3.1.2. Server Processing of Outbound Subscription Request โจ
Okay bestie, so when Romeo's outbound subscription request reaches his server, the user's server MUST proceed as follows ๐
- Before doing anything else, the user's server MUST check the syntax of the JID in the 'to' attribute. Heads up though: some existing implementations skip this check, which is so messy ๐. If the JID looks like <contact@domainpart/resourcepart> instead of <contact@domainpart>, the user's server SHOULD treat it as if the request was aimed at the contact's bare JID and update the 'to' address to match. The server MAY also check that the JID follows the format in [XMPP-ADDR], and it might send back a
<jid-malformed/>stanza error. - If the potential contact lives on the same server as the user, then the server MUST follow the rules in Section 3.1.3 when processing the subscription request and delivering it to the (local) contact ๐ .
- If the potential contact is on a remote server, subject to local service policies the user's server MUST then route the stanza to that remote domain following core XMPP stanza processing rules. This can end with an appropriate stanza error going back to the user, like
<remote-server-timeout/>๐ฌ.
As mentioned, before delivering the request locally or routing it remotely, the user's server MUST stamp the outbound subscription request with the user's bare JID <user@domainpart> ๐ท๏ธ.
US: <presence from='romeo@example.net'
id='xk3h1v69'
to='juliet@example.com'
type='subscribe'/>
If the presence subscription request can't be delivered locally or routed remotely (for example, because the request is malformed, the local contact doesn't exist, the remote server doesn't exist, contacting the remote server times out, or the user's server runs into any other error), then the user's server MUST return an appropriate error stanza to the user. Here's an example ๐จ.
US: <presence from='juliet@example.com'
id='xk3h1v69'
to='romeo@example.net'
type='error'>
<error type='modify'>
<remote-server-not-found
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</presence>
After delivering or routing the request, the user's server MUST then send a roster push to all of the user's interested resources. That push contains the potential contact with a subscription state of "none" and shows that the subscription is pending, using an 'ask' attribute whose value is "subscribe" โณ.
US: <iq id='b89c5r7ib574'
to='romeo@example.net/foo'
type='set'>
<query xmlns='jabber:iq:roster'>
<item ask='subscribe'
jid='juliet@example.com'
subscription='none'/>
</query>
</iq>
US: <iq id='b89c5r7ib575'
to='romeo@example.net/bar'
type='set'>
<query xmlns='jabber:iq:roster'>
<item ask='subscribe'
jid='juliet@example.com'
subscription='none'/>
</query>
</iq>
If a remote contact doesn't approve or deny the request within some configurable amount of time, the user's server SHOULD resend the subscription request to the contact using an implementation-specific algorithm. For example, it might retry whenever a new resource becomes available for the user, or after a certain amount of time has passed. This helps recover from transient, silent errors that might have happened when the original request was routed to the remote domain ๐. When doing this, it is RECOMMENDED for the server to include an 'id' attribute, so it can track responses to the resent subscription request ๐ฏ.
3.1.3. Server Processing of Inbound Subscription Request
Before processing the inbound presence subscription request, the contact's server SHOULD check the syntax of the JID in the 'to' attribute ๐. If the JID is in the form <contact@domainpart/resourcepart> instead of <contact@domainpart>, the contact's server SHOULD treat it as if the request was aimed at the contact's bare JID and update the 'to' address to match. The server MAY also check that the JID follows the format in [XMPP-ADDR], and it might send back a <jid-malformed/> stanza error.
When processing the inbound presence subscription request, the contact's server MUST adhere to the following rules ๐:
- Above all, the contact's server MUST NOT automatically approve subscription requests on the contact's behalf ๐ซ. The only exceptions are if the contact has (a) pre-approved subscription requests from the user, as described under Section 3.4, (b) configured the account to automatically approve subscription requests, or (c) accepted an agreement with its service provider that allows automatic approval (for instance, through an employment agreement within an enterprise deployment). Instead, if a subscription request requires approval, then the contact's server MUST deliver that request to the contact's available resource(s) so the contact can approve or deny it ๐โโ๏ธ.
- If the contact exists and the user already has a subscription to the contact's presence, then the contact's server MUST auto-reply on behalf of the contact by sending a presence stanza of type "subscribed" from the contact's bare JID to the user's bare JID ๐ค. Likewise, if the contact previously sent a presence stanza of type "subscribed" and the contact's server treated that as indicating "pre-approval" for the user's presence subscription (see Section 3.4), then the contact's server SHOULD also auto-reply on behalf of the contact.
CS: <presence from='juliet@example.com'
id='xk3h1v69'
to='romeo@example.net'
type='subscribed'/>
- Otherwise, if at least one available resource is associated with the contact when the subscription request reaches the contact's server, then the contact's server MUST send that subscription request to all available resources in accordance with Section 8 ๐จ. As a way of acknowledging receipt, the contact's server MAY send a presence stanza of type "unavailable" from the contact's bare JID to the user's bare JID. The user's client MUST NOT assume that this acknowledgement provides presence information about the contact, since it comes from the contact's bare JID and arrives before the subscription request has been approved ๐.
- Otherwise, if the contact has no available resources when the subscription request reaches the contact's server, then the contact's server MUST keep a record of the complete presence stanza that makes up the subscription request, including any extended content in it (see Section 8.4 of [XMPP-CORE]). It then delivers the request when the contact next has an available resource ๐ฆ. The contact's server MUST continue delivering the subscription request whenever the contact creates an available resource, until the contact either approves or denies it. (The contact's server MUST NOT deliver more than one subscription request from any given user when the contact next has an available resource. For example, if the user sends multiple subscription requests while the contact is offline, the contact's server SHOULD store only one of them, such as the first or the last, and MUST deliver only one of them when the contact next has an available resource. This helps prevent "subscription request spam" ๐ โโ๏ธ.)
Security Warning: Until and unless the contact approves the subscription request as described under Section 3.1.4, the contact's server MUST NOT add an item for the user to the contact's roster. ๐
Security Warning: The mandate for the contact's server to store the complete stanza of the presence subscription request introduces the possibility of an application resource exhaustion attack (see Section 2.1.2 of [DOS]). For example, a rogue server or a coordinated group of users (like a botnet) could target the contact's server or a particular contact. Server implementers are advised to consider the possibility of such attacks and provide tools for counteracting them, such as letting service administrators set limits on the number or size of inbound presence subscription requests that the server will store, either in aggregate or for any given contact. ๐จ๐
3.1.4. Client Processing of Inbound Subscription Request
When an interactive client receives a subscription request, it MUST present the request to the natural person controlling the client (in other words, the "contact") for approval ๐โโ๏ธ. The only exception is when the contact has explicitly configured the client to automatically approve or deny some or all subscription requests, as described above. An automated client that isn't controlled by a natural person will have its own application-specific rules for approving or denying subscription requests ๐ค.
A client approves a subscription request by sending a presence stanza of type "subscribed". That gets processed as described under Section 3.1.5 for the contact's server and Section 3.1.6 for the user's server ๐.
CC: <presence id='h4v1c4kj'
to='romeo@example.net'
type='subscribed'/>
A client denies a subscription request by sending a presence stanza of type "unsubscribed". That gets processed as described under Section 3.2 for both the contact's server and the user's server ๐ โโ๏ธ.
CC: <presence id='tb2m1b59'
to='romeo@example.net'
type='unsubscribed'/>
For tracking purposes, a client SHOULD include an 'id' attribute in a subscription approval or subscription denial. This 'id' attribute MUST NOT mirror the 'id' attribute of the subscription request ๐งพโจ.
3.1.5. Server Processing of Outbound Subscription Approval
Okay, the contact's client sends the approval, and now the contact's server has to do the heavy lifting ๐
. It MUST stamp the outbound stanza with the contact's bare JID, <contact@domainpart>, and then either deliver it locally or route it remotely to the user ๐ฆ.
CS: <presence from='juliet@example.com'
id='h4v1c4kj'
to='romeo@example.net'
type='subscribed'/>
Next, the contact's server MUST send an updated roster push to all of the contact's interested resources, with the subscription attribute set to "from" ๐. (Here we're assuming the contact doesn't already have a subscription to the user. If they did, subscription would be "both", as explained under Appendix A.)
CS: <iq id='a78b4q6ha463'
to='juliet@example.com/balcony'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='romeo@example.net'
subscription='from'/>
</query>
</iq>
CS: <iq id='x81g3bdy4n19'
to='juliet@example.com/chamber'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='romeo@example.net'
subscription='from'/>
</query>
</iq>
From the contact's point of view, there's now a subscription from the user, which is why subscription says "from" ๐ธ. (Same caveat: if the contact already had a subscription to the user, it would say "both", per Appendix A.)
The contact's server MUST then also send current presence to the user from each of the contact's available resources ๐ง.
CS: <presence from='juliet@example.com/balcony'
id='pw72bc5j'
to='romeo@example.net'/>
CS: <presence from='juliet@example.com/chamber'
id='ux31da4q'
to='romeo@example.net'/>
If the contact wants to subscribe to the user's presence too, they'd have to send their own subscription request to the user. (XMPP clients will often send that request automatically, since the end goal is usually a mutual subscription ๐.) And when the contact does send that request, the subscription states will look different from the examples above, and the roles flip. See Appendix A for the details ๐.
3.1.6. Server Processing of Inbound Subscription Approval
When the user's server gets a subscription approval, it MUST first check whether the contact is in the user's roster with subscription='none' or subscription='from' and the ask flag set to "subscribe". That's a subscription state of "None + Pending Out", "None + Pending Out+In", or "From + Pending Out" (see Appendix A) ๐. If the check passes, the user's server MUST do the following:
- Deliver the inbound subscription approval to all of the user's interested resources. This is important because it gives the user's clients proper context, so they can tell a roster push from another one of the user's own resources apart from a subscription approval that came from the contact ๐ซถ. This MUST happen before the roster push in the next step is sent.
US: <presence from='juliet@example.com'
id='h4v1c4kj'
to='romeo@example.net'
type='subscribed'/>
- Start a roster push to all of the user's interested resources, containing an updated roster item for the contact. The
subscriptionattribute gets set to "to" (if the state was "None + Pending Out" or "None + Pending Out+In") or "both" (if the state was "From + Pending Out") ๐ฌ.
US: <iq id='b89c5r7ib576'
to='romeo@example.net/foo'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='juliet@example.com'
subscription='to'/>
</query>
</iq>
US: <iq id='b89c5r7ib577'
to='romeo@example.net/bar'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='juliet@example.com'
subscription='to'/>
</query>
</iq>
- The user's server MUST also deliver the available presence stanza received from each of the contact's available resources to each of the user's available resources ๐.
[ ... to resource1 ... ]
US: <presence from='juliet@example.com/balcony'
id='pw72bc5j'
to='romeo@example.net'/>
[ ... to resource2 ... ]
US: <presence from='juliet@example.com/balcony'
id='pw72bc5j'
to='romeo@example.net'/>
[ ... to resource1 ... ]
US: <presence from='juliet@example.com/chamber'
id='ux31da4q'
to='romeo@example.net'/>
[ ... to resource2 ... ]
US: <presence from='juliet@example.com/chamber'
id='ux31da4q'
to='romeo@example.net'/>
Implementation Note: Say the user's account has no available resources when the inbound approval comes in. The user's server MAY keep a record of the notification (ideally the whole presence stanza) and then deliver it once the account has an available resource again ๐ง . That gives the user a much clearer picture of why their roster changed while they were offline.
Otherwise, meaning the user doesn't exist, the contact isn't in the user's roster, or the contact is in the roster with a subscription state that isn't one of the ones in the check above, the user's server MUST silently ignore the subscription approval notification. That means it doesn't deliver it to the user, doesn't modify the user's roster, and doesn't generate a roster push to the user's interested resources ๐.
From the user's perspective, there's now a subscription to the contact's presence, which is why subscription says "to" ๐.
3.2. Canceling a Subscription โจ
3.2.1. Client Generation of Subscription Cancellation
If a contact wants to cancel a subscription they previously granted to a user, cancel a subscription pre-approval (Section 3.4), or deny a subscription request, they send a presence stanza of type "unsubscribed" ๐ซ.
CC: <presence id='ij5b1v7g'
to='romeo@example.net'
type='unsubscribed'/>
3.2.2. Server Processing of Outbound Subscription Cancellation
When the outbound subscription cancellation shows up, the contact's server MUST proceed as follows ๐ง.
- If the user's bare JID isn't in the contact's roster yet, or it is in the roster with a state of "None", "None + Pending Out", or "To", the contact's server SHOULD NOT route or deliver the presence stanza of type "unsubscribed" to the user. It also MUST NOT send presence notifications of type "unavailable" to the user, as described below ๐ฅฒ.
- If the user's bare JID is in the contact's roster with a state of "None", "None + Pending Out", or "To" and the
approvedflag is set to "true" (which signals a subscription pre-approval, as described under Section 3.4), the contact's server MUST remove the pre-approval. It MUST NOT route or deliver the presence stanza of type "unsubscribed" to the user ๐. - Otherwise, as the examples below show, the contact's server MUST route or deliver both the presence notifications of type "unavailable" and the presence stanzas of type "unsubscribed" to the user. It MUST also send a roster push to the contact ๐ .
Here's the thing: while the user is still subscribed to the contact's presence (so, before the contact's server routes or delivers the "unsubscribed" presence stanza), the contact's server MUST send a presence stanza of type "unavailable" from all of the contact's online resources to the user ๐ธ.
CS: <presence from='juliet@example.com/balcony'
id='i8bsg3h3'
type='unavailable'/>
CS: <presence from='juliet@example.com/chamber'
id='bvx2c9mk'
type='unavailable'/>
After that, the contact's server MUST route or deliver the presence stanza of type "unsubscribed" to the user. It has to stamp the outbound subscription cancellation with the contact's bare JID, <contact@domainpart> ๐.
CS: <presence from='juliet@example.com'
id='ij5b1v7g'
to='romeo@example.net'
type='unsubscribed'/>
Finally, the contact's server MUST send a roster push with the updated roster item to all of the contact's interested resources. At this point the subscription state is either "none" or "to" (see Appendix A) ๐ฆ.
CS: <iq id='pw3f2v175b34'
to='juliet@example.com/balcony'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='romeo@example.net'
subscription='none'/>
</query>
</iq>
CS: <iq id='zu2y3f571v35'
to='juliet@example.com/chamber'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='romeo@example.net'
subscription='none'/>
</query>
</iq>
3.2.3. Server Processing of Inbound Subscription Cancellation ๐
Okay bestie, when the user's server gets an inbound subscription cancellation, it MUST first check if the contact is in the user's roster with subscription='to' or subscription='both' (see Appendix A) ๐. If that check passes, then the user's server MUST do the following:
- Deliver the inbound subscription cancellation to all of the user's interested resources. This is so the user's client(s) get proper context about the cancellation ๐ง , so they can tell a roster push that came from another of the user's own resources apart from a subscription cancellation that came from the contact. This MUST occur before sending the roster push described in the next step.
US: <presence from='juliet@example.com'
id='ij5b1v7g'
to='romeo@example.net'
type='unsubscribed'/>
- Initiate a roster push to all of the user's interested resources. It contains an updated roster item for the contact with the
subscriptionattribute set to "none" (if the subscription state was "To" or "To + Pending In") or "from" (if the subscription state was "Both") ๐.
US: <iq id='h37h3u1bv400'
to='romeo@example.net/foo'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='juliet@example.com'
subscription='none'/>
</query>
</iq>
US: <iq id='h37h3u1bv401'
to='romeo@example.net/bar'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='juliet@example.com'
subscription='none'/>
</query>
</iq>
The user's server MUST also deliver the inbound presence stanzas of type "unavailable" ๐ฆ.
Implementation Note: If the user's account has no available resources when the inbound unsubscribed notification is received, the user's server MAY keep a record of the notification (ideally the complete presence stanza) and then deliver the notification when the account next has an available resource. This behavior provides more complete signaling to the user regarding the reasons for the roster change that occurred while the user was offline. ๐
Otherwise, that is, if the user does not exist, if the contact is not in the user's roster, or if the contact is in the user's roster with a subscription state other than the ones in the check above, then the user's server MUST silently ignore the unsubscribed notification ๐. That means it doesn't deliver it to the user, doesn't modify the user's roster, and doesn't generate a roster push to the user's interested resources.
3.3. Unsubscribing ๐ธ
3.3.1. Client Generation of Unsubscribe
If a user wants to unsubscribe from a contact's presence, they send a presence stanza of type "unsubscribe" ๐ .
UC: <presence id='ul4bs71n'
to='juliet@example.com'
type='unsubscribe'/>
3.3.2. Server Processing of Outbound Unsubscribe
Once the user's server gets the outbound unsubscribe, it MUST proceed as follows ๐ฎ.
- If the contact is hosted on the same server as the user, then the server MUST adhere to the rules in Section 3.3.3 when processing the unsubscribe.
- If the contact is hosted on a remote server, then, subject to local service policies, the user's server MUST route the stanza to that remote domain following the core XMPP stanza processing rules. This can result in an appropriate stanza error going back to the user, such as
<remote-server-timeout/>๐ฌ.
As mentioned, before locally delivering or remotely routing the unsubscribe, the user's server MUST stamp the stanza with the bare JID <user@domainpart> of the user ๐ท๏ธ.
US: <presence from='romeo@example.net'
id='ul4bs71n'
to='juliet@example.com'
type='unsubscribe'/>
After that, the user's server MUST send a roster push with the updated roster item to all of the user's interested resources, where the subscription state is now "none" or "from" (see Appendix A) โจ.
US: <iq id='h37h3u1bv402'
to='romeo@example.net/foo'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='juliet@example.com'
subscription='none'/>
</query>
</iq>
US: <iq to='romeo@example.net/bar'
type='set'
id='h37h3u1bv403'>
<query xmlns='jabber:iq:roster'>
<item jid='juliet@example.com'
subscription='none'/>
</query>
</iq>
3.3.3. Server Processing of Inbound Unsubscribe
When the contact's server receives the unsubscribe notification, it MUST first check if the user's bare JID is in the contact's roster with subscription='from' or subscription='both'. That means a subscription state of "From", "From + Pending Out", or "Both" (see Appendix A) ๐. If that check passes, then the contact's server MUST do the following:
- Deliver the inbound unsubscribe to all of the contact's interested resources. This gives the contact's client(s) proper context about the unsubscribe ๐งฉ, so they can tell a roster push from another of the contact's resources apart from an unsubscribe that came from the user. This MUST occur before sending the roster push described in the next step.
CS: <presence from='romeo@example.net'
id='ul4bs71n'
to='juliet@example.com'
type='unsubscribe'/>
- Initiate a roster push to all of the contact's interested resources. It contains an updated roster item for the user with the
subscriptionattribute set to "none" (if the subscription state was "From" or "From + Pending Out") or "to" (if the subscription state was "Both") ๐.
CS: <iq id='tn2b5893g1s4'
to='juliet@example.com/balcony'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='romeo@example.net'
subscription='none'/>
</query>
</iq>
CS: <iq id='sp3b56n27hrp'
to='juliet@example.com/chamber'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='romeo@example.net'
subscription='none'/>
</query>
</iq>
- Generate an outbound presence stanza of type "unavailable" from each of the contact's available resources to the user ๐.
CS: <presence from='juliet@example.com/balcony'
id='o5v91w49'
to='romeo@example.net'
type='unavailable'/>
CS: <presence from='juliet@example.com/chamber'
id='n6b1c37k'
to='romeo@example.net'
type='unavailable'/>
Implementation Note: If the contact's account has no available resources when the inbound unsubscribe notification is received, the contact's server MAY keep a record of the notification (ideally the complete presence stanza) and then deliver the notification when the account next has an available resource. This behavior provides more complete signaling to the user regarding the reasons for the roster change that occurred while the user was offline. ๐
Otherwise, that is, if the contact does not exist, if the user is not in the contact's roster, or if the user's bare JID is in the contact's roster with a subscription state other than the ones in the check above, then the contact's server MUST silently ignore the unsubscribe stanza ๐. That means it doesn't deliver it to the contact, doesn't modify the contact's roster, and doesn't generate a roster push to the contact's interested resources. However, if the contact's server is keeping track of an inbound presence subscription request from the user to the contact, but the user is not yet in the contact's roster (functionally equivalent to a subscription state of "None + Pending In" where the contact never added the user to the contact's roster), then the contact's server MUST simply remove any record of the inbound presence subscription request. It cannot remove the user from the contact's roster, because the user was never added to it ๐ซถ.
Implementation Note: The user's client MUST NOT depend on receiving the unavailable presence notification from the contact, since it MUST consider its presence subscription to the contact, and its presence information about the contact, to be null and void when it sends the presence stanza of type "unsubscribe" or when it receives the roster push triggered by the unsubscribe request. ๐
3.4. Pre-Approving a Subscription Request ๐ง
If a user hasn't received a subscription request from a contact, the user can "pre-approve" that request, so the user's server will approve it automatically ๐ฆ.
Support for subscription pre-approvals is OPTIONAL on the part of clients and servers. If a server supports subscription pre-approvals, then it MUST advertise the following stream feature during stream negotiation ๐.
<sub xmlns='urn:xmpp:features:pre-approval'/>
The subscription pre-approval stream feature is merely informative, so it is never mandatory-to-negotiate ๐.
3.4.1. Client Generation of Subscription Pre-Approval
If the server a client connects to has advertised support for subscription pre-approvals, the client MAY generate a subscription pre-approval by sending a presence stanza of type "subscribed" to the contact ๐.
UC: <presence id='pg81vx64'
to='juliet@example.com'
type='subscribed'/>
If the server does not advertise support for subscription pre-approvals, the client MUST NOT attempt to pre-approve subscription requests from potential or actual contacts ๐ซ.
3.4.2. Server Processing of Subscription Pre-Approval โจ
okay so when a presence stanza of type "subscribed" shows up at the user's server, the server MUST follow these steps, but only if it supports subscription pre-approvals ๐
Here's the breakdown:
- If the contact is in the user's roster with a state of
"Both","From", or"From + Pending Out", the user's server MUST silently ignore the stanza. ๐ - If the contact is in the user's roster with a state of
"To + Pending In","None + Pending In", or"None + Pending Out+In", the user's server MUST handle the stanza as a normal subscription approval (see under Section 3.1.5). That means updating the existing roster item to a state of"Both","From", or"From + Pending Out"(respectively), pushing the modified roster item to all of the user's interested resources, and routing the presence stanza of type"subscribed"to the contact. ๐ฅ - If the contact is in the user's roster with a state of
"To","None", or"None + Pending Out", the user's server MUST note the subscription pre-approval by setting theapprovedflag to a value of"true", then push the modified roster item to all of the user's interested resources. BUT the user's server MUST NOT route the presence stanza of type"subscribed"to the contact. ๐ - If the contact is not yet in the user's roster, the user's server MUST create a roster item for the contact with a state of
"None"and set theapprovedflag to a value of"true", then push the roster item to all of the user's interested resources. Again, the user's server MUST NOT route the presence stanza of type"subscribed"to the contact. ๐ซถ
Here's an example of the roster push ๐
US: <iq id='h3bs81vs763f'
to='romeo@example.net/bar'
type='set'>
<query xmlns='jabber:iq:roster'>
<item approved='true'
jid='juliet@example.com'
subscription='none'/>
</query>
</iq>
When the approved flag is set to "true", the user's server MUST NOT deliver a presence stanza of type "subscribe" from the contact to the user. Instead, it MUST automatically respond to that stanza on the user's behalf by returning a presence stanza of type "subscribed" from the bare JID of the user to the bare JID of the contact. Main character server behavior ๐
Implementation Note: It is a matter of implementation or local service policy whether the server maintains a record of the subscription approval after it has received a presence subscription request from the contact. If the server does not maintain such a record, then upon receiving the subscription request it will not include theapprovedattribute in the roster item for the contact (i.e., in subsequent roster pushes and roster results). If the server does maintain such a record, it will always include theapprovedattribute (set to"true") in the roster item for the contact, until and unless the user sends a presence stanza of type"unsubscribed"to the contact (or removes the contact from the roster entirely). ๐ง
Implementation Note: A client can cancel a pre-approval by sending a presence stanza of type"unsubscribed", as described more fully under Section 3.2. In this case, the user's server would send a roster push to all of the user's interested resources with theapprovedattribute removed. (Alternatively, the client can simply remove the roster item entirely.) ๐
4. Exchanging Presence Information โจ
4.1. Presence Fundamentals ๐ฆ
Presence is all about an entity's availability for communication over a network. At the most basic level, it's a boolean "on/off" variable that signals whether an entity is available or unavailable for communication (people also say "online" and "offline"). In XMPP, an entity is signaled as available when its client generates a <presence/> stanza with no type attribute. An entity's lack of availability is signaled when its client generates a <presence/> stanza whose type attribute has a value of "unavailable". Simple but iconic ๐
XMPP presence typically follows a "publish-subscribe" or "observer" pattern. An entity sends presence to its server, and then its server broadcasts that info to all of the entity's contacts who have a subscription to the entity's presence. (In the terminology of [IMP-MODEL], an entity that generates presence is a "presentity", and the entities that receive presence are "subscribers".) A client generates presence for broadcast to all subscribed entities by sending a presence stanza to its server with no to address. That stanza has either no type attribute or a type attribute whose value is "unavailable". This kind of presence is called "broadcast presence". ๐ฃ
A client can also send "directed presence", which is a presence stanza with a to address. It's less common, but sometimes it's used to send presence to entities that are not subscribed to the user's presence. See Section 4.6 for more on that. ๐ซฃ
After a client completes the preconditions specified in [XMPP-CORE], it can establish a "presence session" at its server by sending initial presence (Section 4.2). That presence session is terminated by sending unavailable presence (Section 4.5). For the duration of its presence session, a connected resource (in the terminology of [XMPP-CORE]) is said to be an "available resource". โญ
In XMPP, applications that combine messaging and presence functionality default to messaging as the type of communication that presence signals availability for. It's not necessary for XMPP applications to combine the two, though. They can provide standalone presence features without messaging. (Also, XMPP servers don't need info about network availability to successfully route message and IQ stanzas. Good to know! ๐ง )
Informational Note: In the examples that follow, the user is<juliet@example.com>. She has two available resources, "balcony" and "chamber", and she has three contacts in her roster with a subscription state of "from" or "both":<romeo@example.net>,<mercutio@example.com>, and<benvolio@example.net>. ๐
4.2. Initial Presence ๐ธ
4.2.1. Client Generation of Initial Presence
After completing the preconditions described in [XMPP-CORE] (REQUIRED) and requesting the roster (RECOMMENDED), a client signals its availability for communication by sending "initial presence" to its server. Initial presence is a presence stanza with no to address (meaning the server broadcasts it on the client's behalf) and no type attribute (meaning the user is available). ๐
UC: <presence/>
The initial presence stanza MAY contain the <priority/> element, the <show/> element, and one or more instances of the <status/> element. It can also have extended content. Details are under Section 4.7. โจ
4.2.2. Server Processing of Outbound Initial Presence
Upon receiving initial presence from a client, the user's server MUST send the initial presence stanza from the full JID <user@domainpart/resourcepart> of the user to all contacts that are subscribed to the user's presence. Those contacts are the ones with a JID in the user's roster whose subscription attribute is set to "from" or "both". ๐ซถ
US: <presence from='juliet@example.com/balcony'
to='romeo@example.net'/>
US: <presence from='juliet@example.com/balcony'
to='mercutio@example.com'/>
US: <presence from='juliet@example.com/balcony'
to='benvolio@example.net'/>
The user's server MUST also broadcast initial presence from the user's newly available resource to all of the user's available resources. That includes the resource that generated the presence in the first place, because an entity is implicitly subscribed to its own presence. Mirror mirror ๐ช
[... to the "balcony" resource ...]
US: <presence from='juliet@example.com/balcony'
to='juliet@example.com'/>
[... to the "chamber" resource ...]
US: <presence from='juliet@example.com/balcony'
to='juliet@example.com'/>
And if there's no presence info about the user's contacts, the user's server MUST also send presence probes to those contacts on the user's behalf, as specified under Section 4.3. ๐
4.2.3. Server Processing of Inbound Initial Presence
Upon receiving presence from the user, the contact's server MUST deliver the user's presence stanza to all of the contact's available resources. ๐ฌ
[ ... to resource1 ... ]
CS: <presence from='juliet@example.com/balcony'
to='romeo@example.net'/>
[ ... to resource2 ... ]
CS: <presence from='juliet@example.com/balcony'
to='romeo@example.net'/>
4.2.4. Client Processing of Initial Presence
When the contact's client receives presence from the user, the following behavior is suggested for interactive clients:
- If the user's bare JID is in the contact's roster, display the presence information in an appropriate roster interface. ๐
- If the user is not in the contact's roster but the contact and the user are actively exchanging message or IQ stanzas, display the presence information in the user interface for that communication session (see also Section 4.6 and Section 5.1). ๐ฌ
- Otherwise, ignore the presence information and do not display it to the contact. ๐
4.3. Presence Probes ๐ฎ
A "presence probe" is a request for a contact's current presence information, sent on a user's behalf by the user's server. Syntactically, it's a presence stanza whose type attribute has a value of "probe". In the context of presence subscriptions, the from address MUST be the bare JID of the subscribed user, and the to address MUST be the bare JID of the contact the user is subscribed to. Subscriptions are based on the bare JID, so that's the rule ๐
US: <presence from='juliet@example.com'
id='ign291v5'
to='romeo@example.net'
type='probe'/>
Interoperability Note: RFC 3921 specified that probes are sent from the full JID, not the bare JID. That rule was changed because subscriptions are based on the bare JID. Some existing implementations still send from the full JID instead of the bare JID. ๐ฐ๏ธ
Probes can also be sent by an entity that has received presence outside the context of a presence subscription. This typically happens when the contact has sent directed presence as described under Section 4.6. In that case, the from or to address can be a full JID instead of a bare JID. See Section 4.6 for the full scoop. ๐
Presence probes SHOULD NOT be sent by a client, because a client generally won't need to send them. Gathering presence from a user's contacts is managed by the user's server. However, if a user's client does generate an outbound presence probe, then the user's server SHOULD route the probe (if the contact is at another server) or process the probe (if the contact is at the same server). The server MUST NOT use its receipt of the presence probe from a connected client as the sole cause for returning a stanza or stream error to the client. Server, don't you dare throw an error just for that ๐ โโ๏ธ
4.3.1. Server Generation of Outbound Presence Probe โจ
Okay so, when a server wants to figure out whether one of the user's contacts is around ๐, it sends a presence probe from the user's bare JID <user@domainpart> to the contact's bare JID <contact@domainpart>. Simple, but so important ๐
Implementation Note: Presence probes are meant to go to contacts (aka entities the user is subscribed to), but a server MAY send a presence probe to the full JID of an entity that the user has received presence from during the current session. Lowkey useful ๐ง
The user's server SHOULD send a presence probe whenever the user starts a new presence session by sending initial presence ๐. The server MAY choose not to send the probe at that point, though, if it already has what it considers reliable and up-to-date presence info about the user's contacts. This could happen because the user has another available resource, or because they briefly logged off and back on before the new session started. Also, a server MAY periodically send a presence probe to a contact if it hasn't gotten any presence info or other traffic from that contact in some configurable amount of time. This helps stop "ghost" contacts who look online but aren't actually online ๐ป๐
US: <presence from='juliet@example.com'
id='ign291v5'
to='romeo@example.net'
type='probe'/>
US: <presence from='juliet@example.com'
id='xv291f38'
to='mercutio@example.com'
type='probe'/>
Naturally, the user's server doesn't need to send a presence probe to a contact whose account is on the same server as the user, since the server already has that contact's info locally ๐
4.3.2. Server Processing of Inbound Presence Probe โจ
Okay, this is the part where the contact's server has to respond, and it MUST reply as follows ๐ซถ Upon getting a presence probe to the contact's bare JID from the user's server (on behalf of the user), the contact's server MUST reply using whichever of these rules applies:
Rule 1. If the contact account doesn't exist, or the user's bare JID is in the contact's roster with a subscription state other than "From", "From + Pending Out", or "Both" (as explained under Appendix A), then the contact's server SHOULD return a presence stanza of type "unsubscribed" in response to the presence probe. This triggers a protocol flow for canceling the user's subscription to the contact, as described under Section 3.2. However, this MUST NOT result in cancellation of a subscription pre-approval, as described under Section 3.4 ๐ Also, the 'from' address MUST be the bare JID of the contact, because specifying a full JID would be a presence leak as described in [XMPP-CORE] ๐
CS: <presence from='mercutio@example.com'
id='xv291f38'
to='juliet@example.com'
type='unsubscribed'/>
That said, if a server gets a presence probe from a configured domain of the server itself or from another trusted service, it MAY provide presence information about the user to that entity ๐ฅ
Rule 2. Else, if the contact has moved temporarily or permanently to another address, then the server SHOULD return a presence stanza of type "error" with a stanza error condition of <redirect/> (temporary) or <gone/> (permanent). That error should include the contact's new address ๐งณ
CS: <presence from='mercutio@example.com'
id='xv291f38'
to='juliet@example.com'
type='error'>
<error type='modify'>
<gone xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>
xmpp:la-mer@example.com
</gone>
</error>
</presence>
Rule 3. Else, if the contact has no available resources, then the server SHOULD reply to the presence probe by sending the user a presence stanza of type "unavailable". Sending unavailable presence here is preferable, because it gives a deterministic answer to the probe. It isn't mandatory, though, because it can greatly increase the number of presence notifications the contact's server generates ๐ Here the 'from' address is the bare JID, because there's no available resource associated with the contact. If local security policies allow it, this presence notification MAY include the full XML of the last unavailable presence stanza the server received from the contact (including the 'id' of the original stanza). If not, the presence notification SHOULD simply say the contact is unavailable, without any of the original details. Either way, the presence notification returned to the probing entity SHOULD include info about when the last unavailable presence stanza was generated, formatted using the XMPP delayed delivery extension [DELAY] โฐ
CS: <presence from='mercutio@example.com'
id='xv291f38'
to='juliet@example.com'
type='unavailable'>
<delay xmlns='urn:xmpp:delay'
stamp='2002-09-10T23:41:07Z'/>
</presence>
Rule 4. Else, if the contact has at least one available resource, then the server MUST reply to the presence probe by sending the user the full XML of the last presence stanza with no 'to' attribute that the server received from each of the contact's available resources. Here, the 'from' addresses are the full JIDs of each available resource ๐
CS: <presence from='romeo@example.net/foo'
id='hzf1v27k'
to='juliet@example.com'/>
CS: <presence from='romeo@example.net/bar'
id='ps6t1fu3'
to='juliet@example.com'>
<show>away</show>
</presence>
Implementation Note: "Full XML" means the complete stanza, from the opening <presence> tag to the closing </presence> tag. That includes all elements and attributes, whether they're qualified by the content namespace or by extended namespaces. However, per [XMPP-CORE], if the contact's server sends the complete stanza over a server-to-server stream, it needs to transform the content namespace from 'jabber:client' to 'jabber:server' ๐
If the contact's server gets a presence probe addressed to a full JID of the contact, it MUST NOT return presence info about any resource except the one named in the probe's 'to' address. Rules #1 and #2 for bare JID probes apply just the same to full JID probes ๐ If there's a resource matching that full JID, and the probing entity is authorized via a presence subscription to see the contact's presence, then the server MUST return an available presence notification. That notification SHOULD only communicate the fact that the resource is available, not detailed stuff like <show/>, <status/>, <priority/>, or presence extensions ๐คซ
CS: <presence from='romeo@example.net/bar'
to='lobby@chat.example.com'/>
Implementation Note: Check out Section 4.6 for extra rules that supplement all of this for directed presence ๐
4.3.2.1. Handling of the 'id' Attribute โจ
Okay, this one's a little plot twist ๐ญ The 'id' attribute for presence probes wasn't specified in RFC 3921. You might think "send a probe, get a reply" is a request-response thing, like the XMPP <iq/> stanza. But it isn't! A single probe can get back multiple presence stanzas, one for each active available resource the contact has ๐งฉ So, if the contact currently has available resources, the contact's server SHOULD preserve the 'id' attribute of the contact's original presence stanza (if there is one) when it sends those presence notifications to the probing entity. On the flip side, if the contact has no available resources, if the probing entity isn't authorized (via presence subscription) to see the contact's presence, or if an error happens with the probe, then the contact's server SHOULD mirror the 'id' of the user's presence probe in its reply ๐ช
Here are two examples so you can see the difference ๐
In the first scenario, Juliet sends presence from her "chamber" resource.
CC: <presence from='juliet@example.com/chamber' id='pres1'>
<show>dnd</show>
<status>busy!</status>
</presence>
She also sends presence from her "balcony" resource.
CC: <presence from='juliet@example.com/balcony' id='pres2'>
<show>away</show>
<status>stepped away</status>
</presence>
Then Romeo's server sends a probe to Juliet.
US: <presence from='romeo@example.net' id='probe1' type='probe'/>
Juliet's server then sends both of her presence notifications to Romeo, keeping the 'id' attributes from the stanzas her client sent ๐
CS: <presence from='juliet@example.com/chamber' id='pres1'>
<show>dnd</show>
<status>busy!</status>
</presence>
CS: <presence from='juliet@example.com/balcony' id='pres2'>
<show>away</show>
<status>stepped away</status>
</presence>
In the second scenario, Juliet is offline when Romeo's server sends a probe.
US: <presence from='romeo@example.net'
id='probe2'
type='probe'/>
Juliet's server replies with an unavailable notification that mirrors the 'id' of Romeo's presence probe, because there's no 'id' from an available notification that her client sent to preserve ๐ธ
CS: <presence from='juliet@example.com'
id='probe2'
type='unavailable'/>
4.4. Subsequent Presence Broadcast โจ
4.4.1. Client Generation of Subsequent Presence Broadcast ๐ฆ
After sending initial presence, the user's client can update its availability for broadcast at any time during its session. It just sends a presence stanza with no 'to' address and no 'type' attribute ๐
UC: <presence>
<show>away</show>
</presence>
The presence broadcast MAY contain the <priority/> element, the <show/> element, and one or more instances of the <status/> element, as well as extended content. Details are under Section 4.7 ๐
That said, a user SHOULD send a presence update only to broadcast info that's relevant to the user's availability for communication, or to the communication capabilities of the resource ๐ง Info that isn't relevant in that way might still interest the user's contacts, but it SHOULD be sent via other means, like the "publish-subscribe" method described in [XEP-0163] ๐ซง
4.4.2. Server Processing of Subsequent Outbound Presence โจ
Okay bestie, so when the user's server gets a presence stanza saying their availability changed, it's giving broadcast ๐ฃ. The user's server MUST broadcast the full XML of that presence stanza to the contacts who are in the user's roster with a subscription type of "from" or "both" ๐.
Interoperability Note: Back in RFC 3921, the user's server checked whether it had received a presence error from the contact before sending subsequent presence notifications. That rule is gone now ๐ โโ๏ธ. This spec uses presence stanzas of type "unsubscribe" (not "error") to fix subscription synchronization problems, partly because those stanzas change the contact's subscription state in the user's roster to either "none" or "to" (see Section 3.3 and Appendix A). So the error check isn't needed anymore ๐ .
Interoperability Note: If the subscription type is "both", some existing server implementations only send subsequent presence notifications to a contact if the contact is online according to the user's server. That means if the user's server never got a positive indication that the contact is online in response to the presence probe it sent, the user's server doesn't send subsequent presence notifications from the user to the contact ๐ค. This is perceived to save bandwidth, since most presence subscriptions are bidirectional and many contacts won't be online at any given time ๐ธ.
US: <presence from='juliet@example.com/balcony'
to='romeo@example.net'>
<show>away</show>
</presence>
US: <presence from='juliet@example.com/balcony'
to='benvolio@example.net'>
<show>away</show>
</presence>
US: <presence from='juliet@example.com/balcony'
to='mercutio@example.com'>
<show>away</show>
</presence>
Implementation Note: See Section 4.6 for the rules that supplement the above for handling directed presence ๐ง.
The user's server MUST also send the presence stanza to all of the user's available resources, including the resource that generated the presence notification in the first place ๐.
US: <presence from='juliet@example.com/balcony'
to='juliet@example.com/chamber'>
<show>away</show>
</presence>
US: <presence from='juliet@example.com/balcony'
to='juliet@example.com/balcony'>
<show>away</show>
</presence>
4.4.3. Server Processing of Subsequent Inbound Presence ๐ฆ
Upon receiving presence from the user, the contact's server MUST deliver the user's presence stanza to all of the contact's available resources. Main character energy for every single device ๐.
[ ... to resource1 ... ]
CS: <presence from='juliet@example.com/balcony'
to='romeo@example.net'>
<show>away</show>
</presence>
[ ... to resource2 ... ]
CS: <presence from='juliet@example.com/balcony'
to='romeo@example.net'>
<show>away</show>
</presence>
4.4.4. Client Processing of Subsequent Presence ๐ซถ
From the contact's client's point of view, there's no significant difference between the initial presence broadcast and subsequent presence. So the contact's client just follows the rules for processing inbound presence in Section 4.4.3. Honestly so clean ๐ญ.
4.5. Unavailable Presence ๐
4.5.1. Client Generation of Unavailable Presence
Before ending its presence session with a server, the user's client SHOULD gracefully become unavailable by sending "unavailable presence". That's a presence stanza with no 'to' attribute and with a 'type' attribute whose value is "unavailable" ๐.
UC: <presence type='unavailable'/>
Optionally, the unavailable presence stanza MAY contain one or more <status/> elements that say why the user is no longer available ๐.
UC: <presence type='unavailable'>
<status>going on vacation</status>
</presence>
However, the unavailable presence stanza MUST NOT contain the <priority/> element or the <show/> element, since those elements only apply to available resources ๐.
4.5.2. Server Processing of Outbound Unavailable Presence
The user's server MUST NOT depend on receiving unavailable presence from an available resource ๐. A resource might go unavailable ungracefully, like its XML stream getting closed with or without a stream error for any of the reasons described in [XMPP-CORE].
If an available resource becomes unavailable for any reason (gracefully or ungracefully), the user's server MUST broadcast unavailable presence to all contacts in the user's roster with a subscription type of "from" or "both" ๐ฃ.
Interoperability Note: Back in RFC 3921, the user's server checked whether it had received a presence error from the contact before sending unavailable presence notifications. That rule is removed now. This spec uses presence stanzas of type "unsubscribe" (not "error") to solve subscription synchronization problems, partly because those stanzas change the contact's subscription state in the user's roster to either "none" or "to" (see Section 3.3 and Appendix A), so the error check is obsolete ๐ซ .
Implementation Note: Even if the user's server doesn't broadcast the user's subsequent presence notifications to contacts who are offline (as described under Section 4.4.2), it MUST broadcast the user's unavailable presence notification. If it didn't, the last presence the contact's server received would be the user's initial presence for the presence session, and the contact would think the user is online ๐ฑ.
Implementation Note: See Section 4.6 for the rules that supplement the above for handling directed presence ๐ง.
If the unavailable notification was gracefully received from the client, then the server MUST broadcast the full XML of the presence stanza โจ.
US: <presence from='juliet@example.com/balcony'
to='romeo@example.net'
type='unavailable'>
<status>going on vacation</status>
</presence>
US: <presence from='juliet@example.com/balcony'
to='benvolio@example.net'
type='unavailable'>
<status>going on vacation</status>
</presence>
US: <presence from='juliet@example.com/balcony'
to='mercutio@example.com'
type='unavailable'>
<status>going on vacation</status>
</presence>
The user's server MUST also send the unavailable notification to all of the user's available resources, as well as to the resource that generated the unavailable presence in the first place ๐.
US: <presence from='juliet@example.com/balcony'
to='juliet@example.com/chamber'
type='unavailable'>
<status>going on vacation</status>
</presence>
If the server detects that the user has gone offline ungracefully, then the server MUST generate the unavailable presence broadcast on the user's behalf ๐ฅบ.
Implementation Note: Any presence stanza with no 'type' attribute and no 'to' attribute that the client sends after the server broadcasts or generates an unavailable presence notification MUST be routed or delivered by the user's server to all subscribers. In other words, it MUST be treated as equivalent to initial presence for a new presence session ๐.
4.5.3. Server Processing of Inbound Unavailable Presence
Upon receiving an unavailable notification from the user, the contact's server MUST deliver the user's presence stanza to all of the contact's available resources ๐.
[ ... to resource1 ... ]
CS: <presence from='juliet@example.com/balcony'
to='romeo@example.net'
type='unavailable'>
<status>going on vacation</status>
</presence>
[ ... to resource2 ... ]
CS: <presence from='juliet@example.com/balcony'
to='romeo@example.net'
type='unavailable'>
<status>going on vacation</status>
</presence>
Implementation Note: If the contact's server doesn't broadcast subsequent presence notifications to users who are offline (as described under Section 4.4.2), it MUST also update its internal representation of which entities are online by noting that the user is unavailable ๐๏ธ.
4.5.4. Client Processing of Unavailable Presence ๐ซง
From the contact's client's point of view, there's no significant difference between an available presence broadcast and an unavailable presence broadcast. So in general, the contact's client follows the rules for processing inbound presence in Section 4.4.3 ๐.
However, if the contact receives an unavailable notification from the bare JID of the user (rather than the full JID of a particular available resource), the contact's client SHOULD treat the unavailable notification as applying to all resources ๐ธ.
4.6. Directed Presence ๐
This section adds to the rules for client and server processing of presence notifications and presence probes, but only for the special case of directed presence ๐งโโ๏ธ.
4.6.1. General Considerations
In general, a client sends directed presence when it wants to share availability info with an entity that isn't subscribed to its presence, usually on a temporary basis โณ. Common uses of directed presence include casual one-to-one chat sessions (as described under Section 5.1) and multi-user chat rooms (as described in [XEP-0045]) ๐.
The temporary relationship made by sharing directed presence with another entity is secondary to the permanent relationship made through a presence subscription. So the acts of creating, modifying, or canceling a presence subscription MUST take precedence over the rules in the following subsections ๐. For example, if a user shares directed presence with a contact but then adds the contact to the user's roster by completing the presence subscription "handshake", the user's server MUST treat that contact just like any normal subscriber as described under Section 3. That means things like sending subsequent presence broadcasts to the contact ๐ค. As another example, if the user then cancels the contact's subscription to the user's presence, the user's server MUST handle the cancellation just like it normally would as described under Section 3.2. That includes sending unavailable presence to the contact, even if the user has sent directed presence to the contact ๐.
XMPP servers usually do directed presence by keeping a list of the entities (bare JIDs or full JIDs) that a user has sent directed presence to during the user's current session for a given resource (full JID). Then they clear the list when the user goes offline (for example, by sending a broadcast presence stanza of type "unavailable") ๐งน. The server MUST remove from the directed presence list (or its functional equivalent) any entity that the user sends directed unavailable presence to, and SHOULD remove any entity that sends unavailable presence to the user ๐ .
4.6.2. Client Generation of Directed Presence
As we just covered, directed presence is a client-generated presence stanza. It has a 'to' attribute whose value is the bare JID or full JID of the other entity, and it has either no 'type' attribute (meaning availability) or a 'type' attribute whose value is "unavailable" ๐ฆโจ.
4.6.3. Server Processing of Outbound Directed Presence โจ
okay so when the user's server gets a directed presence stanza, it SHOULD handle it using these rules ๐
- okay so if the user sends directed available or unavailable presence to a contact who's in their roster with a subscription type of "from" or "both" ๐ฆ, after sending initial presence but before sending unavailable presence broadcast (aka during the user's presence session), the user's server MUST locally deliver or remotely route the full XML of that presence stanza. It SHOULD NOT otherwise change the contact's status regarding presence broadcast, which means it SHOULD include the contact's JID in any later presence broadcasts the user starts. ๐
- if the user sends directed presence to an entity who's NOT in their roster with a subscription type of "from" or "both" during that same presence session ๐ธ, the user's server MUST locally deliver or remotely route the full XML of that presence stanza to the entity. It MUST NOT change the contact's status regarding available presence broadcast, so it MUST NOT include the entity's JID in any later broadcasts of available presence the user starts. BUT, if the available resource that sent the directed presence becomes unavailable, the user's server MUST route that unavailable presence to the entity (as long as the user hasn't already sent directed unavailable presence to that entity). ๐ญ
- if the user sends directed presence without first sending initial presence, or after sending unavailable presence broadcast (so the resource is connected but not available) ๐ง, the user's server MUST treat the entity they sent it to as in case #2 above. ๐
4.6.4. Server Processing of Inbound Directed Presence โจ
from the contact's server's point of view, there's no real difference between presence broadcast and directed presence ๐. So the contact's server follows the rules for processing inbound presence defined under Sections 4.3.2, 4.4.3, and 4.5.3. ๐ซถ
4.6.5. Client Processing of Inbound Directed Presence โจ
same vibe on the contact's client side ๐. There's no big difference between presence broadcast and directed presence, so the contact's client follows the rules for processing inbound presence defined under Section 4.4.3. ๐
4.6.6. Server Processing of Presence Probes โจ
okay this one is lowkey so important ๐. Say a user's client sent directed presence to another entity (like a one-to-one chat partner or a multi-user chat room). After a while, that entity or its server might wanna know if the client is still online ๐. This is super common in multi-user chat rooms, where someone might stay in the room for a long time โณ. If the user's client goes offline and nobody tells the room (either the client or the client's server), the user can turn into a "ghost" ๐ป: they look like they're still hanging out, but they're actually gone. To catch these "ghosts", some multi-user chat room implementations send presence probes to users who've joined the room ๐ต๏ธโโ๏ธ.
In the case of directed presence, the probing entity SHOULD send the probe from the JID that received the directed presence (whether that's a full JID or a bare JID) ๐ฆ. The probe SHOULD go to the user's full JID, NOT the user's bare JID without a resourcepart ๐ โโ๏ธ, because the temporary "authorization" that comes with directed presence is based on the full JID the user sent directed presence from to the probing entity. When the user's server gets a probe, it MUST first apply any logic tied to presence subscriptions, as described under Section 4.3.2 ๐ . If the probing entity doesn't have a subscription to the user's presence, then the server MUST check whether the user sent directed presence to that entity during its current session. If it did, the server SHOULD answer the probe with only mere presence of type "available" or "unavailable" (so no child elements), and ONLY for that full JID (not any other resources that might be connected to the user's bare JID) โจ.
4.7. Presence Syntax ๐
4.7.1. Type Attribute ๐
no type attribute at all means the entity is available for communication (see Section 4.2 and Section 4.4) ๐ท.
A type attribute with the value "unavailable" means the entity is NOT available for communication (see Section 4.5) ๐ฅ.
The XMPP presence stanza is also used to negotiate and manage subscriptions to other entities' presence ๐ฌ. These jobs get done with presence stanzas of type "subscribe", "unsubscribe", "subscribed", and "unsubscribed", as described under Section 3 ๐ซถ.
If a user and a contact are on different XMPP servers, those servers also use a special presence stanza of type "probe" to figure out whether the entity is available on the peer server ๐. The details are under Section 4.3. Clients SHOULD NOT send presence stanzas of type "probe" ๐ โโ๏ธ.
The values of the type attribute go like this ๐
:
- error -- an error happened while processing a presence stanza that was sent earlier. If the presence stanza is of type "error", it MUST include an
<error/>child element (check out [XMPP-CORE]) ๐ญ. - probe -- a request for an entity's current presence. It SHOULD only be generated by a server on behalf of a user ๐ต๏ธโโ๏ธ.
- subscribe -- the sender wants to subscribe to the recipient's presence ๐ฌ.
- subscribed -- the sender has let the recipient receive their presence ๐ฆ.
- unavailable -- the sender is no longer available for communication ๐.
- unsubscribe -- the sender is unsubscribing from the receiver's presence ๐.
- unsubscribed -- the subscription request was denied, or a subscription that was granted has been canceled ๐ฅฒ.
If the type attribute's value isn't one of those values, the recipient or an intermediate router SHOULD return a stanza error of <bad-request/> ๐ซ.
Implementation Note: There is no default value for the 'type' attribute of the <presence/> element. ๐
Implementation Note: There is no value of "available" for the 'type' attribute of the <presence/> element. ๐
4.7.2. Child Elements ๐ธ
Because of the default namespace declaration, a presence stanza is qualified by the 'jabber:client' or 'jabber:server' namespace ๐. That namespace defines certain child elements of presence stanzas, especially <show/>, <status/>, and <priority/>. These child elements give more detailed info about an entity's availability ๐. Usually they only show up if the presence stanza has no 'type' attribute, though the text that follows notes some exceptions ๐.
4.7.2.1. Show Element ๐
The OPTIONAL <show/> element gives the specific availability sub-state of an entity, or of one of its specific resources ๐ฆ. A presence stanza MUST NOT contain more than one <show/> element. There are no attributes defined for the <show/> element. The <show/> element MUST NOT contain mixed content (as defined in Section 3.2.2 of [XML]). The XML character data of the <show/> element isn't meant to be shown to a human user ๐. The XML character data MUST be one of the following (more availability states could be defined through extended content elements) ๐
:
- away -- the entity or resource is temporarily away ๐โโ๏ธ.
- chat -- the entity or resource is actively up for chatting ๐ฌ.
- dnd -- the entity or resource is busy (dnd = "Do Not Disturb") ๐ซ.
- xa -- the entity or resource is away for an extended period (xa = "eXtended Away") ๐.
If there's no <show/> element, the entity is assumed to be online and available ๐ข.
Any special processing of availability states by recipients and intermediate routers is up to the implementation (e.g., folding availability states into stanza routing and delivery logic) โ๏ธ.
4.7.2.2. Status Element ๐
The OPTIONAL <status/> element holds human-readable XML character data that describes an entity's availability in natural language ๐ฃ๏ธ. It's normally paired with the show element to give a detailed description of an availability state (e.g., "In a meeting") when the presence stanza has no 'type' attribute โจ.
<presence from='romeo@example.net/orchard'
xml:lang='en'>
<show>dnd</show>
<status>Wooing Juliet</status>
</presence>
There are no attributes defined for the <status/> element, except the 'xml:lang' attribute it inherits from [XML] ๐. The <status/> element MUST NOT contain mixed content (as defined in Section 3.2.2 of [XML]). Multiple instances of the <status/> element MAY be included, but ONLY if each instance has an 'xml:lang' attribute with a distinct language value (either set explicitly or inherited from the 'xml:lang' value of an element higher up in the XML hierarchy, which from the sender's perspective can include the XML stream header as described in [XMPP-CORE]) ๐.
<presence from='romeo@example.net/orchard'
id='jx62vs97'
xml:lang='en'>
<show>dnd</show>
<status>Wooing Juliet</status>
<status xml:lang='cs'>Dvořím se Julii</status>
</presence>
A presence stanza of type "unavailable" MAY also include a <status/> element to give detailed info about why the entity is going offline ๐ฅ.
<presence from='romeo@example.net/orchard'
id='oy6sb241'
type='unavailable'
xml:lang='en'>
<status>Busy IRL</status>
</presence>
The <status/> child MAY also be sent in a subscription-related presence stanza (i.e., type "subscribe", "subscribed", "unsubscribe", or "unsubscribed") to describe the action ๐ฌ. An interactive client MAY show this <status/> info to a human user (see Section 11) ๐.
<presence from='romeo@example.net'
id='uc51xs63'
to='nurse@example.com'
type='subscribe'>
<status>Hi, Juliet told me to add you to my buddy list.</status>
</presence>
4.7.2.3. Priority Element โจ
The OPTIONAL <priority/> element ๐ข holds non-human-readable XML character data that sets the priority level of the resource. The value MUST be an integer between -128 and +127. A presence stanza MUST NOT contain more than one <priority/> element, and there are no attributes defined for it. The <priority/> element MUST NOT contain mixed content (as defined in Section 3.2.2 of [XML]) ๐
โโ๏ธ
<presence xml:lang='en'>
<show>dnd</show>
<status>Wooing Juliet</status>
<status xml:lang='cs'>Dvořím se Julii</status>
<priority>1</priority>
</presence>
If no priority is provided, the processing server or client MUST consider the priority to be zero ("0") ๐
Now here's the plot twist: the client's server MAY override the priority value the client gave it ๐ For example, a server might want to impose a message handling rule that delivers a message meant for the account's bare JID to all of the account's available resources. If the server does this, it MUST communicate the modified priority value when it echoes the client's presence back to itself and when it sends the presence notification to the user's contacts. Since this modified value is usually the default of zero, the server can communicate it simply by leaving out the <priority/> child element ๐ซถ
For the semantics of priority values in stanza processing within instant messaging and presence applications, check out Section 8 ๐ง
4.7.3. Extended Content ๐
As described in [XMPP-CORE], an XML stanza MAY contain any child element that is qualified by a namespace other than the default namespace, and that goes for the presence stanza too ๐
(In the following example, the presence stanza includes entity capabilities information as defined in [XEP-0115].)
<presence from='romeo@example.net'>
<c xmlns='http://jabber.org/protocol/caps'
hash='sha-1'
node='http://psi-im.org'
ver='q07IKJEyjvHSyhy//CH0CxmKi8w='/>
</presence>
Any extended content in a presence stanza SHOULD represent aspects of an entity's availability for communication, or provide information about communication-related capabilities. That's the vibe โจ
5. Exchanging Messages ๐
Once a client has authenticated with a server and bound a resource to an XML stream as described in [XMPP-CORE], an XMPP server will route XML stanzas to and from that client ๐ One kind of stanza that can be exchanged is <message/>, but only if messaging is enabled on the server. Exchanging messages is the basic move in XMPP, and it happens when a user generates a message stanza addressed to another entity. As defined under Section 8, the sender's server is responsible for delivering the message to the recipient if they're on the same local server, or for routing it to the recipient's server if they're on a remote one. So a message stanza is how you "push" information to someone ๐จ
5.1. One-to-One Chat Sessions ๐ฃ๏ธ
Real talk: IM activity between humans usually happens in a conversational burst that we call a "chat session." That's when two parties trade several messages in quick succession within a fairly short window of time ๐ฌ
When a human user wants to start a chat session with a contact (instead of sending one message nobody needs to answer), the message type generated by the user's client SHOULD be "chat", and the contact's client SHOULD keep that message type in its replies. The user's client also SHOULD include a <thread/> element with its initial message, and the contact's client SHOULD also preserve it for the whole life of the chat session (see Section 5.2.5) ๐งต
The user's client SHOULD address the initial message in a chat session to the contact's bare JID <contact@domainpart>. It should NOT try to guess a full JID <contact@domainpart/resourcepart> based on the <show/>, <status/>, or <priority/> value from any presence notifications it might have gotten from the contact ๐
โโ๏ธ Until the user's client gets a reply, it SHOULD keep sending further messages to the bare JID. The contact's client SHOULD address its replies to the user's full JID <user@domainpart/resourcepart>, as provided in the 'from' address of the initial message. Once the user's client gets a reply from the contact's full JID, it SHOULD address its later messages to that full JID, taken from the 'from' address of the contact's replies. That's the "locking in" moment ๐
A client SHOULD "unlock" after it has received a <message/> or <presence/> stanza from any other resource controlled by the peer (or a presence stanza from the locked resource). So it SHOULD address its next message(s) in the chat session to the peer's bare JID, which unlocks the previous lock, until it gets a message from one of the peer's full JIDs. It's giving flexible ๐ฆ
When two parties are in a chat session but don't share presence through a presence subscription, they SHOULD send directed presence to each other. That way either party can easily tell if the peer goes offline during the session. However, a client MUST provide a way for a user to turn this presence sharing off globally, or to turn it on only for particular entities. Also, a party SHOULD send directed unavailable presence to the peer when it has reason to think the chat session is over (for example, if no messages have been exchanged between the parties for some reasonable amount of time) ๐ธ
An example of a chat session is provided under Section 7 ๐
5.2. Message Syntax ๐
The following sections describe the syntax of the <message/> stanza.
5.2.1. To Attribute ๐
An instant messaging client specifies an intended recipient for a message by putting the recipient's JID in the 'to' attribute of the <message/> stanza.
If the message is sent outside the context of any existing chat session or received message, the 'to' address SHOULD be of the form <localpart@domainpart> instead of <localpart@domainpart/resourcepart> (see Section 5.1) ๐ซ
<message
from='juliet@example.com/balcony'
id='ktx72v49'
to='romeo@example.net'
type='chat'
xml:lang='en'>
<body>Art thou not Romeo, and a Montague?</body>
</message>
If the message is a reply to a message previously received from an address of the form <localpart@domainpart/resourcepart> (for example, within a one-to-one chat session as described under Section 5.1), the 'to' address SHOULD be of the form <localpart@domainpart/resourcepart> rather than <localpart@domainpart>. The exception is when the sender knows (for example, via presence) that the intended recipient's resource is no longer available ๐ป
<message
from='romeo@example.net/orchard'
id='sl3nx51f'
to='juliet@example.com/balcony'
type='chat'
xml:lang='en'>
<body>Neither, fair saint, if either thee dislike.</body>
</message>
5.2.2. Type Attribute ๐ท๏ธ
Message stanzas show up in IM apps for lots of reasons: single messages, messages in a one-to-one chat session, messages in a multi-user chat room, alerts or notifications where no reply is expected, and errors. The 'type' attribute is how we tell these apart. Including the 'type' attribute is RECOMMENDED. If it's included, the 'type' attribute MUST have one of the following values:
chat-- The message is sent in the context of a one-to-one chat session. An interactive client will typically show a "chat" message in an interface that allows one-to-one chat between the two parties, with an appropriate conversation history. Detailed recommendations about one-to-one chat sessions are under Section 5.1 ๐ฌerror-- The message is generated by an entity that hit an error while processing a message from another entity (for details on stanza error syntax, see [XMPP-CORE]). A client that receives a message of type "error" SHOULD show an interface that tells the original sender what went wrong ๐จgroupchat-- The message is sent in the context of a multi-user chat environment (similar to [IRC]). A receiving client will typically show a "groupchat" message in an interface that allows many-to-many chat, with a roster of the people in the chatroom and an appropriate conversation history. For detailed information about XMPP-based groupchat, see [XEP-0045] ๐ฏโโ๏ธheadline-- The message provides an alert, a notification, or other transient information where no reply is expected (for example, news headlines, sports updates, near-real-time market data, or syndicated content). Since no reply is expected, a receiving client will typically show a "headline" message in an interface that clearly sets it apart from standalone, chat, and groupchat messages (for example, by not letting the recipient reply). If the 'to' address is the bare JID, the receiving server SHOULD deliver the message to all of the recipient's available resources with non-negative presence priority, and MUST deliver it to at least one of those resources. If the 'to' address is a full JID and there's a matching resource, the server MUST deliver the message to that resource. Otherwise, the server MUST either silently ignore the message or return an error (see Section 8) ๐ฐnormal-- The message is a standalone message sent outside the context of a one-to-one conversation or groupchat, and the sender expects the recipient to reply. A receiving client will typically show a "normal" message in an interface that lets the recipient reply, but without a conversation history. The default value of the 'type' attribute is "normal" ๐
An IM application SHOULD support all of the message types above. If an application receives a message with no 'type' attribute, or with a value it doesn't understand, it MUST consider the message to be of type "normal" (because "normal" is the default) ๐ซถ
Guidelines for how servers handle the different message types are under Section 8 ๐บ๏ธ
Even though the 'type' attribute is OPTIONAL, it's considered polite to mirror the type in any replies to a message ๐ท And some specialized applications (for example, a multi-user chat service) MAY, at their discretion, enforce the use of a particular message type (for example, type='groupchat') ๐
5.2.3. Body Element ๐ฌ
okay so the <body/> element is where the actual words of the message live ๐ซถ It's human-readable XML character data, and it's normally included, but it's OPTIONAL, so you can skip it if you want ๐ธ
<message
from='juliet@example.com/balcony'
id='b4vs9km4'
to='romeo@example.net'
type='chat'
xml:lang='en'>
<body>Wherefore art thou, Romeo?</body>
</message>
the only attribute <body/> gets is xml:lang, no others ๐
you're allowed to send several <body/> elements if you want alternate versions of the same text, but ONLY if each copy has its own xml:lang with a different language value. (that value can be set directly, or inherited from an xml:lang further up the XML hierarchy, which from the sender's side can include the XML stream header as described in [XMPP-CORE].) the MAY is doing the heavy lifting here โจ
<message
from='juliet@example.com/balcony'
id='z94nb37h'
to='romeo@example.net'
type='chat'
xml:lang='en'>
<body>Wherefore art thou, Romeo?</body>
<body xml:lang='cs'>
PročeŽ jsi ty, Romeo?
</body>
</message>
and the <body/> element MUST NOT contain mixed content (as defined in Section 3.2.2 of [XML]). no mixing text and child elements inside it, bestie ๐
โโ๏ธ
5.2.4. Subject Element ๐
the <subject/> element is the topic of the message, also human-readable XML character data ๐ฆ
<message
from='juliet@example.com/balcony'
id='c8xg3nf8'
to='romeo@example.net'
type='chat'
xml:lang='en'>
<subject>I implore you!</subject>
<body>Wherefore art thou, Romeo?</body>
</message>
same deal as <body/> for attributes: the only one is xml:lang (inherited from [XML]) ๐ you MAY include several <subject/> elements for alternate versions of the same subject, but again, each one needs its own distinct xml:lang value, either set directly or inherited from further up the XML hierarchy (including the stream header, per [XMPP-CORE]) ๐
<message
from='juliet@example.com/balcony'
id='jk3v47gw'
to='romeo@example.net'
type='chat'
xml:lang='en'>
<subject>I implore you!</subject>
<subject xml:lang='cs'>
Úpěnlivě prosím!
</subject>
<body>Wherefore art thou, Romeo?</body>
<body xml:lang='cs'>
Pročež jsi ty, Romeo?
</body>
</message>
and yep, <subject/> MUST NOT contain mixed content either (Section 3.2.2 of [XML]) ๐
5.2.5. Thread Element ๐งต
the main job of the XMPP <thread/> element is to uniquely label a conversation thread, or "chat session", between two entities, carried by <message/> stanzas of type 'chat' ๐ BUT it MAY also be used to mark an analogous thread between two entities in <message/> stanzas of type 'headline' or 'normal', or among multiple entities in a multi-user chat room (type 'groupchat') ๐ธ it MAY also show up on <message/> stanzas that aren't human chatting at all, like a game session or plugin-to-plugin stuff ๐ฎ and it's not for labelling individual messages, only conversations or messaging sessions, so don't get it twisted โจ
including <thread/> is OPTIONAL. since it tells you which conversation a message belongs to, a message stanza MUST NOT contain more than one <thread/> element. one thread per stanza, periodt ๐
the <thread/> element MAY possess a 'parent' attribute that points to another thread the current one branches off from or is a child of ๐ณ that 'parent' value MUST conform to the syntax of the <thread/> element itself, and it MUST be different from the XML character data of the <thread/> element it's on ๐
Implementation Note: the ability to specify both a parent thread and a child thread introduces the possibility of conflicts between thread identifiers for overlapping threads. For example, one<thread/>element might contain XML character data of "foo" and a 'parent' attribute whose value is "bar", a second<thread/>element might contain XML character data of "bar" and a 'parent' attribute whose value is "baz", and a third<thread/>element might contain XML character data of "baz" and a 'parent' attribute whose value is once again "foo". It is up to the implementation how it will treat conflicts between such overlapping thread identifiers (e.g., whether it will "chain together" thread identifiers by showing "foo" as both a parent and grandchild of "baz" in a multi-level user interface, or whether it will show only one level of dependency at a time).
the value inside <thread/> is not human-readable ๐ค it MUST be treated as opaque by entities, meaning no semantic meaning can be derived from it, and the only thing you can do is exact comparisons ๐ that value MUST uniquely identify the conversation thread, either between the conversation partners or more generally (one way to get uniqueness is generating a universally unique identifier (UUID) as described in [UUID]) ๐
Security Warning: an application that generates a ThreadID MUST ensure that it does not reveal identifying information about the entity (e.g., the MAC address of the device on which the XMPP application is running). this is serious, bestie ๐ญ
and <thread/> MUST NOT contain mixed content (as defined in Section 3.2.2 of [XML]) ๐
โโ๏ธ
<message
from='juliet@example.com/balcony'
to='romeo@example.net'
type='chat'
xml:lang='en'>
<subject>I implore you!</subject>
<subject xml:lang='cs'>
Úpěnlivě prosím!
</subject>
<body>Wherefore art thou, Romeo?</body>
<body xml:lang='cs'>
Pročež jsi ty, Romeo?
</body>
<thread parent='e0ffe42b28561960c6b12b944a092794b9683a38'>
0e3141cd80894871a68e6fe6b1ec56fa
</thread>
</message>
for detailed recommendations on using <thread/>, check out [XEP-0201] ๐
5.3. Extended Content ๐
as described in [XMPP-CORE], an XML stanza MAY contain any child element qualified by a namespace other than the default namespace, and that goes for message stanzas too ๐ guidelines for handling extended content, on both routing servers and end recipients, live in Section 8.4 of [XMPP-CORE] ๐ง
(in the example below, the message stanza carries an XHTML-formatted version of the message as defined in [XEP-0071].)
<message
from='juliet@example.com/balcony'
to='romeo@example.net'
type='chat'
xml:lang='en'>
<body>Wherefore art thou, Romeo?</body>
<html xmlns='http://jabber.org/protocol/xhtml-im'>
<body xmlns='http://www.w3.org/1999/xhtml'>
<p>Wherefore <span style='font-style: italic'>art</span>
thou, <span style='color:red'>Romeo</span>?</p>
</body>
</html>
</message>
6. Exchanging IQ Stanzas ๐
as described in [XMPP-CORE], IQ stanzas give you a structured request-response mechanism ๐ the basic semantics of that mechanism (like the fact that the 'id' attribute is mandatory) are defined in [XMPP-CORE], but the specific semantics needed for particular use cases are defined by whichever extended namespace qualifies the direct child element of an IQ stanza of type "get" or "set" ๐
the 'jabber:client' and 'jabber:server' namespaces don't define any IQ children other than the <error/> element that every stanza type shares ๐ this document defines one such extended namespace, for Managing the Roster (Section 2) ๐ and an IQ stanza MAY contain structured information qualified by any extended namespace ๐
7. A Sample Session โจ
Okay bestie, this section is basically a little romance-and-presence tea session ๐ซ๐ It shows what a possible instant messaging and presence session could look like. Our main character is <romeo@example.net>, who has an available resource with the resourcepart "orchard". His roster has three people in it:
- <juliet@example.com> (subscription="both", and she has two available resources, "chamber" and "balcony") ๐น
- <benvolio@example.net> (subscription="to") ๐งข
- <mercutio@example.org> (subscription="from") ๐ญ
First, Romeo completes the preconditions (stream establishment, TLS and SASL negotiation, and resource binding) described in [XMPP-CORE]. Those protocol flows are not reproduced here, so we're skipping straight to the good stuff ๐
Next, Romeo requests his roster.
Example 1: User requests current roster from server
UC: <iq from='romeo@example.net/orchard'
id='hf61v3n7'
type='get'>
<query xmlns='jabber:iq:roster'/>
</iq>
Example 2: User receives roster from server
US: <iq id='hf61v3n7'
to='romeo@example.net/orchard'
type='result'>
<query xmlns='jabber:iq:roster'>
<item jid='juliet@example.com'
name='Juliet'
subscription='both'>
<group>Friends</group>
</item>
<item jid='benvolio@example.org'
name='Benvolio'
subscription='to'/>
<item jid='mercutio@example.org'
name='Mercutio'
subscription='from'/>
</query>
</iq>
Now Romeo starts his presence session. Let's gooo ๐โจ
Example 3: User sends initial presence
UC: <presence/>
Example 4: User's server sends presence probes to contacts with subscription="to" and subscription="both" on behalf of the user
US: <presence
from='romeo@example.net'
to='juliet@example.com'
type='probe'/>
US: <presence
from='romeo@example.net'
to='benvolio@example.org'
type='probe'/>
Example 5: User's server sends initial presence to contacts with subscription="from" and subscription="both" on behalf of the user's available resource, as well as to user
US: <presence
from='romeo@example.net/orchard'
to='juliet@example.com'/>
US: <presence
from='romeo@example.net/orchard'
to='mercutio@example.org'/>
US: <presence
from='romeo@example.net/orchard'
to='romeo@example.net'/>
Example 6: Contacts' servers reply to presence probe on behalf of all available resources
CS: <presence
from='juliet@example.com/balcony'
to='romeo@example.net'
xml:lang='en'>
<show>away</show>
<status>be right back</status>
<priority>0</priority>
</presence>
CS: <presence
from='juliet@example.com/chamber'
to='romeo@example.net'>
<priority>1</priority>
</presence>
CS: <presence
from='benvolio@example.org/pda'
to='romeo@example.net'
xml:lang='en'>
<show>dnd</show>
<status>gallivanting</status>
</presence>
Example 7: Contacts' servers deliver user's initial presence to all available resources
CS: <presence
from='romeo@example.net/orchard'
to='juliet@example.com'/>
CS: <presence
from='romeo@example.net/orchard'
to='juliet@example.com'/>
CS: <presence
from='romeo@example.net/orchard'
to='mercutio@example.org'/>
Example 8: User sends directed presence to another user not in his roster
UC: <presence
from='romeo@example.net/orchard'
to='nurse@example.com'
xml:lang='en'>
<show>dnd</show>
<status>courting Juliet</status>
<priority>0</priority>
</presence>
Now the drama really kicks off. Romeo gets into a chat session with one of his contacts ๐ฌ๐
Example 9: A threaded conversation
CC: <message
from='juliet@example.com/balcony'
to='romeo@example.net'
type='chat'
xml:lang='en'>
<body>My ears have not yet drunk a hundred words</body>
<thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread>
</message>
CC: <message
from='juliet@example.com/balcony'
to='romeo@example.net'
type='chat'
xml:lang='en'>
<body>Of that tongue's utterance, yet I know the sound:</body>
<thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread>
</message>
CC: <message
from='juliet@example.com/balcony'
to='romeo@example.net'
type='chat'
xml:lang='en'>
<body>Art thou not Romeo, and a Montague?</body>
<thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread>
</message>
UC: <message
from='romeo@example.net/orchard'
to='juliet@example.com/balcony'
type='chat'
xml:lang='en'>
<body>Neither, fair saint, if either thee dislike.</body>
<thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread>
</message>
CC: <message
from='juliet@example.com/balcony'
to='romeo@example.net/orchard'
type='chat'
xml:lang='en'>
<body>How cam'st thou hither, tell me, and wherefore?</body>
<thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread>
</message>
And so on. The thread stays the same the whole time, so it's giving organized ๐งตโจ
Romeo can also send out a fresh presence broadcast whenever his vibe changes ๐ฆ
Example 10: User sends updated available presence for broadcast
UC: <presence xml:lang='en'>
<show>away</show>
<status>I shall return!</status>
<priority>1</priority>
</presence>
Example 11: User's server broadcasts updated presence to the contacts who have a subscription of type "both" or "from" (but not to the entity to which the user sent directed presence)
US: <presence
from='romeo@example.net/orchard'
to='juliet@example.com'
xml:lang='en'>
<show>away</show>
<status>I shall return!</status>
<priority>1</priority>
</presence>
US: <presence
from='romeo@example.net/orchard'
to='mercutio@example.org'
xml:lang='en'>
<show>away</show>
<status>I shall return!</status>
<priority>1</priority>
</presence>
Example 12: Contacts' servers deliver updated presence
CS: <presence
from='romeo@example.net/orchard'
to='juliet@example.com'
xml:lang='en'>
<show>away</show>
<status>I shall return!</status>
<priority>1</priority>
</presence>
CS: <presence
from='romeo@example.net/orchard'
to='juliet@example.com'
xml:lang='en'>
<show>away</show>
<status>I shall return!</status>
<priority>1</priority>
</presence>
CS: <presence
from='romeo@example.net/orchard'
to='mercutio@example.org'
xml:lang='en'>
<show>away</show>
<status>I shall return!</status>
<priority>1</priority>
</presence>
Example 13: One of the contact's resources broadcasts unavailable notification
CC: <presence from='juliet@example.com/chamber' type='unavailable'/>
Example 14: Contact's server sends unavailable notification to user
CS: <presence
from='juliet@example.com/chamber'
to='romeo@example.net'
type='unavailable'/>
Now Romeo wraps up his presence session ๐
Example 15: User sends unavailable notification
UC: <presence type='unavailable' xml:lang='en'>
<status>gone home</status>
</presence>
Example 16: User's server broadcasts unavailable notification to contacts as well as to the entity to whom the user sent directed presence
US: <presence
from='romeo@example.net/orchard'
to='juliet@example.com'
type='unavailable'
xml:lang='en'>
<status>gone home</status>
</presence>
US: <presence
from='romeo@example.net/orchard'
to='mercutio@example.org'
type='unavailable'
xml:lang='en'>
<status>gone home</status>
</presence>
US: <presence
from='romeo@example.net/orchard'
to='nurse@example.com'
type='unavailable'
xml:lang='en'>
<status>gone home</status>
</presence>
Finally, Romeo closes his stream, and the server closes its end right back ๐ซถ
Example 17: User closes stream
UC: </stream:stream>
Example 18: User's server closes stream
US: </stream:stream>
THE END ๐ฌ๐
8. Server Rules for Processing XML Stanzas ๐
Okay, the basic server rules for processing XML stanzas live in [XMPP-CORE], so go read that for the underlying rules and the security implications. This section adds extra rules just for XMPP instant messaging and presence servers ๐ง โจ
Some delivery rules in this section talk about "offline storage". That's when the server holds a message stanza on the user's behalf and then delivers it once the user is next available ๐ญโก๏ธ๐ฌ For recommendations on offline message storage, check out [XEP-0160].
8.1. General Considerations
[XMPP-CORE] covers the general considerations for stanza delivery, especially the tradeoffs between (i) giving an acceptable level of service for stanza delivery and (ii) preventing directory harvesting attacks and presence leaks. ๐ต๏ธโโ๏ธ However, the idea of a directory harvesting attack doesn't apply if a contact is known to and trusted by a user, because the contact is in the user's roster as described under Section 2. Likewise, the idea of a presence leak doesn't apply if a contact is authorized to know a user's presence (through a presence subscription as described under Section 3), or if the user has voluntarily sent presence to an entity (through directed presence as described under Section 4.6).
So, in cases where the following sections guard against directory harvesting attacks and presence leaks by offering either (a) silently ignoring a stanza or (b) returning an error, a server SHOULD return an error if the originating entity is in the user's roster (when the error would reveal whether the user's account exists) or is authorized to receive presence from the user or has received directed presence from the user (when the error would reveal the presence of a user's resource). ๐ โโ๏ธ
Security Warning: All of the stanza processing rules described below are defined with the understanding that they will be applied subject to enforcement of relevant privacy and security policies, such as those deployed by means of [XEP-0016] or [XEP-0191]. The conformance language (MUST, SHOULD, etc.) in the following sections is not meant to override any such local service policies. ๐จ๐
8.2. No 'to' Address
If the stanza has no 'to' attribute, the rules defined in [XMPP-CORE] apply. Simple as that ๐โโ๏ธ
8.3. Remote Domain
If the domainpart of the address in the 'to' attribute of an outbound stanza doesn't match a configured domain of the server itself, then the rules in Section 10.4 of [XMPP-CORE] apply ๐
Interoperability Note: RFC 3921 specified how to use the _im._xmpp and _pres._xmpp SRV records [IMP-SRV] as a fallback method for discovering whether a remote instant messaging and presence service communicates via XMPP. Because those SRV records have not been widely deployed, this document no longer specifies their use, and new implementations are not encouraged. ๐ฅฒ
8.4. Local Domain ๐
okay so if the domainpart in the to attribute matches one of the server's configured domains, the server handles that domain itself (no specialized local service needed ๐
), and the JID looks like <domainpart> or <domainpart/resourcepart>, then the rules in [XMPP-CORE] apply. โจ
8.5. Local User ๐ซถ
bestie, this is where it gets spicy. If the to address is a bare JID <localpart@domainpart> or a full JID <localpart@domainpart/resourcepart>, and that domainpart is one of the domains the server serves itself, the server MUST proceed as follows. ๐ฅ
8.5.1. No Such User ๐ป
if the user account named in the to attribute doesn't exist, the outcome depends on the stanza type. ๐
- For an IQ stanza, the server MUST return a
<service-unavailable/>stanza error to the sender. ๐ญ - For a message stanza, the server MUST either (a) silently ignore the message or (b) return a
<service-unavailable/>stanza error to the sender. ๐ - For a presence stanza with no
typeattribute or atypeattribute of "unavailable", the server MUST silently ignore the stanza. ๐ซฅ - For a presence stanza of type "subscribe", "subscribed", "unsubscribe", or "unsubscribed", the server MUST silently ignore the stanza. ๐ซฅ
- For a presence stanza of type "probe", the server MUST either (a) silently ignore the stanza or (b) return a presence stanza of type "unsubscribed". ๐
8.5.2. localpart@domainpart ๐
if the JID in the to attribute looks like <localpart@domainpart>, then the server MUST follow these rules. ๐
8.5.2.1. Available or Connected Resources ๐ธ
if there's at least one available resource or connected resource, the outcome depends on the stanza type. โจ
8.5.2.1.1. Message ๐
For a message stanza of type "normal":
- If all of the available resources have a negative presence priority, then the server SHOULD either (a) store the message offline for later delivery or (b) return a stanza error to the sender, which SHOULD be
<service-unavailable/>. ๐ฅบ - If there is one available resource with a non-negative presence priority, then the server MUST deliver the message to that resource. ๐ฏ
- If there is more than one resource with a non-negative presence priority, then the server MUST either (a) deliver the message to the "most available" resource or resources (according to the server's implementation-specific algorithm, e.g., treating the resource or resources with the highest presence priority as "most available") or (b) deliver the message to all of the non-negative resources. ๐ง
For a message stanza of type "chat":
- If the only available resource has a negative presence priority, then the server SHOULD either (a) store the message offline for later delivery or (b) return a stanza error to the sender, which SHOULD be
<service-unavailable/>. ๐ฅน - If the only available resource has a non-negative presence priority, then the server MUST deliver the message to that resource. ๐
- If there is more than one resource with a non-negative presence priority, then the server MUST either (a) deliver the message to the "most available" resource or resources (according to the server's implementation-specific algorithm, e.g., treating the resource or resources with the highest presence priority as "most available") or (b) deliver the message to all of the non-negative resources that have opted in to receive chat messages. ๐ฆ
For a message stanza of type "groupchat", the server MUST NOT deliver the stanza to any of the available resources, but instead MUST return a stanza error to the sender, which SHOULD be <service-unavailable/>. ๐ซ
For a message stanza of type "headline":
- If the only available resource has a negative presence priority, then the server MUST silently ignore the stanza. ๐คซ
- If the only available resource has a non-negative presence priority, then the server MUST deliver the message to that resource. ๐ฃ
- If there is more than one resource with a non-negative presence priority, then the server MUST deliver the message to all of the non-negative resources. ๐ฃ
For a message stanza of type "error", the server MUST silently ignore the message. ๐ โโ๏ธ
However, for any message type the server MUST NOT deliver the stanza to any available resource with a negative priority. If the only available resource has a negative priority, the server SHOULD handle the message as if there were no available resources or connected resources, as described under Section 8.5.2.2. ๐ซ
In all cases, the server MUST NOT rewrite the to attribute (i.e., it MUST leave it as <localpart@domainpart> rather than change it to <localpart@domainpart/resourcepart>). ๐
8.5.2.1.2. Presence ๐
For a presence stanza with no type or of type "unavailable", the server MUST deliver it to all available resources. ๐ก
For a presence stanza of type "subscribe", "subscribed", "unsubscribe", or "unsubscribed", the server MUST adhere to the rules defined under Section 3 and summarized under Appendix A. ๐
For a presence stanza of type "probe", the server MUST handle it directly as described under Section 4.3. ๐
In all cases, the server MUST NOT rewrite the to attribute (i.e., it MUST leave it as <localpart@domainpart> rather than change it to <localpart@domainpart/resourcepart>). ๐
8.5.2.1.3. IQ ๐งพ
For an IQ stanza, the server itself MUST reply on behalf of the user with either an IQ result or an IQ error, and MUST NOT deliver the IQ stanza to any of the user's available resources. Specifically, if the semantics of the qualifying namespace define a reply that the server can provide on behalf of the user, then the server MUST reply to the stanza on behalf of the user by returning either an IQ stanza of type "result" or an IQ stanza of type "error" that is appropriate to the original payload. If not, then the server MUST reply with a <service-unavailable/> stanza error. ๐ค
8.5.2.2. No Available or Connected Resources ๐ด
if there are no available resources or connected resources associated with the user, the outcome depends on the stanza type. ๐ค
8.5.2.2.1. Message ๐ญ
For a message stanza of type "normal" or "chat", the server SHOULD either (a) add the message to offline storage or (b) return a stanza error to the sender, which SHOULD be <service-unavailable/>. ๐ฆ
For a message stanza of type "groupchat", the server MUST return an error to the sender, which SHOULD be <service-unavailable/>. ๐
โโ๏ธ
For a message stanza of type "headline" or "error", the server MUST silently ignore the message. ๐ค
8.5.2.2.2. Presence ๐
For a presence stanza with no type or of type "unavailable", the server SHOULD silently ignore the stanza by not storing it for later delivery and not replying to it on behalf of the user. ๐ซง
For a presence stanza of type "subscribe", "subscribed", "unsubscribe", or "unsubscribed", the server MUST adhere to the rules defined under Section 3 and summarized under Appendix A. ๐
For a presence stanza of type "probe", the server MUST handle it directly as described under Section 4.3. ๐
8.5.2.2.3. IQ ๐งพ
For an IQ stanza, the server itself MUST reply on behalf of the user with either an IQ result or an IQ error. Specifically, if the semantics of the qualifying namespace define a reply that the server can provide on behalf of the user, then the server MUST reply to the stanza on behalf of the user by returning either an IQ stanza of type "result" or an IQ stanza of type "error" that is appropriate to the original payload. If not, then the server MUST reply with a <service-unavailable/> stanza error. ๐ค
8.5.3. localpart@domainpart/resourcepart ๐ฏ
if the domainpart of the JID in the to attribute of an inbound stanza matches one of the domains the server itself serves, and the JID in the to attribute looks like <localpart@domainpart/resourcepart>, then the server MUST follow these rules. ๐
8.5.3.1. Resource Matches ๐
if an available resource or connected resource exactly matches the full JID, the outcome depends on the stanza type. โจ
- For an IQ stanza of type "get" or "set", if the intended recipient does not share presence with the requesting entity, either by means of a presence subscription of type "both" or "from" or by means of directed presence, then the server SHOULD NOT deliver the IQ stanza, but instead SHOULD return a
<service-unavailable/>stanza error to the requesting entity. This policy helps to prevent presence leaks (see Section 11). ๐ - For an IQ stanza of type "result" or "error", the server MUST deliver the stanza to the resource. ๐ฌ
- For a message stanza, the server MUST deliver the stanza to the resource. ๐
- For a presence stanza with no
typeattribute or atypeattribute of "unavailable", the server MUST deliver the stanza to the resource. ๐ก - For a presence stanza of type "subscribe", "subscribed", "unsubscribe", or "unsubscribed", the server MUST follow the guidelines provided under Section 3. ๐
- For a presence stanza of type "probe", the server MUST follow the guidelines provided under Section 4.3. ๐
8.5.3.2. No Resource Matches ๐ซฅ
if no available resource or connected resource exactly matches the full JID, the outcome depends on the stanza type. ๐
8.5.3.2.1. Message ๐ฌ
For a message stanza of type "normal", "groupchat", or "headline", the server MUST either (a) silently ignore the stanza or (b) return an error stanza to the sender, which SHOULD be <service-unavailable/>. ๐
For a message stanza of type "chat":
- If there is no available or connected resource, the server MUST either (a) store the message offline for later delivery or (b) return an error stanza to the sender, which SHOULD be
<service-unavailable/>. ๐ฆ - If all of the available resources have a negative presence priority, then the server SHOULD (a) store the message offline for later delivery or (b) return a stanza error to the sender, which SHOULD be
<service-unavailable/>. ๐ฅบ - If there is one available resource with a non-negative presence priority, then the server MUST deliver the message to that resource. ๐ฏ
- If there is more than one resource with a non-negative presence priority, then the server MUST either (a) deliver the message to the "most available" resource or resources (according to the server's implementation-specific algorithm, e.g., treating the resource or resources with the highest presence priority as "most available") or (b) deliver the message to all of the non-negative resources that have opted in to receive chat messages. ๐ฆ
For a message stanza of type "error", the server MUST silently ignore the stanza. ๐คซ
8.5.3.2.2. Presence ๐
For a presence stanza with no type attribute or a type attribute of "unavailable", the server MUST silently ignore the stanza. ๐ซฅ
For a presence stanza of type "subscribe", the server MUST follow the guidelines provided under Section 3.1.3. ๐
For a presence stanza of type "subscribed", "unsubscribe", or "unsubscribed", the server MUST ignore the stanza. ๐
For a presence stanza of type "probe", the server MUST follow the guidelines provided under Section 4.3. ๐
8.5.3.2.3. IQ ๐งพ
For an IQ stanza, the server MUST return a <service-unavailable/> stanza error to the sender. ๐
โโ๏ธ
8.5.4. Summary of Message Delivery Rules โจ
Okay bestie, here's the cheat sheet ๐๐ This table sums up the message (not stanza) delivery rules we covered earlier in this section. The left column mixes conditions (the account doesn't exist, there are no active resources, there's just one resource with a negative presence priority, there's just one with a non-negative one, or there are more than one and they're all non-negative) with the 'to' address types (bare JID, full JID matching an available resource, or full JID matching nothing available). The other columns cover the four main message types (normal, chat, groupchat, headline) and six possible moves ๐:
- Store it offline (O)
- Bounce it with a stanza error (E)
- Silently ignore it (S)
- Deliver it to the resource in the 'to' address (D)
- Deliver it to the "most available" resource or resources, based on the server's own implementation-specific algorithm. For example, the server could treat the resource with the highest presence priority as "most available" (M).
- Deliver it to all resources with non-negative presence priority (A). For chat messages, "all resources" can mean the set of resources that explicitly opted in to receiving every chat message ๐ฆ
The '/' character means "exclusive or" ๐ค Also, the server SHOULD observe the rules in section 8.1 when choosing what to do with a particular message ๐ซถ
Table 1: Message Delivery Rules
+----------------------------------------------------------+
| Condition | Normal | Chat | Groupchat | Headline |
+----------------------------------------------------------+
| ACCOUNT DOES NOT EXIST |
| bare | S/E | S/E | E | S |
| full | S/E | S/E | S/E | S/E |
+----------------------------------------------------------+
| ACCOUNT EXISTS, BUT NO ACTIVE RESOURCES |
| bare | O/E | O/E | E | S |
| full (no match) | S/E | O/E | S/E | S/E |
+----------------------------------------------------------+
| 1+ NEGATIVE RESOURCES BUT ZERO NON-NEGATIVE RESOURCES |
| bare | O/E | O/E | E | S |
| full match | D | D | D | D |
| full no match | S/E | O/E | S/E | S/E |
+----------------------------------------------------------+
| 1 NON-NEGATIVE RESOURCE |
| bare | D | D | E | D |
| full match | D | D | D | D |
| full no match | S/E | D | S/E | S/E |
+----------------------------------------------------------+
| 1+ NON-NEGATIVE RESOURCES |
| bare | M/A | M/A* | E | A |
| full match | D | D/A* | D | D |
| full no match | S/E | M/A* | S/E | S/E |
+----------------------------------------------------------+
* For messages of type "chat", a server SHOULD NOT act in accordance with option (A) unless clients can explicitly opt in to receiving all chat messages. Heads up though: methods for opting in are outside the scope of this spec ๐
9. Handling of URIs ๐
The addresses of XMPP entities used on an XMPP network (like the 'from' and 'to' addresses of an XML stanza) MUST NOT be prepended with a Uniform Resource Identifier [URI] scheme. No URI prefixes on XMPP addresses, period ๐ โโ๏ธ
However, apps that live outside XMPP (like a page on the World Wide Web) might need to identify an XMPP entity as either a URI or an Internationalized Resource Identifier [IRI]. An XMPP client might also need to interact with that kind of external app. For example, a client might get opened when you click a link on a web page ๐ In those situations, XMPP clients are encouraged to handle addresses encoded as "xmpp:" URIs and IRIs as specified in [XMPP-URI] and further described in [XEP-0147]. Clients are also encouraged to handle addresses encoded as "im:" URIs as specified in [CPIM] and "pres:" URIs as specified in [CPP]. They can do that by stripping off the "im:" or "pres:" scheme and leaving address resolution to the server, as specified under Section 8.3 ๐
10. Internationalization Considerations ๐
For internationalization considerations, check the relevant section of [XMPP-CORE] ๐
11. Security Considerations ๐๐ญ
This part is serious, so read it slowly ๐ฅบ Core security considerations for XMPP are in Section 13 of [XMPP-CORE], including channel encryption, authentication, information leaks, denial-of-service attacks, and interdomain federation.
Section 13.1 of [XMPP-CORE] lays out the architectural roles of clients and servers in typical XMPP deployments and talks about the security properties tied to those roles. These roles affect the security of instant messages, presence subscriptions, and presence notifications as described in this document. Basically, an XMPP user registers (or has an account provisioned) on an XMPP server, so they place some level of trust in the server to handle tasks on their behalf, enforce security policies, and so on. That means it's the server's responsibility to:
- Preferably mandate channel encryption for communication with local clients and remote servers ๐
- Authenticate any client that wants to access the user's account ๐ชช
- Process XML stanzas to and from clients that have authenticated as the user. For IM and presence, this specifically covers storing the user's roster, processing inbound and outbound subscription requests and responses, generating and handling presence probes, broadcasting outbound presence notifications, routing outbound messages, and delivering inbound messages and presence notifications ๐ฌ
As discussed in Sections 13.1 and 13.4 of [XMPP-CORE], even when the server does all of that, the client has no assurance that the stanzas it exchanges with other clients (whether on the same server or a remote one) are protected for every hop along the XMPP communication path, or inside the server itself. So if a client wants end-to-end confidentiality and integrity for its communications, it's the client's job to use an appropriate technology for encrypting and signing its XML stanzas ๐โจ
Additional considerations that apply only to IM and presence applications of XMPP are defined in several places in this document. Specifically:
- When a server processes an inbound presence stanza of type "probe" whose intended recipient is a user associated with one of the server's configured domains, the server MUST NOT reveal the user's presence if the sender is an entity that isn't authorized to receive that info, as determined by presence subscriptions (see Section 4) ๐
- A user's server MUST NOT leak the user's network availability to entities that aren't authorized to know the user's presence. In XMPP itself, authorization takes the form of an explicit subscription from a contact to the user (as described under Section 3). Some XMPP deployments might still consider an entity authorized if there's an existing trust relationship between that entity and the user generating the presence info. For example, a corporate deployment might automatically add the user's presence info to a private employee directory if the organization requires sharing presence as part of an employment agreement ๐ผ
- When a server processes an outbound presence stanza with no type or of type "unavailable", it MUST follow the rules defined under Section 4, so that the presence info isn't sent to entities that aren't authorized to know it ๐ก๏ธ
- A client MAY ignore the
<status/>element when it's in a presence stanza of type "subscribe", "unsubscribe", "subscribed", or "unsubscribed". This can help prevent "presence subscription spam" ๐ซ๐
12. Conformance Requirements โจ
okay bestie, this section is basically the ultimate checklist ๐๐ It's a feature set that sums up every conformance requirement in this spec, and it's giving certification-ready energy ๐ It's built for software certification, interoperability testing, and implementation reports ๐ฆ Every feature comes with:
- A human-readable name
- An informational description
- A reference to the section that normatively defines it
- Whether it applies to the Client role, the Server role, or both (where "N/A" means not applicable to that role)
- Whether the feature MUST or SHOULD be implemented, where the capitalized terms work the way [KEYWORDS] describes ๐
The feature set tries to vibe with the concepts and formats Larry Masinter proposed in the IETF's NEWTRK Working Group in 2005, as captured in [INTEROP] ๐ง It's more detailed than [REPORTS] asks for, but it's a solid base for implementation reports supporting this spec's move from Proposed Standard to Draft Standard under [PROCESS] ๐
Feature: message-body
Description: Support the <body/> child element of the <message/>
stanza.
Section: Section 5.2.3
Roles: Client MUST, Server N/A.
Feature: message-subject
Description: Support the <subject/> child element of the <message/>
stanza.
Section: Section 5.2.4
Roles: Client SHOULD, Server N/A.
Feature: message-thread
Description: Support the <thread/> child element of the <message/>
stanza.
Section: Section 5.2.5
Roles: Client SHOULD, Server N/A.
Feature: message-type-support
Description: Support reception of messages of type "normal", "chat",
"groupchat", "headline", and "error".
Section: Section 5.2.2
Roles: Client SHOULD, Server N/A.
Feature: message-type-deliver
Description: Appropriately deliver messages of type "normal",
"chat", "groupchat", "headline", and "error".
Section: Section 8
Roles: Client N/A, Server SHOULD.
Feature: presence-notype
Description: Treat a presence stanza with no 'type' attribute as
indicating availability.
Section: Section 4.7.1
Roles: Client MUST, Server MUST.
Feature: presence-probe
Description: Send and receive presence stanzas with a 'type'
attribute of "probe" for the discovery of presence information.
Section: Section 4.7.1
Roles: Client N/A, Server MUST.
Feature: presence-sub-approval
Description: Treat an outbound presence stanza of type "subscribed"
as the act of approving a presence subscription request previously
received from another entity, and treat an inbound presence stanza
of type "subscribed" as a subscription approval from another
entity.
Section: Section 3.1
Roles: Client MUST, Server MUST.
Feature: presence-sub-cancel
Description: Treat an outbound presence stanza of type
"unsubscribed" as the act of denying a subscription request
received from another entity or canceling a subscription approval
previously granted to another entity, and treat an inbound
presence stanza of type "unsubscribed" as an subscription denial
or cancellation from another entity.
Section: Section 3.2
Roles: Client MUST, Server MUST.
Feature: presence-sub-preapproval
Description: Treat an outbound presence stanza of type "subscribed"
in certain circumstances as the act of pre-approving a
subscription request received from another entity; this includes
support for the 'approved' attribute of the <item/> element within
the 'jabber:iq:roster' namespace.
Section: Section 3.4
Roles: Client MAY, Server MAY.
Feature: presence-sub-request
Description: Treat an outbound presence stanza of type "subscribe"
as the act of requesting a subscription to the presence
information of another entity, and treat an inbound presence
stanza of type "subscribe" as a presence subscription request from
another entity.
Section: Section 3.1
Roles: Client MUST, Server MUST.
Feature: presence-sub-unsubscribe
Description: Treat an outbound presence stanza of type "unsubscribe"
as the act of unsubscribing from another entity, and treat an
inbound presence stanza of type "unsubscribe" as an unsubscribe
notification from another entity.
Section: Section 3.3
Roles: Client MUST, Server MUST.
Feature: presence-unavailable
Description: Treat a presence stanza with a 'type' attribute of
"unavailable" as indicating lack of availability.
Section: Section 4.7.1
Roles: Client MUST, Server MUST.
Feature: roster-get
Description: Treat an IQ stanza of type "get" containing an empty
<query/> element qualified by the 'jabber:iq:roster' namespace as
a request to retrieve the roster information associated with an
account on a server.
Section: Section 2.1.3
Roles: Client MUST, Server MUST.
Feature: roster-set
Description: Treat an IQ stanza of type "set" containing a <query/>
element qualified by the 'jabber:iq:roster' namespace as a request
to add or update the item contained in the <query/> element.
Section: Section 2.1.5
Roles: Client MUST, Server MUST.
Feature: roster-push
Description: Send a roster push to each interested resource whenever
the server-side representation of the roster information
materially changes, or handle such a push when received from the
server.
Section: Section 2.1.6
Roles: Client MUST, Server MUST.
Feature: roster-version
Description: Treat the 'ver' attribute of the <query/> element
qualified by the 'jabber:iq:roster' namespace as an identifier of
the particular version of roster information being sent or
received.
Section: Section 2.1.1
Roles: Client SHOULD, Server MUST.
13. References ๐
13.1. Normative References ๐ธ
Okay, these are the normative refs, the ones this spec genuinely leans on ๐ซถ
[DELAY] Saint-Andre, P., "Delayed Delivery", XSF XEP 0203,
September 2009.
[KEYWORDS]
Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[XML] Maler, E., Yergeau, F., Sperberg-McQueen, C., Paoli, J.,
and T. Bray, "Extensible Markup Language (XML) 1.0 (Fifth
Edition)", World Wide Web Consortium
Recommendation REC-xml-20081126, November 2008,
<http://www.w3.org/TR/2008/REC-xml-20081126>.
[XML-NAMES]
Bray, T., Hollander, D., and A. Layman, "Namespaces in
XML", W3C REC-xml-names, January 1999,
<http://www.w3.org/TR/REC-xml-names>.
[XMPP-CORE]
Saint-Andre, P., "Extensible Messaging and Presence
Protocol (XMPP): Core", RFC 6120, March 2011.
That's the reference list for this part! Next up, the rest of the doc ๐ฆโจ
13.2. Informative References โจ
okay so these are the background reads ๐ the ones that give you the bigger picture, not the core rules. they're all listed right here, with every detail intact bestie ๐ซถ
[CPIM] Peterson, J., "Common Profile for Instant Messaging (CPIM)", RFC 3860, August 2004.
[CPP] Peterson, J., "Common Profile for Presence (CPP)", RFC 3859, August 2004.
[DOS] Handley, M., Rescorla, E., and IAB, "Internet Denial-of-Service Considerations", RFC 4732, December 2006.
[IMP-MODEL] Day, M., Rosenberg, J., and H. Sugano, "A Model for Presence and Instant Messaging", RFC 2778, February 2000.
[IMP-REQS] Day, M., Aggarwal, S., and J. Vincent, "Instant Messaging / Presence Protocol Requirements", RFC 2779, February 2000.
[IMP-SRV] Peterson, J., "Address Resolution for Instant Messaging and Presence", RFC 3861, August 2004.
[INTEROP] Masinter, L., "Formalizing IETF Interoperability Reporting", Work in Progress, October 2005.
[IRC] Kalt, C., "Internet Relay Chat: Architecture", RFC 2810, April 2000.
[IRI] Duerst, M. and M. Suignard, "Internationalized Resource Identifiers (IRIs)", RFC 3987, January 2005.
[PROCESS] Bradner, S., "The Internet Standards Process -- Revision 3", BCP 9, RFC 2026, October 1996.
[REPORTS] Dusseault, L. and R. Sparks, "Guidance on Interoperation and Implementation Reports for Advancement to Draft Standard", BCP 9, RFC 5657, September 2009.
[RFC3920] Saint-Andre, P., Ed., "Extensible Messaging and Presence Protocol (XMPP): Core", RFC 3920, October 2004.
[RFC3921] Saint-Andre, P., Ed., "Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence", RFC 3921, October 2004.
[SASL] Melnikov, A. and K. Zeilenga, "Simple Authentication and Security Layer (SASL)", RFC 4422, June 2006.
[SIP-PRES] Rosenberg, J., "A Presence Event Package for the Session Initiation Protocol (SIP)", RFC 3856, August 2004.
[TLS] Dierks, T. and E. Rescorla, "The Transport Layer Security (TLS) Protocol Version 1.2", RFC 5246, August 2008.
[TLS-CERTS] Saint-Andre, P. and J. Hodges, "Representation and Verification of Domain-Based Application Service Identity within Internet Public Key Infrastructure Using X.509 (PKIX) Certificates in the Context of Transport Layer Security (TLS)", RFC 6125, March 2011.
[UNICODE] The Unicode Consortium, "The Unicode Standard, Version 6.0", 2010, <http://www.unicode.org/versions/Unicode6.0.0/>.
[URI] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, January 2005.
[UUID] Leach, P., Mealling, M., and R. Salz, "A Universally Unique IDentifier (UUID) URN Namespace", RFC 4122, July 2005.
[XEP-0016] Millard, P. and P. Saint-Andre, "Privacy Lists", XSF XEP 0016, February 2007.
[XEP-0045] Saint-Andre, P., "Multi-User Chat", XSF XEP 0045, July 2008.
[XEP-0054] Saint-Andre, P., "vcard-temp", XSF XEP 0054, July 2008.
[XEP-0071] Saint-Andre, P., "XHTML-IM", XSF XEP 0071, September 2008.
[XEP-0115] Hildebrand, J., Saint-Andre, P., and R. Troncon, "Entity Capabilities", XSF XEP 0115, February 2008.
[XEP-0147] Saint-Andre, P., "XMPP URI Scheme Query Components", XSF XEP 0147, September 2006.
[XEP-0160] Saint-Andre, P., "Best Practices for Handling Offline Messages", XSF XEP 0160, January 2006.
[XEP-0163] Saint-Andre, P. and K. Smith, "Personal Eventing Protocol", XSF XEP 0163, July 2010.
[XEP-0191] Saint-Andre, P., "Simple Communications Blocking", XSF XEP 0191, February 2007.
[XEP-0201] Saint-Andre, P., Paterson, I., and K. Smith, "Best Practices for Message Threads", XSF XEP 0201, November 2010.
[XEP-0237] Saint-Andre, P. and D. Cridland, "Roster Versioning", XSF XEP 0237, March 2010.
[XML-DATATYPES] Biron, P. and A. Malhotra, "XML Schema Part 2: Datatypes Second Edition", W3C REC-xmlschema-2, October 2004, <http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/>.
[XML-SCHEMA] Thompson, H., Maloney, M., Mendelsohn, N., and D. Beech, "XML Schema Part 1: Structures Second Edition", World Wide Web Consortium Recommendation REC-xmlschema-1-20041028, October 2004, <http://www.w3.org/TR/2004/REC-xmlschema-1-20041028>.
[XMPP-ADDR] Saint-Andre, P., "Extensible Messaging and Presence Protocol (XMPP): Address Format", RFC 6122, March 2011.
[XMPP-URI] Saint-Andre, P., "Internationalized Resource Identifiers (IRIs) and Uniform Resource Identifiers (URIs) for the Extensible Messaging and Presence Protocol (XMPP)", RFC 5122, February 2008.
[VCARD] Dawson, F. and T. Howes, "vCard MIME Directory Profile", RFC 2426, September 1998.
Appendix A. Subscription States ๐ฆ
this part is the deep dive on subscription states ๐ฅ it covers how the server handles presence stanzas that are about subscriptions (the ones with type "subscribe", "subscribed", "unsubscribe", and "unsubscribed") ๐
A.1. Defined States ๐
there are four main subscription states ๐ and they're all described from the user's point of view, NOT the contact's, so keep that in mind bestie ๐
- None: the user doesn't have a subscription to the contact's presence, and the contact doesn't have one to the user's presence either.
- To: the user has a subscription to the contact's presence, but the contact doesn't have one to the user's presence.
- From: the contact has a subscription to the user's presence, but the user doesn't have one to the contact's presence.
- Both: both the user and the contact have subscriptions to each other's presence (basically the union of 'from' and 'to') ๐
Implementation Note: For the purpose of processing subscription-related presence stanzas as described in the following sections, a subscription state of "None" includes the case of the contact not being in the user's roster at all, i.e., an unknown entity from the perspective of the user's roster.
okay so the four main states get extra sub-states for pending inbound and outbound subscriptions ๐ which gives us nine possible subscription states total โจ
- "None" = Contact and user are not subscribed to each other, and neither has requested a subscription from the other; this is reflected in the user's roster by subscription='none'.
- "None + Pending Out" = Contact and user are not subscribed to each other, and user has sent contact a subscription request but contact has not replied yet; this is reflected in the user's roster by subscription='none' and ask='subscribe'.
- "None + Pending In" = Contact and user are not subscribed to each other, and contact has sent user a subscription request but user has not replied yet. This state might or might not be reflected in the user's roster, as follows: if the user has created a roster item for the contact then the server MUST maintain that roster item and also note the existence of the inbound presence subscription request, whereas if the user has not created a roster item for the contact then the user's server MUST note the existence of the inbound presence subscription request but MUST NOT create a roster item for the contact (instead, the server MUST wait until the user has approved the subscription request before adding the contact to the user's roster). ๐ซฃ
- "None + Pending Out+In" = Contact and user are not subscribed to each other, contact has sent user a subscription request but user has not replied yet, and user has sent contact a subscription request but contact has not replied yet; this is reflected in the user's roster by subscription='none' and ask='subscribe'.
- "To" = User is subscribed to contact (one-way); this is reflected in the user's roster by subscription='to'.
- "To + Pending In" = User is subscribed to contact, and contact has sent user a subscription request but user has not replied yet; this is reflected in the user's roster by subscription='to'.
- "From" = Contact is subscribed to user (one-way); this is reflected in the user's roster by subscription='from'.
- "From + Pending Out" = Contact is subscribed to user, and user has sent contact a subscription request but contact has not replied yet; this is reflected in the user's roster by subscription='from' and ask='subscribe'.
- "Both" = User and contact are subscribed to each other (two-way); this is reflected in the user's roster by subscription='both'. ๐
A.2. Server Processing of Outbound Presence Subscription Stanzas ๐
outbound subscription stanzas are how the user manages their own subscription to the contact's presence (with the "subscribe" and "unsubscribe" types) ๐ง and how they manage the contact's access to the user's presence (with the "subscribed" and "unsubscribed" types) ๐
the rules below cover how the stanza gets routed AND how the user's roster changes ๐บ๏ธ (again, all from the user's side, not the contact's). quick decoder ring: "S.N." stands for SHOULD NOT and "M.N." stands for MUST NOT ๐
A.2.1. Subscribe ๐ธ
here's the table for outbound "subscribe" stanzas ๐ (footnote [1] is at the bottom, bestie, don't miss it ๐)
+------------------------------------------------------------------+
| EXISTING STATE | ROUTE? | NEW STATE |
+------------------------------------------------------------------+
| "None" | MUST [1] | "None + Pending Out" |
| "None + Pending Out" | MUST | no state change |
| "None + Pending In" | MUST [1] | "None + Pending Out+In" |
| "None + Pending Out+In" | MUST | no state change |
| "To" | MUST | no state change |
| "To + Pending In" | MUST | no state change |
| "From" | MUST [1] | "From + Pending Out" |
| "From + Pending Out" | MUST | no state change |
| "Both" | MUST | no state change |
+------------------------------------------------------------------+
[1] A state change to "pending out" includes setting the 'ask'
flag to a value of "subscribe" in the user's roster.
A.2.2. Unsubscribe ๐
Okay so this one is the outbound unsubscribe stanza, which is basically you saying "bye, I'm done watching your presence" ๐ซ . The table below shows what your server has to do depending on your current state, and whether it routes the stanza. Spoiler: this is where a lot of "none" states just chill and don't change, which is very on-brand for them ๐ธ
Table 3: Processing of outbound "unsubscribe" stanzas
+-----------------------------------------------------------------+
| EXISTING STATE | ROUTE? | NEW STATE |
+-----------------------------------------------------------------+
| "None" | MUST | no state change |
| "None + Pending Out" | MUST | "None" |
| "None + Pending In" | MUST | no state change |
| "None + Pending Out+In" | MUST | "None + Pending In" |
| "To" | MUST | "None" |
| "To + Pending In" | MUST | "None + Pending In" |
| "From" | MUST | no state change |
| "From + Pending Out" | MUST | "From" |
| "Both" | MUST | "From" |
+-----------------------------------------------------------------+
A.2.3. Subscribed โจ
Now the outbound subscribed stanza, aka the "yes, you can see me" energy ๐ฅน. Read the table carefully because there are a few M.N. entries, and those mean the server doesn't route it, plus a pre-approval footnote that's giving plot twist ๐
Table 4: Processing of outbound "subscribed" stanzas
+-----------------------------------------------------------------+
| EXISTING STATE | ROUTE? | NEW STATE |
+-----------------------------------------------------------------+
| "None" | M.N. | pre-approval [1] |
| "None + Pending Out" | M.N. | pre-approval [1] |
| "None + Pending In" | MUST | "From" |
| "None + Pending Out+In" | MUST | "From + Pending Out" |
| "To" | M.N. | pre-approval [1] |
| "To + Pending In" | MUST | "Both" |
| "From" | M.N. | no state change |
| "From + Pending Out" | M.N. | no state change |
| "Both" | M.N. | no state change |
+-----------------------------------------------------------------+
[1] Pre-approval is covered in more detail in Section 3.4, so go check that out ๐
A.2.4. Unsubscribed ๐ง
Last outbound one: the unsubscribed stanza, which is the "okay, you're off the list" move ๐. Lots of S.N. here too, so your server basically holds back on routing in a bunch of states. Iconic restraint, honestly ๐
Table 5: Processing of outbound "unsubscribed" stanzas
+-----------------------------------------------------------------+
| EXISTING STATE | ROUTE? | NEW STATE |
+-----------------------------------------------------------------+
| "None" | S.N. | no state change [1] |
| "None + Pending Out" | S.N. | no state change [1] |
| "None + Pending In" | MUST | "None" |
| "None + Pending Out+In" | MUST | "None + Pending Out" |
| "To" | S.N. | no state change [1] |
| "To + Pending In" | MUST | "To" |
| "From" | MUST | "None" |
| "From + Pending Out" | MUST | "None + Pending Out" |
| "Both" | MUST | "To" |
+-----------------------------------------------------------------+
[1] This one can cancel a pre-approved subscription, which is described in Section 3.4 ๐ซถ
A.3. Server Processing of Inbound Presence Subscription Stanzas ๐ฌ
Now we flip it and look at what the server does with stanzas coming in ๐ฅ. These are the ones that either ask the user to do a subscription thing (subscribe), tell the user the contact did one (unsubscribe), or let the user handle the contact's access to their presence (subscribed and unsubscribed). Big "who's knocking at my door" energy ๐ชโจ
The rules below cover delivering the inbound stanza and any changes to the user's roster. They're written from the user's point of view, not the contact's, so keep that in mind as you read ๐ Also, in these tables "S.N." is shorthand for SHOULD NOT ๐
A.3.1. Subscribe ๐
Okay, inbound subscribe is when someone is literally asking to see you ๐ฅบ. Here's how the server handles it depending on your current state:
Table 6: Processing of inbound "subscribe" stanzas
+------------------------------------------------------------------+
| EXISTING STATE | DELIVER? | NEW STATE |
+------------------------------------------------------------------+
| "None" | MUST [1] | "None + Pending In" |
| "None + Pending Out" | MUST | "None + Pending Out+In" |
| "None + Pending In" | S.N. | no state change |
| "None + Pending Out+In" | S.N. | no state change |
| "To" | MUST | "To + Pending In" |
| "To + Pending In" | S.N. | no state change |
| "From" | S.N. [2] | no state change |
| "From + Pending Out" | S.N. [2] | no state change |
| "Both" | S.N. [2] | no state change |
+------------------------------------------------------------------+
[1] If the user earlier sent a presence stanza of type "subscribed" as described under Appendix A.2.3 and Section 3.4, then the server MAY auto-reply with "subscribed" and move the state to "From" instead of "None + Pending In". Pretty clever, no cap ๐ง
[2] The server SHOULD auto-reply with "subscribed" ๐
A.3.2. Unsubscribe ๐
Inbound unsubscribe is the contact saying "I'm out" ๐ญ. The rule is pretty simple: if it actually changes the user's subscription state, the server has to update the state and deliver the stanza, and it SHOULD auto-reply with an unsubscribed stanza on the user's behalf. If it doesn't change anything, the state stays put and the stanza usually doesn't get delivered. The table breaks it all down ๐
Table 7: Processing of inbound "unsubscribe" stanzas
+------------------------------------------------------------------+
| EXISTING STATE | DELIVER? | NEW STATE |
+------------------------------------------------------------------+
| "None" | S.N. | no state change |
| "None + Pending Out" | S.N. | no state change |
| "None + Pending In" | MUST [1] | "None" |
| "None + Pending Out+In" | MUST [1] | "None + Pending Out" |
| "To" | S.N. | no state change |
| "To + Pending In" | MUST [1] | "To" |
| "From" | MUST [1] | "None" |
| "From + Pending Out" | MUST [1] | "None + Pending Out" |
| "Both" | MUST [1] | "To" |
+------------------------------------------------------------------+
[1] The server SHOULD auto-reply with "unsubscribed" ๐ซถ
A.3.3. Subscribed ๐
Inbound subscribed is the contact saying yes to your request ๐ฅณ, but only if you actually asked. If there's no pending outbound request, the server does NOT change the state and usually doesn't deliver it, since nothing changed. If there is a pending request and the stanza actually changes the state, then the server updates the state and delivers the stanza. And if you're already subscribed, it's a no-op: no state change, no delivery. Not every yes is a new yes, lol ๐
Table 8: Processing of inbound "subscribed" stanzas
+------------------------------------------------------------------+
| EXISTING STATE | DELIVER? | NEW STATE |
+------------------------------------------------------------------+
| "None" | S.N. | no state change |
| "None + Pending Out" | MUST | "To" |
| "None + Pending In" | S.N. | no state change |
| "None + Pending Out+In" | MUST | "To + Pending In" |
| "To" | S.N. | no state change |
| "To + Pending In" | S.N. | no state change |
| "From" | S.N. | no state change |
| "From + Pending Out" | MUST | "Both" |
| "Both" | S.N. | no state change |
+------------------------------------------------------------------+
A.3.4. Unsubscribed ๐
Last one: inbound unsubscribed is the contact (or the server acting for them) saying "you're not on my list anymore" ๐ค. If you had a pending outbound request or you're currently subscribed, the server updates the state and delivers the stanza. Otherwise it leaves the state alone and usually doesn't deliver it. Here's the table:
Table 9: Processing of inbound "unsubscribed" stanzas
+------------------------------------------------------------------+
| EXISTING STATE | DELIVER? | NEW STATE |
+------------------------------------------------------------------+
| "None" | S.N. | no state change |
| "None + Pending Out" | MUST | "None" |
| "None + Pending In" | S.N. | no state change |
| "None + Pending Out+In" | MUST | "None + Pending In" |
| "To" | MUST | "None" |
| "To + Pending In" | MUST | "None + Pending In" |
| "From" | S.N. | no state change |
| "From + Pending Out" | MUST | "From" |
| "Both" | MUST | "From" |
+------------------------------------------------------------------+
Appendix B. Blocking Communication ๐ซ
Okay, so the instant messaging requirements in Sections 2.3.5 and 5.4.10 of [IMP-REQS] say a compliant IM and presence tech has to let a user block communication from selected people ๐ โโ๏ธ. The protocols for doing that live in [XEP-0016] and [XEP-0191], so that's where to look ๐
Appendix C. vCards ๐
Sections 3.1.3 and 4.1.4 of [IMP-REQS] want users to be able to look up out-of-band contact info for other people, like a phone number or an email address ๐. The XML version of the vCard spec from RFC 2426 [VCARD] is what the XMPP community mostly uses for that, but it's out of scope for this spec. If you want the details, [XEP-0054] has them ๐
Appendix D. XML Schema for jabber:iq:roster โจ
Here's the formal XML Schema for the jabber:iq:roster namespace from this doc, written to follow [XML-SCHEMA] ๐
. Validating XML streams and stanzas is optional, so this schema isn't normative ๐. It's just here to describe things. For the schemas for the core XMPP namespaces, check [XMPP-CORE] ๐ง
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema
xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='jabber:iq:roster'
xmlns='jabber:iq:roster'
elementFormDefault='qualified'>
<xs:element name='query'>
<xs:complexType>
<xs:sequence>
<xs:element ref='item'
minOccurs='0'
maxOccurs='unbounded'/>
</xs:sequence>
<xs:attribute name='ver'
type='xs:string'
use='optional'/>
</xs:complexType>
</xs:element>
<xs:element name='item'>
<xs:complexType>
<xs:sequence>
<xs:element ref='group'
minOccurs='0'
maxOccurs='unbounded'/>
</xs:sequence>
<xs:attribute name='approved'
type='xs:boolean'
use='optional'/>
<xs:attribute name='ask'
use='optional'>
<xs:simpleType>
<xs:restriction base='xs:NMTOKEN'>
<xs:enumeration value='subscribe'/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name='jid'
type='xs:string'
use='required'/>
<xs:attribute name='name'
type='xs:string'
use='optional'/>
<xs:attribute name='subscription'
use='optional'
default='none'>
<xs:simpleType>
<xs:restriction base='xs:NMTOKEN'>
<xs:enumeration value='both'/>
<xs:enumeration value='from'/>
<xs:enumeration value='none'/>
<xs:enumeration value='remove'/>
<xs:enumeration value='to'/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name='group' type='xs:string'/>
</xs:schema>
Appendix E. Differences From RFC 3921 ๐ฆ
Okay bestie, this part is the tea โ The spec team went through [RFC3921] and changed a bunch of stuff. The changes came from what people actually built and deployed, plus formal interoperability testing, so it's all receipts ๐งพ Here's the list of the big substantive changes. There were also tons of editorial tweaks, but those aren't on the list.
- Session establishment got cut ๐ช. It was deemed unnecessary, so the stuff in Section 3 of RFC 3921 is gone. But for backward-compatibility, servers are encouraged to still advertise support for the feature, even though session establishment is a "no-op" ๐
- Error handling for presence subscription requests, presence probes, and presence notifications got clarified and modified. The goal is to make it easier to fix situations where subscription states between rosters on different servers don't match ๐ง
- The
fromaddress for presence probes is now the bare JID instead of the full JID ๐ - Stanza delivery rules got adjusted and clarified based on implementation and deployment experience ๐ฌ
- A server is now explicitly allowed to deliver a message stanza of type "normal" or "chat" to all resources, as long as it has a way for resources to opt in to that behavior ๐
- Servers can use their own algorithm to pick the "most available" resource for delivering messages ๐ฏ. The algorithm from RFC 3921 (based on presence priority) is still mentioned, but only as one possible option.
- Roster versioning was added as an optional feature ๐. It can save bandwidth when the roster hasn't changed much, or hasn't changed at all, between sessions. The protocol interactions were first described in [XEP-0237] โจ
- Servers can optionally support pre-approved presence subscriptions through presence stanzas of type "subscribed" ๐ซถ. There's a new
approvedattribute that can be set to "true" for a pre-approved subscription, or "false", which is the default. - The
<thread/>element can now have an optionalparentattribute ๐งต - The communications blocking protocol (originally in Section 10 of RFC 3921) moved back to [XEP-0016], where it originally came from ๐
- Returning presence unavailable in response to probes is now recommended ๐
- Handling of presence probes sent to full JIDs got clarified ๐
- The default value for the presence
<priority/>element is now explicitly specified as zero ๐ข - The recommendation to support the "_im" and "_pres" SRV records got removed ๐๏ธ
Appendix F. Acknowledgements ๐ซถ
This document is an update to RFC 3921, and it's derived from that one too ๐. None of this would've happened without the people who contributed to and commented on RFC 3921. Their names are in that document.
Hundreds of people have sent in implementation feedback, bug reports, questions asking for clarification, and ideas for improvement since RFC 3921 came out ๐. The document editor tried to address all of it, but he takes sole responsibility for any errors and ambiguities that are still left ๐ซ
Some of the roster versioning text was borrowed from [XEP-0237], and some of the message thread text was borrowed from [XEP-0201] ๐งต
Special thanks to Kevin Smith, Matthew Wild, Dave Cridland, Waqas Hussain, Philipp Hancke, Florian Zeitz, Jonas Lindberg, Jehan Pages, Tory Patnoe, and others for their comments during Working Group Last Call ๐
Thanks also to Richard Barnes for his review on behalf of the Security Directorate ๐ก๏ธ
The Working Group chairs were Ben Campbell and Joe Hildebrand ๐ธ. The responsible Area Director was Gonzalo Camarillo โจ
Author's Address ๐
Peter Saint-Andre
Cisco
1899 Wyknoop Street, Suite 600
Denver, CO 80202
USA
Phone: +1-303-308-3282
EMail: psaintan@cisco.com
That's the whole thing, bestie ๐๐๐ฆ RFC 6121, all done!! ๐
๐ฆ where this page comes from
- ietf: rfc6121 2011-03
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms