RFC3921

来自Jabber/XMPP中文翻译计划
跳转到: 导航, 搜索


本文的英文原文来自RFC 3921

被替代标准: 6121 建议标准
网络工作组 Saint-Andre, Ed.
申请讨论: 3921 Jabber软件基金会
类别: 标准跟踪 2004年10月
可扩展的消息和出席信息协议 (XMPP): 即时消息和出席信息

关于本文的说明

本文为互联网社区定义了一个互联网标准跟踪协议,并且申请讨论协议和提出了改进的建议。请参照“互联网官方协议标准”的最新版本(STD 1)获得这个协议的标准化进程和状态。本文可以不受限制的分发。

版权声明

本文版权属于互联网社区 (C) The Internet Society (2004).

摘要

本文定义了可扩展消息和出席信息协议(XMPP)的核心功能的扩展和应用,XMPP提供了RFC 2779 定义的基本的即时消息和出席信息功能。

目录

绪论

概览

XMPP是一个流化XML[XML]元素的协议,用于准实时的交换消息和出席信息。XMPP的核心功能定义在Extensible Messaging and Presence Protocol (XMPP): Core [XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]. 这些功能 -- 主要是 XML流, 使用 TLS和SASL,以及流的根元素之下的<message/>, <presence/>, 和 <iq/> 子元素 -- 为各种类型的准实时应用提供了一个构造基础, 它可以被放在核心的顶层,使用特定XML名字空间[XML-NAMES]发送特定的应用数据. 本文描述XMPP核心功能的扩展和应用,XMPP核心功能提供了RFC 2779 [IMP-REQS]定义的基本的即时消息和出席信息功能。

需求

为了达到本文的目的, 基本的即时消息和出席信息应用的需求定义在[IMP-REQS],它是一个高阶的规定,一个用户必须完成以下用例:
  • 和其他用户交换消息
  • 和其他用户交换出席信息
  • 管理和其他用户之间的订阅和被订阅
  • 管理联系人列表中的条目(在 XMPP 中这被称为 "roster")
  • 屏蔽和特定的其他用户之间的通信(出或入)
这些功能领域的详细定义在[IMP-REQS]中, 感兴趣的用户可以直接阅读原文关于需求方面的内容。
[IMP-REQS]也规定出席信息服务必须从即时消息服务中分离; 例如, 它必须可能用这个协议来提供一个出席信息服务,一个即时消息服务,或同时提供两者. 尽管本文假定实现和部署希望提供统一的即时消息和出席信息服务, 但没有要求一个服务必须同时提供出席信息服务和即时消息服务, 并且协议也提供了把出席信息服务和即时消息服务分离成为独立服务的可能性.
注意: 虽然基于XMPP的即时消息和出席信息符合[IMP-REQS]的要求,但它不是特意为那个协议设计的,因为基础协议是在RFC 2779成文之前通过Jabber开放源代码社区的一个开放的开发过程发展出来的. 也请注意尽管在Jabber社区发展的协议中定义了许多其他方面的功能,但是这些协议不包含在本文之中,因为它们不是[IMP-REQS]所要求的.

术语

本文继承了 [XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]定义的术语.
大写关键字 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", 和 "OPTIONAL" 在本文中的含义定义在 BCP 14, RFC 2119 [TERMS].

XML 节的语法

符合'jabber:client'和'jabber:server'名字空间的XML节的基本语义和通用属性已经在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中定义了. 无论如何, 这些名字空间也定义了一些其他的子元素, 比如通用属性'type'的值, 对于即时消息和出席信息应用就是特殊的. 因而, 在选择用于这类应用的特定用例之前, 我们在这里需要先描述一下XML节的语法, 用来补充[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中的讨论.

消息语法

符合'jabber:client' or 'jabber:server'名字空间的消息节用于"推" 信息到另一个实体. 在即时消息应用中通常的用法是包含,一个单独的消息,在一个聊天会话中的消息,一个多用户聊天室的上下文中的消息,标题或其他警告和错误的消息,

消息的类型

一个消息节的'type' 属性是建议的(RECOMMENDED); 如果包含了它,它指明这个消息的会话上下文,从而提供一个关于表达的线索(例如, 在一个GUI中). 如果包含了它, 'type' 属性必须(MUST)是以下的值之一 :
  • chat -- 消息是在一对一聊天会话的语境被发送. 一个兼容的客户端应该(SHOULD)在一个允许两个实体进行一对一聊天的界面中显示消息,包括适当的会话历史.
  • error -- 发生了一个和上次发送者发送的消息有关的错误(关于节错误语法的详细信息, 参考 [XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]). 一个兼容客户端应该(SHOULD)在一个适当的界面展示它以通知发送者这个错误的种类.
  • groupchat -- 消息是在一个多用户聊天环境的语境下发送的(类似[IRC]). 一个兼容客户端应该(SHOULD)在允许多对多聊天的界面显示这个消息,包括, 包括这个聊天室的名册和适当的会话历史. 基于XMPP的群聊协议的完整定义超出了本文的范围.
  • headline -- 一个消息可能是由一个递送或广播内容的自动化服务生成的(新闻, 体育, 市场信息, RSS feeds, 等等.). 这个消息是不需要回复的, 一个兼容客户端应该(SHOULD) 在一个适当的和单独消息,聊天会话,或群聊会话不同的界面显示这个消息(例如, 不给接收者提供回复能力).
  • normal -- 这个消息是一个在一对一会话或群聊会话之外的单独消息, 并且它希望接收者能够回复.一个兼容客户端应该(SHOULD)在一个允许接收者回复的界面显示这个消息, 但不需要会话历史.
一个 IM 应用应该(SHOULD)支持所有前述的消息类型;如果一个应用接收了一个没有'type'属性的消息或这个应用不理解'type'属性的值, 它必须(MUST)认为这个消息是一个 "normal" 类型(如,"normal" 是缺省的). "error"类型必须(MUST)仅仅在应答一个和从别的实体接收到的消息有关的错误时生成.
尽管'type'属性是可选的(OPTIONAL), 处于礼貌原因对于消息的任何回复总是和原来的消息同一类型;此外, 一些特殊的应用(例如, 一个多用户聊天服务) 可以(MAY)根据它们的判断强制特定消息类型的使用(例如, type='groupchat').

子元素

正如 扩展名字空间extended namespaces(第二章第四节)所述, 一个消息节可以(MAY)包含任何适当名字空间的子元素.
和缺省名字空间声明一致, 缺省消息节的名字空间是'jabber:client' 或 'jabber:server', 定义了某几个允许的消息节的子元素. 如果消息节的类型是 "error", 它必须(MUST)包含一个<error/>子元素; 详细情况, 见[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]. 否则, 消息节可以(MAY)包含以下子元素的任何一种并且无需显式地声明名字空间:
  1. <subject/>
  2. <body/>
  3. <thread/>
主题
<subject/> 元素包含了人类可读的 XML 字符数据指明这个消息的主题. <subject/>元素不能(MUST NOT)拥有任何属性, 除了'xml:lang'属性. <subject/> 元素可以(MAY)包含多个实例用于为同一主题提供备用版本, 但是仅在每个实例的拥有的'xml:lang'属性的值互不相同的时候才可以. <subject/> 元素不能(MUST NOT)包含混合的内容(定义在 [XML]第三章第二节第二小节).
主体
<body/> 元素包含人类可读的XML字符数据表达消息的文本内容; 这个子元素通常会有但是是可选的(OPTIONAL). <body/>元素不能(MUST NOT)拥有任何属性, 除非是'xml:lang'属性. <body/> 元素可以(MAY)包含多个实例用于为同一主体提供备用版本, 但是仅在每个实例的拥有的'xml:lang'属性的值互不相同的时候才可以. <body/>元素不能(MUST NOT)包含混合的内容(定义在 [XML]第三章第二节第二小节).
线索
<thread/> 元素包含非人类可读的XML字符数据表达一个标识符用于跟踪两个实体之间的一个会话线索(有时相当于一个"即时消息会话"). <thread/>元素的值是由发送者生成的并且应该(SHOULD)在任何回复中拷贝回来. 如果使用了它, 它必须(MUST)在这个流的会话线索中是唯一的并且必须(MUST)和那个会话相一致(一个从同一个全JID但不同线索ID接收到消息的客户端必须(MUST)假定这个有问题的消息存在于已有的会话线索之外. <thread/>元素的使用是可选的(OPTIONAL)并且不是用于标识独立的消息,而是标识会话. 一个消息节不能(MUST NOT)包含超过一个的<thread/>元素. <thread/>元素不能(MUST NOT)拥有任何属性. <thread/>属性的值必须(MUST)被实体处理成不透明的; 不能从它得到任何语义学上的含义,并且只能对它做精确的比较. <thread/>元素不能(MUST NOT)包含混合内容(定义在 [XML]第三章第二节第二小节).

出席信息语法

符合'jabber:client' 或 'jabber:server'名字空间的出席信息节用于表达一个实体当前的网络可用性(离线或在线, 包括之后的各种亚状态和可选的用户名义的描述性文本), 并且通知其他实体它的可用性. 出席信息节也用于协商和管理对于其他实体的出席信息的订阅.

出席信息的类型

出席信息节的'type'属性是可选的(OPTIONAL). 一个不拥有任何'type'属性的出席信息节用来通知服务器发送者已经在线并且可以进行通信了, 'type' 属性表示缺乏可用性, 请求管理对其他实体的出席信息的订阅, 请求其他实体的当前出席信息, 或发生了和上次发出的出席信息节有关的错误. 如果包含了它, 'type'属性必须(MUST)拥有以下值之一:
  • unavailable -- 通知实体将不可通信.
  • subscribe -- 发送者希望订阅接收者的出席信息.
  • subscribed -- 发送者允许接收者接收他们的出席信息.
  • unsubscribe -- 发送者取消订阅另一个实体的出席信息.
  • unsubscribed -- 订阅者的请求被拒绝或以前的订阅被取消.
  • probe -- 对一个实体当前的出席信息的请求; 只应(SHOULD)由服务器代替一个用户生成.
  • error -- 处理或递送之前发送的出席信息节的时候发生了错误.
关于出席信息语义学的详细信息和基于XMPP的即时消息和出席信息应用程序的订阅模式,参考 交换出席信息Exchanging Presence Information(第五章) 和 管理订阅Managing Subscriptions(第六章).

子元素

如 扩展名字空间extended namespaces(第二章第四节)所述, 一个出席信息节可以(MAY)包含任何适当名字空间的子元素.
和缺省名字空间声明一致, 缺省出席信息节的名字空间是'jabber:client' 或 'jabber:server', 定义了某几个允许的出席信息节的子元素. 如果出席信息节的类型是 "error", 它必须(MUST)包含一个<error/>子元素; 详细情况, 见[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]. 如果出席信息节不拥有'type'属性,它可以(MAY)包含以下任何子元素(注意<status/>子元素可以(MAY)在一个类型为"unavailable"或"subscribe"(出于历史原因)的出席信息中被发送):
  1. <show/>
  2. <status/>
  3. <priority/>
展示
可选的(OPTIONAL)<show/>元素包含非人类可读的XML字符数据表达一个特定的实体或资源的特定的可用性状态. 一个出席信息节不能(MUST NOT)包含多于一个<show/>元素. <show/>元素不能(MUST NOT)拥有任何属性. 如果提供了, 这个XML字符数据值必须(MUST)是以下之一(额外的可用性类型可以通过出席信息的适当名字空间来定义):
  • away -- 实体或资源临时离开.
  • chat -- 实体或资源在聊天中是激活的.
  • dnd -- 实体或资源是忙(dnd = "不要打扰").
  • xa -- 实体或资源是长时间的离开(xa = "长时间离开").
如果没有提供<show/>元素, 实体被假定是在线和可用的.
状态
可选的(OPTIONAL)<status/>元素包含XML字符数据表达一个可用性状态的自然语言描述. 它通常用于联合show元素以提供可用性状态的详细描述(例如, "会议中"). <status/>元素不能(MUST NOT)拥有任何属性,除了'xml:lang'属性. <status/>元素可以(MAY)包含多个实例但是每个实例的'xml:lang'属性值必须各不相同.
优先权
可选的(OPTIONAL)<priority/>元素包含非人类可读的XML字符数据指明资源的优先级别. 这个值必须(MUST)是一个介于-128和+127之间的数字. 一个出席信息小节不能(MUST NOT)包含超过一个的<priority/>元素. <priority/>元素不能(MUST NOT)拥有任何属性. 如果没有优先权被提供,一个服务器应该(SHOULD)认为优先级是零. 关于即时消息和出席信息系统中节路由的优先级的语义, 参考 处理XML节的服务器规则Server Rules for Handling XML Stanzas(第十一章).

IQ语法

IQ节提供一个结构化的请求-应答机制. 这个机制的基本语义学(例如, 'id'属性是必需的(REQUIRED))定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920], 然而完成特定用例所需要的特定语义的所有案例定义在扩展名字空间extended namespace(第二章第四节)之中(注意'jabber:client'和'jabber:server'名字空间没有定义除通用的<error/>子元素之外的任何IQ节子元素). 本文定义了两个这样的名字空间,一个用于 名册管理Roster Management(第七章)而另一个用于 屏蔽通信Blocking Communication(第十章); 无论如何, 一个IQ节可以(MAY)包含符合任何扩展名字空间的结构化信息.

扩展名字空间

因为在"jabber:client"或"jabber:server"名字空间中定义的三个XML节类型(也包括它们的属性和子元素)提供了一个基本功能级用于消息和出席信息, XMPP使用XML名字空间来扩展节用于提供额外的功能, 所以一个消息或出席信息节可以(MAY)包含一个或更多可选的子元素表达扩展消息含义的内容(例如, 一个XHTML格式版本的消息主体), 并且一个IQ节可以(MAY)包含一个这样的子元素. 这个子元素可以(MAY)有任何名字并且可以(MUST)拥有一个'xmlns'名字空间声明(不同于"jabber:client", "jabber:server", 或"http://etherx.jabber.org/streams")定义所有包含在子元素中的数据.
对于任何特定的扩展名字空间的支持在任何实现中的一部分是可选的(OPTIONAL)(除了在这里定义的扩展名字空间以外). 如果一个实体不理解这样一个名字空间, 实体被期望的行为依赖于这个实体是(1) 接收者 或 (2) 一个正在路由到接收者的实体
接收者: 如果一个接收者接收了一个包含不理解的子元素的节, 它应该(SHOULD)忽略那个特定的XML数据,例如, 它应该(SHOULD)不处理它或不向用户或相关的应用程序(如果有的话)显示它. 具体来说:
  • 如果一个实体接收了一个消息或出席信息节包含一个不理解的名字空间, 在节的未知名字空间的这部分应该(SHOULD)被忽略.
  • 如果一个实体接收了一个消息节中仅有的一个子元素是不理解的, 它必须(MUST)忽略整个节.
  • 如果一个实体接收了一个类型"get"或"set"的IQ节包含一个不理解的子元素, 这个实体应该(SHOULD)返回一个类型为"error"的<service-unavailable/>错误条件的IQ节.
路由: 如果一个路由实体(通常是一个服务器)处理一个包含它不理解的子元素的节, 它应该(SHOULD)原封不动地把它转给接收者而忽略相关的XML数据.

会话的建立

绝大部分基于XMPP的消息和出席信息应用是由一个客户端-服务器体系结构实现的,为了参加期望的即时消息和出席信息活动,需要客户端在服务器上建立一个会话. 无论如何, 在客户端能够建立一个即时消息和出席信息会话之前有很多前提必须(MUST)满足. 它们是:
  1. 流验证 -- 客户端在尝试建立一个会话或发送任何XML节之前必须(MUST)完成[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中定义的流验证.
  2. 资源绑定 -- 完成流验证之后, 一个客户端必须(MUST)绑定一个资源到流上,使得客户端的地址符合<user@domain/resource>格式, 然后实体以[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]规定的术语来说就是一个 已连接的资源"connected resource".
如果一个服务器支持会话, 在完成一个[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]定义的流验证之后它必须(MUST)在它向客户端声明的流特性中包含一个符合'urn:ietf:params:xml:ns:xmpp-session'名字空间的<session/>元素:
服务器向客户端声明会话确定特性:
   <stream:stream
       xmlns='jabber:client'
       xmlns:stream='http://etherx.jabber.org/streams'
       id='c2s_345'
       from='example.com'
       version='1.0'>
   <stream:features>
     <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>
     <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>
   </stream:features>
收到需要会话确立的通知之后(并且是在完成资源绑定之后), 客户端如果想使用即时消息和出席信息功能必须(MUST)建立一个会话; 它向服务器发送一个符合'urn:ietf:params:xml:ns:xmpp-session'名字空间的类型为"set"并包含空的<session/>子元素的IQ节以完成这一步骤:
步骤 1: 客户端向服务器请求会话:
   <iq to='example.com'
       type='set'
       id='sess_1'>
     <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>
   </iq>
步骤 2: 服务器通知客户端会话已经建立:
   <iq from='example.com'
       type='result'
       id='sess_1'/>
建立会话之后, 一个 已连接的资源([XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]术语)就被称为一个 激活的资源"active resource".
许多错误条件是可能的. 例如, 服务器可能遭遇一个内部条件阻碍了它建立会话, 用户名或授权身份可能缺乏建立会话的许可, 或同一个名字相关的这个资源ID已经有一个激活的资源.
如果服务器遭到一个内部条件阻碍了它建立会话, 它必须(MUST)返回一个错误.
步骤 2 (替代): 服务器应答一个错误(内部服务器错误):
   <iq from='example.com' type='error' id='sess_1'>
     <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>
     <error type='wait'>
       <internal-server-error
           xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
     </error>
   </iq>
如果用户名或资源不被允许建立一个会话, 服务器必须(MUST)返回一个错误(例如, 被禁止).
步骤 2 (替代): 服务器应答错误(用户名或资源不被允许建立一个会话):
   <iq from='example.com' type='error' id='sess_1'>
     <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>
     <error type='auth'>
       <forbidden
           xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
     </error>
   </iq>
如果同一名字已经存在一个激活的资源,服务器必须(MUST) (1) 终止这个激活的资源并允许新请求的会话, 或者 (2) 不允许新申请的会话并继续激活的资源. 服务器做哪一步取决于具体的实现, 尽管建议的(RECOMMENDED)实现 情景 #1. 在 情景 #1, 服务器应该(SHOULD)发送一个<conflict/>流错误给激活的资源, 终止用于这个激活的资源的XML流和相关的TCP连接, 并返回一个类型为"result" 的IQ节(表示成功)给新申请的会话. 在 情景 #2, 服务器应该(SHOULD)发送一个<conflict/>节错误给新申请的会话但是继续那个连接的XML流使得新申请的会话在发送另一个会话建立申请之前有机会协商出一个不冲突的资源ID.
步骤 2 (替代): 服务器通知现有的激活的资源 资源冲突(情景 #1):
   <stream:error>
     <conflict xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>
   </stream:error>
   </stream:stream>
步骤 2 (替代): 服务器通知新申请的的会话资源冲突(情景 #2):
   <iq from='example.com' type='error' id='sess_1'>
     <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>
     <error type='cancel'>
       <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
     </error>
   </iq>
建立一个会话之后, 客户端应该(SHOULD)按以下描述来发送初始化出席信息并请求它的名册, 尽管这些动作是可选的(OPTIONAL).
注意: 在允许建立即时消息和出席信息会话之前, 一个服务器可能(MAY)需要先提供帐号. 可能的提供帐号的方法包括由服务器管理员新建帐号以及使用'jabber:iq:register'名字空间进行带内帐号注册; 后一个方法超出了本文的范围, 但是记录在[JEP-0077](译者注:这个协议已改名为 XEP-0077), 由 Jabber Software Foundation [JSF]发行(译者注:这个组织也已改名为XSF).

交换消息

交换消息是XMPP的一个基本用途并且随之而来的是一个用户生成一个发给另一个实体的消息节. 正如 用于处理XML节的服务器规则Server Rules for Handling XML Stanzas(第十一章)中所定义的 , 发送者的服务器负责递送消息给预定的接收者(如果接收者在同一个服务器上)或路由消息给接收者的服务器(如果接收者在不同的服务器上).
关于消息节的语法和它们已定义的属性和子元素信息, 参考 消息语法Message Syntax(第二章第一节).

指明一个预定的接收者

一个即时消息客户端应该(SHOULD)通过提供一个JID或<message/>节中不同于发送者的'to'属性来指定一个消息的预定接收者. 如果这个消息是在回复之前接收到的消息,而接收到的消息是从JID格式为<user@domain/resource>(例如,在一个聊天会话的上下文中)实体发来的, 这个回复消息的'to'地址的值应该(SHOULD)是<user@domain/resource>而不是<user@domain>,除非发送者知道(通过出席信息)预定的接收者的资源将不再可用. 如果消息是在任何现存的聊天会话或接收到的消息之外被发送的,'to'地址的值应该(SHOULD)格式为<user@domain>而不是<user@domain/resource>.

指定一个消息类型

大家知道, 对于一个消息节来说拥有'type'属性(它的值代表了消息的会话上下文(参见 Type(第二章第一节第一小节)))是建议的(RECOMMENDED).
以下例子展示一个'type'属性的合法值:
例子: 一个已定义类型的消息:
   <message
       to='romeo@example.net'
       from='juliet@example.com/balcony'
       type='chat'
       xml:lang='en'>
     <body>Wherefore art thou, Romeo?</body>
   </message>

指定一个消息主体

一个消息节可以(MAY)(并且经常会)包含一个<body/>子元素,它的XML字符数据表达消息的主要含义(见 Body(第二章第一节第二小节第二小小节)).
例子: 一个带主体的消息:
   <message
       to='romeo@example.net'
       from='juliet@example.com/balcony'
       type='chat'
       xml:lang='en'>
     <body>Wherefore art thou, Romeo?</body>
     <body xml:lang='cz'>Pro&#x010D;e&#x017D; jsi ty, Romeo?</body>
   </message>

指定一个消息主题

一个消息节可以(MAY)包含一个或多个<subject/>子元素指明消息的主题(见 Subject(第二章第一节第二小节第一小小节)).
例子: 一个带主题的消息:
   <message
       to='romeo@example.net'
       from='juliet@example.com/balcony'
       type='chat'
       xml:lang='en'>
     <subject>I implore you!</subject>
     <subject
         xml:lang='cz'>&#x00DA;p&#x011B;nliv&#x011B; prosim!</subject>
     <body>Wherefore art thou, Romeo?</body>
     <body xml:lang='cz'>Pro&#x010D;e&#x017D; jsi ty, Romeo?</body>
   </message>

指定一个会话线索

一个消息可以(MAY)包含一个<thread/>子元素指定消息处于哪个会话线索, 用于跟踪会话(见 Thread(第二章第一节第二小节第三小小节)).
例子: 一个带线索的会话:
   <message
       to='romeo@example.net/orchard'
       from='juliet@example.com/balcony'
       type='chat'
       xml:lang='en'>
     <body>Art thou not Romeo, and a Montague?</body>
     <thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread>
   </message>
   <message
       to='juliet@example.com/balcony'
       from='romeo@example.net/orchard'
       type='chat'
       xml:lang='en'>
     <body>Neither, fair saint, if either thee dislike.</body>
     <thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread>
   </message>
   <message
       to='romeo@example.net/orchard'
       from='juliet@example.com/balcony'
       type='chat'
       xml:lang='en'>
     <body>How cam'st thou hither, tell me, and wherefore?</body>
     <thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread>
   </message>

交换出席信息

交换出席信息通过使用出席信息节直接和XMPP相关. 无论如何, 我们看到在这里和消息处理形成一个对比:尽管一个客户端可以(MAY)通过包含一个'to'地址直接给另一个实体发送出席信息, 通常出席信息通知(例如,不包含'type'的或类型为"unavailable"的并且没有'to'地址的出席信息节) 被客户端发送给它的服务器然后由服务器广播给任何订阅了发送实体的出席信息的实体(在 RFC 2778 [IMP-MODEL]术语中, 这些实体称为订阅者). 这个广播模式不适用于和订阅相关的节或类型为"error"的出席信息, 而仅适用于以上定义的出席信息通知. (注意: 虽然出席信息可以(MAY)由一个自动化服务代替用户提供, 通常它还是由用户的客户端提供.)
关于出席信息节的语法以及它们的已定义的属性和子元素的信息, 参考[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920].

客户端和服务器出席信息职责

初始化出席信息

建立起一个会话之后, 一个客户端应该(SHOULD)发送初始化出席信息给服务器来通知它的通信可用性.如这里定义的, 初始化出席信息节 (1) 必须(MUST) 不拥有'to'地址(这表示它是由服务器代替客户端发送的广播) 并且 (2) 必须(MUST) 不拥有'type'属性(者表示拥护的可用性). 在发送初始化出席信息之后, 一个激活的资源被称为 可用的资源"available resource".
从一个客户端接收到初始化出席信息之后, 如果这个用户没有一个或更多的已存在的可用资源(如果这个用户已经有一个或更多可用的资源, 服务器明显不需要发送出席信息探测, 因为它已经拥有需要的信息),用户的服务器必须(MUST)做以下的步骤:
  1. 从用户的全JID(例如,<user@example.com/resource>)发送出席信息探针(例如, 'type'属性值为'probe'的出席信息节)给已被这个用户订阅了的所有联系人以确定它们是否可用; 这些联系人就是那些显示在用户的名册中的JID并且'subscription'属性值为"to"或"both"(注意: 用户的服务器不能(MUST NOT)发送出席信息探针给用户已经屏蔽入站出席信息通知的联系人, 具体的描述在 屏蔽入站出席信息通知Blocking Inbound Presence Notifications(第十章第十节).)
  2. 从用户的全JID (e.g.,<user@example.com/resource>)广播初始化出席信息给所有订阅了该用户的出席信息的联系人; 这些联系人就是那些显示在用户的名册中的JID并且'subscription'属性值为"from"或"both"(注意: 用户的服务器不能(MUST NOT)发送出席信息探针给用户已经屏蔽出站出席信息通知的联系人, 具体的描述在 屏蔽出站出席信息通知Blocking Outbound Presence Notifications(第十章第十一节).)
另外, 用户的服务器必须(MUST)从用户的新的可用的资源向用户任何现存的可用的资源(如果有的话)广播初始化出席信息.
从用户接收到初始化出席信息之后, 联系人的服务器必须(MUST)递送这个用户的出席信息节给所有联系人的可用资源相应的全JID(<contact@example.org/resource>), 但是仅适用于用户在联系人名册中并且订阅状态为"to"或"both"并且联系人的纯JID或全JID没有被屏蔽入站出席信息通知(定义在 屏蔽入站出席信息通知Blocking Inbound Presence Notifications(第十章第十节)).
如果用户的服务器接收到一个类型为"error"的出席信息节,而这个节是用来回复服务器代替用户向联系人发送的初始化出席信息, 它不应该(SHOULD NOT)发送更多的出席信息更新给那个联系人(直到并且除非它从这个联系人接收到一个出席信息节).

出席信息广播

发送初始化出席信息之后, 用户可以(MAY)在任何时候更新它的出席信息,方法是在会话期间发送一个没有'to'地址也没有'type'属性的出席信息节或'type'属性值为"unavailable"的出席信息节.(注意:一个用户的客户端不应该(SHOULD NOT)发送一个出席信息更新来自行广播用户出席信息和可用性的改变信息.)
如果出席信息节缺乏'type'属性(例如, 表达可用性), 用户的服务器必须(MUST)广播那个出席信息节的全XML给所有联系人(满足以下三点) (1) 它们在用户的联系人名册中并且订阅类型是"from"或"both", (2) 用户对于这些联系人没有屏蔽出站出席信息通知, 并且 (3) 服务器在用户的会话期间没有从它们那里接收到出席信息错误(同样适用于这个用户的其他可用的资源).
如果出席信息节的'type'属性值是"unavailable", 用户的服务器必须(MUST)广播那个出席信息节的全XML给所有符合以上描述的实体, 也适用于用户曾经在会话过程中直接发送了可用出席信息的任何实体(如果用户还没来得及直接发送不可用出席信息给那个实体).

出席信息调查

从用户接收到一个出席信息调查之后, 联系人的服务器应该(SHOULD)应答如下:
  1. 如果用户联系人的名册中的状态不是 "From", "From + Pending Out", 或 "Both" (定义在 订阅状态Subscription States(第九章)), 联系人的服务器必须(MUST)返回一个类型为"error"的出席信息节应答这个出席信息调查 (无论如何, 如果一个服务器从这个服务器的主机名的子域或其他信任的服务接收到一个出席信息调查, 它可以(MAY)提供这个用户的出席信息给那个实体). 具体来说:
    1. 如果用户在联系人的名册中的订阅状态是 "None", "None + Pending Out", 或 "To" (或根本不在联系人的名册中), 联系人的服务器必须(MUST)返回一个<forbidden/>节错误应答这个出席信息调查.
    2. 如果用户在联系人的名册中的订阅状态是 "None + Pending In", "None + Pending Out/In", 或 "To + Pending In", 联系人的服务器必须(MUST)返回一个<not-authorized/>节错误应答这个出席信息调查.
  2. 其次, 如果联系人对这个用户的纯JID或全JID屏蔽了出席信息通知(使用缺省列表或激活列表,定义在 屏蔽出站出席信息通知Blocking Outbound Presence Notifications (第十章第十一节)), 服务器不能(MUST NOT)应答这个出席信息调查.
  3. 然后, 如果联系人没有可用的资源, 服务器必须(MUST) 要么 (1) 应答这个出席信息调查, 向这个用户发送服务器从联系人接收到的最后的类型为"unavailable"的出席信息节的全XML, 或 (2) 不应答.
  4. 最后, 如果联系人至少有一个可用的资源, 服务器必须(MUST)应答这个出席信息调查, 向这个用户发送服务器从联系人的每一个可用的资源收到的最后的没有'to'属性的出席信息节的全XML (再一次的,对于每一个会话都要强制服从隐私列表).

直接出席信息

一个用户可以(MAY)直接发送出席信息给另一个实体 (例如, 一个出席信息节,包含'to'属性并且值为另一个实体的JID并且没有'type'属性或'type'属性值为"unavailable"). 可能出现三种情形:
  1. 如果用户在已经发送过初始化出席信息广播之后,发送不可用信息广播之前,直接发送出席信息给它的名册中一个订阅状态为"from" 或 "both"的联系人, 这个用户的服务器必须(MUST)路由或递送这个出席信息节的全XML(服从隐私列表)但是不应该(SHOULD NOT) 根据出席信息广播修改联系人的状态(例如, 它应该(SHOULD)在任何接下来的由用户初始化的出席信息广播包含这个联系人的JID).
  2. 如果用户在已经发送过初始化出席信息广播之后,发送不可用信息广播之前,直接发送出席信息给一个不在用户名册中的实体并且其订阅状态为"from" 或 "both", 这个用户的服务器必须(MUST)路由或递送这个出席信息节的全XML(服从隐私列表)但是不能(MUST NOT) 根据可用性的出席信息广播来修改这个联系人的状态(例如, 它不能(MUST NOT)在任何接下来的由用户初始化的可用性的出席信息广播中包含这个联系人的JID); 无论如何, 如果无法从用户的可用的资源直接发送出席信息, 用户的服务器必须( MUST)广播不可用出席信息给那个实体(如果这个用户还没有直接发送不可用出席信息给那个实体).
  3. 如果用户不是在已经发送过初始化出席信息广播之后,或在发送不可用信息广播之前,直接发送出席信息(例如, 资源激活了但是还不可用), 用户的服务器必须(MUST)认为用户向其直接发送出席信息的这个实体视为上述第二种情形中的那个实体,采用相同的处理方式.

不可用出席信息

在和一个服务器结束它的会话之前, 客户端应该(SHOULD)雅致地成为不可用的,发送一个最后的没有'to'属性并且'type'属性值为"unavailable"的出席信息节(可选的, 最后的出席信息节可以(MAY)包含一个或多个<status/>元素以指明为什么用户不再可用). 无论如何, 用户的服务器不能(MUST NOT)依赖于从一个可用的资源接收最后的出席信息, 因为资源可能意外的变成不可用或可能被服务器判定超时. 如果用户的资源之一因为任何原因成为不可用的(包括雅致的或粗鲁的), 用户的服务器必须(MUST)广播不可用出席信息给所有如下的联系人 (1) 在用户的名册中并且订阅类型为 "from" 或 "both", (2) 用户没有对它们屏蔽出站出席信息的联系人, 以及 (3) 用户会话期间,服务器没有从它们那里收到出席信息错误的联系人; 用户的服务器也必须(MUST)发送不可用出席信息节给这个用户的任何其他可用的资源, 以及任何用户的资源曾经在会话期间直接向其发送过出席信息的实体(如果用户还没有直接发送不可用出席信息给那个实体). 在直接发送或广播不可用出席信息之后发送的任何没有'type'属性也没有'to'属性的出席信息节必须(MUST)由服务器广播给所有订阅者.

出席信息订阅

一个订阅请求就是一个'type'属性值为"subscribe"的出席信息节. 如果订阅请求被发送给一个即时消息联系人, 在'to'属性中提供的JID的格式应该(SHOULD)是<contact@example.org>而不是<contact@example.org/resource>, 因为用户期望的结果通常是从联系人的所有资源接收到出席信息, 而不仅是'to'属性中的特定资源.
一个用户的服务器不能(MUST NOT)代替用户自动批准订阅请求. 所有订阅申请必须(MUST)直接发给用户的客户端, 具体来说就是这一用户的一个或多个可用的资源. 如果当订阅申请被用户的服务器接收到的时候没有这个用户的可用资源, 用户的服务器必须(MUST)保持这个订阅申请的记录并且在用户下次建立一个可用的资源时递送这个订阅申请, 直到这个用户批准或拒绝这个请求. 如果如果当订阅申请被用户的服务器接收到的时候这个用户有多于一个的可用资源, 用户的服务器必须(MUST)广播这个订阅申请给所有可用的资源(根据 处理XML节的服务器规则Server Rules for Handling XML Stanzas(第十一章)). (注意: 如果一个激活的资源还没有提供初始化出席信息, 服务器不能(MUST NOT)认为它是可用的并且因而不能(MUST NOT)发送订阅申请给它.) 无论如何, 如果用户从一个它已授权可以看到用户的出席信息的联系人那里收到一个类型为"subscribe"的出席信息节(例如, 当一个联系人重新同步订阅状态的时候),用户的服务器应该(SHOULD)代替用户自动应答. 另外, 用户的服务器可以(MAY)基于一个特定实现的法则(例如, 无论何时当用户的一个新的资源可用的时候, 或在一段特定长度的时间过去之后)选择重新发送一个未批准的未决订阅申请给这个联系人; 这有助于恢复可能和原始订阅申请有关的瞬间的,无声的错误.

指明可用性状态

一个客户端可以(MAY)使用<show/>元素提供关于可用性状态的更多信息(参见 Show (第二章第二节第二小节第一小小节)).
例子: 可用性状态:
   <presence>
 
     <show>dnd</show>
 
   </presence>

指明详细的可用性状态信息

通过联合<show/>元素, 客户端使用<status/>元素可以(MAY)提供详细的可用性状态信息(参见Status (第二章第二节第二小节第二小小节)).
例子: 详细的状态信息:
   <presence xml:lang='en'>
     <show>dnd</show>
     <status>Wooing Juliet</status>
     <status xml:lang='cz'>Ja dvo&#x0159;&#x00ED;m Juliet</status>
   </presence>

指明出席信息优先级

客户端可以(MAY)使用<priority/>元素为它的资源提供优先级(参见 Priority (第二章第二节第二小节第三小小节)).
例子: 出席信息优先级:
   <presence xml:lang='en'>
     <show>dnd</show>
     <status>Wooing Juliet</status>
     <status xml:lang='cz'>Ja dvo&#x0159;&#x00ED;m Juliet</status>
     <priority>1</priority>
   </presence>

出席信息例子

本章的例子用于阐明上述和出席信息相关的协议. 用户是 romeo@example.net, 他有一个可用的资源, 资源ID为 "orchard", 并且他的名册中有以下这些人:
  • juliet@example.com (subscription="both" 并且她有两个可用的资源, 一个资源名为"chamber" 而另一个资源名为 "balcony")
  • benvolio@example.org (subscription="to")
  • mercutio@example.org (subscription="from")
例子 1: 用户发送初始化出席信息:
   <presence/>
例子 2: 用户的服务器代替用户发送出席信息调查给 subscription="to" 和 subscription="both" 的联系人的可用资源:
   <presence
       type='probe'
       from='romeo@example.net/orchard'
       to='juliet@example.com'/>
   <presence
       type='probe'
       from='romeo@example.net/orchard'
       to='benvolio@example.org'/>
例子 3: 用户的服务器代替用户发送初始化出席信息给 subscription="from" 和 subscription="both"的联系人的可用资源:
   <presence
       from='romeo@example.net/orchard'
       to='juliet@example.com'/>
   <presence
       from='romeo@example.net/orchard'
       to='mercutio@example.org'/>
例子 4: 联系人的服务器代替所有可用的资源应答出席信息调查:
   <presence
       from='juliet@example.com/balcony'
       to='romeo@example.net/orchard'
       xml:lang='en'>
     <show>away</show>
     <status>be right back</status>
     <priority>0</priority>
   </presence>
   <presence
       from='juliet@example.com/chamber'
       to='romeo@example.net/orchard'>
     <priority>1</priority>
   </presence>
   <presence
       from='benvolio@example.org/pda'
       to='romeo@example.net/orchard'
       xml:lang='en'>
     <show>dnd</show>
     <status>gallivanting</status>
   </presence>
例子 5: 联系人的服务器递送用户的初始化出席信息给所有可用的资源或返回错误给用户:
   <presence
       from='romeo@example.net/orchard'
       to='juliet@example.com/chamber'/>
   <presence
       from='romeo@example.net/orchard'
       to='juliet@example.com/balcony'/>
   <presence
       type='error'
       from='mercutio@example.org'
       to='romeo@example.net/orchard'>
     <error type='cancel'>
       <gone xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
     </error>
   </presence>
例子 6: 用户直接发送出席信息给另一个不在他的名册中的用户:
   <presence
       from='romeo@example.net/orchard'
       to='nurse@example.com'
       xml:lang='en'>
     <show>dnd</show>
     <status>courting Juliet</status>
     <priority>0</priority>
   </presence>
例子 7: 用户发送更新的可用出席信息用于广播:
   <presence xml:lang='en'>
     <show>away</show>
     <status>I shall return!</status>
     <priority>1</priority>
   </presence>
例子 8: 用户的服务器仅向一个联系人广播更新的出席信息 (不是那些返回错误的联系人,也不是那些用户直接向其发送出席信息的联系人):
   <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>
例子 9: 联系人的服务器递送更新的出席信息给联系人所有可用的资源:
   [to "balcony" resource...]
   <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>
   [to "chamber" resource...]
   <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>
例子 10: 联系人的资源之一广播最后出席信息:
   <presence from='juliet@example.com/balcony' type='unavailable'/>
例子 11: 联系人的服务器发送不可用出席信息给用户:
   <presence
       type='unavailable'
       from='juliet@example.com/balcony'
       to='romeo@example.net/orchard'/>
例子 12: 用户发送最后出席信息:
   <presence from='romeo@example.net/orchard'
             type='unavailable'
             xml:lang='en'>
     <status>gone home</status>
   </presence>
例子 13: 用户的服务器广播不可用出席信息给联系人,包括用户直接向其发送出席信息的那个人:
   <presence
       type='unavailable'
       from='romeo@example.net/orchard'
       to='juliet@example.com'
       xml:lang='en'>
     <status>gone home</status>
   </presence>
   <presence
       from='romeo@example.net/orchard'
       to='nurse@example.com'
       xml:lang='en'>
     <status>gone home</status>
   </presence>

管理订阅

为了保护即时消息用户和任何其他实体的隐私, 出席信息和可用性信息仅向用户已批准的其他实体披露. 当一个用户同意其他用户可以看到它的出席信息, 这个实体被称为对于用户的出席信息有一个订阅. 订阅超越了会话; 实际上, 它一直存在直到订阅者取消订阅或被订阅者取消曾经授权的订阅为止. 在XMPP中订阅是通过发送包含特定属性的出席信息节来管理的.
注意: 在订阅和名册之间有重要的交互; 这些定义在 名册条目和出席信息订阅的集成Integration of Roster Items and Presence Subscriptions (第八章), 而且读者必须参考那一章才能完整地理解出席信息订阅.

请求一个订阅

对另一个实体的出席信息的订阅请求是由发送一个类型为"subscribe"的出席信息节来开始的.
例子: 发送一个订阅请求:
   <presence to='juliet@example.com' type='subscribe'/>
关于客户端和服务器在订阅请求中的职责, 参考 出席信息订阅Presence Subscriptions(第五章第一节第六小节).

处理一个订阅请求

当一个客户端从另一个实体接收到一个订阅请求, 它必须(MUST)批准这个请求(发送一个类型为"subscribed"的出席信息节)或拒绝这个请求(发送一个类型为"unsubscribed"的出席信息节).
例子: 批准一个订阅请求:
   <presence to='romeo@example.net' type='subscribed'/>
例子: 拒绝一个出席信息订阅的请求:
   <presence to='romeo@example.net' type='unsubscribed'/>

从另一个实体取消一个订阅

如果一个用户想取消一个曾经允许的订阅请求, 它发送一个类型为"unsubscribed"的出席信息节.
例子: 取消一个曾经允许的订阅请求:
   <presence to='romeo@example.net' type='unsubscribed'/>

取消对于另一个实体的出席信息的订阅

如果用户想取消对于另一个实体的出席信息的订阅, 它发送一个类型为"unsubscribe"的出席信息节.
例子: 取消对一个实体的出席信息的订阅:
   <presence to='juliet@example.com' type='unsubscribe'/>

名册管理

在XMPP中, 一个人的联系人列表被称为名册(roster), 它包括任意数量的特定名册条目, 每个名册条目被一个唯一的JID(通常格式是<contact@domain>)所标识. 一个用户的名册由用户的服务器代替用户储存从而这个用户可以从任何资源访问名册信息.
注意: 在名册和订阅之间有重要的交互; 这些定义在 名册条目和出席信息订阅的集成Integration of Roster Items and Presence Subscriptions (第八章), 而且读者必须参考那一章才能完整地理解名册管理.

语法和语义

名册使用IQ节来管理, 具体来说就是符合'jabber:iq:roster'名字空间的<query/>子元素的含义.这个<query/>元素可以(MAY)包含一个或更多<item/>子元素, 每个描述一个唯一的名册条目或曰 联系人"contact".
每个名册条目的"key"或者说唯一标识符就是一个JID,封装在<item/>元素的'jid'属性(它是必需的(REQUIRED))之中. 如果这个条目是和另一个(人类)即时消息用户相关的,'jid'属性的值的格式应该(SHOULD)是<user@domain>.
和一个名册条目相关的出席信息订阅的状态从<item/>元素的'subscription'属性可以得到.这个属性允许的值包括:
  • "none" -- 这个用户没有对这个联系人出席信息的订阅, 这个联系人也没有订阅用户的出席信息
  • "to" -- 这个用户订阅了这个联系人的出席信息, 但是这个联系人没有订阅用户的出席信息
  • "from" -- 这个联系人订阅了用户的出席信息, 但是这个用户没有订阅这个联系人的出席信息
  • "both" -- 用户和联系人互相订阅了对方的出席信息
每个<item/>条目可以(MAY)包含一个'name'属性, 它设置和这个JID相关的"nickname", 取决于用户(而不是联系人). 'name'属性的值是不透明的.
每个<item/>条目可以(MAY)包含一个或多个<group/>子元素,用于把名册条目收集到多个类别之中. <group/>子元素的XML字符数据是不透明的.

商业规则

在一个名册"set"中一个服务器必须(MUST)忽略任何'to'地址, 并且必须(MUST)认为任何名册"set"是应用于发送者的. 为了更多的安全性, 一个客户端应该(SHOULD)检查"roster push"(包含一个名册条目的类型为"set"的输入IQ)的"from"地址以保证它来自一个信任的源; 具体的, 这个节必须(MUST)没有 'from'属性(例如, 从服务器隐含的) 或'from'属性的值匹配用户的纯JID(格式为<user@domain>)或全JID(格式为<user@domain/resource>); 否则, 客户端应该(SHOULD)忽略这个"roster push".

登录时接收一个人的名册

在连接到服务器并成为一个激活的资源之后, 一个客户端应该(SHOULD)在发送初始化出席信息之前请求名册(无论如何, 因为可能不是所有的资源都想接收名册, 例如, 一个带宽受限的连接, 客户端对于名册的请求是可选的(OPTIONAL)). 如果一个可用的资源在一个会话期间没有请求名册, 服务器不能(MUST NOT)向它发送出席信息订阅以及相关的名册更新.
例子: 客户端向服务器请求当前的名册:
   <iq from='juliet@example.com/balcony' type='get' id='roster_1'>
     <query xmlns='jabber:iq:roster'/>
   </iq>
例子: 客户端从服务器收到名册:
   <iq to='juliet@example.com/balcony' type='result' id='roster_1'>
     <query xmlns='jabber:iq:roster'>
       <item jid='romeo@example.net'
             name='Romeo'
             subscription='both'>
         <group>Friends</group>
       </item>
       <item jid='mercutio@example.org'
             name='Mercutio'
             subscription='from'>
         <group>Friends</group>
       </item>
       <item jid='benvolio@example.org'
             name='Benvolio'
             subscription='both'>
         <group>Friends</group>
       </item>
     </query>
   </iq>

增加一个名册条目

任何时候, 一个用户可以(MAY)增加一个条目到他或她的名册.
例子: 客户端添加一个新的条目:
   <iq from='juliet@example.com/balcony' type='set' id='roster_2'>
     <query xmlns='jabber:iq:roster'>
       <item jid='nurse@example.com'
             name='Nurse'>
         <group>Servants</group>
       </item>
     </query>
   </iq>
服务器必须(MUST)在持久信息存储机构中更新名册信息,并且也要向这个用户的所有已请求名册的可用资源推送这一改变. 这个"名册推送"包括一个类型为"set"的IQ节,从服务器发送给客户端,使用户的所有可用资源保持和基于服务器的名册信息的同步.
例子: 服务器 (1) 推送更新的名册信息给所有已请求名册的可用资源 并且 (2) 以一个IO结果应答发送的资源:
   <iq to='juliet@example.com/balcony'
       type='set'
       id='a78b4q6ha463'>
     <query xmlns='jabber:iq:roster'>
       <item jid='nurse@example.com'
             name='Nurse'
             subscription='none'>
         <group>Servants</group>
       </item>
     </query>
   </iq>
   <iq to='juliet@example.com/chamber'
       type='set'
       id='a78b4q6ha464'>
     <query xmlns='jabber:iq:roster'>
       <item jid='nurse@example.com'
             name='Nurse'
             subscription='none'>
         <group>Servants</group>
       </item>
     </query>
   </iq>
   <iq to='juliet@example.com/balcony' type='result' id='roster_2'/>
正如IQ节类型(定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920])的语义所要求的,每个接收到了名册推送的资源必须(MUST)应答一个类型为"result"(或 "error")的IQ节.
例子: 资源应答一个IQ结果给服务器:
   <iq from='juliet@example.com/balcony'
       to='example.com'
       type='result'
       id='a78b4q6ha463'/>
   <iq from='juliet@example.com/chamber'
       to='example.com'
       type='result'
       id='a78b4q6ha464'/>

更新名册条目

更新一个已有的名册条目(例如, 改变组) 的方法和增加一个新的名册条目是一样的, 换言之, 在IQ set 节中发送名册条目给服务器.
例子: 用户更新名册条目(增加组):
   <iq from='juliet@example.com/chamber' type='set' id='roster_3'>
     <query xmlns='jabber:iq:roster'>
       <item jid='romeo@example.net'
             name='Romeo'
             subscription='both'>
         <group>