The namespaces that qualify attachments to <iq/> elements are many and varied. After all, you could say that the raison d'etre of this request/response mechanism is to exchange structured information—and what better way to define that information than with namespaces?
This section looks briefly at each of the IQ namespaces in turn. Some of them will be covered in more detail in later Chapters, as they will be used in examples that appear later in the book.
The jabber:iq:agent namespace is used to request and return information on an agent. An agent is a service running on a Jabber server, and it has a JID. To find out what features the particular agent offers, an info-request (an <iq/> get request) can be made using this namespace:
SEND: <iq type='get' to='yak/groups'>
<query xmlns='jabber:iq:agent'/>
</iq>Here, a request for features is being made of the agent with the JID yak/groups, which is the standard name for the “Shared Groups” service. The JID here is composed of a hostname (yak) and a resource (groups).
The response looks like this:
RECV: <iq type='result' to='dj@yak/Work' from='yak/groups'>
<query xmlns='jabber:iq:agent'>
<name>Jabber Server at yak</name>
<url>http://yak</url>
<service>jabber</service>
<register/>
</query>
</iq>In reality, although the agent or service itself is specified as the recipient of the query, it is often a centralized mechanism that responds on behalf of the agent if the agent itself doesn't or can't respond. [1] This means that the results of the query might not be as helpful as you might expect. The only detail in the response shown here that might be of some use is the <register/> tag, but that's actually misleading as it's picked up from the general registration capabilities configuration and not anything particular to the JUD.
The main reason for this is actually also the answer to a question you might have right now: "How do I know which agent JIDs I can query on a particular Jabber server?" Indeed. It's very hit and miss to pick agent JIDs at random. The jabber:iq:agents (plural) namespace defines a list of agents. Usually what happens is that a query is made using the jabber:iq:agents namespace, and then further detail is requested with the jabber:iq:agent for a particular agent. However:
The general information for both queries comes from the same place in the Jabber server configuration.
That place is the <agents/> tag inside the JSM custom configuration…and is deprecated in favor of the <browse/> tag.
The jabber:iq:agent-based agent facility query is slowly but surely being replaced by the more generic but more powerful jabber:iq:browse mechanism (which is directly related to the <browse/> configuration area of the JSM). That said, it is still supported for compatibility reasons; many Jabber clients still use the jabber:iq:agent and jabber:iq:agents namespaces in calls to discover services on the server. See the section called jabber:iq:browse for more details on the jabber:iq:browse mechanism.
The jabber:iq:agent namespace is used in a query of an individual Jabber agent, or service. Likewise, the jabber:iq:agents namespace is used in a query to retrieve a list of these agents.
As mentioned in the description for the jabber:iq:agent namespace, the Jabber server configuration (in the JSM custom configuration section) in earlier releases contained an <agents/> tag, which was used to list the agents that were available on the Jabber server. The listing looked like this:
<agents>
<!-- Note: this <agents/> listing is not used in 1.4.1 -->
<agent jid='users.jabber.org'>
<name>Jabber 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='...'>
...
</agent>
...
</agents>The <agents/> listing has now been superseded by the <browse/> tag. In fact, when responding to jabber:iq:agents and jabber:iq:browse queries, the Jabber server itself will refer to the same <browse/> listing in both cases. Here's an example of a response to a jabber:iq:agents query:
RECV: <iq type='result' to='dj@yak/laptop' from='yak' id='agents'>
<query xmlns='jabber:iq:agents'>
<agent jid='users.jabber.org'>
<name>Jabber User Directory</name>
<service>jud</service>
<register/>
<search/>
</agent>
</query>
</iq>We can see that this response pretty much reflects the information in the <agents/> configuration.
For more details on how this differs in response to a jabber:iq:browse query, see the section called jabber:iq:browse.
Further examples of jabber:iq:agents usage can be found in the section called RSS punter in Chapter 8.
The jabber:iq:auth namespace is used to qualify a structured authentication procedure between client and server.
Details of authentication are covered in Chapter 6; however, here we will look at the simplest authentication conversation between client and server. In this example, the client sends a username and password, and the server responds by sending a “successful” response, acknowledging the user's credentials, thus creating a session for that user.
SEND: <iq type='set' id='auth0'>
<query xmlns='jabber:iq:auth'>
<username>sabine</username>
<password>geheimnis</password>
<resource>WinJab</resource>
</query>
</iq>
RECV: <iq type='result' id='auth0'/>In this authentication procedure, the name of the query subelement containing the xmlns attribute must be query. This is an exception to the rule mentioned in the previous section, which stated that the name of the tag was irrelevant.
The “Update Info Request” configuration description in the section called Update Info Request in Chapter 4 describes a mechanism for Jabber servers to query a software version information repository to find out about new versions of the server. [2] This version information repository that responds to queries is also known as the “Auto-Update” service.
Not only can servers request software update information, but clients can too. The procedure is the same in both cases, and involves the jabber:iq:autoupdate and jabber:x:autoupdate namespaces. If clients support this software update information request, it will be usually in the form of a "silent" request that it sends out at startup. The sending out of this request can be often switched on and off in the client's configuration.
The conversation starts with the requester sending a special availability packet to the information repository. Currently, there are two such public repositories: one running at jabber.org covering a wide range of Jabber software, and the other running at jabber.com covering certain clients including Jabber Instant Messenger (JIM).
This special availability packet looks like this:
SEND: <presence to='959967024@update.jabber.org/1.6.0.3'/>
This is a directed <presence/> packet because it has a to attribute. What's even more interesting is that if we breakdown the JID, we're left with 959967024 as the username, update.jabber.org as the hostname, and 1.6.0.3 as the resource. This doesn't mean that the availability is destined for a user called 959967024 registered on the update.jabber.org Jabber server. While most presence packets are destined for users (within the presence subscription model), this one is destined for a service.
The service is running with the identification update.jabber.org—a component connected to the jabberd server backbone running at jabber.org. Therefore, the <presence/> packet will be routed to that service. Unlike the JSM, the update.jabber.org service has no concept of users or sessions. Instead, it receives the complete <presence/> packet and disassembles the JID in the destination address and interpret component parts as it sees fit.
The service uses the username portion of the JID to identify the piece of software for which new version information is being requested. In our example, this is 959967024. This value actually represents the JIM client, and is the key to the client database kept on http://www.jabbercentral.org. Using a unique client database key to represent the piece of software allows the client's name to be changed without causing problems in the retrieval of version information by the Auto-Update service.
The version information stored in the repository is compared to the current version of the requesting piece of software; in this case our JIM version 1.6.0.3. If a new version isn't available, nothing will happen. Because the initial part of the request was a <presence/> packet, no official response is expected (unlike a situation where the initial part of the request was an <iq/> get packet).
If there is, however, information stored in the repository about newer versions of the software, the query is replied to using a <message/> element, with an autoupdate attachment:
RECV: <message to='qmacro@jabber.org/Work' from='959967024@update.jabber.org'>
<subject>Upgrade available for Jabber Instant Messenger</subject>
<body>
There is an update available for Jabber Instant Messenger.
If your client supports the iq:autoupdate namespace then
you should see something in the client that will list the
available files. If not, then goto http://www.jabbercentral.com
and grab the new version.
</body>
<x xmlns='jabber:x:autoupdate'>959967024@update.jabber.org</x>
</message>The reply contains some text (in the <subject/> and <body/> tags) that could be displayed to the user.
Furthermore, the autoupdate attachment—an <x/> subelement qualified by the jabber:x:autoupdate namespace—contains information on where further information can be obtained in a programmatic way. [3]
This “programmatic way” sends an empty <iq/> query, qualified by the jabber:iq:autoupdate namespace, to the address given in the jabber:x:autoupdate <message/> attachment:
SEND: <iq type="get" id="id_3" to="959967024@update.jabber.org">
<query xmlns="jabber:iq:autoupdate"/>
</iq>
We're back on familiar ground; the Auto-Update service responds to the request by sending version information for that piece of software:
RECV: <iq type='result' to='qmacro@jabber.org/Work'
from='959967024@update.jabber.org' id='id_3'>
<query xmlns='jabber:iq:autoupdate'>
<release priority='optional'>
<url>http://www.jabber.com/download/jabbersetup.exe</url>
<version>1.7.0.14</version>
<desc/>
</release>
</query>
</iq>The response contains information about the latest software release that prompted the version request. The release is either required or optional (as in this example). The tags within the jabber:iq:autoupdate qualified query are fairly self-explanatory; note that the version description is empty in this example.
The jabber:iq:browse namespace is relatively new and could almost be seen as a departure from the traditional namespaces found elsewhere in Jabber. While namespaces such as jabber:iq:agents and jabber:iq:register define very strict content using specific tag names, jabber:iq:browse allows a more free-form containment of information. Both forms of tight and loose namespaces have a place in Jabber.
The real world contains countless types and classifications of information far more than you could ever reasonably cover with a finite collection of namespaces. And even if you did, that coverage would be out of date as soon as it was completed. The Jabber concept of browsing, introduced in Chapter 2 is an approach to being able to classify and exchange information of all kinds without the definitions being previously cast in stone.
More or less any hierarchical information can be represented in the jabber:iq:browse namespace. It can be seen as an open-ended way of describing structures in an almost ad-hoc way. That said, the namespace comes with some general rules and some predefined classifications.
Information represented and described in a jabber:iq:browse extension is subject to classification. This classification is in two levels: categories and subtypes. The category is used to define the general area or type of information being represented. The subtype is to give a more specific definition of that category. Table 5a-1 shows a list of initial categories.
Table 5a-1. jabber:iq:browse Categories
| Category | Description |
|---|---|
| application | Applications addressable via a JID can be described in this category. Initial suggestions for such application subtypes include calendar (calendar/schedule services), whiteboard (collaborative whiteboard tools), and game (multiplayer games). |
| conference | Used to describe elements in the conferencing (talk between three or more entities) world, such as private and public rooms. Subtypes of this category include private (private chat rooms), irc (IRC rooms), and url (for web-based conferences). |
| headline | Stock-ticker-style notification systems can be described using this category. Subtypes already defined include rss, logger, and notice. |
| item | A category placeholder, to effect hierarchies and lists in a jabber:iq:browse structure. You can fall back to the this category for representation of pretty much any type of information in a navigable drill-down fashion. |
| keyword | IRC-style utilities that are invoked from a chat-input command line; so-called keyword services such as dictionary lookups (subtype dictionary), DNS resolution (subtype dns), and FAQ answers (subtype faq) have their category in the jabber:iq:browse world. |
| render | Translation services such as English to French (subtype en2fr), or spelling tools (subtype spell) are defined in this category. |
| service | Maps to traditional Jabber services, such as IM transports and gateways to other systems, user directories, and so on. Typical subtypes within this category are irc (IRC gateway), aim (AIM transport), and jud (Jabber User Directory). |
| user | Various addressable elements of users, such as their clients (subtype client), inbox mechanisms (subtype inbox) and so on, find themselves in this category. |
The categories listed in Table 5a-1 are not exhaustive; the jabber:iq:browse namespace and the browsing idea was introduced with version 1.4 of the Jabber server and is still evolving. The same goes for the category subtypes.
Any particular browsable entity can be described using the combination of the category and subtype. For example, user/client can be used much in the same way as MIME-types. Following the MIME meme further, we can define our own subtypes on the fly and specify them with an x- prefix, such as user/x-schedule.
Indeed, the browsing description model of category/subtype follows the MIME model; in places the category is often referred to in Jabber documentation as the JID-type. The JID is critical to browsing; it is a required attribute of all entities described in a jabber:iq:browse-based hierarchy. The JID is the key to navigating the hierarchy structure.
Earlier in this section we saw the results of making a query in the jabber:iq:agents namespace to retrieve information on the services available on a Jabber server. Now let's have a look at the a similar query using the jabber:iq:browse namespace:
SEND: <iq type='get' to='yak'>
<query xmlns='jabber:iq:browse'/>
</iq>
RECV: <iq type='result' to='dj@yak/home' from='yak'>
<service name='Jabber Server' type='jabber'
xmlns='jabber:iq:browse' jid='yak'>
<conference name='yak Conferencing'
type='public' jid='conference.yak'/>
<service name='yak User Directory' type='jud' jid='jud.yak'>
<ns>jabber:iq:search</ns>
<ns>jabber:iq:register</ns>
</service>
<service name='User Directory (Browsable)'
type='jud' jid='jud.merlix/users'/>
</service>
</iq>Notice how the information returned forms a hierarchy. The outermost item in the browse results represents the Jabber server as a whole (with the JID yak) and contains subitems that are services of that Jabber server (the yak Conferencing service, and the two forms of the JUD).
How many levels of hierarchy can we expect to receive (as a browsing information consumer) or provide (as a browsing information provider) in any given situation? It really depends on the application situation. and the balance you want to achieve between shallow hierarchy responses and many IQ calls for navigational descent (light extensions but more traffic) and deeper hierarchy responses and few IQ calls for navigational descent (heavier extensions but less traffic).
As illustration, let's have a look how we might perform a hierarchy descent in the navigation of LDAP information provided by a custom LDAP reflector in a jabber:iq:browse context. Each time, the link to the next level is via the item's JID, which is the target of the browse query.
First, we send an initial query:
SEND: <iq type="get" id="browser_JCOM_15" to="ldap.yak">
<query xmlns="jabber:iq:browse"></query>
</iq>In answer to the initial query to what is effectively the LDAP root represented by the JID of the LDAP component itself (ldap.yak, no username prefix), the initial hierarchy level containing People and Groups is returned, wrapped in a pseudo root:
RECV: <iq type='result' to='dj@yak/winjab' from='ldap.yak' id='browser_JCOM_15'>
<item name='root entry' xmlns='jabber:iq:browse' jid='ldap.yak'>
<item name='ou=People' jid='ou=People@ldap.yak'/>
<item name='ou=Groups' jid='ou=Groups@ldap.yak'/>
</item>
</iq>We see the items presented to us and choose to descend the path marked Groups; our second browse request is made to the JID that represents that item, ou=Groups@ldap.yak.
SEND: <iq type="get" id="browser_JCOM_17" to="ou=People@ldap.yak">
<query xmlns="jabber:iq:browse"></query>
</iq>The LDAP reflector component receives the IQ packet addressed to the JID ou=People@ldap.yak and interprets the username part of the JID (ou=People) as an LDAP RDN (relative distinguished name, a form of key within an LDAP structure that's further qualified by a common suffix), which returns the appropriate information from the next level in the LDAP hierarchy: the countries.
RECV: <iq type='result' to='dj@yak/winjab' from='ou=People@ldap.yak'
id='browser_JCOM_17'>
<item name='ou=People' xmlns='jabber:iq:browse'
jid='ou=People@ldap.yak'>
<item name='ou=UK' jid='ou=UK,ou=People@ldap.yak'/>
<item name='ou=France' jid='ou=France,ou=People@ldap.yak'/>
<item name='ou=Germany' jid='ou=Germany,ou=People@ldap.yak'/>
</item>
</iq>And so the descent continues, via the JID ou=UK,ou=People@ldap.yak that was specified as the unique identifier for that item (the country UK).
SEND: <iq type="get" id="browser_JCOM_18" to="ou=UK,ou=People@ldap.yak">
<query xmlns="jabber:iq:browse"></query>
</iq>which continues:
RECV: <iq type='result' to='dj@yak/winjab' from='ou=UK,ou=People@ldap.yak'
id='browser_JCOM_18'>
<item name='ou=UK,ou=People' xmlns='jabber:iq:browse'
jid='ou=UK,ou=People@ldap.yak'>
<user name='cn=JanetAbrams' jid='JanetAbrams@yak'/>
<user name='cn=PaulAnthill' jid='PaulAnthill@yak'/>
...
</item>
</iq>The section of the actual LDAP hierarchy browsed is shown in Figure 5a-1.
Figure 5a-1. The LDAP hierarchy browsed in the section called Descending the browse hierarchy from an LDAP reflector
+--------+ -+
| LDAP | |
| | |
+--------+ |
| |
| | first
+------------------+ | query
| | | result
| | |
+--------+ +--------+ | -+
| People | | Groups | | |
| | | | | |
+--------+ +--------+ -+ |
| |
| | second
+------------------+------------------+ | query
| | | | result
| | | |
+---------+ +--------+ +---------+ | -+
| Germany | | France | | UK | | |
| | | | | | | |
+---------+ +--------+ +---------+ -+ |
| |
| | third
+---------------------+ | query
| | | result
| | |
+--------+ +---------+ |
| Janet | | Paul | |
| Abrams | | Anthill | |
+--------+ +---------+ -+
Browse data isn't just something that can be retrieved; like presence, it can be pushed to an entity when required. In the same way that an alert in the form of a <message/> element might arrive at a client unannounced, so might browse information also appear. This is referred to as live browsing, as the information that is pushed is effectively live.
The Conferencing service uses this mechanism to push information on room participants to a new joiner. As the browse information is enveloped in an IQ element, it makes the most sense to use a type='set' (it might help to consider the parallel with the HTTP verb 'POST' as introduced in Chapter 2) to push this information. And this is what happens, as seen in this excerpt from information sent to a client as a conference room is joined:
RECV: <iq type='set' to='qmacro@jabber.org/winjab'
from='jdev@conference.jabber.org'>
<conference xmlns='jabber:iq:browse' name='Development Room'
type='public'>
<user name='piers'
jid='jdev@conference.jabber.org/445d4b864bd6988b52c5244e7aa50536125e373a'/>
<user name='pgmillard'
jid='jdev@conference.jabber.org/1cffcbf43c75a007677246edc4c6f8d8c5e65b46'/>
<user name='reatmon'
jid='jdev@conference.jabber.org/b3f3c19859de4d25c1362711b81e42e36c417309'/>
...
</conference>
</iq>An example of a simple jabber:iq:browse implementation can be found in the section called RSS punter in Chapter 8.
The conferencing service provides facilities for entities to join rooms and chat to each other. The entry negotiations that take place between a room (via the service) and a potential participant are made using the jabber:iq:conference namespace. With this namespace, information on rooms can be requested, and attempts to enter rooms can be made.
Here we see a typical sequence of IQ elements that ensue in the entry negotiations for the JDEV room hosted by the conferencing service on jabber.org's Jabber server.
Information on the JDEV room is requested:
SEND: <iq type="get" id="c2" to="jdev@conference.jabber.org">
<query xmlns="jabber:iq:conference"/>
</iq>The conferencing service replies with the relevant information.
: The JID to which the query was sent—jdev@conference.jabber.org—works in a similar way to the LDAP reflector in the section called Descending the browse hierarchy from an LDAP reflector. There's no real distinction between conferencing service usernames in the same way that there's a distinction in the JSM service, but that part of the JID is used to identity each room hosted by that service.
We see that the “friendly” name of the JDEV room is “Development Room” and that we need to specify a nickname in order to gain entry. There are no other requirements (such as a secret password) that would have been identified with an extra <secret/> tag in the results.
RECV: <iq type='result' id='c2' to='qmacro@jabber.org/hailsham'
from='jdev@conference.jabber.org'>
<query xmlns='jabber:iq:conference'>
<name>Development Room</name>
<nick/>
</query>
</iq>We choose a nickname, and send this back in an IQ set request.
Before doing this, we must send our presence to the room to invoke the Availability Tracker, which is described in the sidebar Availability Tracker. More information on joining and interacting with conference rooms can be found in the section called Keyword assistant in Chapter 8.
SEND: <presence to="jdev@conference.jabber.org"/>
SEND: <iq to="jdev@conference.jabber.org" type="set" id="c3">
<query xmlns="jabber:iq:conference">
<nick>qmacro</nick>
</query>
</iq>The Conferencing service acknowledges our entry to the room with our chosen nickname, having assigned us an anonymous handle in the <id/> tag:
RECV: <iq to='qmacro@jabber.org/winjab' type='result' id='c3'
from='jdev@conference.jabber.org'>
<query xmlns='jabber:iq:conference'>
<nick>qmacro</nick>
<name>Development Room</name>
<id>jdev@conference.jabber.org/650e81de0fcc265d43357ec09ded0ce421ecdff5</id>
</query>
</iq>Closely linked with the jabber:iq:conference namespace is the jabber:iq:browse namespace, which is also used as a conduit for room-specific information and activity; see the section called jabber:iq:browse.
The jabber:iq:gateway namespace is used to envelope a utility mechanism for converting external system identifiers (usernames, and so on) to a JID equivalent. The requirement for this grew out of the transport services to other IM systems (AIM, Yahoo!, and so on), which have their own formats for user identification.
First, we know whether a service offers this utility from the namespace list that is returned if we browse that service. The next section shows how this might be done with the AIM Transport service.
By browsing a service, we can tell whether it supports the jabber:iq:gateway utility or not:
SEND: <iq type="get" id="aim1" to='aim.jabber.org'>
<query xmlns="jabber:iq:browse"/>
</iq>
RECV: <iq type='result' id='aim1' to='qmacro@jabber.org/winjab'
from='aim.jabber.org'>
<service xmlns='jabber:iq:browse' type='jabber'
jid='aim.jabber.org' name='AIM Transport'>
<ns>jabber:iq:register</ns>
<ns>jabber:iq:gateway</ns>
</service>
</iq>We can now avail ourselves of this utility, to convert an AIM screenname test ScreenName to the equivalent JID to be used (in relation to the AIM transport service) in a Jabber context:
SEND: <iq type='get' to='aim.jabber.org' id='conv5'>
<query xmlns='jabber:iq:gateway'/>
</iq>
RECV: <iq type='result' to='qmacro@jabber.org/hailsham' id='conv5'
from='aim.jabber.org'>
<query xmlns='jabber:iq:gateway'>
<desc>Enter the user's screenname</desc>
<prompt/>
</query>
</iq>We can reply, with an IQ set, with our screen name:
SEND: <iq type='set' to='aim.jabber.org' id='conf6'>
<query xmlns='jabber:iq:gateway'>
<prompt>test ScreenName</prompt>
</query>
</iq>and receive the result of the transport-specific to JID conversion:
RECV: <iq type='result' to='qmacro@jabber.org/Work' id='conf6'
from='aim.jabber.org'>
<query xmlns='jabber:iq:gateway'>
<prompt>testScreenName@aim.jabber.org</prompt>
</query>
</iq>Like the jabber:iq:time and jabber:iq:version namespaces, the jabber:iq:last namespace allows a simple query on uptime or idletime to be made on clients and servers alike.
Elapsed time information, in seconds, is returned in response to queries in the jabber:iq:last namespace. If the query is made of a server element (the Jabber server itself, or a component connected to that server), then the information returned represents the time since that element started, that is, the uptime:
SEND: <iq type='get' to='yak'>
<query xmlns='jabber:iq:last'></query>
</iq>
RECV: <iq type='result' to='dj@yak/Work' from='yak'>
<query xmlns='jabber:iq:last' seconds='2339811'/>
</iq>Not all components support the jabber:iq:last namespace; then again, in many cases the components—certainly those that are connected with the library load mechanism (see Chapter 4)—will have the same uptime as the Jabber server they're connected to. In other cases, for STDIO and TCP socket connected components that can be attached while the Jabber server is running, the uptime may be less. [4]
When a client disconnects, the last (un)availability information in the closing <presence/> element is stored for that user, along with the current time:
SEND: <presence type='unavailable'>
<status>Gone home for the evening!</status>
</presence>Making a jabber:iq:last based query on a user's JID will return the information that was stored from the <status/> tag as well as the number of seconds representing the elapsed time since that disconnection (as a difference between the time that the query was made and the time stored for that user):
SEND: <iq type='get' to='dj@yak' id='lastq'>
<query xmlns='jabber:iq:last'/>
</iq>
RECV: <iq type='result' to='sabine@yak/Work' id='lastq' from='dj@yak'>
<query xmlns='jabber:iq:last' seconds='4521'>
Gone home for the evening!
</query>
</iq>Notice that the JID of the user being queried is dj@yak and not, for example, dj@yak/Work. This, of course, is because the user was still disconnected. The query was addressed to the user with no resource specified, and was answered on behalf of the user by the server (by the mod_last module—the same module that looks after storing this information). In a disconnected context, a resource is not appropriate for a user's JID (in the JSM); they are only found in a connected context.
The jabber:iq:last is also designed to support a similar client-targeted query, this time requesting information on how long it has been since the user of that client was active (sent a message, changed their presence, and so on). In contrast to the previous jabber:iq:last query type, this query is designed to be made to a connected user.
SEND: <iq type="get" to="dj@yak/Work">
<query xmlns='jabber:iq:last'/>
</iq>
RECV: <iq type='result' from='dj@yak/Work'>
<query xmlns='jabber:iq:last' seconds='19'/>
</iq>Here we see that the user is using a client that supports this type of jabber:iq:last query and was last active 19 seconds ago.
We've already seen a form of the oob—"Out Of Band" [5] —namespace in action, in the imaginary conversation in Chapter 1, where jabber:x:oob was used to pass information about a third-party file location (in the form of a Uniform Resource Locator (URL).
The jabber:iq:oob namespace is used for pretty much the same thing, except that its usage describes a very simple handshake between two Jabber clients to exchange a file between themselves. (Yes, real peer-to-peer for the purists.) Typically, the client sending the file will only start listening for HTTP requests at the beginning of the transfer process, and stop listening at the end of the transfer process. The handshake is used to coordinate the process.
The sender initiates the process by making the file available via HTTP on a specific (non-standard) port, and notifying the recipient of the URL:
SEND: <iq type='set' to='sabine@yak/winjab' id='file_2'>
<query xmlns='jabber:iq:oob'>
<url>http://192.168.0.7:5600/meetingnotes.txt</url>
<desc>Meeting Notes</desc>
</query>
</iq>The recipient retrieves the file, and notifies the sender when the transfer is complete.
RECV: <iq type='result' to='dj@yak/Work' id='file_2' from='sabine@yak/winjab'/>
The jabber:iq:private namespace is traditionally a way of storing user-defined data that should be kept private. Persistency across sessions is achieved by storing the data in the user's records on the server. The data is, of course, formatted in XML.
How private is private?: Private data stored by a user is only accessible to that user. Remember, however, that the private data is stored on the server. Unencrypted. If you're paranoid, encrypt it before storing it.
Example 5a-1 shows a typical use. The JIM client stores countless user preferences on a per-user basis using this namespace. Once a user has connected and authenticated with a Jabber server, those user preferences are retrieved and used by the client to customize the settings.
Example 5a-1. JIM retrieves user preferences stored in a jabber:iq:private namespace
SEND: <iq id="jabberim:prefs3860" type="get">
<query xmlns="jabber:iq:private">
<jabberIM xmlns="jabberim:prefs"/>
</query>
</iq>
RECV: <iq id='jabberim:prefs3860' type='result' from='dj@yak/Work'>
<query xmlns='jabber:iq:private'>
<jabberim xmlns='jabberim:prefs'
UseAutoAway='true'
AwayTime='5'
XATime='30'
AwayStatus='Away (auto)'
XAStatus='Ext. Away (auto)'
WizardShown='false'
... >
</jabberim>
</query>
</iq>In this example, you can see that a private namespace is used to qualify the particular chunk of stored data, jabberim:prefs. Also of interest is the difference between the tags—<jabberIM/> in the retrieval request and <jabberim/> in the response. Again we see evidence of an XML usage convention previously seen (for example, in the Jabber server component configuration stanzas; see Chapter 4 for more details). The namespace itself is critical, not the enclosing tag name. If the preferences were originally stored using a tag name of <jabberim/> then that's how it will be stored, and returned.
To add (or change) private data, use the namespace in an IQ set context:
SEND: <iq id="private-s3" type="set">
<query xmlns="jabber:iq:private">
<reminders xmlns="cal:events">
<event date='20010617'>Father's Day</event>
</reminders>
</query>
</iq>Due to the way the jabber:iq:private storage mechanism is currently implemented, you can only interact with one private namespace-qualified chunk. In other words, a private store request like this:
SEND: <iq id="private-s4" type="set">
<query xmlns="jabber:iq:private">
<reminders xmlns="cal:events">
<event date='20010617'>Father's Day</event>
</reminders>
<favorites xmlns='url:favourites'>
<fav url='http://dev.jabber.org'>Jabber DevZone</fav>
<fav url='http://www.scripting.com'>Scripting News</fav>
</favorites>
</query>
</iq>would only result in the storage of the cal:events chunk. The url:favorites chunk would be ignored.
In the 1.4.1 release of the Jabber server, the mod_xml JSM module that services the jabber:iq:private namespace has been extended to allow this server-side storage to encompass nonprivate (i.e., publically accessible) user data. The namespace in this case is, fittingly not jabber:iq:private. It can be anything you wish, provided that it doesn't encroach on the standard Jabber namespace names—jabber:* and vcard-temp are not allowed—however, anything else goes. [6]
The idea of publically accessible data is just that; you can make information available to your fellow Jabber users (share URLs, contact lists, and so on). Of course, this sharing is only one way; you write and others can only read. But how do they find out what you've made available for them to read? The namespaces of any data stored publically (i.e., any namespace except for jabber:iq:private) are returned by the Jabber server acting on behalf of the user in response to a jabber:iq:browse request to that user's JID. [7]
Let's have a look at this in action. We'll also have a peek at how the storage of the public and private information is structured in the user's spool file on the server to understand how this works. [8] In addition to the Father's Day event that was stored privately in the previous example, we can also set some favorite URLs in a publically accessible namespace and receive an acknowledgement of successful storage from the server:
SEND: <iq type='set' id='setfavs'>
<query xmlns='dj:public:favorites'>
<item url='http://dev.jabber.org'>Jabber DevZone</item>
<item url='http://www.scripting.com'>Scripting News</item>
</query>
</iq>
RECV: <iq type='result' from='dj@yak/Work' to='a1@yak/Work' id='setfavs'/>Now, the relevant section of dj@yak's spool file on the server looks something like that shown in Example 5a-2.
Example 5a-2. Section of user's spool storage showing public and private data
... <foo xmlns='jabber:xdb:nslist' xdbns='jabber:xdb:nslist'> <ns type='private'>cal:events</ns> <ns>dj:public:favourites</ns> </foo> <reminders xmlns='cal:events' j_private_flag='1' xdbns='cal:events'> <event date='20010617'>Father's Day</event> </reminders> <query xmlns='dj:public:favorites' xdbns='dj:public:favourites'> <item url='http://dev.jabber.org'>Jabber DevZone</item> <item url='http://www.scripting.com'>Scripting News</item> </query> ...
There are a few things to note in this example:
The jabber:xdb:nslist namespace maintains a list of namespaces containing information stored for private and public reference.
The private namespaces are marked in this list with a type='private' attribute.
There is an additional flag (j_private_flag='1') which is held as an attribute of each of the privately stored fragments.
Otherwise the information is stored exactly as it was set (additional xdbns attributes related to the XDB storage mechanisms notwithstanding).
The namespaces (<ns/> tags) in the jabber:xdb:nslist qualified list are returned in any browse request to that user:
SEND: <iq type='get' to='dj@yak'>
<query xmlns='jabber:iq:browse'/>
</iq>
RECV: <iq type='result' to='sabine@yak/Work' from='dj@yak'>
<user name='DJ Adams' xmlns='jabber:iq:browse' jid='dj@yak'>
<ns>dj:public:favorites</ns>
</user>
</iq>and can be subsequently retrieved by anyone:
SEND: <iq type='get' to='dj@yak'>
<query xmlns='dj:public:favorites'/>
</iq>
RECV: <iq type='result' to='sabine@yak/Work' from='dj@yak'>
<query xmlns='dj:public:favorites'>
<item url='http://dev.jabber.org'>Jabber DevZone</item>
<item url='http://www.scripting.com'>Scripting News</item>
</query>
</iq>Publically stored data can contain multiple fragments qualified by different namespaces, such as:
SEND: <iq type='set'>
<query xmlns='my:resume'>
<education xmlns='resume:education'>
<degree type='BA'>Classics</degree>
</education>
<employment xmlns='work:clients'>
<client from='2001'>Author, O'Reilly & Associates, Inc.</client>
<client from='1999'>Deluxe Video Services</client>
<client from='1996'>Andersen Consulting</client>
...
</employment>
</query>
</iq>However, the retrieval resolution is still limited to all of the fragment defined by the top-level namespace (my:resume in this case).
As the name suggests, the jabber:iq:register namespace is used to conduct registration exchanges between the client and server. The most obvious example of this is to create (register) a new user on the Jabber server. Chapter 6 covers user registration in detail, so here we'll look at how to use the namespace to add or change an entry in the JUD.
First we request the fields for registration with an IQ get:
SEND: <iq type='get' to='jud.yak' id='jud-2'>
<query xmlns='jabber:iq:register'/>
</iq>
RECV: <iq type='result' to='dj@yak/Work' from='jud.yak' id='jud-2'>
<query xmlns='jabber:iq:register'>
<instructions>
Complete the form to submit your searchable attributes
in the Jabber User Directory
</instructions>
<name/>
<first/>
<last/>
<nick/>
<email/>
</query>
</iq>and then send an IQ set to set our information:
SENT: <iq type='set' to='jud.yak' id='jud-3'>
<query xmlns='jabber:iq:register'>
<name>DJ Adams</name>
<first>DJ</first>
<last>Adams</last>
<nick>qmacro</nick>
<email>dj.adams@pobox.com</email>
</query>
</iq>
RECV: <iq type='result' to='dj@yak/Work' from='jud.yak'/>Making requests for form fields: This idiom—making a request to a service to return the fields appropriate for completion—is common in Jabber and is worth bearing in mind if you're intending to build a Jabber client. The nature of the form field requests means that the client application has to be flexible and accommodating, to bend itself around the dynamic server.
Services offering a registration mechanism are identifiable in the list returned from a jabber:iq:agents or a jabber:iq:browse query, as shown in Example 5a-3.
Example 5a-3. An agents or browse query reveals registration and search mechanisms
RECV: <iq to='dj@yak/Work' type='result' from='yak'>
<query xmlns='jabber:iq:agents'>
<agent jid='jud.yak'>
<name>yak JUD (0.4)</name>
<service>jud</service>
<search/>
<register/>
</agent>
...
</query>
</iq>
...
RECV: <iq type='result' to='dj@yak/Work' from='yak'>
<service xmlns='jabber:iq:browse' type='jabber' jid='yak'
name='Jabber Server'>
<service type='jud' jid='jud.yak' name='yak JUD (0.4)'>
<ns>jabber:iq:search</ns>
<ns>jabber:iq:register</ns>
</service>
...
</service>
</iq>There are a couple of extra elements that are fairly common across different implementations of the jabber:iq:register namespace:
When sent with an IQ set request, the <remove/> tag requests that the registration be cancelled, revoked, or reversed.
When received in an IQ result, the <registered/> tag signifies that registration has already been made with the service, and any further registration IQ sets will serve to modify the current registration details.
Another example of registration using the jabber:iq:register namespace is shown in the section called RSS punter in Chapter 8.
In the section called Presence Subscription in Chapter 5, we looked at the presence subscription mechanism used to coordinate and record information about the relationships between users and how they exchange availability information. This mechanism revolves around certain types of <presence/> packets and storage of information in the users' rosters.
The roster structure is managed within the jabber:iq:roster namespace. Clients make roster requests when they connect to the Jabber server, to pull down the roster which is stored server side. They also update the roster to add, change, or remove entries. However, roster updates aren't limited to just the client; there are certain attributes within each roster item that are maintained by the server, in response to presence subscription activity.
The roster in Example 5a-4 contains five items. Three are friends, grouped together using <group>Friends</group>, which is used by clients to build the roster item display in a structured (hierarchical) way.
Example 5a-4. A typical roster
<query xmlns='jabber:iq:roster'>
<item jid='shiels@jabber.org' subscription='both' name='Robert'>
<group>Friends</group>
</item>
<item jid='piers@jabber.org' subscription='both' name='Piers'>
<group>Friends</group>
</item>
<item jid='sabine@pipetree.com' subscription='to' name='Sabine'>
<group>Friends</group>
</item>
<item jid='jim@company-a.com' subscription='from' name='Jim'>
<group>Work</group>
</item>
<item jid='jim@company-b.com' subscription='none'
ask='subscribe' name='John'>
<group>Work</group>
</item>
</query>The subscription attribute is used to store the presence subscription state between the roster owner and the particular item that holds that attribute. With two of the Friends, Robert and Piers, the roster owner is subscribed to each of their presences, and they are each subscribed to the presence of the roster owner. This is denoted by the both value, which means that the presence subscription flows both ways. Where the attribute has the value to (as in Sabine's case), or from (Jim's case), the subscription flows in only one direction. Here, the roster owner is subscribed to Sabine's presence (but Sabine is not subscribed to the roster owner's presence), and Jim is subscribed to the roster owner's presence (i.e., the roster owner has a presence subscription from Jim). [9]
Where the value of the subscription attribute is none, neither party has a subscription to the other. In this case, a further attribute ask may be used to reflect that a presence subscription request is in progress. [10] The ask attribute can have one of two values:
This attribute sends a request to subscribe to a user's presence.
Sends a request to unsubscribe from a user's presence.
In both cases, these requests are sent using a <presence/> element with an appropriate value for the type attribute.
The server, is responsible for maintaining the subscription and ask attributes; the client may maintain all the other elements. If an item is updated by the server—for example, as a result of a correspondent accepting a previous subscription request—the server will push the updated item to the client with an IQ set:
SEND: <iq type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='john@company-b.com' subscription='to' name='John'/>
</query>
</iq>Here, John has accepted the roster owner's subscription request by sending the following:
<presence to='dj@yak/Work' type='subscribed'/>
The server will update the roster item accordingly by removing the ask='subscribe' and setting the value of the subscription attribute to to.
The jabber:iq:search is closely related to the jabber:iq:register namespace, in that the dance steps are pretty much the same. As with jabber:iq:register, you can discover which entities (usually server components) support search features from the results of an agents or browse query, as shown in Example 5a-3.
Also, as with the jabber:iq:register namespace, the fields to be used in the interaction are first retrieved with an IQ get qualified by the jabber:iq:search namespace. Here we see an example of that with the JUD running on the jabber.org server:
SEND: <iq type='get' to='users.jabber.org' id='800'>
<query xmlns='jabber:iq:search'/>
</iq>
RECV: <iq type='result' from='users.jabber.org'
to='qmacro@jabber.org/laptop' id='800'>
<query xmlns='jabber:iq:search'>
<instructions>
Fill in a field to search for any matching Jabber User
</instructions>
<first/>
<last/>
<nick/>
<email/>
</query>
</iq>To continue the similarity theme, an IQ set is used to submit the search, sending back a value (or values) in the fields like this: <email>pipetree.com</email>.
The only exciting feature of the jabber:iq:search namespace is perhaps the way it can return results in response to an IQ set. This depends on the component, and how the feature is implemented.
While the JUD component will return all results in one IQ element:
RECV: <iq type='result' from='users.jabber.org' to='qmacro@jabber.org/laptop'>
<query xmlns='jabber:iq:search'>
<item jid='qmacro@jabber.org'>
<name>DJ Adams</name>
<first>DJ</first>
<last>Adams</last>
<nick>qmacro</nick>
<email>dj@pipetree.com</email>
</item>
<item jid='piers@jabber.org'>
<name>Piers Harding</name>
<first>Piers</first>
<last>Harding</last>
<nick>pxh</nick>
<email>piers@pipetree.com</email>
</item>
...
</query>
</iq>The component providing transport services to the ICQ IM system returns the results item-by-item:
RECV: <iq type='set' from='icq.jabber.org' id='icqs8'
to='qmacro@jabber.org/laptop'>
<query xmlns='jabber:iq:search'>
<item jid='4711471@icq.jabber.org'>
<given>DJ</given>
<family>Adams</family>
<nick>qmacro</nick>
<email>dj@pipetree.com</email>
</item>
</query>
</iq>
RECV: <iq type='set' from='icq.jabber.org' id='icqs8'
to='qmacro@jabber.org/laptop'>
<query xmlns='jabber:iq:search'>
<item jid='1234567@icq.jabber.org'>
<given>Piers</given>
<family>Harding</family>
<nick>pxh</nick>
<email>piers@pipetree.com</email>
</item>
</query>
</iq>The component signals the end of the search results with an empty IQ result element:
RECV: <iq type='result' from='icq.jabber.org' id='icqs8'
to='qmacro@jabber.org/laptop'>
<query xmlns='jabber:iq:search'/>
</iq>The jabber:iq:time namespace qualifies an info/query-based conversation to make or respond to a query on time information.
To query the time at a particular entity, an <iq/> get request is sent like this:
SEND: <iq type='get' id='time_19' to='conference.yak'>
<query xmlns='jabber:iq:time'/>
</iq>There are three pieces of information returned in response to such a query, the time in UTC (coordinated universal time) format, the local timezone, and a nice display version of the local time:
RECV: <iq type='result' id='time_19' to='sabine@yak/Work'
from='conference.yak'>
<query xmlns='jabber:iq:time'>
<utc>20010520T08:55:38</utc>
<tz>GMT</tz>
<display>Sun May 20 09:55:38 2001</display>
</query>
</iq>The format of the <tz/> and <display> tags is not fixed. While this is what the Conferencing service returns, a response from the JIM client would give “GMT Standard Time” and “20/05/01 09:55:38,” respectively.
Incidentally, if you've tried to send a jabber:iq:time query to a client and received an error in response, check the description in the sidebar Specifying Clients as Query Targets.
Different components running in different timezones: If you consider that certain components can be connected to the Jabber backbone but be running on different hosts, communicating over TCP socket connections, as described in the section called Server Constellations in Chapter 4, this may be more useful than you initially think.
Similar to the jabber:iq:time namespace, the :version namespace is used to make and respond to queries regarding the version of the particular piece of software being addressed. The query is formulated like this:
SEND: <iq type='get' id='ver-a' to='JID'>
<query xmlns='jabber:iq:version'/>
</iq>Responses depend on the entity being queried. Here are responses from three different entities:
a client (sjabber):
RECV: <iq type='result' to='dj@yak/Work' from='sabine@yak/sjabber'>
<query xmlns='jabber:iq:version'>
<name>sjabber</name>
<version>0.4</version>
<os>linux</os>
</query>
</iq>The Jabber server itself (well, the JSM):
RECV: <iq type='result' to='dj@yak/Work' from='sabine@yak/sjabber'> <query xmlns='jabber:iq:version'> <name>jsm</name> <version>1.4.1</version> <os>linux 2.2.12-45SAP</os> </query> </iq>
And the JUD component:
RECV: <iq type='result' to='dj@yak/Work' from='sabine@yak/sjabber'> <query xmlns='jabber:iq:version'> <name>jud</name> <version>0.4</version> <os>linux 2.2.12-45SAP</os> </query> </iq>
Another example of registration using the jabber:iq:version namespace is shown in the section called RSS punter in Chapter 8.
| [1] | The mod_agents module within the JSM. |
| [2] | By “Jabber server,” we're referring to the JSM. |
| [3] | Remember that the Jabber namespaces used to qualify <iq/> queries begin jabber:iq, while Jabber namespaces used to qualify general payloads to any of <message/>, <iq/>, and <presence/> begin jabber:x. |
| [4] | There is a feature in the Jabber server version 1.4.1 that allows dynamic starting and stopping of library load components, but it is not completely developed at the moment. |
| [5] | The word "band" here refers to the bandwidth, or connection, between the client and the server. The point of an out of band connection is that it's independent of that client-to-server connection (it typically is a connection from one client directly to another), and so doesn't impact the traffic, or bandwidth on that connection. This makes sense when you consider that out of band connections are typically used for exchanging large volumes of data, such as binary files. |
| [6] | The reason for the vcard-temp namespace name is that there is an emerging but nevertheless not-yet-established standard for vCard data. Until that standard is established, the Jabber server developers have decided to handle this format in a temporary way. |
| [7] | That is, the JID without a specified resource; otherwise it would be passed on by the server to be handled by the client connection with that resource. |
| [8] | The location of the spool files is defined in the xdb component instances configuration—see the section called Component instance: xdb in Chapter 4. |
| [9] | In colloquial Jabber terms, Jim is known as a lurker, as he knows about the roster owner's availability, without the roster owner knowing about his. |
| [10] | “Pending,” in Jabber client parlance. |