Subscriptions是Jabber中最复杂的部分。服务端和客户端做了大量的工作,以保证用户在不同状态下接收或发送正确的subscription请求,接受或拒绝其他用户的请求,取消订阅,删除花名册条目,等等。本文档着重解释subscription在两层结构中是如何工作的:(1)XML协议要求对特定动作进行响应;(2)user:xml文件的返回状态包括Jabber User(如 订阅者等等)以及联系人(如被订阅者)。
总共有四种subscription状态:
1、 None——Jabber用户和联系人互相都不订阅对方的presence
2、 To——Jabber用户被联系人的presence订阅,但联系人并不被Jabber用户的presence订阅。
3、 From——联系人接受来自Jabber用户的subscription,但联系人不被Jabber用户的presence所订阅(这样的结果就是Jabber用户在联系人的花名册中“不可见”)。
4、 Both——Jabber用户和联系人被彼此的presence订阅。
当Jabber用户将联系人加入他的花名册中(通常是通过对联系人发送一个subscriptiong请求实现),名义上还存在第五种状态,就是Jabber用户和联系人甚至不知道对方的存在(至少通过每一个用户的花名册显示)。不过,我们对这种状态没有命名。从本文档出发,我将这种状态定义为初始状态。
就象上面提到的,subscriptions和以及它们相关联的花名册状态是相当复杂的。所以这里我将把一个Jabber用户与一个联系人之间的交互进行极其详尽的描述,以便你能搞清楚当一个Jabber用户订阅一个联系人的presence,结果引起该Jabber用户对联系人产生了一个subcription这样的过程中,究竟发生了些什么。我们将从Jabber用户对联系人发送一个subscription请求开始。
1、为了让联系人在Jabber用户的花名册上可见,Jabber用户客户端
(1) 发送一个<iq/>包,其jabber:iq:roster名字空间中包含一个type=’set’;
(2) 成功的情况下,从服务器接收到一个<iq/>包,其type=’result’。
(3) 从服务器接收到一个“roster push”,产生一个新的roster条目,其subscription状态置为“none”:
JABBER USER SENDS:
<iq type=’set’>
<query xmlns=’jabber:iq:roster’>
<item
jid=’contact@host’
name=’contact’/>
</query>
</iq>
JABBER USER RECEIVES:
<iq
type=’result’
from=’jabberuser@host/work’
to=’jabberuser@host/work’/>
<iq type=’set’>
<query xmlns=’jabber:iq:roster’>
<item
jid=’contact@host’
subscription=’none’
name=’contact’/>
</query>
</iq>
2、Jabber用户的客户端接着发送一个type=’subscribe’的<presence/>的包给联系人:
JABBER USER SENDS:
<presence
to=’contact@host’
type=’subscribe’>
<status>I would like to add you to my roster.</status>
</presence>
3、Jabber用户客户端接着从服务器收到第二个包含联系人待定子状态的’none’订阅状态的“roster push”;这个待定子状态在其花名册条目中包含一个ask=’subscribe’属性:
JABBER USER RECEIVES:
<iq type=’set’>
<query xmlns=’jabber:iq:roster’>
<item
jid=’contact@host’
subscription=’none’
name=’contact’
ask=’subscribe’/>
</query>
</iq>
4、一旦Jabber用户客户端发送type=’subscribe’的<presence/>包,该包被发送给联系人(我们假定该联系人在线):
CONTACT RECEIVES:
<presence
to=’contact@host’
type=’subscribe’
from=’jabberuser@host’>
<status>I would like to add you to my roster.</status>
</presence>
5、 联系人下一步要做的就是决定是否接受订阅请求。这里我们假定为”happy path”,即联系人接受订阅,这样联系人的Jabber客户端:
(1) 发送一个type=’subscribed’的<presence/>的包给Jabber用户
(2) 从服务器接收一个“roster push”包含Jabber用户的条目,其中subscription状态置为“from”:
CONTACT SENDS:
<presence to=’jabberuser@host’ type=’subscribed’/>
CONTACT RECEIVES:
<iq type=’set’>
<query xmlns=’jabber:iq:roster’>
<item
jid=’jabberuser@host’
subscription=’from’/>
</query>
</iq>
6、 联系人接受订阅请求的结果是:Jabber用户客户端接收到
(1) 一个从联系人发来的type=’subscribed’的<presence/>的包
(2) 从服务器发来的一个“roster push”,其中包含一个更新的条目,用来更新联系人的subscription为“to”;
JABBER USER RECEIVES:
<presence
to=’jabberuser@host’
type=’subscribed’
from=’contact@host’/>
<iq type=’set’>
<query xmlns=’jabber:iq:roster’>
<item
jid=’contact@host’
subscription=’to’
name=’contact’/>
</query>
</iq>
现在Jabber用户已经订阅了联系人。每个user.xml的花名册条目将如下所示:
JABBER USER’S ROSTER:
<item
jid=’contact@host’
subscription=’to’
name=’contact’/>
CONTACT’S ROSTER:
<item
jid=’jabberuser@host’
subscription=’from’/>
(注意:如果在这里Jabber用户发送一个subscription请求给联系人,Jabber用户的Jabber服务器将“吞没”该请求,而不再将其发送给联系人。)
如我们在前面所见,需要有一个Jabber用户和联系人之间的双向的subscription。在这个过程结束部分,我们将研究Jabber用户与联系人互相订阅的情况。
要建立一个相互的Subscription(如 a subscription=’both’),联系必须发送一个subscription请求给Jabber用户,并且Jabber用户必须接受该请求。让我们看看XML传回了什么,弄清楚其中发生了什么,以及每个人的花名册文件发生了什么变化。
1、 首先,联系人发送一个订阅请求给Jabber用户:
CONTACT SENDS:
<presence to=’jabberuser@host’ type=’subscribe’>
<status>I would like to add you to my roster.</status>
</presence>
2、 联系人客户端从服务器接收到一个“roster push”,其中包含Jabber用户仍然是‘from’的subscription状态,但同时一个待定’to’的subscription通过花名册条目中的ask=’subscribe’的属性产生了:
CONTACT RECEIVES:
<iq type=’set’>
<query xmlns=’jabber:iq:roster’>
<item
jid=’jabberuser@host’
subscription=’from’
name=’jabberuser’
ask=’subscribe’/>
</query>
</iq>
此行为的一个结果是,联系人和Jabber用户的花名册文件的状态如下所示:
CONTACT’S ROSTER:
<item
jid=’jabberuser@host’
subscription=’from’
name=’jabberuser’
ask=’subscribe’/>
JABBER USER’S ROSTER:
<item
jid=’contact@host’
subscription=’to’
name=’contact’
subscribe=’I would like to add you to my roster.’/>
3、 一旦联系人客户端发送一个包含type=’subscribe’的<presence/>包,该包将直接发送给Jabber用户(我们假定此时Jabber用户在线):
JABBER USER RECEIVES:
<presence
to=’jabberuser@host’
type=’subscribe’
from=’contact@host’>
<status>I would like to add you to my roster.</status>
</presence>
4、Jabber用户下一步要做的就是决定是否接受订阅请求。这里我们假定为”happy path”,即联系人接受订阅,这样Jabberyonghu的Jabber客户端:
(1) 发送一个type=’subscribed’的<presence/>的包给联系人
(2) 从服务器接收一个“roster push”包含联系人的条目,其中subscription状态置为“both”:
JABBER USER SENDS:
<presence to=’contact@host’ type=’subscribed’/>
JABBER USER RECEIVES:
<iq type=’set’>
<query xmlns=’jabber:iq:roster’>
<item
jid=’contact@host’
subscription=’both’/>
</query>
</iq>
5、Jabber用户接受订阅请求的结果是:联系人客户端接收到
(1) 一个从Jabber用户发来的type=’subscribed’的<presence/>的包
(2) 从服务器发来的一个“roster push”,其中包含一个更新的条目,用来更新Jabber用户的subscription为“to”;
CONTACT RECEIVES:
<presence
to=’contact@host’
type=’subscribed’
from=’jabberuser@host’/>
<iq type=’set’>
<query xmlns=’jabber:iq:roster’>
<item
jid=’jabberuser@host’
subscription=’both’
name=’jabberuser’/>
</query>
</iq>
此行为的一个结果是,联系人和Jabber用户的花名册文件的状态如下所示:
CONTACT’S ROSTER:
<item
jid=’jabberuser@host’
subscription=’both’
name=’jabberuser’/>
JABBER USER’S ROSTER:
<item
jid=’contact@host’
subscription=’both’
name=’contact’/>
Jabber用户和联系人现在有了一个相互交互的subscription——其subscription的类型为“both”。(注意:如果在这里Jabber用户发送一个subscription请求给联系人,或者联系人发送一个subscription请求给Jabber用户,发送方的Jabber服务器将“吞没”该请求,而不再将其发送给联系人。)