Peter Saint-Andre
1.4 版 Jabber 服务协议的概述
Jabber 是一个由开源社区发起并领导开发的即时消息和在线状态的系统。 Jabber 系统和其它即时消息( IM )服务的一个功能上的差别在于 Jabber 拥有开放的 XML 协议。在保持 Jabber1.0 版本有关消息核心以及在线状态的协议的基础上,增加了一些必要的扩展。本文档将对 Jabber 服务器 1.4 版的 Jabber 协议进行介绍。
在 XML 上下文的数据流中, Jabber 开放的 XML 协议包括三个顶级 XML 元素 :
l <message/>
l <presence/>
l <iq/>(info/query)
每一个元素通过属性和名字空间包含大量的数据,这些属性和名字空间都是 Jabber 的组成部分(但不包括为特殊应用的名字空间应用)。下面将描述整个 Jabber 协议。如果您想获得关于 Jabber 系统结构的信息,请查看名为 Jabber 技术概述的文档( http://docs.jabber.org/general/html/overview.html )。
一个 Jabber 会话由两个平行的 XML 流组成,一个从客户端到服务器端,另一个从服务端到客户端。当一个 Jabber 客户端连接上一个 Jabber 服务器时,这个客户端将发起一个客户端-服务器的 XML 流,同时作为响应,服务器也将发起一个服务器-客户端的 XML 流。所有 <message/> , <presence/> ,以及 <iq/> 元素都被放在这些 XML 流的上下文中。下面就有一个例子:
SEND:<?xml version=” 1.0” encoding=”UTF -8” ?>
SEND:<stream:stream
SEND:to=’jabber.org’
SEND:xmlns=’jabber:client’
SEND:xmlns:stream=’http://ether.jabber.org/streams’>
RECV:<stream:stream
RECV:xmlns:stream=’http://etherx.jabber.org/streams’
RECV:id=’39ABA7D 2’
RECV:xmlns=’jabber:client’
RECV:from=’jabber.org’>
(XML for user session goes here)*
SEND:</stream:stream>
RECV:</stream:stream>
* 注意:必须等到当一个 <iq/> 元素(特别指一个 ’jabber:iq:auth’ 名字空间下的 <query/> 元素)发送了认证信息后,服务器才会同意用户会话进行工作。
<message/> 元素是 Jabber 开放 XML 协议三个顶级元素中的一个。它被用来包含两个 Jabber 用户间互相发送消息内容,或者两个 Jabber IDs 之间更一般的消息(因为,通过神奇的传输器,另一个 IM 系统可以用 Jabber ID 代替, 如 [email protected] )。
Jabber 支持几种不同的消息,这些消息通过 <message/> 的“ type ”属性来进行区分。下面就是“ type ”属性的有效值:
表示本消息是一个普通消息。默认的情况下,客户端在没有设置属性时,将消息类型定为普通消息。
例子:
<message to="[email protected]/orchard">
<body>Wherefore art though Romeo?</body>
</message>
表示消息需要被一个接一个的显示在聊天界面上(一般是一条接一条的界面,不过实际界面可以被用户自己定义。)
例子:
<message to="[email protected]/orchard" type="chat" >
<body>Wherefore art though Romeo?</body>
</message>
表示消息被描述成一个错误条件。实际的错误在消息中用一个 <error/> 元素 来描述。一个 <message/> 元素包括一个 <body/> 和一个 <error/> 。下面的例子将演示,当 Juliet 对一个不存在的用户发送一个“ hi ”的消息时,将收到的包体:
例子:
<message
to="[email protected]"
from="[email protected]"
type="error">
<body>hi</body>
<error code="404">Not Found</error>
</message>
表示本消息需要在一个聊天室的界面中进行显示。
例子:
<message to="[email protected]" type="groupchat" >
<body>Double, double toil and trouble</body>
</message>
除了设置“ type ”属性,还可以通过下面的属性修改 <message/> 元素:
消息发送者的标志。总得来说, Jabber ID 的 ”from” 必须是 user@host/resource 的格式。从 XML 的观点来说,这个属性必须包含于所有的 <message/> 元素中,为了对付一些欺骗,实际应用中服务器添加或置换这个属性。因此,它并不是客户端开发者需要关心的问题。
例子:
<message from="[email protected]/balcony">
<body>Wherefore art thou Romeo?</body>
</message>
“ id ”属性是作为消息的一个唯一标志。它由 Jabber 客户端或客户库(类似 WinJab 或 JabberCOM ),生成,客户端用它来为跟踪消息(比如将发送到一个群组聊天室的信息和从这个聊天室收到的消息相关联,或将一个消息与它可能产生的错误相关联)进行标识。“ id ”属性是可选的,并且在系统的别的方是不可用的。
例子:
<message to="[email protected]/orchard" id="JCOM_85">
<body>Wherefore art thou Romeo?</body>
</message>
表示消息的接收者。 Jabber ID 的“ to ”属性一般是 user@host/resource 格式, user@host 也可以被接受。如果接收者在线,通过 user@host/resource 方式解决,如果用户不在线,直接发送离线存储器。这个属性是所有 <message/> 元素必须的。
例子:
<message to="[email protected]/orchard">
<body>Wherefore art thou Romeo?</body>
</message>
下面的子元素是用来定义一个 Jabber 消息的上下文或数据元。
这个元素包含消息的主要文本。 <body/> 元素只存在于一个 <message/> 元素中,并且只能包含明文。不过,它可以由其它子元素构成(如 <error/> 、 <x/> )。
当消息类型属性被置为“ error ”时,这个元素将被使用。错误代码被一个 ”type” 属性定义,这个 ”type” 属性包含代码数,通过 <error/> 元素来包含一个这个错误的文本描述。 <error/> 元素必须包含在原始消息的 <body/> 中。下面的例子将演示,当 Juliet 向一个不存在的用户发送“ hi ”消息后的包体:
例子:
<message
to="[email protected]"
from="[email protected]"
type="error">
<body>hi</body>
<error code="404">Not Found</error>
</message>
附文中有非法代码与它们所定义的含义表。
<html/> 元素结合 XHTML 名字空间( http://www.w3.org/1999/xhtml ),为一个消息提供一个交替的名字空间,就像在 email 世界中规定同时发送普通文本与 HTML 版本的邮件消息一样。这个功能使用的是 W 3C 开发的基本 XHTML 格式( http://www.w3.org/TR/xhtml-basic/ ),关于 Jabber 在消息中的 XHTML 执行细节,请看 Jabber 消息的暂定格式规范( http://docs.jabber.org/draft-proto/html/xhtml.html )。所有 XHTML 的根元素都必须是 <html xmlns=”http://www.w3.org/1999/xhmtl”></html> 。这个根元素中,支持任何一个基本 XHTML 格式中定义的元素,但不是每一个元素可以通过即时消息的上下文来进行理解。
这是一个可选元素,包含消息的标题。
当一个 Jabber 客户端发送一个 ”chat” 类型的消息,将生成唯一的线程 ID (通常是由发送者的 Jabber ID 和当前时间生成的一个 hash )。消息发送者和接收者在聊天中后续的消息都包含一个 <thread/> 子元素,这个子元素包含原始线程 ID 。这使得消息发送者和接收者对回复进行认证并创建一个对话线程。下面的是例子:
<message
from="[email protected]/balcony"
to="[email protected]/orchard"
type="chat">
<thread>AAC96FEFDE 226C 2C 04BE 8F 2E 19A 2151B</thread>
<body>Art thou not Romeo and a Montague?</body>
</message>
<message
from="[email protected]/orchard"
to="[email protected]/balcony"
type="chat">
<thread>AAC96FEFDE 226C 2C 04BE 8F 2E 19A 2151B</thread>
<body>Neither, fair saint, if either thee dislike.</body>
</message>
<x/> 元素作为一个扩展机制来使用,或发送从服务器发送命令给客户端,或从一个客户端发送命令到另一个客户端。每次用到这个元素时,必须指明相关的 XML 名字空间。单一消息可以包含多个 <x/> 子元素实例。下列已定义的名字空间可以被 <x/> 子元素使用:
l jabber:x:autoupdate
l jabber:x:delay
l jabber:x:encrypted
l jabber:x:oob
l jabber:x:roster
这些名字空间在下面的 Jabber 名字空间中被更完整地描述。
下面是一个使用 jabber:x:delay 名字空间在加入的群组聊天室的显示上下文的例子:
<message
type=’groupchat’
from=’[email protected]’>
<body>Thrice the brinded cat hath mew’d.</body>
<x xmlns=’jabber:x:delay’
stamp=’10541031T21:43: 40’ >Cached In GC History</x>
</message>
<presence/> 元素提供关于一个 Jabber 实体的可用性信息。任何一个通过一个 Jabber ID 确认的实体可以与另一个实体进行在线状态信息的通信,这种通信大多以订阅在线状态信息的方式进行。
所有实体表现出的在线状态不是“可用”就是“不可用”。“可用”状态表示发送者可以立即收到消息。“不可用”状态表示发送者不能在当前时间收到任何数据。默认情况下,所有 <presence/> 元素除非包含 type=”unavailable” 属性外,都表示“可用”。“可用”的更多特殊形势通过 <status/> 和 <show/> 子元素进行指定。
<presence/> 的“ type ”属性根据不同目的使用。除了提示其它用户本用户的可用性状态的“普通”用法外,还包括订阅、取消订阅、以及探测在线状态信息。下面是“ type ”属性的可用值:
如果没有包含任何“ type ”属性,在线状态包将被设为 type=”available” ,用来提供用户在线时的信息。一个 type=”available” 的在线状态包通常包含一个 <show/> 元素以详细说明 Jabber 实体的可用类型,以及一个 <status/> 元素,该元素包含人能看懂的关于该可用类型的描述。在线状态包还可以包含一个 <priority/> 元素,来指明该连接的 Jabber ID 的优先级。
例子:
<presence
from="[email protected]/balcony"
to="[email protected]/orchard"/>
<show>away</show>
<status>Stay but a little, I will come again.</status>
</presence>
<show/> 元素的可用值为:
l away ―― Jabber 用户或实体在线,但不能马上联系上
l chat ―― Jabber 用户或实体在线并有兴趣聊天
l dnd ―― Jabber 用户或实体在线,但不想被打扰(“ dnd ”表示“ do not disturb ”)
l xa ―― Jabber 用户或实体在线,但已经离开很长时间了(“ xa ”表示“ extended away ”)
<status/> 可以包含任意特性数据,这些数据通常包含对于用户状态的描述,如,“开会中”是“ away ”的一个表现值,或者“忙于编码”可以是“ dnd ”的一个表现。
当一个在线状态包发送给一个不存在的 JID 时,或在发送在线状态请求时发生一个错误时,服务器都将返回一个 type=”error” 的在线状态包。
下面是一个例子(注意域名的类型):
<presence
type="subscribe"
to="[email protected]"/>
回复的例子:
<presence
from="[email protected]"
to="[email protected]/balcony"
type="error">
<error code=’ 504’ >Remote server timeout. Unable to deliver
packet.</error>
</presence>
向一个特定实体(实体不能发送在线状态消息给自己)发出在线状态信息请求。服务器而非客户端,进行一个探测请求。实际上,虽然 Jabber 客户端也可以发送一个探测一个指定 Jabber 用户是否在线的请求,但通常都是服务器端发出探测请求。注意,只有在发起请求的用户在请求所对应的用户的花名册上,并且拥有“ from ”或“ both ”订阅类型时,服务器才会发出探测请求。在下面的例子中,我们将看到我们的英雄 Romeo 向 Juliet 发出一个探测请求, Juliet 所在服务器回复一个“状态报告包”(包含 jabber:x:delay 名字空间中指明的上次在线状态更新的时间戳)
探测请求的例子:
<presence
from="[email protected]"
to="[email protected]"
type="probe"/>
回复探测请求的例子:
<presence
from="[email protected]/."
to="[email protected]">
<status>Stay but a little, I will come again.</status>
<show>away</show>
<x
xmlns="jabber:x:delay"
from="[email protected]/."
stamp="15310309T23:47:15"/>
</presence>
发送一个请求,这个请求是接收者在其在线状态改变时,自动发送在线状态信息给发送者。
例子:
<presence
from="[email protected]"
to="[email protected]"
type="subscribe"/>
发送一个消息,表明发送者接受了接受者对其再现状态订阅的请求。从现在起,当发送者的在线状态信息改变时,服务器将会把状态信息发送给接收者。
例子:
<presence
from="[email protected]"
to="[email protected]"
type="subscribed"/>
例子:
<presence
from="[email protected]"
to="[email protected]"
type="unavailable">
<status>Disconnnected</status>
</presence>
发送一个请求,表明接收者停止发送在线状态信息给发送者。
例子:
<presence
from="[email protected]"
to="[email protected]"
type="unsubscribe"/>
这种类型的在线状态包有两个用途:
1. 发送一个表明发送者接受接收者关于不订阅其在线状态信息的请求的通知。服务器将不再发送发送者的在线状态信息给接收者。
2. 拒绝一个订阅请求。服务器将不再发送发送者的在线状态信息给试图订阅其在线状态信息的用户。
例子:
<presence
from="[email protected]"
to="[email protected]"
type="unsubscribed"/>
除了设置“ type ”属性,还可以通过下列属性修改 <presence/> 元素:
标识在线状态包的发送者。一般 Jabber ID 再“ from ”属性中必须写成 user@host/resource 的格式。从 XML 的观点来说,这个属性是所有 <presence/> 元素所必须的,而在实际应用中,都是服务器对该属性进行添加和修改(防止一些欺骗的手段),因此客户端开发者不需要考虑它。
例子:
<presence from="[email protected]/balcony"/>
为在线状态请求包配置唯一的验证符。“ id ”属性由 Jabber 客户端或客户库(如 Gabber 或 JabberCOM )生成,客户端用其为在线状态包的轨迹进行验证。“ id ”属性是可选的,并且不能用于系统其它任何地方。
例子:
<presence to="[email protected]/orchard" id="JCOM_86"/>
标识在线状态包的接收者。一般 Jabber ID 在“ to ”属性中都是 user@host/resource 的格式, user@host 的格式也是可以的,但当接收者在线时,它将转化为 user@host/resource 。在 Jabber 的一般用法中, Jabber 客户端向服务器发出在线状态包,服务器将这些在线状态包发送到该用户花名册上所有的用户。当一个 Jabber 客户端发送的 <presence/> 元素中不含“ to ”属性时,服务器将将其转化为在线状态包发送给指定的 Jabber 实体。下面的例子将演示这一过程。
发送给服务器的在线状态的例子:
<presence>
<status>Stay but a little, I will come again.</status>
<show>away</show>
</presence>
服务器发给指定用户的在线状态例子:
<presence
to="[email protected]/orchard"
from="[email protected]/balcony">
<status>Stay but a little, I will come again.</status>
<show>away</show>
</presence>
下面的元素用于 <presence/> 协议。
在 Jabber 中,根据 Jabber 知道的设备数或位置数,一个用户可以建立相同数量的连接。用户可以给每一个资源赋予一个数字优先级(通过对指派给该资源的 Jabber 客户端进行设置),这个优先级与 <presence/> 元素的子元素 <priority/> 方法进行通信。
当在线状态包发送到服务器后,服务器有能力决定哪一个连接资源需要指派一个单一的 Jabber ID ,该资源将收到发往该 Jabber ID 的消息,这是因为数字最高的资源是默认或第一资源。如果最高优先级的资源不可用,消息和其它 Jabber 通信将发送给次高优先级的资源(当其它资源都不可用时,一个没有从默认数到 0 的优先级的客户端,也可以成为第一资源)
举例来说, Julie 可以通过两个资源: the balcony 和 the chamber 连接她的帐号 [email protected] 。如果“ balcony ”资源的优先级被设置为“ 2 ” ,而“ chamber ”资源的优先级被设为“ 1 ” ,而且两个资源都可以连接,消息将发送到 [email protected]/balcony ,而不是 [email protected]/chamber 。
可选的 <show/> 元素告诉 Jabber 客户端如何显示一个用户的在线状态。 <show> 标签是一个典型的 <status> 标签的伴随标签, <status> 标签包含更多在线状态改变理由的描述信息。如果 <show/> 元素不在 <presence/> 元素中, Jabber 接收客户端将指明该用户处于“普通”状态。下面是四个可选项:
标签 |
含义 |
<show>chat</show> |
该客户可以马上联系上 |
<show>away</show> |
该客户在线,但刚刚离开(如吃午饭,开会) |
<show>xa</show> |
该客户在线,但已经处于非活动状态很长时间了。 |
<show>dnd<show> |
该用户处于谢绝打扰的模式 |
<status/> 元素包含更多关于用户在线状态的描述。大多数 Jabber 客户端都包含一些 <status/> 元素的默认设置;另外,它们还允许我们提供富有个性的描述如“我在吃午饭”或者“钓鱼中”。
<x/> 元素作为一个扩展机制来使用,或发送从服务器发送命令给客户端,或从一个客户端发送命令到另一个客户端。每次用到这个元素时,必须指明相关的 XML 名字空间。单一消息可以包含多个 <x/> 子元素实例。下列已定义的名字空间可以被 <x/> 子元素使用:
l jabber:x:autoupdate
l jabber:x:delay
l jabber:x:encrypted
l jabber:x:oob
l jabber:x:roster
这些名字空间在下面的 Jabber 名字空间中被更完整地描述。
信息 / 查询 (IQ) 在 Jabber 中在两个实体间构建一个根本的会话,并且允许实体间来回传送 XML 格式的请求和响应。信息 / 查询主要的用处是取得或设置公共的用户信息,比如名字,电子邮件,地址等等。但它的灵活设计使得任何种类的会话都可以发生。任何通过一个 Jabber ID 标识的实体都能通过一个 IQ 与其它实体进行会话。
<iq/> 元素的“ type ”属性用于决定信息 / 查询是请求还是响应。下面是“ type ”属性的可用值:
表示查询失败。实际错误在 <iq/> 元素的 <error/> 子元素中描述。
例子:
<iq type="error" to="[email protected]">
<error code="403">Forbidden</error>
</iq>
找回指派给一个查询名字空间的信息。如果没有设置属性,默认情况,这个属性包含在查询中。一个 type=”get” 的 <iq/> 元素由一个子元素构成,这个子元素通常是 <query> ,但也可以是 <vcard/> 或另一个已有的子元素。不过,指定的子元素必须左空,以便接收一个用户所需提供的信息的空间的清单。一个成功的 get 查询的结果 type=”result” 的 <iq/> 元素,是元素嵌套在包含了所需信息的指定子元素(如 <query> 或 <vcard/> )。
例子:
<iq type="get">
<vCard xmlns="vcard-temp"/>
</iq>
表示 <iq/> 包是一个 type=”get” 或 type=”set” 的 <iq/> 查询的成功响应。这个成功查询的结果是一个 type=”result” 的 <iq/> 元素,该元素嵌套在一个包含所查询的信息的子元素中(如 <query> 、 <vcard/> )。一个成功的查询或获取查询结果的返回是一个空的 type=”result” 的 <iq/> 元素。一个不成功的返回是一个 type=”error” 的 <iq/> 元素。 <iq type=”result”/> 通常与“ id ”属性的获取、设定查询有关。
例子:
<iq type="result">
<vCard version="3.0" xmlns="vcard-temp">
vCard data goes here
</vCard>
</iq>
表示 <iq/> 包是对设值或更改现有数据值。一个 type=”set” 的 <iq/> 元素总是包含一个指定的子元素,通常是 <query> ,也可以是 <vcard/> 或者其它可以接受的子元素。一个设置命令查询的成功返回是一个空的 type=”result” 的 <iq/> 元素。
例子:
<iq type="set">
<vCard version="3.0">
vCard data goes here
</vCard>
</iq>
除了“ type ”属性外, IQ 元素还可以通过下面的属性进行修改。
表示 iq 包的发送者。从 XML 观点来说,这个属性是所有 <iq/> 元素所必须的,实际应用中这个属性是服务器来增加和修改的(为防止某些欺骗),因此客户端的开发人员不需要过多关注这个属性。
例子:
<iq from="[email protected]"/>
一个 iq 包只有唯一的标识。 Jabber 客户端或客户库生成“ id ”属性,客户端通过它来标识 <iq/> 包,以完成对 <iq/> 包的跟踪(如:一个 type=”result” 对应一个 type=”get” 或 type=”set” )。“ id ”属性是可选的,并且不能用于系统的其它地方。
例子:
<iq type="get" from="[email protected]/balcony" id="JCOM_87"/>
<iq type="result" to="[email protected]/balcony" id="JCOM_87"/>
表示 iq 包的接收者。在 Jabber 客户端,对应“ to ”属性的 Jabber ID 的格式为 user@host/resource 。 user@host 也是可以的,如果用户在线, user@host 将被置换成 user@host/resource ,如果用户不在线, user@host 将被直接指向一个离线模块(对于类似服务器端网关这种非用户实体,情况又有所不同,因为它们不拥有资源,并且只是简单通过 Jabber ID 的一个“ server ”端口进行标识。 Jud.jabber.org —— Jabber 用户目录就是这样一个例子)。如果 <iq/> 包没有 <to> 属性,服务器将对该包进行处理。
例子:
<iq to="[email protected]/balcony">
下面介绍 <iq/> 元素的子元素。
当 iq 的属性类型被设置为“ error ”时,将用到本属性。错误代码根据一个含有错误数的“ type ”属性进行定义, <error/> 员司包含该错误的文本描述。比如,下面就是一个坏请求:
<error code="400">Bad Request</error>
在附录中,列有错误编码及其对应的错误描述。
<key/> 元素为客户端-服务器之间交互提供一层安全保护。它被用户 jabber:iq:register 和 jabber:iq:search 名字空间中。
当一个客户端发起一个与服务其之间的交互时,服务器将发送一个包含一个唯一值的 <key> 给客户端。客户端在返回 <iq type=”set”/> 的消息中,包含上诉唯一值到 <key/> 子元素中。这样,服务器就认为该客户端时接收到原来密码的同一实体。
<iq/> 元素中的 <query/> 子元素定义所执行的查询的类型。特殊情况下,查询可以拥有一个特殊的名字空间,这个名字空间是一个通过“ xmlns ”属性定义的 <query/> 子元素。一个 <iq/> 元素中只能有一个 <query/> 子元素。
下面的例子是当我通过我的 Linux 机器上的 Grabber 客户端登陆到服务器上,将出现的 XML 。
<iq type="set">
<query xmlns="jabber:iq:auth">
<username>stpeter</username>
<resource>Gabber</resource>
<digest>f1e881517e9917bb815fed112d81d32b4e4b3aed</digest>
</query>
</iq>
就象你看到的那样,认证查询通过客户端认证名字空间( jabber:iq:auth )向服务器发送认证信息。一般, Jabber 核心协议保留 jabber:iq:* 这样的名字空间。而开发者可以通过增加 jabber:iq:* 名字空间对 Jabber 核心进行扩展。这些将在下面的名字空间中进行更完整的描述。
一个空 <query/> 子元素可以与 <iq type=”get”> 元素一起发送,这样可以找回与 <query/> 子元素中指定的名字空间相关的一个 Jabber 实体的信息。比如,找回一个客户端的花名册(“联系人名单”),下面的 XML 可以被发送:
<iq to="[email protected]/balcony" type="get">
<query xmlns="jabber:iq:roster"/>
</iq>
现面是 Jabber 中的标准名字空间:
l jabber:iq:agent ——代理工具
l jabber:iq:agents ——有效的代理组
l jabber:iq:auth ——简单用户认证
l jabber:iq:autoupdate ——版本更新申请
l jabber:iq:browse —— Jabber 浏览
l jabber:iq:conference ——一般会议
l jabber:iq:gateway ——用户地址网关
l jabber:iq:last ——上次使用时间
l jabber:iq:oob ——绑定数据输出
l jabber:iq:private ——私有数据存储
l jabber:iq:register ——注册请求
l jabber:iq:roster ——花名册(联系人名单)管理
l jabber:iq:search ——用户数据库查询
l jabber:iq:time ——客户端时间
l jabber:iq:version ——客户端版本
l jabber:x:autoupdate ——版本通知申请
l jabber:x:conference ——会议邀请
l jabber:x:delay ——显示的对象
l jabber:x:encrypted ——加密的消息
l jabber:x:envelope ——消息封套
l jabber:x:event ——消息事件
l jabber:x:expire ——消息终止
l jabber:x:oob ——绑定数据(文件传输)输出
l jabber:x:roster ——内部的花名册条目
l jabber:x:signed ——标记的在线状态
l vcard-temp ——临时的 vCard
下面将详细介绍这些名字空间的细节。
代理工具名字空间包含一个代理的所有工具。 jabber:iq:angents 查询通常用于注册到一个指定的服务、代理、传输器。
它也可能检验一个指定代理的所有工具细节。比如,一个客户端可以决定一个开放的注册是否可以进行。
例子:
<iq id="wjAgent" type="result" from="Jabber.org">
<query xmlns="jabber:iq:agent">
<agent jid="aim.jabber.org">
<name>AIM Transport</name>
<description>This is the AIM Transport</description>
<transport>AIM/AOL ScreenName</transport>
<service>aim</service>
<register/>
</agent>
</query>
</iq>
可用代理列表名字空间包含一组实体,这些实体拥有一些特殊工具,并能够为另一个实体提供服务。大多数情况下,可用代理列表是用来显示一台服务器上的可用传输器列表。
注意:这个名字空间被 jabber:iq:browse 的支持者所反对(??)。
例子:
<iq id="wjAgents" type="result" from="jabber.org">
<query xmlns="jabber:iq:agents">
<agent jid="users.jabber.org">
<name>User Directory</name>
<description>
You may register and create a public searchable
profile, and search for other registered Jabber
users.
</description>
<service>jud</service>
<register/>
<search/>
</agent>
<agent jid="aim.jabber.org">
<name>AIM Transport</name>
<description>This is the AIM Transport</description>
<transport>AIM/AOL ScreenName</transport>
<service>aim</service>
<register/>
</agent>
</query>
</iq>
简单客户认证名字空间是对客户端进行认证的一个简单机制,它为客户端到服务器之间的连接创建一个资源。
认证成功返回一个 type=”result” 的 IQ 响应。不成功,就返回一个错误 IQ 元素。
如果没有发送名字空间或密码,如果服务器允许,服务器将创建一个匿名资源。
例子:
<iq type="set" id="JCOM_0">
<query xmlns="jabber:iq:auth">
<username>juliet</username>
<password>secret</password>
<resource>balcony</resource>
</query>
</iq>
<iq type="set" id="JCOM_0">
<query xmlns="jabber:iq:auth">
<username>juliet</username>
<digest>a5e 052c 48c 455bf21d937ccf17225916d9486b09</digest>
<resource>balcony</resource>
</query>
</iq>
<iq type="set" id="JCOM_0">
<query xmlns="jabber:iq:auth">
<username>juliet</username>
<hash499>secret</hash499>
<resource>balcony</resource>
</query>
</iq>
版本更新申请名字空间允许客户端对所有可用软件更新进行申请请求。
例子:
<iq type="get" to="jabber.org" id="1">
<query xmlns="jabber:iq:autoupdate"/>
</iq>
Jabber 浏览名字空间的作用是,一是为 Jabber 世界中已有的 Jabber IDs 增加结构的一个途径,一是发现为不同 Jabber 实体提供的服务或应用。一个 Jabber 浏览的基本概念就是一个 jid-type (类似文件的一个模拟类型的概念)。下面是想象中的最高级别的 jid-types ,不过随着时间的推移,一些其它的逻辑将被增加进来:
l 应用
l 会议
l 标题
l 关键字
l 回报
l 服务
l 用户
上面每一个范畴都有一个子类列表,如用户 / 客户端,或用户 / 设备(“客户端”或“设备”只是一个“资源”的概念),会议 /irc ,服务 /icq ,标题 / 库存。一般的,通过使用 jabber:iq:browse 名字空间你将拥有一个与上述某一 jid-type 范畴相对应的元素,这个元素通常有一个指定子类型的“ type ”属性。
Jabber:iq:browse 的一个用户就是代替 jabber:iq:agents 名字空间来列出一个服务器上所对应的代理或其它服务。下面是一个浏览服务器的例子:
Jabber 客户端发送:
<iq type="get" to="jabber.org">
<query xmlns="jabber:iq:browse"/>
</iq>
Jabber 服务器返回:
<iq type="result" from="jabber.org">
<service
type="jabber"
jid="jabber.org"
xmlns="jabber:iq:browse>
<service
type="jud"
jid="users.jabber.org"
name="Jabber User Directory">
<ns>jabber:iq:register</ns>
<ns>jabber:iq:search</ns>
</service>
<service
type="aim"
jid="aim.jabber.org"
name="AIM Transport">
<ns>jabber:iq:register</ns>
<ns>jabber:iq:search</ns>
</service>
<conference
type="private"
jid="conference.jabber.org"
name="Private Chatrooms">
</service>
</service>
</iq>
在会议中的一个例子:
<iq type="set" to="room@server">
<conference xmlns="jabber:iq:browse" name="Room Name">
<user jid="room@server/jidhash" name="nick1"/>
<user jid="room@server/jidhash" name="nick2"/>
</conference>
</iq>
一般会议名字空间提供一个会议室的机制(如群组聊天室),并提供该会议室的入口。这个名字空间与 </iq> 元素配套使用来获得一个会议室的信息,包括要求加入这个会议室的请求信息,以及为这个会议室设置信息(通常是为了加入这个房间)。一个普通进入房间的请求将和下面的类似:
1. 想要加入的房间提交一个 type=”get” 的请求。这个 XML 将是下面的形式:
<iq type="get" to="room@server">
<query xmlns="jabber:iq:conference"/>
</iq>
2. 接受来自要加入的房间的 type=”result” 的 iq 响应,其中有进入房间所需要的参数。这个 XML 将是下面的形式:
<iq type="result" from="room@server">
<query xmlns="jabber:iq:conference">
<nick/>
<secret/>
<privacy/>
<name>Room Name</name>
</query>
</iq>
这里所有的请求元素的子元素都是可选的。昵称 (nickname) 元素表示进入房间需要一个昵称。密钥 (secret) 元素表示进入房间的用户需要提供一个密码。独处 (privacy) 元素表示如果用户在一个 type=”set” (下面可以看到例子)的 iq 包中提供这样的元素,会议服务器将隐藏用户的真实 Jabbere ID 。名字( name )元素是房间的名字(用 jabber : iq:browse 浏览房间时可以看到同样的房间名)。
3. 发送当前状态给要加入的房间。 XML 如下:
<presence to="room@server"/>
4. 想要加入的房间提交一个 type=”set” 的 iq 包以及进入所需信息。 XML 如下:
<iq type="set" to="room@server">
<query xmlns="jabber:iq:conference">
<nick>mynick</nick>
<nick>mysecondnick</nick>
<secret>thesecret</secret>
</query>
</iq>
注意在用户第一个选择被接受时,用户可以提交多个昵称。如果用户没有提供昵称,服务器将指派一个昵称给用户。
5. 收到你加入的房间的通知,这个 iq 以下面的格式返回:
<iq type="result" from="room@server">
<query xmlns="jabber:iq:conference">
<id>room@server/uniqueidnumber</id>
<nick>mynick</nick>
</query>
</iq>
这个唯一的 ID 号是用户 Jabber ID 的一个哈希。
一般通过一个网关或传输器(比如 AIM 传输器)来实现与非 Jabber 网络用户的通信,每一个非 Jabber 网络都可能拥有唯一的用户地址,这个地址可能和 Jabber IDs 并不统一。用户地址网关就是解决这个问题的,它使得 Jabber 客户端向非 Jabber 网络用户发出订阅时给出正确 Jabber IDs 变得很容易。这些通过对用户进行提示和会话,引导用户提供创建一个正确 Jabber ID 所需信息来实现。下面将演示这种普通的交互:
1. 客户端向网关发出带有 jabber:iq:gate 名字空间查询的 iq get :
<iq type="get" to="aim.jabber.org">
<query xmlns="jabber:iq:gateway"/>
</iq>
2. 服务器返回一个包含请求批准及其描述文本的 iq :
<iq type="result" from="aim.jabber.org">
<query xmlns="jabber:iq:gateway">
<desc>
Please enter the AOL Screen Name of the person
you would like to contact.
</desc>
<prompt>Screen Name</prompt>
</query>
</iq>
3. 客户端向网关发送一个包含指定信息的 iq set :
<iq type="set" to="aim.jabber.org">
<query xmlns="jabber:iq:gateway">
<prompt>Joe Cool</prompt>
</query>
</iq>
4. 服务器返回一个包含正确 Jabber ID 的 iq result
<iq type="result" from="aim.jabber.org">
<query xmlns="jabber:iq:gateway">
<jid>[email protected]</jid>
</query>
</iq>
最后一次在线时间名字空间提供一个标准的方法,通过这个方法可以查询一个 Jabber 实体一个或多个服务更新时间,或者一个客户最后一次连接(或活动)到一台服务器上的时间。每一次返回的值都是一个秒的数目。进行查询的实体可以通过下面的法则解释获取的信息:
l user@server/resource ——用户最后一次活动的时间
l user@server ——用户最后一次连接的时间
l server ——服务器最后一次启动的时间
例子(服务器):
<iq type="get" to="jabber.org">
<query xmlns="jabber:iq:last"/>
</iq>
<iq type="result" to="[email protected]/Gabber" from="jabber.org">
<query xmlns="jabber:iq:last" seconds="124933"/>
</iq>
例子(客户端):
<iq type="get" to="[email protected]">
<query xmlns="jabber:iq:last"/>
</iq>
<iq type="result" [email protected]/Gabber from="[email protected]">
<query xmlns="jabber:iq:last" seconds="5024">
Disconnected
</query>
</iq>
绑定数据输出名字空间为客户端-客户端的文件传输提供一个标准方法,通过服务器的传输 / 代理的传输器实现一个特殊的名字空间:
例子:
<iq type="set" to="[email protected]" id="file_1">
<query xmlns="jabber:iq:oob">
<url>http://denmark.com/act4/letter-1.html</url>
<desc>There’s a letter for you sir.</desc>
</query>
</iq>
私有数据存储名字空间是 Jabber 服务器上存储私有数据的一个机制。存储的数据可以是任何合法的 XML 数据。在服务端存放客户端的当前状态信息是这个名字空间的典型用法。
例子 1 (客户端存储私有数据):
<iq type="set" id="1001">
<query xmlns="jabber:iq:private">
<winjab xmlns="winjab:prefs">
<defaultnick>Hamlet</defaultnick>
</winjab>
</query>
</iq>
例子 2 (客户端找回私有数据):
<iq type="get" id="1002">
<query xmlns="jabber:iq:private">
<winjab xmlns="winjab:prefs"/>
</query>
</iq>
另外,对于私有数据存储, 1.4 版服务器支持服务器上所有有效名字空间(以“ jabber ”开头的名字空间保留,为 Jabber 系统进行调用)的 XML 数据。这个数据存在向服务器端发送 type=”set” 的 iq 包的用户的花名册中。
例子 1 (客户端保存公有数据):
<iq type="set" id="1003">
<query xmlns="stpeter:public:favorites">
<fav_things>
<food>Thai</food>
<color>blue</color>
<composer>Bach</composer>
</fav_things>
</query>
</iq>
例子 2 (客户端找回公有数据):
<iq type="get" id="1004">
<query xmlns="stpeter:public:favorites">
<fav_things/>
</query>
</iq>
注册请求名字空间对一个或多个服务进行注册。它也被用来更新或删除一个注册。
例子:
<query xmlns="jabber:iq:register">
<instructions>
Some instructions to be displayed when the
user is filling out the form.
</instructions>
<username/>
<password/>
<email/>
<date/>
<key/>
</query>
联系人名单管理名字空间是客户端用来管理他们的花名册的,该花名册保存在服务器上,这样用户可以在任何地方得到它。花名册是该帐号上所有订阅信息的命令列表,包括用户昵称和联系列表。当用户从任何一个资源登陆上来,服务器将把花名册发送给用户。
花名册是一个条目的列表。每一个条目元素都有描述它的属性。每一个条目元素都包含它所属组的组元素。下面是描述 <item/> 元素的属性:
l “ jid ”是条目的 Jabber ID
l “ subscription ”所有和本条目相关的订阅所对应的用户的当前状态。它可以是“ none ”(不可订阅),“ to ”(有一个发到该条目的订阅),“ from ”(从该条目发送一个订阅给我们),“ both ”( to 、 from ),或者“ remove ”(从花名册上删除一个条目)。
l “ ask ”是对这个条目的一个请求的当前状态。 Subscribe 表示请求对该条目进行订阅,它的值就是, Unsubscribe 表示取消订阅。
l “ name ”表示昵称
通过使用一个 <iq type=”set”/> ,一个 Jabber 客户端可以控制用户的 JabberID ,名称属性,群组元素,并且可以在联系人名单上创建或删除联系人。服务器根据客户端对当前状态订阅请求的响应来管理其它所有属性。
订阅请求的例子:
<iq type="set" id="uniquevalue">
<query xmlns="jabber:iq:roster">
<item jid="[email protected]"
name="Romeo"
subscription="none"
ask="subscribe">
<group>friends</group>
</item>
</query>
</iq>
当一个花名册条目在服务器上改变时,服务器将把这个改变推送给一个用户。这个推送是一个普通的从服务器发送到客户端的 <iq type=”set”/> 包。下面是一个例子:
<iq type="set">
<query xmlns="jabber:iq:roster">
<item jid="[email protected]" subscription="both"/>
</query>
</iq>
在上面的例子中,服务器推送给客户端一个花名册,表明该用户对 [email protected] 的当前状态信息有订阅。一个花名册推送可能发生一个连接的任何时间中,该连接是另一个连接修改资源或服务器(修改订阅属性)的结果。客户端只有使用花名册推送来改变花名册的显示。但不是每次花名册推送都对用户起作用。
任何一个代理都可以成为一个查询代理。例如, JUD 查询 Jabber 用户, ICQ 传输器查询 ICQ 用户。
用户发送一个进行可查询域的 Get 请求:
<iq
type="get"
id="1001"
to="users.jabber.org"
from="[email protected]/orchard">
<query xmlns="jabber:iq:search"/>
</iq>
查询代理返回一个可查域:
<iq type="result" id="1001" from="users.jabber.org">
<query xmlns="jabber:iq:search">
<instructions>Fill in a field to search for any
matching Jabber User
</instructions>
<name/>
<first/>
<last/>
<nick/>
<email/>
<key>067941fd 96a 6a 2752a 21abcb6d737130dd51dd50</key>
</query>
</iq>
注意这些域是以提示的形式返回。为了传输的安全还包含一个密钥(下面会看到)。用户现在可以在允许的域内进行标准的查询了。用户发回一个 Set 请求给代理进行实际查询:
<iq
type="set"
id="1002"
to="users.jabber.org"
from="[email protected]/orchard">
<query xmlns="jabber:iq:search">
<last>Capulet</last>
<key>11b830e 604215c 3a 2a 24652c 69fd4efa 2a 7a 5746</key>
</query>
</iq>
服务器根据查询返回结果:
<iq type="result" id="1002" from="users.jabber.org">
<query xmlns="jabber:iq:search">
<item jid="[email protected]">
<name>Juliet Capulet</name>
<first>Juliet</first>
<last>Capulet</last>
<nick>juliC</nick>
<email></email>
</item>
<item jid="[email protected]>
<name>Sampson Capulet</name>
<first>Sampson</first>
<last>Capulet</last>
<nick>sammy</nick>
<email></email>
</item>
</query>
</iq>
注意有两套 items 标记含有指定信息。这是因为通过代理发送返回有两种方法:
l 单一返回标签
l 多个“ pushed ”到用户的标签,类似花名册推送,如在一个时间上的一个记录。
发送的返回的样式是查询代理的一个工具。比如:
<iq type="set" from="icq.jabber.org" id="1003">
<query xmlns="jabber:iq:search">
<item jid="[email protected]">
<email>[email protected]</email>
<nick>juliC</nick>
<given>Juliet</given>
<family>Capulet</family>
</item>
</query>
</iq>
多个查询结果通过服务器进行推送。当所有数据发送完毕,服务器将发送下面的返回结果:
<iq type="result" from="icq.jabber.org" id="1003">
<query xmlns="jabber:iq:search"/>
</iq>
客户端接收到多个“ sets ”,每一个都被记录,最后收到一个表示“数据结尾”的“返回”。在每一个 <item> 标签中, JID 属性都被强制带上。
例子:
<iq
type="get"
id="1001"
to="users.jabber.org"
from="[email protected]">
<query xmlns="jabber:iq:search"/>
</iq>
客户端时间名字空间是客户端改变当前时间的一个标准方法。
例子:
<iq type="result" from="[email protected]">
<query xmlns="jabber:iq:time">
<utc>20010214T18:55:06</utc>
<display> 2/15/00 4:55:06 PM </display>
</query>
</iq>
客户端版本名字空间是得到另一个用户的客户端的版本信息的一个标准方法。
例子:
<iq type="result" from="[email protected]/Gabber">
<query xmlns="jabber:iq:version">
<name>Gabber</name>
<version> 0.8.1 (Powered by: jabberoo 1.0.0</version>
<os>Linux 2.2.16 -22 i686</os>
</query>
</iq>
版本更改申请名字空间使服务器可以在一个应用的新版本可用时通知客户端。
例子:
<message from="winjab.sourceforge.net">
<x xmlns="jabber:x:autoupdate">A new version of WinJab
is available, see http://winjab.sourceforge.net/
</x>
</message>
会议邀请名字空间使用户可以邀请其它 Jabber 用户到指定会议室。相关联信息——该会议室的 Jabber ID ,内嵌在一个消息的 <x/> 元素中。
例子:
<message to="[email protected]" from="[email protected]">
<body>Wherefore art thou Romeo?</body>
<x xmlns="jabber:x:conference" jid="[email protected]/>
</message>
标记对象延时名字空间是消息和当前状态信息的时间戳信息,其中,当一个 Jabber 实体不在线时,当前状态信息可以保存并在稍后发送。当实体上线时,包含的信息标记对象延时名字空间使 Jabber 客户端显示出该包体最早产生的时间,而不是它发送给 Jabber 实体的时间。
例子:
<message
type=’groupchat’
from=’[email protected]’>
<body>Thrice the brinded cat hath mew’d.</body>
<x xmlns=’jabber:x:delay’
stamp=’10541031T21:43: 40’ >Cached In GC History</x>
</message>
加密消息名字空间用来支持使用公共密钥(一般通过客户端使用 PGP 或 GPG ,服务端用同样的名字空间进行加密来实现)加密的消息交互。一个相关的名字空间, jabber:x:signed ,用来进行当前状态信息的加密。
例子:
<message from=’[email protected]/balcony’ to=’[email protected]/orchard’>
<body>This Message is Encrypted</body>
<x xmlns=’jabber:x:encrypted’>
hQEOA7ucqu53AhlPEAP/ZbU6oPnRAbIcUxMK1XRVnkgZ/Agtq1tcTQuEZxbpZLl4
C/4psQGLgBU5h5Y3/khxtJTPXKn1izyc+DRZ8hqn2p4mwC8ioKTBJ6P6dfEpQEyt
a4bimM5fqdeh4gRkMhwThRSJxBCJBVVWFEViu+0KlHHB5AeeL4qwRGb2dhGjIgQD
/R9x0D0qtgBGwf/TVnRGZYRX7epxCNuNDEYKZSs4LEoTPL8CVsAWOzS2QgS0GBqt
tFDKId6XaNu36dB2D8VHdxQnI8RtHo9pfTYDaXWB3dMGTt896iEO/sTuucYObf3s
K5Kygg0uWpBpvQPj8Y041FhnUBz8DRGCnuFLQxCI6ch4ybauXfOKNOGDQwmsnJZm
6OaeVFUwdsedI 3c 6VdQtodnWVutckR5BOjnn0VqnhrVTu7cp6VXrrRK 4g 9atPEe6
C4R/MilBjzIJBcET0jhWuAyiBo3gN/6IqYRZNSXL9ZqGPJwNTlYim1EHN3qBqiUw
zUMamEoRzcusn80Z7kylve5ujIeSD/pVwoawHHvLp92kO2hd0yGD0UrWSfKU1o6y
EY8yhZ5P1v02pIKigAUI 2c 6LTDxt/KhSxQ==
=fijN
</x>
</message>
消息信封名字空间是表明消息有更多的寻址方式,如联合 email 进行的寻址。下面是一些所支持的名字空间:
l to
l cc
l replyto
l from
l forwardedby
上述每一个元素都带有一个 ”jid” 属性来标识 Jabber 实体是发送、中转、还是收到消息。
例子:
<message from=’[email protected]/tomb’ to=’[email protected]/tomb’>
<body>And there I am. Where is my Romeo?</body>
<x xmlns=’jabber:x:envelope’>
<to jid=’[email protected]>Romeo</to>
<forwardedby jid=’[email protected]>God</forwardedby>
</x>
</message>
消息时间名字空间是标识一条消息的状态的一个机制。现在,事件与一条消息如下般相关联:
l <composing/> ——个用户正在对消息进行回复
l <delivered/> ——发送给指定接收者的消息
l <displayed/> ——显示给指定接收者的消息
l <offline/> ——为离线进行存储的消息
对于客户端来说,这些消息事件的支持是可选的,而且,只有在另一用户在聊天中发出请求,这些消息事件才会被发送。不同的 Jabber 客户端将对当前状态消息事件进行不同的显示。
对消息通知的请求的例子:
<message
from="[email protected]/balcony"
to="[email protected]/orchard"
id="1001">
<body>By whose direction found’st thou out this place?</body>
<x xmlns="jabber:x:event">
<composing/>
</x>
</message>
发送消息通知的例子:
<message from="[email protected]/orchard" to="[email protected]/balcony">
<body>By whose direction found’st thou out this place?</body>
<x xmlns="jabber:x:event">
<composing/>
<id>1001<id/>
</x>
</message>
可以同时请求多个消息事件。
消息到期名字空间是说明一条消息拥有一个有限的存活事件的一个简单扩展。如果消息被离线存储,而到了到期时间,服务器将不再发送该消息。如果一条消息为预览就进行发送, Jabber 客户端可以选择不显示该消息。“ secondes ”属性定义消息发送的事件。
例子:
<message from="[email protected]" to="[email protected]">
<body>There’s a letter for you sir</body>
<x xmlns="jabber:x:expire" seconds="3600"/>
</message>
绑定数据输出名字空间使用户可以通过交换一个标准的 URL 来实现文件传输的目电。使用 jabber:x:oob 的 URLs 交换可以包含任一消息(在一个 <x/> 子元素内),感觉就像 email 里的附件一样。多个附件可以包含在同一个消息中。
例子:
<message from="[email protected]" to="[email protected]">
<body>URL Attached.</body>
<x xmlns="jabber:x:oob">
<url>http://denmark.com/act4/letter-1.html</url>
<desc>There’s a letter for you sir</desc>
</x>
</message>
内置的花名册条目使用户可以在一个消息中包含花名册条目,这样很容易在用户之间发送联系方式。每一个花名册条目都包含在一个 <x/> 的一个 <item/> 子元素中。这个 <x/> 元素一般用在一个 <message/> 元素中,但这不是必须的。
例子:
<message to="[email protected]">
<body>
Here are some new Jabber users
to add to your contact list!
</body>
<x xmlns="jabber:x:roster">
<item jid="[email protected]" name="King">
<group>Royalty</group>
</item>
<item jid="[email protected]" name="Horatio">
<group>Friends</group>
</item>
<item jid="fortinbras@norway" name="Prince Fortinbras"/>
</x>
</message>
有符号的当前状态名字空间用来支持交换使用公共密钥(客户端使用 PGP 或 GPG ,服务端使用同样的名字空间进行加密)加密的当前状态信息。一个相关的名字空间, jabber:x:encrypted 用来支持加密消息。
例子:
<presence from=’[email protected]/balcony’ to=’[email protected]/orchard’>
<show>away</show>
<status>be back later</status>
<x xmlns=’jabber:x:signed’>
iD8DBQA6kasv0xpc2/POfPkRAnz0AJ9UEYYWWSReddIKk3AYMfTFtqQDJwCfbcLd
JcSUOR0FlS+rDFjAPaSMgSM+iNaNm
</x>
</presence>
vCard 格式是一个“电子商务卡的标准格式,通过使用通过互联网进行个人数据的直接交换,如同在非互联网下的环境一样”。由于 XML 的 vCard 的格式还没有标准化, Jabber.org 项目在 XML 的 vCard 标准建立之前,暂时设置了这样一个临时名字文件。由于这几年在 vCard 的 XML 的官方标准的指定上没有任何进步, Jabber.org 开发者专门为这个项目创建了一个项目吸引 Jabber 社区外其它开发者的注意。因此,最后的 XML 的 vCard 格式的最后 DTD 可能会在下面的 URL 中找到:
http://www.vcard-xml.org/
例子 1 (对 vCard 的客户端请求):
<iq type="get">
<vCard xmlns="vcard-temp"/>
</iq>
例子 2 (客户端收到 vCard 数据):
<iq type="result">
<vCard version="3.0" xmlns="vcard-temp">
vCard data goes here
</vCard>
</iq>
例子 3 (客户端向服务端发送 vCard ):
<iq type="set">
<vCard version="3.0">
vCard data goes here
</vCard>
</iq>
这一部分提供一些在 Jabber 协议上略有不同的观点,通过用例来阐述。下面每一个例子都展示一个 Jabber 用户完成一个完整的任务的消息流程,该流程包括接收和发送,如注册到一台服务器,登陆,改变当前状态,或者发送一条消息。如果时间允许,我将把这部分引申的更远。
本用例同时邪显示 Jabber 用户向服务器开启一个 socket 的连接,以及服务器的响应 ( 如: <stream:stream> 标签 ) 。
1. Jabber 用户通过开启一个从客户端到服务器端的 XML 流,来申请一个在服务器上的 socket 连接。
SEND: <stream:stream
to=’capulet.com’
xmlns=’jabber:client’
xmlns:stream=’http://etherx.jabber.org/streams’>
2. 服务器通过开启一个从服务器到客户端的 XML 流进行回复。
RECV: <stream:stream
from=’capulet.com’
id=’ 180763465’
xmlns=’jabber:client’
xmlns:stream=’http://etherx.jabber.org/streams’>
3. Jabber 用户提供一个需要注册一个帐号(理论上,这需要一个不同的顺序:首先询问服务器需要什么信息,然后服务器器告知客户端需要什么样的信息;但在实际中,假定需要的信息是:用户名,资源,密码)的信息。
SEND: <iq id=’ 1’ type=’set’>
<query xmlns=’jabber:iq:register’>
<username>Juliet</username>
<resource>balcony</resource>
</query>
</iq>
4. 服务器响应一个空的类型为 ”result” 的 iq 元素,表示注册已成功。
RECV: <iq id=’ 1’ type=’result’/>
1. Jabber 用户询问服务器,登陆所需要提供的信息。
SEND: <iq id=’ 2’ type=’get’>
<query xmlns=’jabber:iq:auth’>
<username>Juliet</username>
</query>
</iq>
2. 服务器提示 Jabber 用户登陆所需要的信息。
RECV: <iq id=’ 2’ type=’result’>
<query xmlns=’jabber:iq:auth’>
<username>Juliet</username>
<password/>
<digest/>
<sequence>500<sequence/>
<token>3B905BFD</token>
<resource/>
</query>
</iq>
3. Jabber 用户提供所需的信息——在本例中,是一个 <hash/> 元素,它是对信息进行一个零度知识认证的一个哈希。(详情请见 http://docs.jabber.org/draft-proto/html/zerok.html )。
SEND: <iq id=’ 3’ type=’set’>
<query xmlns=’jabber:iq:auth’>
<username>Juliet</username>
<resource>balcony</resource>
<hash>77d7eacde5e56b9622d 0a 075cb88361b 110f
b9d7</hash>
</query>
</iq>
4. 服务器响应一个空的类型为 ”result” 的 iq 元素,表明登陆成功。
RECV: <iq id=’ 3’ type=’result’/>
5. Jabber 用户发送当前状态给服务器,表明其在线。
SEND: <presence>
<status>Online</status>
</presence>
1. Jabber 客户端在花名册上增加一个联系人(只是预备的操作)。
SEND: <iq type=’set’>
<query xmlns=’jabber:iq:roster’>
<item jid=’[email protected]’
Name=’remeo’/>
</query>
</iq>
2. Jabber 用户发送一个对该联系人的订阅请求。
SEND: <presence to’[email protected]’ type=’subscribe’>
<status>Wherefore are thou?</status>
</presence>
3. 服务器发送一个花名单推送给用户一个新条目和一个类型为 ”none” 的订阅(早已有了该订阅)。
RECV: <iq type=’set’>
<query xmlns=’jabber:iq:roster’>
<item jid=’[email protected]’
name=’romeo’
subscription=’none’/>
</query>
</iq>
4. 服务器发送一个类型为 ”result” 的 iq 包,表示花名册推送成功(让人有点疑惑的是,这个包是从 Jabber 用户发送到 Jabber 用户的!)
RECV: <iq
from=’[email protected]/balcony’
to=’[email protected]/balcony’
type=’result’>
5. 服务器发送另一个花名单推送,这次是 ask=’subscribe’ 属性,表示订阅的状态未定。
RECV: <iq type=’set’>
<query xmlns=’jabber:iq:roster’>
<item
ask=’subscribe’
jid=’[email protected]’
name=’romeo’
subscription=’none’/>
</query>
</iq>
6. Romeo 对订阅请求的下一个响应会是什么呢?现在我们假定订阅以 Romeo 接受订阅请求为“结束”的。
RECV: <presence
from=’[email protected]’
to=’[email protected]’
type=’subscribed’/>
7. 服务器再次发送一个花名单推送给客户端,这次 subscription=’to’ ,表示订阅请求被接受了( Juliet 现在可以订阅到 Romeo 的当前状态了)。
RECV: <iq type=’set’>
<query xmlns=’jabber:iq:roster’>
<item
jid=’[email protected]’
name=’romeo’
subscription=’to’/>
</query>
</iq>
SEND: <iq type=’get’>
<query xmlns=’jabber:iq:roster’/>
</iq>
RECV:<iq from=’[email protected]/balcony’ type=’result’>
<query xmlns=’jabber:iq:roster’>
<item
jid=’[email protected]’
name=’romeo’
subscription=’both’/>
</query>
</iq>
SEND: <message to’[email protected]’>
<body>Wherefore are thou?</body>
</message>
注意:服务器会根据 Jabber 用户的会话信息加上一个源地址,这样接收者收到消息时,消息中已经包含了源地址。
SEND: <presence>
<status>stepped away…</status>
<show>away</show>
</presence>
登出时很容易的,只需要关闭 <stream> ……
SEND: </stream:stream>
RECV: </stream:stream>
本协议参考以下文献
l Jabber 开发指南( http://docs.jabber.org/jpg/ )
l Jabber 协议――标准( http://docs.jabber.org/proto/ )
l Jabber 协议――草案( http://docs.jabber.org/draft-proto/ )
l Romeo and Juliet
( http://tech-two.mit.edu/Shakespeare/Tragedy/romoandjuliet/full.html )
本文档提供了一个关于 Jabber 的 XML 协议的一个详细的怪数。如果你对本文档有任何问题,请通过 email 或 Jabber 的方式自由地与作者联系( Peter Saint-Andre ),他的帐号时 [email protected] 。
This document is copyright 2001 by Peter Saint-Andre.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License (http://www.gnu.org/copyleft/fdl.html),
Version 1.1 or any later version published by the Free Software Foundation, with no
Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. You may obtain a
copy of the GNU Free Documentation License from the Free Software Foundation by
visiting http://www.fsf.org/ or by writing to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston , MA 02111-1307
USA
下面是 Jabber 中错误代码的一些简要描述。 Jabber 服务器在碰到不同的错误条件下生成这些错误代码。一般 Jabber 错误代码以 HTTP 规格的 RFC 2616 ( http://www.ietf.org/rfc/rfc2616.txt )为基础。但 Jabber 没有使用所有的 HTTP 的错误代码,并且 Jabber 错误代码与 HTTP 错误代码相对应时,通常只有 Jabber 自己的含义。注意本附录只包含 Jabber 服务器生成的错误代码,而不包括服务器端组件如网关发到外部消息系统。
错误代码 |
描述 |
注意 |
302 |
重定向 |
尽管 HTTP 规定中包含八种不同代码来表示重定向, Jabber 只用了其中一个(用来代替所有的重定向错误)。不过 Jabber 代码 302 是为以后的功能预留的,目前还没有用到 |
400 |
坏请求 |
Jabber 代码 400 用来通知 Jabber 客户端,一个请求因为其糟糕的语法不能被识别。例如,当一个 Jabber 客户端发送一个的订阅请求给它自己活发送一条没有包含“ to ”属性的消息, Jabber 代码 400 就会产生。 |
401 |
未授权的 |
Jabber 代码 401 用来通知 Jabber 客户端它们提供的是错误的认证信息,如,在登陆一个 Jabber 服务器时使用一个错误的密码,或未知的用户名。 |
402 |
所需的费用 |
Jabber 代码 402 为未来使用进行保留,目前还不用到。 |
403 |
禁止 |
Jabber 代码 403 被 Jabber 服务器用来通知 Jabber 客户端该客户端的请求可以识别,但服务器拒绝执行。目前只用在注册过程中的密码存储失败。 |
404 |
没有找到 |
Jabber 代码 404 用来表明 Jabber 服务器找不到任何与 JabberID 匹配的内容,该 JabberID 是一个 Jabber 客户端发送消息的目的地。如,一个用户打算向一个不存在的 JabberID 发送一条消息。如果接受者的 Jabber 服务器无法到达,将发送一个来自 500 级数的错误代码。 |
405 |
不允许的 |
Jabber 代码 405 用在不允许操作被 ’from’ 地址标识的 JabberID 。例如,它可能产生在,一个非管理员用户试图在服务器上发送一条管理员级别的消息,或者一个用户试图发送一台 Jabber 服务器的时间或版本,或者发送一个不同的 JabberID 的 vCard 。 |
406 |
不被接受的 |
Jabber 代码 406 用于服务器因为某些理由不接受一个包。例如,这个可能发生在,一个 Jabber 客户端试图使用 jabber:iq:private 在服务器上存储信息,但当前的用于存储的名字空间用 ”jabber:” 开头(在 Jabber 里是一个被存的 XML 开头)。另一种可能产生 406 错误的情况是当一个 Jabber 客户端试图用一个空密码注册到一台 Jabber 服务器上。 |
407 |
必须注册 |
Jabber 代码 407 当前不被使用 |
408 |
注册超时 |
当一个 Jabber 客户端不能在服务器准备好的时间内发起一个请求时, Jabber 服务器生成 Jabber 代码 408 。这个代码当前只用于 Jabber 会话管理器使用的零度认证模式中。 |
409 |
冲突 |
略 |
500 |
服务器内部错误 |
当一台 Jabber 服务器遇到一种预期外的条件,该条件阻止服务器处理来自 Jabber 客户端的包,这是将用到 Jabber 代码 500 。现在,唯一会引发 500 错误代码的时间是当一个 Jabber 客户端试图通过服务器认证,而该认证因为某些原因没有被处理(如无法保存密码)。 |
501 |
不可执行 |
当服务器不支持 Jabber 客户端请求的功能,使用 Jabber 代码 501 。例如,该代码只当 Jabber 客户端发送一个认证请求,而该认证请求不包含服务器配置中定义的任何一种认证方式时,服务器发送 Jabber 代码 501 。这个代码还被用于,当一个 Jabber 客户端试图注册一个不允许注册的服务器。 |
502 |
远程服务器错误 |
当因为无法到达远程服务器导致转发一个包失败时,使用 Jabber 代码 502 。该代码发送的特殊例子包括一个远程服务器的连接的失败,无法获取远程服务器的主机名,以及远程服务器错误导致的外部时间过期。 |
503 |
服务无法获得 |
当一个 Jabber 客户端请求一个服务,而 Jabber 服务器通常由于一些临时原因无法提供该服务时,使用 Jabber 代码 503 。例如,一个 Jabber 客户端试图发送一条消息给另一个用户,该用户不在线,但它的服务器不提供离线存储服务,服务器将返回一个 503 错误代码给发送消息的 JabberID 。当为 vcard-temp 和 jabber:iq:private 名字空间设置信息时,出现通过 xdb 进行数据存储的写入错误,也使用该代码。 |
504 |
远程服务器超时 |
Jabber 代码 504 用于下列情况 : 试图连接一台服务器发生超时,错误的服务器名。 |
510 |
连接失败 |
Jabber 代码 510 目前还没有使用。 |
源文件地址:http://blog.csdn.net/kunp/archive/2004/06/30/30465.aspx