RFC 6121

Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence

๐Ÿ“… published March 2011, from ietf

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 (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:

  1. The central point of focus is a list of one's contacts or "buddies" (in XMPP this list is called a "roster") ๐ŸŒธ
  2. 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 โœจ
  3. 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) ๐ŸŸข
  4. 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:

  1. Retrieve one's roster. (See Section 2.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.) ๐ŸŸข
  3. 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.) ๐Ÿ”„
  4. 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 &#x0159; 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: = client
  • CC: = contact's client
  • CS: = contact's server
  • S: = server
  • UC: = user's client
  • US: = 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: The approved attribute 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 the subscription attribute 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:

  1. The <query/> element MUST contain one and only one <item/> element ๐ŸŽฏ
  2. The server MUST ignore any value of the subscription attribute 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:

  1. The <query/> element in a roster push MUST contain one and only one <item/> element ๐ŸŽ€
  2. 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 ๐Ÿ™…โ€โ™€๏ธ:

  1. The <query/> element contains more than one <item/> child element.
  2. 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 ๐Ÿ™ˆ:

  1. The length of the 'name' attribute is greater than a server-configured limit.
  2. 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.)
  3. 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:

  1. Adding a group
  2. Deleting a group
  3. Changing the handle
  4. 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 empty name attribute is equivalent to including no name attribute. 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:

  1. 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).
  2. 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).
  3. 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 ๐Ÿ‘‘

  1. 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").
  2. 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" ๐Ÿ˜ณ
  3. 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 ๐Ÿ’…

  1. 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.
  2. 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 ๐Ÿ .
  3. 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 ๐Ÿ“‹:

  1. 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 ๐Ÿ™‹โ€โ™€๏ธ.
  2. 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'/>
  1. 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 ๐Ÿ‘€.
  2. 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:

  1. 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'/>
  1. Start a roster push to all of the user's interested resources, containing an updated roster item for the contact. The subscription attribute 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>
  1. 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 ๐Ÿง.

  1. 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 ๐Ÿฅฒ.
  2. If the user's bare JID is in the contact's roster with a state of "None", "None + Pending Out", or "To" and the approved flag 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 ๐Ÿ“.
  3. 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:

  1. 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'/>
  1. Initiate a roster push to all of the user's interested resources. It contains an updated roster item for the contact with the subscription attribute 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 ๐Ÿ“ฎ.

  1. 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.
  2. 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:

  1. 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'/>
  1. Initiate a roster push to all of the contact's interested resources. It contains an updated roster item for the user with the subscription attribute 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>
  1. 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:

  1. 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. ๐Ÿ™ˆ
  2. 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. ๐Ÿ”ฅ
  3. 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 the approved flag 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. ๐Ÿ›‘
  4. 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 the approved flag 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 the approved attribute 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 the approved attribute (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 the approved attribute 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:

  1. If the user's bare JID is in the contact's roster, display the presence information in an appropriate roster interface. ๐Ÿ“‡
  2. 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). ๐Ÿ’ฌ
  3. 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 ๐Ÿ’…

  1. 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. ๐ŸŽ€
  2. 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). ๐Ÿ˜ญ
  3. 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&#x0159;&#x00ED;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&#x0159;&#x00ED;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&#x010D;e&#x017D; 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'>
    &#x00DA;p&#x011B;nliv&#x011B; pros&#x00ED;m!
  </subject>
  <body>Wherefore art thou, Romeo?</body>
  <body xml:lang='cs'>
     Pro&#x010D;e&#x017E; 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'>
    &#x00DA;p&#x011B;nliv&#x011B; pros&#x00ED;m!
  </subject>
  <body>Wherefore art thou, Romeo?</body>
  <body xml:lang='cs'>
     Pro&#x010D;e&#x017E; 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 type attribute or a type attribute 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 type attribute or a type attribute 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:

  1. Preferably mandate channel encryption for communication with local clients and remote servers ๐Ÿ”’
  2. Authenticate any client that wants to access the user's account ๐Ÿชช
  3. 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 โœจ

  1. "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'.
  2. "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'.
  3. "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). ๐Ÿซฃ
  4. "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'.
  5. "To" = User is subscribed to contact (one-way); this is reflected in the user's roster by subscription='to'.
  6. "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'.
  7. "From" = Contact is subscribed to user (one-way); this is reflected in the user's roster by subscription='from'.
  8. "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'.
  9. "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 from address 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 approved attribute that can be set to "true" for a pre-approved subscription, or "false", which is the default.
  • The <thread/> element can now have an optional parent attribute ๐Ÿงต
  • 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