A description of PubSub.com's use of JEP-0060.
Email: bobwyman@pubsub.com
JID: bobwyman@jabber.org
Blog: http://bobwyman.pubsub.com
Extensible Messaging and Presence Protocol (XMPP): Core draft-ietf-xmpp-core-24
JEP-0004: Data Forms
JEP-0030: Service Discovery
JEP-0060: Publish-Subscribe
JEP-0078: Non-SASL Authentication
JEP-0131: Stanza Headers and Internet Metadata (SHIM)
PubSub Boolean Subscriptions: The Fine Print
The Atom Syndication Format 0.3 (PRE-DRAFT)
Initial version. (Bob Wyman)
Updated April 12th, 2006 (Malcolm Pollack)
This document describes PubSub.com's experimental use of the Jabber/XMPP PubSub protocol as defined in JEP-0060. (Note: A number of modifications to JEP-0060 are anticipated in this document.) The information below is guaranteed to change as we gain experience with JEP-0060 and respond to user comments.
Your comments are both welcome and encouraged.
A sample Jabber/XMPP session is illustrated below to provide guidance in understanding how PubSub.com uses Jabber/XMPP. More detailed documentation will be provided at a later time.
NOTE: At this time, we do not support the mechanisms supported by Jabber/XMPP for creating accounts. (e.g. "register") All accounts and passwords must be created at the PubSub.com website. Users who currently have active PubSub.com subscriptions also have PubSub.com accounts, however, they may not have passwords. To obtain a password, users should access the "My Subscriptions" page on the PubSub.com site.
New subscriptions may be created using either the PubSub.com website or the Jabber/XMPP service. On the website, a simple subscription interface can be found att: https://www.pubsub.com/weblogs. Existing subscriptions may be viewed, modified, and deleted using the "My Subscriptions" interface at on the website: https://www.pubsub.com/account.
2.1 Establishing a Connection to the Server
The information in this section should not be considered a substitute for reading the proper Jabber/XMPP documentation listed in the related documents section at the top of this document. What is presented below should not be considered definitive documentation of the Jabber/XMPP protocol.
Example 1. Client Opens Stream to Server
C: <stream:stream to="xmpp.pubsub.com" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">Example 2. Server Opens Stream to Client
S: <?xml version='1.0'?> <stream:stream xmlns:stream='http://etherx.jabber.org/streams' id='85b86d8' xmlns='jabber:client' from='xmpp.pubsub.com'>The PubSub server at xmpp.pubsub.com does not currently support server-to-server connections. Thus, you must connect to it directly as a client. We are currently using the standard Jabber/XMPP port: 5222.
Example 3. Client Requests Authentication Fields from Server
C: <iq id="auth_1" type="get"> <query xmlns="jabber:iq:auth"> <username>sample_at_pubsub_dot_com@xmpp.pubsub.com</username> </query> </iq>PubSub.com uses email addresses as usernames. When creating a JID for a user, the PubSub username is converted to a form which is appropriate for use in a JID. Thus, the username "sample@pubsub.com" is converted to "sample_at_pubsub_dot_com". The string "@xmpp.pubsub.com" is then appended, so the complete JID becomes "sample_at_pubsub_dot_com@xmpp.pubsub.com". (Note: In the future, it is very likely that a different means will be used to generate or obtain a PubSub user's JID.)
All PubSub.com subscribers have usernames, however, not all subscribers have passwords. For a subscriber to obtain a password, they must access the My Subscriptions page which can be found at https://www.pubsub.com/account. Once a username and password have been obtained, the PubSub subscriber can access their Jabber/XMPP JEP-0060 feed of entries that match their subscriptions.
For a limited time, users who do not have PubSub.com accounts may use the "sample@pubsub.com" username which is used in this document. (Remember: It must be specified as "sample_at_pubsub_dot_com".) The password is, as shown below: "sample". Users of the sample@pubsub.com username will not, however, be able to log into PubSub.com to create, manage, or modify subscriptions. Users are strongly encouraged to create accounts with PubSub.com in order to gain the full benefit of this service. Please do not create or delete subscriptions while using the sample account.
The PubSub server currently uses the "auth" protocol defined in JEP-0078 rather than the authentication methods defined in XMPP.
Example 4. Server Returns Authentication Fields to Client
S: <iq id='auth_1' type='result'> <query xmlns='jabber:iq:auth'> <username/> <password/> <resource/> </query> </iq>Example 5. Client Provides Required Information (Plaintext)
C: <iq id="auth_2" type="set"> <query xmlns="jabber:iq:auth"> <username>sample_at_pubsub_dot_com@xmpp.pubsub.com</username> <password>sample</password> <resource>PubSubClient1</resource> </query> </iq>Example 6. Server Informs Client of Successful Authentication
S: <iq type='result' id='auth_2'/>The PubSub Server uses XMPP presence (see: RFC 3921) status to toggle the delivery of messages to a bound endpoint.
Example 7. Client Sends Presence Message To Server to Enable Message Delivery
Note: This feature is not presently supported, but soon will be.C: <presence/>Example 8. Client Sends Presence To Server to Halt Message Delivery
C: <presence type="unavailable"/>At this point, the Jabber/XMPP session has been completely established and messages for the user's active subscriptions will be delivered as they are matched. It is recommended that the client request a list of active subscriptions at this point to ensure that it anticipates what will be arriving. (See: Section 2.3)
2.2 Receiving Messages
Messages are published to clients as they are received and matched by the PubSub matching engine. Some subscriptions will result in messages being published every few minutes or even more frequently. Other subscriptions may result in intervals of days, weeks or even years between messages. Thus, clients should be prepared to receive either a large number of messages or a very few messages during any particular time period.
Example 9. Server Publishes an Atom Message to the Client
S: <message to='sample_at_pubsub_dot_com@xmpp.pubsub.com' from='pubsub-delivery@xmpp.pubsub.com' > <event xmlns='http://www.jabber.org/protocol/pubsub#event'> <items node='pubsub/topics/101'> <item id='6802'> <headers xmlns='http://jabber.org/protocol/shim'> <header name="subid">pubsub/subs/71304ce006a02c5049b63cb142c9b11ea</header> <header name="subid">pubsub/subs/66271d2e70372c1b4dc5b46e79a6f001a</header> </headers> <pubsub-message xmlns="http://pubsub.com/xmlns"> <feed xmlns="http://purl.org/atom/ns#" xmlns:ps="http://pubsub.com/xmlns" version="0.3" xml:lang="en-us"> <title>PubSub Weblogs</title> <modified>20040507T00:09:46-0500</modified> <entry> <ps:source-feed xmlns="http://pubsub.com/xmlns"> <title>A Sample Blog</title> <link rel="alternate" type="text/html" href="http://example.com/index.html"/> <link rel="alternate" type="text/xml" href="http://example.com/atom.xml"/> <modified>2003-12-13T18:30:02Z</modified> <author> <name>Bob Wyman</name> </author> </ps:source-feed> <title>The title of the entry</title> <link rel="alternate" type="text/html" href="http://example.org/2003/12/13/atom03"/> <id>tag:example.org,2003:3.2397</id> <issued>2003-12-13T08:29:29-04:00</issued> <modified>2003-12-13T18:30:02Z</modified> <content type="text/html" mode="escaped" xml:space="preserve"> This is the text of the entry. This is <b>bold</b>. </content> </entry> </feed> </pubsub-message> </item> </items> </event> </message>The <feed> element is defined by Atom. See: http://www.mnot.net/drafts/draft-nottingham-atom-format-02.html.
The <ps:source-feed> element is an experimental extension to Atom that is used to copy feed-level metadata from an entry's source-feed into the entry itself.
The node attribute of the items element contains the nodeID of the topic that this message was published to. The SHIM headers provide the subID's of all subscriptions that the published message matches. The single message illustrated above should be considered to have matched two distinct subscriptions -- all of which belong to the current user.
It is a good practice for clients to request a list of their "current affiliations" as one of the first things done immediately after establishing a session with the pubsub server. Doing this informs the client of all existing subscriptions and provides metadata that can be useful in handling the messages that may be received during the session.
Example 10. Client Requests Current Affiliations
C: <iq type="get" from="sample_at_pubsub_dot_com@xmpp.pubsub.com" to="xmpp.pubsub.com" id="allsubs"> <pubsub xmlns="http://jabber.org/protocol/pubsub"> <affiliations/> </pubsub> </iq>Example 11. Server Returns Current Affiliations
A client may also request affiliations in "verbose" format; this returns an option list for each subscription.S: <iq id="allsubs" type="result" from="xmpp.pubsub.com"> <pubsub xmlns="http://jabber.org/protocol/pubsub"> <affiliations> <entity node="pubsub/topics/101" subid="pubsub/subs/71304ce006a02c5049b63cb142c9b11e" jid="sample_at_pubsub_dot_com@xmpp.pubsub.com" affiliation="none" subscription="subscribed"/> <entity node="pubsub/topics/101" subid="pubsub/subs/66271d2e70372c1b4dc5b46e79a6f001" jid="sample_at_pubsub_dot_com@xmpp.pubsub.com" affiliation="none" subscription="subscribed"/> </affiliations> </pubsub> </iq>Example 12. Client Requests "Verbose" Affiliations
C: <iq type="get" from="sample_at_pubsub_dot_com@xmpp.pubsub.com" to="xmpp.pubsub.com" id="allsubs"> <pubsub xmlns="http://jabber.org/protocol/pubsub"> <affiliations> <ps:verbose/> </affiliations> </pubsub> </iq>Example 13. Server returns "Verbose" Affiliations
S: <iq id="allsubs" type="result" from="xmpp.pubsub.com"> <pubsub xmlns="http://jabber.org/protocol/pubsub"> <affiliations xmlns:ps="http://pubsub.com/xmlns"> <entity node="pubsub/topics/0" subid="pubsub/subs/e5/e3/d318a2983e6e076de09bb6caab" jid="sample_at_pubsub_dot_com@xmpp.pubsub.com" affiliation="none" subscription="subscribed"> <ps:verbose> <x xmlns="jabber:x:data" type="result"> <field var="FORM_TYPE" type="hidden"> <value>http://jabber.org/protocol/pubsub#sub_meta_info</value> </field> <field var="topic" type="fixed"> <value>pubsub/topics/0</value> </field> <field var="state" type="fixed"> <value>subscribed</value> </field> <field var="title"> <value>RSS</value> </field> <field var="query-string"> <value>RSS</value> </field> <field var="query-keywords"> <value>"RSS"</value> </field> <field var="show-content"> <value>exclude</value> </field> <field var="xmlLink" type="fixed"> <value>https://atom.pubsub.com/e5/e3/d318a2983e6e076de09bb6caab.xml</value> </field> </x> </ps:verbose> </entity> <entity node="pubsub/topics/0" subid="pubsub/subs/cc/89/dabff42b0e4915467395c7842f" jid="sample_at_pubsub_dot_com@xmpp.pubsub.com" affiliation="none" subscription="subscribed"> <ps:verbose> <x xmlns="jabber:x:data" type="result"> <field var="FORM_TYPE" type="hidden"> <value>http://jabber.org/protocol/pubsub#sub_meta_info</value> </field> <field var="topic" type="fixed"> <value>pubsub/topics/0</value> </field> <field var="state" type="fixed"> <value>subscribed</value> </field> <field var="title"> <value>"cinco de mayo"</value> </field> <field var="query-string"> <value>"cinco de mayo"</value> </field> <field var="query-keywords"> <value>"cinco de mayo"</value> </field> <field var="show-content"> <value>exclude</value> </field> <field var="xmlLink" type="fixed"> <value>https://atom.pubsub.com/cc/89/dabff42b0e4915467395c7842f.xml</value> </field> </x> </ps:verbose> </entity> <entity node="pubsub/topics/0" subid="pubsub/subs/d5/4f/c913e84fec63f5d635d3461e00" jid="sample_at_pubsub_dot_com@xmpp.pubsub.com" affiliation="none" subscription="subscribed"> <ps:verbose> <x xmlns="jabber:x:data" type="result"> <field var="FORM_TYPE" type="hidden"> <value>http://jabber.org/protocol/pubsub#sub_meta_info</value> </field> <field var="topic" type="fixed"> <value>pubsub/topics/0</value> </field> <field var="state" type="fixed"> <value>subscribed</value> </field> <field var="title"> <value>fisherman</value> </field> <field var="query-string"> <value>fisherman</value> </field> <field var="query-keywords"> <value>"fisherman"</value> </field> <field var="show-content"> <value>exclude</value> </field> <field var="xmlLink" type="fixed"> <value>https://atom.pubsub.com/d5/4f/c913e84fec63f5d635d3461e00.xml</value> </field> </x> </ps:verbose> </entity> </affiliations> </pubsub> </iq>Each PubSub.com "topic" is mapped to a unique Jabber/XMPP node id.
A single user can have multiple subscriptions to a single topic. Unlike traditional "topic-based" Publish/Subscribe systems, PubSub.com implements a "content-based" Publish/Subscribe system in which each subscriber is able to create subscriptions which, by placing constraints on the content of desired messages, filter the content that flows through or over a topic. In a content-based publish/subscribe system, the topic is simply an attribute of one or more messages that can be subscribed to rather than being the thing to which one subscribes.
Given the nature of our system, we anticipate the clients will only very rarely wish to subscribe to all the content which flows over any particular topic. At present, the topics we support generally publish hundreds of thousands and even millions of messages each day. (For example, one of our topics, topic 101, publishes all new or modified entries/items discovered in any of the over 2 million RSS and Atom files that we monitor on a continuous basis as well as any new items posted to over 50 thousand NNTP newsgroups.
Example 14. Client Requests Info on a Subscription
C: <iq type="get" from="sample_at_pubsub_dot_com@xmpp.pubsub.com" to="xmpp.pubsub.com" id="options1"> <pubsub xmlns="http://jabber.org/protocol/pubsub"> <options node="pubsub/topics/101" subid="pubsub/subs/a00d55e372d07f868dfae2cec97ad759" jid="sample_at_pubsub_dot_com@xmpp.pubsub.com"/> </pubsub> </iq>Example 15. Server Responds with Subscription Information
S: <iq type="result" from="xmpp.pubsub.com" id="options1"> <pubsub xmlns="http://jabber.org/protocol/pubsub"> <options node="pubsub/topics/101" subid="pubsub/subs/a00d55e372d07f868dfae2cec97ad759" jid="bob_at_wyman_dot_com@xmpp.pubsub.com"> <x xmlns="jabber:x:data" type="result"> <field var="FORM_TYPE" type="hidden"> <value>http://jabber.org/protocol/pubsub#sub_meta_info</value> </field> <field var="topic" type="fixed"> <value>pubsub/topics/101</value> </field> <field var="state" type="fixed"> <value>subscribed</value> </field> <field var="title"> <value>Mentions of RSS or Atom</value> </field> <field var="query-string"> <value> RSS | ATOM </value> </field> <field var="xmlLink" type="fixed"> <value>https://rss.pubsub.com/c5/b6/549aac53d56a2cd1b59f5790e0.xml</value> </field> </x> </options> </pubsub> </iq>Subscriptions may also be modified.
Example 16. Client Submits Modifications for a Subscription
Note: the "query-string" element is required for this operation, at least for the time being.C: <iq type="set" from="sample_at_pubsub_dot_com@xmpp.pubsub.com" to="xmpp.pubsub.com" id="sub1"> <pubsub xmlns="http://jabber.org/protocol/pubsub"> <options node="pubsub/topics/0" subid="pubsub/subs/cc/89/dabff42b0e4915467395c7842f" jid="sample_at_pubsub_dot_com@xmpp.pubsub.com"> <x xmlns="jabber:x:data" type="submit"> <field var="title"> <value>5th of May</value> </field> <field var="query-string"> <value>"cinco de mayo"</value> </field> </x> </options> </pubsub> </iq>Example 17. Server Reports Successful Modification of Subscription Options
S: <iq type="result" from="xmpp.pubsub.com" id="sub1"/>The PubSub XMPP server does not persist messages which are sent to disconnected clients. If clients wish to retrieve messages that were not delivered because the client was disconnected when the messages were sent, they should access the RSS file which is identified in the xmlLink field of each subscription record. (Note: It is expected that in the future, the RSS file format currently being used will be replace with a file format more compatible with that used in the XMPP messages.(e.g. An Atom file...)
A typical client will query for outstanding subscriptions upon start up by issuing a request for current affiliations and then using disco#info to retreive the xmlLink for each subscription. The client would then immediately download the RSS files pointed to by the xmlLinks. (Note: Some messages may be missing. At this time, PubSub.com stores a maximum of 30 messages in each disk file and only updates the files once every 15 minutes. Thus, if more than 30 messages matched a subscription since the time that the client was last connected, some messages may be missing. Additionally, if messages have arrived during the 15 minutes prior to the establishment of a new connection, they may not have all been inserted into the file yet. This behavior may be modified in the future.)
Because subscriptions can be created on the PubSub.com website, rather then by using XMPP directly, it is possible that a client will see information being published for a subscription that was not listed in the response to the request for all subscriptions that will typically be issued by the client at the beginning of each session. When the client discovers a message published for an unknown subscription, it should query the server to get the subscription information.
Example 18. Client Requests Info for a Topic
C: <iq type='get' from='sample_at_pubsub_dot_com@xmpp.pubsub.com' to='xmpp.pubsub.com' id='info3'> <query xmlns='http://jabber.org/protocol/disco#info' node='pubsub/topics/101'/> </iq>Example 19. Server Responds with Topic Info
S: <iq type="result" from="xmpp.pubsub.com" id="info3"> <query xmlns="http://jabber.org/protocol/disco#info" node="pubsub/topics/101"> <identity category="pubsub" type="topic" name="PubSub Syndication"/> <feature var="http://jabber.org/protocol/pubsub#subscribe"/> <x xmlns="jabber:x:data" type="result"> <field var="FORM_TYPE" type="hidden"> <value>http://jabber.org/protocol/pubsub#node_meta_info</value> </field> <field var="creator"> <value>pubsub@pubsub.com</value> </field> </x> </query> </iq>In the future, the data returned in response to a query for Topic information will probably be extended. Possible extensions include:
- A machine processable Message Schema that describes the format of messages that are published over the topic
- A machine processable Query Schema that describes the syntax for subscribing to messages published over the topic.
- An XSL template, or pointer to an XSL Template, that provides default content formatting instructions.
- A more detailed topic description.
- "ICE" information. See: http://www.w3.org/TR/1998/NOTE-ice-19981026 which defines the "Information and Content Exchange Format and Protocol".
Example 20. Client Requests Options for a Topic
C: <iq type="get" from="sample_at_pubsub_dot_com@xmpp.pubsub.com" to="xmpp.pubsub.com" id="options1"> <pubsub xmlns="http://jabber.org/protocol/pubsub"> <options node="pubsub/topics/101" jid="sample_at_pubsub_dot_com@xmpp.pubsub.com"/> </pubsub> </iq>Example 21. Server Returns Subscription Options for a Topic
S: <iq type='result' id='' from='xmpp.pubsub.com' > <pubsub xmlns='http://jabber.org/protocol/pubsub'> <options node='pubsub/topics/101' jid='sample_at_pubsub_dot_com@xmpp.pubsub.com'> <x xmlns='jabber:x:data' type='result'> <field var='FORM_TYPE' type='hidden'> <value>http://jabber.org/protocol/pubsub#subscribe_options</value> </field> <field var='title' label='The title or name of the subscription.'> <value></value> </field> <field var='topic' type='fixed' label='The Topic Name.'> <value>pubsub/topics/101</value> </field> <field var='query-string' label='The query or subscription filter.'> <value></value> </field> <field var='show-content' type='list-single' label='Select the handling you would like for content fields.'> <option label='No Content in messages.'> <value>exclude</value> </option> <option label='Full Content in messages.'> <value>include</value> </option> <value>exclude</value> </field> </x> </options> </pubsub> </iq>The "show-content" field in the subscription options allows clients to specify the handling of the content field in messages. In some applications, it is not necessary to have the contents field delivered, yet the various other fields, like entry title, feed title, etc. are necessary. Using the show-content field, clients can specify that messages should either exclude or include the content fields of entries that are matched by the subscription. In the future, other content handling values might be provided. (e.g. "summarize", "KWIC", "first100characters", etc.) The default value for show-content is "exclude."
To create a subscription, there must be a properly formatted "query-string" specified as one of the options in the subscription request. The syntax for creating PubSub.com query strings is defined at: https://www.pubsub.com/booleanhelp.
Subscription options may vary on a topic-by-topic basis. Thus, clients should request that the server describe the subscription options available for a topic prior to making a subscription request. The procedures for doing so can be found in the section on Requesting Topic Information.
NOTE: JEP-0060 supports the creation of a subscription without options with the options being specified in later requests. This is not fully supported by our implementation. Subscription options specified at the time of creating a subscription must at minimum include a <field var="query-string"> element.
Example 22. Client Subscribes to a Topic
C: <iq type="set" to="xmpp.pubsub.com" id="sub1"> <pubsub xmlns="http://jabber.org/protocol/pubsub"> <subscribe node="pubsub/topics/101" jid="sample_at_pubsub_dot_com@xmpp.pubsub.com"> <options> <x xmlns="jabber:x:data" type="submit"> <field var="FORM_TYPE" type="hidden"> <value>http://jabber.org/protocol/pubsub#subscribe_options</value> </field> <field var="title"> <value>Presidential Candidates</value> </field> <field var="query-string"> <value><![CDATA[ ( bush | kerry ) & CATEGORY:501 ]]></value> </field> </x> </options> </subscribe> </pubsub> </iq>Example 23. Server Confirms Subscription
S: <iq type="result" from="xmpp.pubsub.com" id="sub1"> <pubsub xmlns="http://jabber.org/protocol/pubsub"> <entity node="pubsub/topics/101" subid="pubsub/subs/59fbb05b9007a7d0d6cfeefba5e2051f" jid="sample_at_pubsub_dot_com@xmpp.pubsub.com" affiliation="none" subscription="subscribed"> <options> <x xmlns="jabber:x:data" type="result"> <field var="FORM_TYPE" type="hidden"> <value>http://jabber.org/protocol/pubsub#subscribe_options</value> </field> <field var="title"> <value>Presidential Candidates</value> </field> <field var="query-string"> <value><![CDATA[( bush | kerry ) & CATEGORY:501 ]]></value> </field> <field var="xmlLink" type="fixed"> <value>https://rss.pubsub.com/02/79/18b0983335ddfe2f508f56b9fa.xml</value> </field> </x> </options> </entity> </pubsub> </iq>
Example 24. Client Requests Cancellation
C: <iq type="set" from="sample_at_pubsub_dot_com@xmpp.pubsub.com" to="xmpp.pubsub.com" id="unsub1"> <pubsub xmlns="http://jabber.org/protocol/pubsub"> <unsubscribe node="pubsub/topics/101" subid="pubsub/subs/59fbb05b9007a7d0d6cfeefba5e2051f" jid="sample_at_pubsub_dot_com@xmpp.pubsub.com"/> </pubsub> </iq>Example 25. Server Confirms Cancellation
S: <iq type='result' from='xmpp.pubsub.com' id='unsub1'/>
The protocol can be observed using some of the many Jabber/XMPP clients that are currently available. The procedure for using one of these clients, Exodus (available from: http://exodus.jabberstudio.org/, is described below:
To access the PubSub.com XMPP server using telnet, simply open a telnet session to xmpp.pubsub.com on port 5222. The console trace below shows the beginning of a typical session.
$ telnet xmpp.pubsub.com 5222
Trying 209.11.36.153...
Connected to xmpp.pubsub.com.
Escape character is '^]'.
<stream:stream to="xmpp.pubsub.com" xmlns="jabber:client" xmlns:
stream="http://etherx.jabber.org/streams">
<?xml version='1.0' encoding='UTF-8'?>
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' id=
'82566d8' xmlns='jabber:client' from='xmpp.pubsub.com'>
<iq type="set" id="auth">
<query xmlns="jabber:iq:auth">
<username>bob_at_wyman_dot_us</username>
<password>password</password>
<resource>telnet</resource>
</query>
</iq>
<iq type="set"
to="xmpp.pubsub.com"
id="sub1">
<pubsub xmlns="http://jabber.org/protocol/pubsub">
<subscribe
node="pubsub/topics/101"
jid="bob_at_wyman_dot_us@xmpp.pubsub.com">
<options>
<x xmlns="jabber:x:data" type="submit">
<field var="FORM_TYPE" type="hidden">
<value>http:
//jabber.org/protocol/pubsub#subscribe_options</value>
</field>
<field var="title">
<value>Links to Google</value>
</field>
<field var="query-string">
<value>URI:google.com</value>
</field>
</x>
</options>
</subscribe>
</pubsub>
</iq>
<iq type='result' from='xmpp.pubsub.com' id='sub1'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<entity node='pubsub/topics/101' subid=
'pubsub/subs/b4048e7621675bce1f24ea440c9477f6'
jid='bob_at_wyman_dot_us@xmpp.pubsub.com' affiliation='none'
subscription='subscribed'>
<options>
<x xmlns='jabber:x:data' type='result'>
<field var='FORM_TYPE' type='hidden'>
<value>http://jabber.org/protocol/pubsub#subscribe_options</value>
</field>
<field var='title'>
<value>Links to Google</value>
</field>
<field var='query-string'>
<value>URI:google.com</value>
</field>
<field var='xmlLink' type='fixed'>
<value>http:
//rss.pubsub.com/94/75/569f9cd694525b5a8b26a786da.xml</value>
</field>
</x>
</options>
</entity>
</pubsub>
</iq>