📄 x4089.htm
字号:
>
element, extra information can be attached to the
<TT
CLASS="LITERAL"
><presence/></TT
> element by means
of the <TT
CLASS="LITERAL"
><x/></TT
> tag. In the same
way, each <TT
CLASS="LITERAL"
><x/></TT
> tag must be
qualified with a namespace.</P
><P
>While there aren't many external uses for payloads in a
<TT
CLASS="LITERAL"
><presence/></TT
> packet, the Jabber
server uses this facility to add information. In this example, we
see that <TT
CLASS="LITERAL"
>dj@yak</TT
>'s notification of
availability (remember, <TT
CLASS="LITERAL"
>type='available'</TT
>
is assumed for
<TT
CLASS="LITERAL"
><presence/></TT
> packets without
an explicit <TT
CLASS="LITERAL"
>type</TT
> attribute) is being sent
to <TT
CLASS="LITERAL"
>sabine@yak</TT
>.
While <TT
CLASS="LITERAL"
>dj@yak</TT
> connected to the Jabber server
and send his availability (which was stamped on receipt by the Jabber server)
just before 11 a.m.,
<TT
CLASS="LITERAL"
>sabine@yak</TT
> is just logging on now (say,
30 minutes later). When she receives
<TT
CLASS="LITERAL"
>dj@yak</TT
>'s presence, she knows how long that
presence status has been valid for.</P
><P
>See <A
HREF="x6079.htm"
>the section called <I
>The X Namespaces</I
> in Chapter 5a</A
> to find out what
namespaces are available to qualify
<TT
CLASS="LITERAL"
><x/></TT
>-included payloads.</P
></DD
></DL
></DIV
></DIV
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="JABTDG-CH-5-SECT-5.4.2.3"
>Presence Subscription</A
></H3
><P
><I
CLASS="EMPHASIS"
>Presence subscription</I
> is the name given to the mechanism that allows
control over how entity presence information is made available to other
entities.
By default, the availability of an entity is unknown to other entities.</P
><P
>Let's put this into more concrete terms. For example, let's assume that you and I
are both Jabber users. I'm registered with the Jabber server running at
<TT
CLASS="FILENAME"
>jabber.org</TT
>, my JID is
<TT
CLASS="LITERAL"
>qmacro@jabber.org</TT
>, and
you are registered with a Jabber server running at your company, and your
JID is <TT
CLASS="LITERAL"
>you@yourserver.com</TT
>.</P
><P
>If you want to know whether I'm available, you have to
<I
CLASS="EMPHASIS"
>subscribe</I
> to my <TT
CLASS="LITERAL"
>presence</TT
>.
This is done by sending a
<TT
CLASS="LITERAL"
><presence/></TT
>
packet to me with the <TT
CLASS="LITERAL"
>type</TT
> attribute set
to <TT
CLASS="LITERAL"
>subscribe</TT
>. In the example that follows, the XML
fragments are sent and received from <I
CLASS="EMPHASIS"
>your</I
> perspective):</P
><P
><PRE
CLASS="SCREEN"
>SEND: <presence type='subscribe' to='qmacro@jabber.org'/></PRE
></P
><P
>I receive the <TT
CLASS="LITERAL"
><presence/></TT
>
packet, and when I receive it, it's been stamped (by your Jabber
server) with a <TT
CLASS="LITERAL"
>from</TT
> attribute with the
value <TT
CLASS="LITERAL"
>you@yourserver.com</TT
>. So, based upon
who it is, I decide to accept the subscription request and send back
a reply:</P
><P
><PRE
CLASS="SCREEN"
>RECV: <presence type='subscribed' to='you@yourserver.com'/></PRE
></P
><P
>This lets you know that I've accepted your subscription request. From
now on, every time my availability changes (when I send a
<TT
CLASS="LITERAL"
><presence/></TT
> packet or
when I disconnect (and the server generates an <TT
CLASS="LITERAL"
>unavailable</TT
>
<TT
CLASS="LITERAL"
><presence/></TT
> packet on my
behalf), that availability information will be relayed to you.</P
><P
>But how does this work? How does the Jabber server know that you've
subscribed to my presence and I've accepted that subscription?</P
><P
>Enter the <I
CLASS="EMPHASIS"
>roster</I
>, stage right. The roster is a list
of JIDs maintained for each user, stored on the server-side. A roster is similar
to an AOL's Buddy List; one could say that it's a sort of personal
address book, but it's more than that. The presence subscription
and roster mechanisms are tightly intertwined. We'll be examining the
roster in more detail in <A
HREF="x5334.htm#JABTDG-CH-5A-SECT-2.12"
>the section called <I
><TT
CLASS="LITERAL"
>jabber:iq:roster</TT
></I
> in Chapter 5a</A
>.
Here, we'll just look at the characteristics of the roster that are
relevant for the presence subscription mechanism. The roster is managed
using the third basic Jabber element—<TT
CLASS="LITERAL"
><iq/></TT
>—which will be
explained in more detail later in this section. Ignore the tags that
you aren't yet familiar with; it's just important to get the basic
drift of what's going on.</P
><P
>While the roster is stored and maintained on the server-side,
any changes to the roster are made by the server are reflected
(pushed) in the client so it can be synchronized with a local copy.
<A
NAME="LOCALCOPY"
HREF="#FTN.LOCALCOPY"
>[4]</A
> </P
><P
>Let's expand the simple exchange of
<TT
CLASS="LITERAL"
><presence/></TT
> packets from
above and look how the roster is used to record presence subscription
information.</P
><P
>If you wish to subscribe to my presence and add my JID
to your roster at the same time, these two actions are linked for obvious and practical reasons. Many Jabber clients use the roster as a basis for displaying
availability information, and with the exception of an entity sending
presence information directly to another entity irrespective of roster
membership, presence subscription information is stored by-user in the
roster. Here's the order in which the subscription would take place:</P
><P
></P
><OL
TYPE="1"
><LI
><P
>A request is sent to the server to update your roster, adding my
JID to it:</P
><P
><PRE
CLASS="SCREEN"
>SEND: <iq id="adduser1" type="set">
<query xmlns="jabber:iq:roster">
<item jid="qmacro@jabber.org" name="DJ Adams"/>
</query>
</iq></PRE
></P
><P
>You add an <TT
CLASS="LITERAL"
>id</TT
> attribute to be able to
track the request and match up the response when it comes.</P
></LI
><LI
><P
>The server responds with a push of the updated (new) roster item:</P
><P
><PRE
CLASS="SCREEN"
>RECV: <iq type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='qmacro@jabber.org' name='DJ Adams'
subscription='none'/>
</query>
</iq></PRE
></P
><P
>Note that in the update, an additional attribute
<TT
CLASS="LITERAL"
>subscription='none'</TT
>
is sent, reflecting the presence subscription relationship between
you and me. At this stage, the relationship is that I don't have
a subscription to your presence and you don't have a subscription
to my presence, hence the value <TT
CLASS="LITERAL"
>none</TT
>.</P
></LI
><LI
><P
>It also acknowledges the original update request, confirming its
success:</P
><P
><PRE
CLASS="SCREEN"
>RECV: <iq id='adduser1' type='result'
from='you@yourserver.com/Work'
to='you@yourserver.com/Work'/></PRE
></P
><P
>Note the <TT
CLASS="LITERAL"
>id='adduser1'</TT
> identity
is passed back so we can track the original request
and from where this response is being made.</P
></LI
><LI
><P
>Meanwhile, you send the subscription request:</P
><P
><PRE
CLASS="SCREEN"
>SEND: <presence to="qmacro@jabber.org" type="subscribe"/></PRE
></P
></LI
><LI
><P
>The server notes the subscription request going through and once more
updates your roster and pushes the item out to you:</P
><P
><PRE
CLASS="SCREEN"
>RECV: <iq type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='qmacro@jabber.org' name='DJ Adams'
subscription='none' ask='subscribe'/>
</query>
</iq></PRE
></P
><P
>The current subscription relationship is reflected
with the <TT
CLASS="LITERAL"
>subscription='none'</TT
> attribute.
In addition, we have a subscription request status, with
<TT
CLASS="LITERAL"
>ask='subscribe'</TT
>. This request status
shows that there is an outstanding presence subscription request to
the JID in that roster item. If you've ever seen the word “Pending”
next to a username in a Jabber roster, this is where that comes from.
Don't forget that a subscription request might not get an immediate
response, so we need to remember that the request is still outstanding.</P
></LI
><LI
><P
>Your subscription request is received and accepted, and a <TT
CLASS="LITERAL"
>subscribed</TT
> type is sent back to you as part of a
<TT
CLASS="LITERAL"
><presence/></TT
> packet:</P
><P
><PRE
CLASS="SCREEN"
>RECV: <presence to='you@yourserver.com'
type='subscribed' from='qmacro@jabber.org'/></PRE
></P
></LI
><LI
><P
>The server also notices the subscription request acceptance, and
yet again updates your roster to keep track of the presence subscription.
Again, it pushes the subscription information out to you so your client can keep its copy up to
date:</P
><P
><PRE
CLASS="SCREEN"
>RECV: <iq type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='qmacro@jabber.org' name='DJ Adams'
subscription='to'/>
</query>
</iq></PRE
></P
><P
>This time, the <TT
CLASS="LITERAL"
>subscription</TT
> attribute
in the roster item has been set to <TT
CLASS="LITERAL"
>to</TT
>.
This means that the roster owner (you) has a presence subscription
<I
CLASS="EMPHASIS"
>to</I
> the JID in the roster item (i.e., me).</P
></LI
><LI
><P
>The server knows you've just subscribed to my
presence, it generates
a presence probe on your behalf which causes my presence information
to be retrieved and sent to you.</P
><P
><PRE
CLASS="SCREEN"
>RECV: <presence from='qmacro@jabber.org/Work'
to='you@yourserver.com'>
<status>Available</status>
<priority>1</priority>
<x xmlns='jabber:x:delay'
from='qmacro@jabber.org/Work'
stamp='20010515T11:37:40'/>
</presence></PRE
></P
></LI
></OL
><P
>Of course, at this stage, our relationship is a little unbalanced, in
that you have a subscription request to me, but
I don't have a subscription request to you. So you are aware of my
availability, but not the other way around. In order to rectify this
situation, I can repeat the process in the opposite direction, asking
for a subscription to your presence information.</P
><P
>The only difference to the sequence that we've just seen is that
you will already exist on my roster because the server will have
maintained an item for your JID to record the presence subscription
relationship. While the item in your roster that represents my JID
has a <TT
CLASS="LITERAL"
>subscription</TT
> attribute value
of <TT
CLASS="LITERAL"
>to</TT
> (the roster owner has a
presence subscription <I
CLASS="EMPHASIS"
>to</I
> this JID)—we've seen
this in Step 7—the item in
my roster that
represents your JID has a <TT
CLASS="LITERAL"
>subscription</TT
>
attribute value of <TT
CLASS="LITERAL"
>from</TT
> (the roster
owner has a presence subscription <I
CLASS="EMPHASIS"
>from</I
> this JID).</P
><P
>Once I repeat this sequence to subscribe to your
presence (and you accept the request), the value for the
<TT
CLASS="LITERAL"
>subscription</TT
>
attribute in the items in each of our rosters will be set to
<TT
CLASS="LITERAL"
>both</TT
>.</P
><P
>The upshot of all this is that when an entity announces its presence,
it does so using a single
<TT
CLASS="LITERAL"
><presence/></TT
>
packet, with no <TT
CLASS="LITERAL"
>to</TT
> attribute specified. All
the members in that entity's roster who have a subscription
to that entity's presence will receive a copy of that
<TT
CLASS="LITERAL"
><presence/></TT
> packet and thereby
be informed.
<A
NAME="SUBSCRIPTION-TO"
HREF="#FTN.SUBSCRIPTION-TO"
>[5]</A
> </P
></DIV
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-5-SECT-5.4.3"
>The IQ Element</A
></H2
><P
>The third and final element in the Jabber building block set is the
<TT
CLASS="LITERAL"
><iq/></TT
> element (“iq” stands
for “Info/Query”), which represents a mechanism for sending
and receiving information. What the
<TT
CLASS="LITERAL"
><iq/></TT
> element has over
the <TT
CLASS="LITERAL"
><message/></TT
> element for
this purpose is <I
CLASS="EMPHASIS"
>structure</I
> and <I
CLASS="EMPHASIS"
>inherent meaning</I
>. It is useful to liken
the info/query mechanism to the request/response model of the HyperText
Transfer Protocol (HTTP) using GET and POST.</P
><P
>The <TT
CLASS="LITERAL"
><iq/></TT
> element allows a
structured conversation between two Jabber entities. The conversation exists
to exchange data, to retrieve or set it, and to notify the other
party as to the success (or not) of that retrieve or set action. There are
four <I
CLASS="EMPHASIS"
>states</I
> that an <TT
CLASS="LITERAL"
><iq/></TT
>
element can be in, each reflecting one of the activities in this conversation:</P
><P
></P
><DIV
CLASS="VARIABLELIST"
><DL
><DT
>get</DT
><DD
><P
>Get information.</P
></DD
><DT
>set</DT
><DD
><P
>Set information.</P
></DD
><DT
>result</DT
><DD
><P
>The result, in the case where the get or set was successful.</P
></DD
><DT
>error</DT
><DD
><P
>An error, in the case where the get or set was not successful.</P
></DD
></DL
></DIV
><P
>At the beginning of this section, we saw various elements in
action in
<A
HREF="x4089.htm#JABTDG-CH-5-EX-HANDFUL"
>Example 5-2</A
>.
The first two were
<TT
CLASS="LITERAL"
><iq/></TT
> elements, and show
a retrieval request and response for roster information.</P
><P
>First comes the request:</P
><P
><PRE
CLASS="SCREEN"
>SEND: <iq id='roster_0' type='get'>
<query xmlns='jabber:iq:roster'/>
</iq></PRE
></P
><P
>Then the response:</P
><PRE
CLASS="SCREEN"
>RECV: <iq id='roster_0' type='result' from='dj@yak/Work'>
<query xmlns='jabber:iq:roster'>
<item jid='sabine@yak' name='sabine' subscription='both'>
<group>Family</group>
</item>
</query>
</iq></PRE
><P
>There's a number of things we can see in this snippet:</P
><P
></P
><UL
><LI
><P
>The type of each info/query activity is identified by the
<TT
CLASS="LITERAL"
>type</TT
> attribute.</P
></LI
><LI
><P
>Each info/query activity contains a subelement
<TT
CLASS="LITERAL"
><query/></TT
>
which is qualified by a namespace.</P
></LI
><LI
><P
>The subelement is used to carry the information being retrieved.</P
></LI
><LI
><P
>The response (<TT
CLASS="LI
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -