8.4. Unsubscribing
At any time after subscribing to a contact's presence information, a user MAY unsubscribe. While the XML that the user sends to make this happen is the same in all instances, the subsequent subscription state is different depending on the subscription state obtaining when the unsubscribe "command" is sent. Both possible scenarios are described below.8.4.1. Case #1: Unsubscribing When Subscription is Not Mutual
In the first case, the user has a subscription to the contact's presence information but the contact does not have a subscription to the user's presence information (i.e., the subscription is not yet mutual). 1. If the user wants to unsubscribe from the contact's presence information, the user MUST send a presence stanza of type "unsubscribe" to the contact: <presence to='contact@example.org' type='unsubscribe'/> 2. As a result, the user's server (1) MUST send a roster push to all of the user's available resources that have requested the roster, containing an updated roster item for the contact with the 'subscription' attribute set to a value of "none"; and (2) MUST route the presence stanza of type "unsubscribe" to the contact, first stamping the 'from' address as the bare JID (<user@example.com>) of the user: <iq type='set'> <query xmlns='jabber:iq:roster'> <item jid='contact@example.org' subscription='none' name='MyContact'> <group>MyBuddies</group> </item> </query> </iq> <presence from='user@example.com' to='contact@example.org' type='unsubscribe'/>
3. Upon receiving the presence stanza of type "unsubscribe" addressed to the contact, the contact's server (1) MUST initiate a roster push to all available resources associated with the contact that have requested the roster, containing an updated roster item for the user with the 'subscription' attribute set to a value of "none" (if the contact is unavailable or has not requested the roster, the contact's server MUST modify the roster item and send that modified item the next time the contact requests the roster); and (2) MUST deliver the "unsubscribe" state change notification to the contact: <iq type='set'> <query xmlns='jabber:iq:roster'> <item jid='user@example.com' subscription='none' name='SomeUser'> <group>SomeGroup</group> </item> </query> </iq> <presence from='user@example.com' to='contact@example.org' type='unsubscribe'/> 4. Upon receiving the presence stanza of type "unsubscribe", the contact SHOULD acknowledge receipt of that subscription state notification through either "affirming" it by sending a presence stanza of type "unsubscribed" to the user or "denying" it by sending a presence stanza of type "subscribed" to the user; this step does not necessarily affect the subscription state (see Subscription States (Section 9) for details), but instead lets the contact's server know that it MUST no longer send notification of the subscription state change to the contact (see Section 9.4). 5. The contact's server then (1) MUST send a presence stanza of type "unsubscribed" to the user; and (2) SHOULD send unavailable presence from all of the contact's available resources to the user: <presence from='contact@example.org' to='user@example.com' type='unsubscribed'/>
<presence from='contact@example.org/resource' to='user@example.com' type='unavailable'/> 6. When the user's server receives the presence stanzas of type "unsubscribed" and "unavailable", it MUST deliver them to the user: <presence from='contact@example.org' to='user@example.com' type='unsubscribed'/> <presence from='contact@example.org/resource' to='user@example.com' type='unavailable'/> 7. Upon receiving the presence stanza of type "unsubscribed", the user SHOULD acknowledge receipt of that subscription state notification through either "affirming" it by sending a presence stanza of type "unsubscribe" to the contact or "denying" it by sending a presence stanza of type "subscribe" to the contact; this step does not necessarily affect the subscription state (see Subscription States (Section 9) for details), but instead lets the user's server know that it MUST no longer send notification of the subscription state change to the user (see Section 9.4).8.4.2. Case #2: Unsubscribing When Subscription is Mutual
In the second case, the user has a subscription to the contact's presence information and the contact also has a subscription to the user's presence information (i.e., the subscription is mutual). 1. If the user wants to unsubscribe from the contact's presence information, the user MUST send a presence stanza of type "unsubscribe" to the contact: <presence to='contact@example.org' type='unsubscribe'/> 2. As a result, the user's server (1) MUST send a roster push to all of the user's available resources that have requested the roster, containing an updated roster item for the contact with the 'subscription' attribute set to a value of "from"; and (2) MUST route the presence stanza of type "unsubscribe" to the contact, first stamping the 'from' address as the bare JID (<user@example.com>) of the user:
<iq type='set'> <query xmlns='jabber:iq:roster'> <item jid='contact@example.org' subscription='from' name='MyContact'> <group>MyBuddies</group> </item> </query> </iq> <presence from='user@example.com' to='contact@example.org' type='unsubscribe'/> 3. Upon receiving the presence stanza of type "unsubscribe" addressed to the contact, the contact's server (1) MUST initiate a roster push to all available resources associated with the contact that have requested the roster, containing an updated roster item for the user with the 'subscription' attribute set to a value of "to" (if the contact is unavailable or has not requested the roster, the contact's server MUST modify the roster item and send that modified item the next time the contact requests the roster); and (2) MUST deliver the "unsubscribe" state change notification to the contact: <iq type='set'> <query xmlns='jabber:iq:roster'> <item jid='user@example.com' subscription='to' name='SomeUser'> <group>SomeGroup</group> </item> </query> </iq> <presence from='user@example.com' to='contact@example.org' type='unsubscribe'/> 4. Upon receiving the presence stanza of type "unsubscribe", the contact SHOULD acknowledge receipt of that subscription state notification through either "affirming" it by sending a presence stanza of type "unsubscribed" to the user or "denying" it by sending a presence stanza of type "subscribed" to the user; this
step does not necessarily affect the subscription state (see Subscription States (Section 9) for details), but instead lets the contact's server know that it MUST no longer send notification of the subscription state change to the contact (see Section 9.4). 5. The contact's server then (1) MUST send a presence stanza of type "unsubscribed" to the user; and (2) SHOULD send unavailable presence from all of the contact's available resources to the user: <presence from='contact@example.org' to='user@example.com' type='unsubscribed'/> <presence from='contact@example.org/resource' to='user@example.com' type='unavailable'/> 6. When the user's server receives the presence stanzas of type "unsubscribed" and "unavailable", it MUST deliver them to the user: <presence from='contact@example.org' to='user@example.com' type='unsubscribed'/> <presence from='contact@example.org/resource' to='user@example.com' type='unavailable'/> 7. Upon receiving the presence stanza of type "unsubscribed", the user SHOULD acknowledge receipt of that subscription state notification through either "affirming" it by sending a presence stanza of type "unsubscribe" to the contact or "denying" it by sending a presence stanza of type "subscribe" to the contact; this step does not necessarily affect the subscription state (see Subscription States (Section 9) for details), but instead lets the user's server know that it MUST no longer send notification of the subscription state change to the user (see Section 9.4). Note: Obviously this does not result in removal of the roster item from the user's roster, and the contact still has a subscription to the user's presence information. In order to both completely cancel
a mutual subscription and fully remove the roster item from the user's roster, the user SHOULD update the roster item with subscription='remove' as defined under Removing a Roster Item and Cancelling All Subscriptions (Section 8.6).8.5. Cancelling a Subscription
At any time after approving a subscription request from a user, a contact MAY cancel that subscription. While the XML that the contact sends to make this happen is the same in all instances, the subsequent subscription state is different depending on the subscription state obtaining when the cancellation was sent. Both possible scenarios are described below.8.5.1. Case #1: Cancelling When Subscription is Not Mutual
In the first case, the user has a subscription to the contact's presence information but the contact does not have a subscription to the user's presence information (i.e., the subscription is not yet mutual). 1. If the contact wants to cancel the user's subscription, the contact MUST send a presence stanza of type "unsubscribed" to the user: <presence to='user@example.com' type='unsubscribed'/> 2. As a result, the contact's server (1) MUST send a roster push to all of the contact's available resources that have requested the roster, containing an updated roster item for the user with the 'subscription' attribute set to a value of "none"; (2) MUST route the presence stanza of type "unsubscribed" to the user, first stamping the 'from' address as the bare JID (<contact@example.org>) of the contact; and (3) SHOULD send unavailable presence from all of the contact's available resources to the user: <iq type='set'> <query xmlns='jabber:iq:roster'> <item jid='user@example.com' subscription='none' name='SomeUser'> <group>SomeGroup</group> </item> </query> </iq>
<presence from='contact@example.org' to='user@example.com' type='unsubscribed'/> <presence from='contact@example.org/resource' to='user@example.com' type='unavailable'/> 3. Upon receiving the presence stanza of type "unsubscribed" addressed to the user, the user's server (1) MUST initiate a roster push to all of the user's available resources that have requested the roster, containing an updated roster item for the contact with the 'subscription' attribute set to a value of "none" (if the user is unavailable or has not requested the roster, the user's server MUST modify the roster item and send that modified item the next time the user requests the roster); (2) MUST deliver the "unsubscribed" state change notification to all of the user's available resources; and (3) MUST deliver the unavailable presence to all of the user's available resources: <iq type='set'> <query xmlns='jabber:iq:roster'> <item jid='contact@example.org' subscription='none' name='MyContact'> <group>MyBuddies</group> </item> </query> </iq> <presence from='contact@example.org' to='user@example.com' type='unsubscribed'/> <presence from='contact@example.org/resource' to='user@example.com' type='unavailable'/> 4. Upon receiving the presence stanza of type "unsubscribed", the user SHOULD acknowledge receipt of that subscription state notification through either "affirming" it by sending a presence stanza of type "unsubscribe" to the contact or "denying" it by sending a presence stanza of type "subscribe" to the contact;
this step does not necessarily affect the subscription state (see Subscription States (Section 9) for details), but instead lets the user's server know that it MUST no longer send notification of the subscription state change to the user (see Section 9.4).8.5.2. Case #2: Cancelling When Subscription is Mutual
In the second case, the user has a subscription to the contact's presence information and the contact also has a subscription to the user's presence information (i.e., the subscription is mutual). 1. If the contact wants to cancel the user's subscription, the contact MUST send a presence stanza of type "unsubscribed" to the user: <presence to='user@example.com' type='unsubscribed'/> 2. As a result, the contact's server (1) MUST send a roster push to all of the contact's available resources that have requested the roster, containing an updated roster item for the user with the 'subscription' attribute set to a value of "to"; (2) MUST route the presence stanza of type "unsubscribed" to the user, first stamping the 'from' address as the bare JID (<contact@example.org>) of the contact; and (3) SHOULD send unavailable presence from all of the contact's available resources to all of the user's available resources: <iq type='set'> <query xmlns='jabber:iq:roster'> <item jid='user@example.com' subscription='to' name='SomeUser'> <group>SomeGroup</group> </item> </query> </iq> <presence from='contact@example.org' to='user@example.com' type='unsubscribed'/> <presence from='contact@example.org/resource' to='user@example.com' type='unavailable'/>
3. Upon receiving the presence stanza of type "unsubscribed" addressed to the user, the user's server (1) MUST initiate a roster push to all of the user's available resources that have requested the roster, containing an updated roster item for the contact with the 'subscription' attribute set to a value of "from" (if the user is unavailable or has not requested the roster, the user's server MUST modify the roster item and send that modified item the next time the user requests the roster); and (2) MUST deliver the "unsubscribed" state change notification to all of the user's available resources; and (3) MUST deliver the unavailable presence to all of the user's available resources: <iq type='set'> <query xmlns='jabber:iq:roster'> <item jid='contact@example.org' subscription='from' name='MyContact'> <group>MyBuddies</group> </item> </query> </iq> <presence from='contact@example.org' to='user@example.com' type='unsubscribed'/> <presence from='contact@example.org/resource' to='user@example.com' type='unavailable'/> 4. Upon receiving the presence stanza of type "unsubscribed", the user SHOULD acknowledge receipt of that subscription state notification through either "affirming" it by sending a presence stanza of type "unsubscribe" to the contact or "denying" it by sending a presence stanza of type "subscribe" to the contact; this step does not necessarily affect the subscription state (see Subscription States (Section 9) for details), but instead lets the user's server know that it MUST no longer send notification of the subscription state change to the user (see Section 9.4). Note: Obviously this does not result in removal of the roster item from the contact's roster, and the contact still has a subscription to the user's presence information. In order to both completely cancel a mutual subscription and fully remove the roster item from
the contact's roster, the contact should update the roster item with subscription='remove' as defined under Removing a Roster Item and Cancelling All Subscriptions (Section 8.6).8.6. Removing a Roster Item and Cancelling All Subscriptions
Because there may be many steps involved in completely removing a roster item and cancelling subscriptions in both directions, the roster management protocol includes a "shortcut" method for doing so. The process may be initiated no matter what the current subscription state is by sending a roster set containing an item for the contact with the 'subscription' attribute set to a value of "remove": <iq type='set' id='remove1'> <query xmlns='jabber:iq:roster'> <item jid='contact@example.org' subscription='remove'/> </query> </iq> When the user removes a contact from his or her roster by setting the 'subscription' attribute to a value of "remove", the user's server (1) MUST automatically cancel any existing presence subscription between the user and the contact (both 'to' and 'from' as appropriate); (2) MUST remove the roster item from the user's roster and inform all of the user's available resources that have requested the roster of the roster item removal; (3) MUST inform the resource that initiated the removal of success; and (4) SHOULD send unavailable presence from all of the user's available resources to the contact: <presence from='user@example.com' to='contact@example.org' type='unsubscribe'/> <presence from='user@example.com' to='contact@example.org' type='unsubscribed'/>
<iq type='set'> <query xmlns='jabber:iq:roster'> <item jid='contact@example.org' subscription='remove'/> </query> </iq> <iq type='result' id='remove1'/> <presence from='user@example.com/resource' to='contact@example.org' type='unavailable'/> Upon receiving the presence stanza of type "unsubscribe", the contact's server (1) MUST initiate a roster push to all available resources associated with the contact that have requested the roster, containing an updated roster item for the user with the 'subscription' attribute set to a value of "to" (if the contact is unavailable or has not requested the roster, the contact's server MUST modify the roster item and send that modified item the next time the contact requests the roster); and (2) MUST also deliver the "unsubscribe" state change notification to all of the contact's available resources: <iq type='set'> <query xmlns='jabber:iq:roster'> <item jid='user@example.com' subscription='to' name='SomeUser'> <group>SomeGroup</group> </item> </query> </iq> <presence from='user@example.com' to='contact@example.org' type='unsubscribe'/> Upon receiving the presence stanza of type "unsubscribed", the contact's server (1) MUST initiate a roster push to all available resources associated with the contact that have requested the roster, containing an updated roster item for the user with the 'subscription' attribute set to a value of "none" (if the contact is unavailable or has not requested the roster, the contact's server
MUST modify the roster item and send that modified item the next time the contact requests the roster); and (2) MUST also deliver the "unsubscribe" state change notification to all of the contact's available resources: <iq type='set'> <query xmlns='jabber:iq:roster'> <item jid='user@example.com' subscription='none' name='SomeUser'> <group>SomeGroup</group> </item> </query> </iq> <presence from='user@example.com' to='contact@example.org' type='unsubscribed'/> Upon receiving the presence stanza of type "unavailable" addressed to the contact, the contact's server MUST deliver the unavailable presence to all of the user's available resources: <presence from='user@example.com/resource' to='contact@example.org' type='unavailable'/> Note: When the user removes the contact from the user's roster, the end state of the contact's roster is that the user is still in the contact's roster with a subscription state of "none"; in order to completely remove the roster item for the user, the contact needs to also send a roster removal request.9. Subscription States
This section provides detailed information about subscription states and server handling of subscription-related presence stanzas (i.e., presence stanzas of type "subscribe", "subscribed", "unsubscribe", and "unsubscribed").9.1. Defined States
There are nine possible subscription states, which are described here from the user's (not contact's) perspective:
1. "None" = contact and user are not subscribed to each other, and neither has requested a subscription from the other 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 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 (note: contact's server SHOULD NOT push or deliver roster items in this state, but instead SHOULD wait until contact has approved subscription request from user) 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 5. "To" = user is subscribed to contact (one-way) 6. "To + Pending In" = user is subscribed to contact, and contact has sent user a subscription request but user has not replied yet 7. "From" = contact is subscribed to user (one-way) 8. "From + Pending Out" = contact is subscribed to user, and user has sent contact a subscription request but contact has not replied yet 9. "Both" = user and contact are subscribed to each other (two-way)9.2. Server Handling of Outbound Presence Subscription Stanzas
Outbound presence subscription stanzas enable the user to manage his or her subscription to the contact's presence information (via the "subscribe" and "unsubscribe" types), and to manage the contact's access to the user's presence information (via the "subscribed" and "unsubscribed" types). Because it is possible for the user's server and the contact's server to lose synchronization regarding subscription states, the user's server MUST without exception route all outbound presence stanzas of type "subscribe" or "unsubscribe" to the contact so that the user is able to resynchronize his or her subscription to the contact's presence information if needed.
The user's server SHOULD NOT route a presence stanza of type "subscribed" or "unsubscribed" to the contact if the stanza does not result in a subscription state change from the user's perspective, and MUST NOT make a state change. If the stanza results in a subscription state change, the user's server MUST route the stanza to the contact and MUST make the appropriate state change. These rules are summarized in the following tables. Table 1: Recommended handling of outbound "subscribed" stanzas +----------------------------------------------------------------+ | EXISTING STATE | ROUTE? | NEW STATE | +----------------------------------------------------------------+ | "None" | no | no state change | | "None + Pending Out" | no | no state change | | "None + Pending In" | yes | "From" | | "None + Pending Out/In" | yes | "From + Pending Out" | | "To" | no | no state change | | "To + Pending In" | yes | "Both" | | "From" | no | no state change | | "From + Pending Out" | no | no state change | | "Both" | no | no state change | +----------------------------------------------------------------+ Table 2: Recommended handling of outbound "unsubscribed" stanzas +----------------------------------------------------------------+ | EXISTING STATE | ROUTE? | NEW STATE | +----------------------------------------------------------------+ | "None" | no | no state change | | "None + Pending Out" | no | no state change | | "None + Pending In" | yes | "None" | | "None + Pending Out/In" | yes | "None + Pending Out" | | "To" | no | no state change | | "To + Pending In" | yes | "To" | | "From" | yes | "None" | | "From + Pending Out" | yes | "None + Pending Out" | | "Both" | yes | "To" | +----------------------------------------------------------------+9.3. Server Handling of Inbound Presence Subscription Stanzas
Inbound presence subscription stanzas request a subscription-related action from the user (via the "subscribe" type), inform the user of subscription-related actions taken by the contact (via the "unsubscribe" type), or enable the contact to manage the user's access to the contact's presence information (via the "subscribed" and "unsubscribed" types).
When the user's server receives a subscription request for the user from the contact (i.e., a presence stanza of type "subscribe"), it MUST deliver that request to the user for approval if the user has not already granted the contact access to the user's presence information and if there is no pending inbound subscription request; however, the user's server SHOULD NOT deliver the new request if there is a pending inbound subscription request, since the previous subscription request will have been recorded. If the user has already granted the contact access to the user's presence information, the user's server SHOULD auto-reply to an inbound presence stanza of type "subscribe" from the contact by sending a presence stanza of type "subscribed" to the contact on behalf of the user; this rule enables the contact to resynchronize the subscription state if needed. These rules are summarized in the following table. Table 3: Recommended handling of inbound "subscribe" stanzas +------------------------------------------------------------------+ | EXISTING STATE | DELIVER? | NEW STATE | +------------------------------------------------------------------+ | "None" | yes | "None + Pending In" | | "None + Pending Out" | yes | "None + Pending Out/In" | | "None + Pending In" | no | no state change | | "None + Pending Out/In" | no | no state change | | "To" | yes | "To + Pending In" | | "To + Pending In" | no | no state change | | "From" | no * | no state change | | "From + Pending Out" | no * | no state change | | "Both" | no * | no state change | +------------------------------------------------------------------+ * Server SHOULD auto-reply with "subscribed" stanza When the user's server receives a presence stanza of type "unsubscribe" for the user from the contact, if the stanza results in a subscription state change from the user's perspective then the user's server SHOULD auto-reply by sending a presence stanza of type "unsubscribed" to the contact on behalf of the user, MUST deliver the "unsubscribe" stanza to the user, and MUST change the state. If no subscription state change results, the user's server SHOULD NOT deliver the stanza and MUST NOT change the state. These rules are summarized in the following table.
Table 4: Recommended handling of inbound "unsubscribe" stanzas +------------------------------------------------------------------+ | EXISTING STATE | DELIVER? | NEW STATE | +------------------------------------------------------------------+ | "None" | no | no state change | | "None + Pending Out" | no | no state change | | "None + Pending In" | yes * | "None" | | "None + Pending Out/In" | yes * | "None + Pending Out" | | "To" | no | no state change | | "To + Pending In" | yes * | "To" | | "From" | yes * | "None" | | "From + Pending Out" | yes * | "None + Pending Out | | "Both" | yes * | "To" | +------------------------------------------------------------------+ * Server SHOULD auto-reply with "unsubscribed" stanza When the user's server receives a presence stanza of type "subscribed" for the user from the contact, it MUST NOT deliver the stanza to the user and MUST NOT change the subscription state if there is no pending outbound request for access to the contact's presence information. If there is a pending outbound request for access to the contact's presence information and the inbound presence stanza of type "subscribed" results in a subscription state change, the user's server MUST deliver the stanza to the user and MUST change the subscription state. If the user already has access to the contact's presence information, the inbound presence stanza of type "subscribed" does not result in a subscription state change; therefore the user's server SHOULD NOT deliver the stanza to the user and MUST NOT change the subscription state. These rules are summarized in the following table. Table 5: Recommended handling of inbound "subscribed" stanzas +------------------------------------------------------------------+ | EXISTING STATE | DELIVER? | NEW STATE | +------------------------------------------------------------------+ | "None" | no | no state change | | "None + Pending Out" | yes | "To" | | "None + Pending In" | no | no state change | | "None + Pending Out/In" | yes | "To + Pending In" | | "To" | no | no state change | | "To + Pending In" | no | no state change | | "From" | no | no state change | | "From + Pending Out" | yes | "Both" | | "Both" | no | no state change | +------------------------------------------------------------------+
When the user's server receives a presence stanza of type "unsubscribed" for the user from the contact, it MUST deliver the stanza to the user and MUST change the subscription state if there is a pending outbound request for access to the contact's presence information or if the user currently has access to the contact's presence information. Otherwise, the user's server SHOULD NOT deliver the stanza and MUST NOT change the subscription state. These rules are summarized in the following table. Table 6: Recommended handling of inbound "unsubscribed" stanzas +------------------------------------------------------------------+ | EXISTING STATE | DELIVER? | NEW STATE | +------------------------------------------------------------------+ | "None" | no | no state change | | "None + Pending Out" | yes | "None" | | "None + Pending In" | no | no state change | | "None + Pending Out/In" | yes | "None + Pending In" | | "To" | yes | "None" | | "To + Pending In" | yes | "None + Pending In" | | "From" | no | no state change | | "From + Pending Out" | yes | "From" | | "Both" | yes | "From" | +------------------------------------------------------------------+9.4. Server Delivery and Client Acknowledgement of Subscription Requests and State Change Notifications
When a server receives an inbound presence stanza of type "subscribe" (i.e., a subscription request) or of type "subscribed", "unsubscribe", or "unsubscribed" (i.e., a subscription state change notification), in addition to sending the appropriate roster push (or updated roster when the roster is next requested by an available resource), it MUST deliver the request or notification to the intended recipient at least once. A server MAY require the recipient to acknowledge receipt of all state change notifications (and MUST require acknowledgement in the case of subscription requests, i.e., presence stanzas of type "subscribe"). In order to require acknowledgement, a server SHOULD send the request or notification to the recipient each time the recipient logs in, until the recipient acknowledges receipt of the notification by "affirming" or "denying" the notification, as shown in the following table:
Table 7: Acknowledgement of subscription state change notifications +--------------------------------------------------+ | STANZA TYPE | ACCEPT | DENY | +--------------------------------------------------+ | subscribe | subscribed | unsubscribed | | subscribed | subscribe | unsubscribe | | unsubscribe | unsubscribed | subscribed | | unsubscribed | unsubscribe | subscribe | +--------------------------------------------------+ Obviously, given the foregoing subscription state charts, some of the acknowledgement stanzas will be routed to the contact and result in subscription state changes, while others will not. However, any such stanzas MUST result in the server's no longer sending the subscription state notification to the user. Because a user's server MUST automatically generate outbound presence stanzas of type "unsubscribe" and "unsubscribed" upon receiving a roster set with the 'subscription' attribute set to a value of "remove" (see Removing a Roster Item and Cancelling All Subscriptions (Section 8.6)), the server MUST treat a roster remove request as equivalent to sending both of those presence stanzas for purposes of determining whether to continue sending subscription state change notifications of type "subscribe" or "subscribed" to the user.10. Blocking Communication
Most instant messaging systems have found it necessary to implement some method for users to block communications from particular other users (this is also required by sections 5.1.5, 5.1.15, 5.3.2, and 5.4.10 of [IMP-REQS]). In XMPP this is done by managing one's privacy lists using the 'jabber:iq:privacy' namespace. Server-side privacy lists enable successful completion of the following use cases: o Retrieving one's privacy lists. o Adding, removing, and editing one's privacy lists. o Setting, changing, or declining active lists. o Setting, changing, or declining the default list (i.e., the list that is active by default). o Allowing or blocking messages based on JID, group, or subscription type (or globally).
o Allowing or blocking inbound presence notifications based on JID, group, or subscription type (or globally). o Allowing or blocking outbound presence notifications based on JID, group, or subscription type (or globally). o Allowing or blocking IQ stanzas based on JID, group, or subscription type (or globally). o Allowing or blocking all communications based on JID, group, or subscription type (or globally). Note: Presence notifications do not include presence subscriptions, only presence information that is broadcasted to entities that are subscribed to a user's presence information. Thus this includes presence stanzas with no 'type' attribute or of type='unavailable' only.10.1. Syntax and Semantics
A user MAY define one or more privacy lists, which are stored by the user's server. Each <list/> element contains one or more rules in the form of <item/> elements, and each <item/> element uses attributes to define a privacy rule type, a specific value to which the rule applies, the relevant action, and the place of the item in the processing order. The syntax is as follows: <iq> <query xmlns='jabber:iq:privacy'> <list name='foo'> <item type='[jid|group|subscription]' value='bar' action='[allow|deny]' order='unsignedInt'> [<message/>] [<presence-in/>] [<presence-out/>] [<iq/>] </item> </list> </query> </iq>
If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID. JIDs SHOULD be matched in the following order: 1. <user@domain/resource> (only that resource matches) 2. <user@domain> (any resource matches) 3. <domain/resource> (only that resource matches) 4. <domain> (the domain itself matches, as does any user@domain, domain/resource, or address containing a subdomain) If the type is "group", then the 'value' attribute SHOULD contain the name of a group in the user's roster. (If a client attempts to update, create, or delete a list item with a group that is not in the user's roster, the server SHOULD return to the client an <item-not-found/> stanza error.) If the type is "subscription", then the 'value' attribute MUST be one of "both", "to", "from", or "none" as defined under Roster Syntax and Semantics (Section 7.1), where "none" includes entities that are totally unknown to the user and therefore not in the user's roster at all. If no 'type' attribute is included, the rule provides the "fall-through" case. The 'action' attribute MUST be included and its value MUST be either "allow" or "deny". The 'order' attribute MUST be included and its value MUST be a non-negative integer that is unique among all items in the list. (If a client attempts to create or update a list with non-unique order values, the server MUST return to the client a <bad-request/> stanza error.) The <item/> element MAY contain one or more child elements that enable an entity to specify more granular control over which kinds of stanzas are to be blocked (i.e., rather than blocking all stanzas). The allowable child elements are: o <message/> -- blocks incoming message stanzas o <iq/> -- blocks incoming IQ stanzas o <presence-in/> -- blocks incoming presence notifications o <presence-out/> -- blocks outgoing presence notifications
Within the 'jabber:iq:privacy' namespace, the <query/> child of an IQ stanza of type "set" MUST NOT include more than one child element (i.e., the stanza MUST contain only one <active/> element, one <default/> element, or one <list/> element); if a sending entity violates this rule, the receiving entity MUST return a <bad-request/> stanza error. When a client adds or updates a privacy list, the <list/> element SHOULD contain at least one <item/> child element; when a client removes a privacy list, the <list/> element MUST NOT contain any <item/> child elements. When a client updates a privacy list, it must include all of the desired items (i.e., not a "delta").10.2. Business Rules
1. If there is an active list set for a session, it affects only the session(s) for which it is activated, and only for the duration of the session(s); the server MUST apply the active list only and MUST NOT apply the default list (i.e., there is no "layering" of lists). 2. The default list applies to the user as a whole, and is processed if there is no active list set for the target session/resource to which a stanza is addressed, or if there are no current sessions for the user. 3. If there is no active list set for a session (or there are no current sessions for the user), and there is no default list, then all stanzas SHOULD BE accepted or appropriately processed by the server on behalf of the user in accordance with the Server Rules for Handling XML Stanzas (Section 11). 4. Privacy lists MUST be the first delivery rule applied by a server, superseding (1) the routing and delivery rules specified in Server Rules for Handling XML Stanzas (Section 11), and (2) the handling of subscription-related presence stanzas (and corresponding generation of roster pushes) specified in Integration of Roster Items and Presence Subscriptions (Section 8). 5. The order in which privacy list items are processed by the server is important. List items MUST be processed in ascending order determined by the integer values of the 'order' attribute for each <item/>.
6. As soon as a stanza is matched against a privacy list rule, the server MUST appropriately handle the stanza in accordance with the rule and cease processing. 7. If no fall-through item is provided in a list, the fall-through action is assumed to be "allow". 8. If a user updates the definition for an active list, subsequent processing based on that active list MUST use the updated definition (for all resources to which that active list currently applies). 9. If a change to the subscription state or roster group of a roster item defined in an active or default list occurs during a user's session, subsequent processing based on that list MUST take into account the changed state or group (for all resources to which that list currently applies). 10. When the definition for a rule is modified, the server MUST send an IQ stanza of type "set" to all connected resources, containing a <query/> element with only one <list/> child element, where the 'name' attribute is set to the name of the modified privacy list. These "privacy list pushes" adhere to the same semantics as the "roster pushes" used in roster management, except that only the list name itself (not the full list definition or the "delta") is pushed to the connected resources. It is up to the receiving resource to determine whether to retrieve the modified list definition, although a connected resource SHOULD do so if the list currently applies to it. 11. When a resource attempts to remove a list or specify a new default list while that list applies to a connected resource other than the sending resource, the server MUST return a <conflict/> error to the sending resource and MUST NOT make the requested change.10.3. Retrieving One's Privacy Lists
Example: Client requests names of privacy lists from server: <iq from='romeo@example.net/orchard' type='get' id='getlist1'> <query xmlns='jabber:iq:privacy'/> </iq>
Example: Server sends names of privacy lists to client, preceded by active list and default list: <iq type='result' id='getlist1' to='romeo@example.net/orchard'> <query xmlns='jabber:iq:privacy'> <active name='private'/> <default name='public'/> <list name='public'/> <list name='private'/> <list name='special'/> </query> </iq> Example: Client requests a privacy list from server: <iq from='romeo@example.net/orchard' type='get' id='getlist2'> <query xmlns='jabber:iq:privacy'> <list name='public'/> </query> </iq> Example: Server sends a privacy list to client: <iq type='result' id='getlist2' to='romeo@example.net/orchard'> <query xmlns='jabber:iq:privacy'> <list name='public'> <item type='jid' value='tybalt@example.com' action='deny' order='1'/> <item action='allow' order='2'/> </list> </query> </iq> Example: Client requests another privacy list from server: <iq from='romeo@example.net/orchard' type='get' id='getlist3'> <query xmlns='jabber:iq:privacy'> <list name='private'/> </query> </iq>
Example: Server sends another privacy list to client: <iq type='result' id='getlist3' to='romeo@example.net/orchard'> <query xmlns='jabber:iq:privacy'> <list name='private'> <item type='subscription' value='both' action='allow' order='10'/> <item action='deny' order='15'/> </list> </query> </iq> Example: Client requests yet another privacy list from server: <iq from='romeo@example.net/orchard' type='get' id='getlist4'> <query xmlns='jabber:iq:privacy'> <list name='special'/> </query> </iq> Example: Server sends yet another privacy list to client: <iq type='result' id='getlist4' to='romeo@example.net/orchard'> <query xmlns='jabber:iq:privacy'> <list name='special'> <item type='jid' value='juliet@example.com' action='allow' order='6'/> <item type='jid' value='benvolio@example.org' action='allow' order='7'/> <item type='jid' value='mercutio@example.org' action='allow' order='42'/> <item action='deny' order='666'/> </list> </query> </iq> In this example, the user has three lists: (1) 'public', which allows communications from everyone except one specific entity (this is the default list); (2) 'private', which allows communications only with
contacts who have a bidirectional subscription with the user (this is the active list); and (3) 'special', which allows communications only with three specific entities. If the user attempts to retrieve a list but a list by that name does not exist, the server MUST return an <item-not-found/> stanza error to the user: Example: Client attempts to retrieve non-existent list: <iq to='romeo@example.net/orchard' type='error' id='getlist5'> <query xmlns='jabber:iq:privacy'> <list name='The Empty Set'/> </query> <error type='cancel'> <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </iq> The user is allowed to retrieve only one list at a time. If the user attempts to retrieve more than one list in the same request, the server MUST return a <bad request/> stanza error to the user: Example: Client attempts to retrieve more than one list: <iq to='romeo@example.net/orchard' type='error' id='getlist6'> <query xmlns='jabber:iq:privacy'> <list name='public'/> <list name='private'/> <list name='special'/> </query> <error type='modify'> <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </iq>10.4. Managing Active Lists
In order to set or change the active list currently being applied by the server, the user MUST send an IQ stanza of type "set" with a <query/> element qualified by the 'jabber:iq:privacy' namespace that contains an empty <active/> child element possessing a 'name' attribute whose value is set to the desired list name.
Example: Client requests change of active list: <iq from='romeo@example.net/orchard' type='set' id='active1'> <query xmlns='jabber:iq:privacy'> <active name='special'/> </query> </iq> The server MUST activate and apply the requested list before sending the result back to the client. Example: Server acknowledges success of active list change: <iq type='result' id='active1' to='romeo@example.net/orchard'/> If the user attempts to set an active list but a list by that name does not exist, the server MUST return an <item-not-found/> stanza error to the user: Example: Client attempts to set a non-existent list as active: <iq to='romeo@example.net/orchard' type='error' id='active2'> <query xmlns='jabber:iq:privacy'> <active name='The Empty Set'/> </query> <error type='cancel'> <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </iq> In order to decline the use of any active list, the connected resource MUST send an empty <active/> element with no 'name' attribute. Example: Client declines the use of active lists: <iq from='romeo@example.net/orchard' type='set' id='active3'> <query xmlns='jabber:iq:privacy'> <active/> </query> </iq> Example: Server acknowledges success of declining any active list: <iq type='result' id='active3' to='romeo@example.net/orchard'/>
10.5. Managing the Default List
In order to change its default list (which applies to the user as a whole, not only the sending resource), the user MUST send an IQ stanza of type "set" with a <query/> element qualified by the 'jabber:iq:privacy' namespace that contains an empty <default/> child element possessing a 'name' attribute whose value is set to the desired list name. Example: User requests change of default list: <iq from='romeo@example.net/orchard' type='set' id='default1'> <query xmlns='jabber:iq:privacy'> <default name='special'/> </query> </iq> Example: Server acknowledges success of default list change: <iq type='result' id='default1' to='romeo@example.net/orchard'/> If the user attempts to change which list is the default list but the default list is in use by at least one connected resource other than the sending resource, the server MUST return a <conflict/> stanza error to the sending resource: Example: Client attempts to change the default list but that list is in use by another resource: <iq to='romeo@example.net/orchard' type='error' id='default1'> <query xmlns='jabber:iq:privacy'> <default name='special'/> </query> <error type='cancel'> <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </iq> If the user attempts to set a default list but a list by that name does not exist, the server MUST return an <item-not-found/> stanza error to the user:
Example: Client attempts to set a non-existent list as default: <iq to='romeo@example.net/orchard' type='error' id='default1'> <query xmlns='jabber:iq:privacy'> <default name='The Empty Set'/> </query> <error type='cancel'> <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </iq> In order to decline the use of a default list (i.e., to use the domain's stanza routing rules at all times), the user MUST send an empty <default/> element with no 'name' attribute. Example: Client declines the use of the default list: <iq from='romeo@example.net/orchard' type='set' id='default2'> <query xmlns='jabber:iq:privacy'> <default/> </query> </iq> Example: Server acknowledges success of declining any default list: <iq type='result' id='default2' to='romeo@example.net/orchard'/> If one connected resource attempts to decline the use of a default list for the user as a whole but the default list currently applies to at least one other connected resource, the server MUST return a <conflict/> error to the sending resource: Example: Client attempts to decline a default list but that list is in use by another resource: <iq to='romeo@example.net/orchard' type='error' id='default3'> <query xmlns='jabber:iq:privacy'> <default/> </query> <error type='cancel'> <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </iq>
10.6. Editing a Privacy List
In order to edit a privacy list, the user MUST send an IQ stanza of type "set" with a <query/> element qualified by the 'jabber:iq:privacy' namespace that contains one <list/> child element possessing a 'name' attribute whose value is set to the list name the user would like to edit. The <list/> element MUST contain one or more <item/> elements, which specify the user's desired changes to the list by including all elements in the list (not the "delta"). Example: Client edits a privacy list: <iq from='romeo@example.net/orchard' type='set' id='edit1'> <query xmlns='jabber:iq:privacy'> <list name='public'> <item type='jid' value='tybalt@example.com' action='deny' order='3'/> <item type='jid' value='paris@example.org' action='deny' order='5'/> <item action='allow' order='68'/> </list> </query> </iq> Example: Server acknowledges success of list edit: <iq type='result' id='edit1' to='romeo@example.net/orchard'/> Note: The value of the 'order' attribute for any given item is not fixed. Thus in the foregoing example if the user would like to add 4 items between the "tybalt@example.com" item and the "paris@example.org" item, the user's client MUST renumber the relevant items before submitting the list to the server. The server MUST now send a "privacy list push" to all connected resources: Example: Privacy list push on list edit: <iq to='romeo@example.net/orchard' type='set' id='push1'> <query xmlns='jabber:iq:privacy'> <list name='public'/> </query> </iq>
<iq to='romeo@example.net/home' type='set' id='push2'> <query xmlns='jabber:iq:privacy'> <list name='public'/> </query> </iq> In accordance with the semantics of IQ stanzas defined in [XMPP-CORE], each connected resource MUST return an IQ result to the server as well: Example: Acknowledging receipt of privacy list pushes: <iq from='romeo@example.net/orchard' type='result' id='push1'/> <iq from='romeo@example.net/home' type='result' id='push2'/>10.7. Adding a New Privacy List
The same protocol used to edit an existing list is used to create a new list. If the list name matches that of an existing list, the request to add a new list will overwrite the old one. As with list edits, the server MUST also send a "privacy list push" to all connected resources.