mirror of
https://github.com/moparisthebest/xeps
synced 2024-11-09 19:05:05 -05:00
7f18520258
git-svn-id: file:///home/ksmith/gitmigration/svn/xmpp/trunk@1037 4b5297f7-1745-476d-ba37-a9c6900126ab
402 lines
23 KiB
XML
402 lines
23 KiB
XML
<?xml version='1.0' encoding='UTF-8'?>
|
|
<!DOCTYPE xep SYSTEM 'xep.dtd' [
|
|
<!ENTITY % ents SYSTEM 'xep.ent'>
|
|
%ents;
|
|
]>
|
|
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
|
|
<xep>
|
|
<header>
|
|
<title>Entity Capabilities</title>
|
|
<abstract>This document defines an XMPP protocol extension for broadcasting and discovering client, device, or generic entity capabilities in a way that minimizes network impact.</abstract>
|
|
&LEGALNOTICE;
|
|
<number>0115</number>
|
|
<status>Draft</status>
|
|
<type>Standards Track</type>
|
|
<sig>Standards</sig>
|
|
<dependencies>
|
|
<spec>XMPP Core</spec>
|
|
<spec>XMPP IM</spec>
|
|
<spec>XEP-0030</spec>
|
|
</dependencies>
|
|
<supersedes/>
|
|
<supersededby/>
|
|
<shortname>caps</shortname>
|
|
<schemaloc>
|
|
<url>http://www.xmpp.org/schemas/caps.xsd</url>
|
|
</schemaloc>
|
|
&hildjj;
|
|
&stpeter;
|
|
&remko;
|
|
<revision>
|
|
<version>1.4pre2</version>
|
|
<date>in progress, last updated 2007-07-11</date>
|
|
<initials>psa/jjh</initials>
|
|
<remark><p>In response to persistent security concerns over caps poisoning, defined method for hashing concatenation of identity and supported features.</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>1.3</version>
|
|
<date>2007-04-10</date>
|
|
<initials>psa/rt/jjh</initials>
|
|
<remark><p>Added developer-friendly introduction; specified that ext names must be stable across application versions; further clarified examples; added stream feature use case; removed message example (send directed presence instead).</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>1.2</version>
|
|
<date>2007-02-15</date>
|
|
<initials>psa</initials>
|
|
<remark><p>Clarified motivation and handling of service discovery requests.</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>1.1</version>
|
|
<date>2004-10-29</date>
|
|
<initials>psa</initials>
|
|
<remark><p>Clarified meaning of service discovery results for client#ver and client#ext.</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>1.0</version>
|
|
<date>2004-08-01</date>
|
|
<initials>psa</initials>
|
|
<remark><p>Per a vote of the Jabber Council, advanced status to Draft.</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>0.7</version>
|
|
<date>2004-06-29</date>
|
|
<initials>jjh/psa</initials>
|
|
<remark><p>Added several items to the Security Considerations; clarified naming requirements regarding 'node', 'ver', and 'ext' attributes.</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>0.6</version>
|
|
<date>2004-04-25</date>
|
|
<initials>psa</initials>
|
|
<remark><p>Made a number of editorial adjustments.</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>0.5</version>
|
|
<date>2004-01-05</date>
|
|
<initials>psa</initials>
|
|
<remark><p>Specified that the protocol can be used whenever presence is used (e.g., by gateways); improved the XML schema; made several editorial adjustments.</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>0.4</version>
|
|
<date>2003-09-04</date>
|
|
<initials>jjh</initials>
|
|
<remark><p>IQ eets must be to a resource, since they are intended to go to a particular session.</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>0.3</version>
|
|
<date>2003-09-02</date>
|
|
<initials>jjh</initials>
|
|
<remark><p>Servers MUST strip extras changed to MAY, due to implementer feedback.</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>0.2</version>
|
|
<date>2003-08-28</date>
|
|
<initials>jjh</initials>
|
|
<remark><p>Add more clarifying assumptions and requirements, make
|
|
it clear that clients don't have to send capabilities every
|
|
time if the server is optimizing.</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>0.1</version>
|
|
<date>2003-08-27</date>
|
|
<initials>jjh</initials>
|
|
<remark><p>Initial version.</p></remark>
|
|
</revision>
|
|
</header>
|
|
<section1 topic='Introduction' anchor='intro'>
|
|
<section2 topic='Motivation' anchor='motivation'>
|
|
<p>It is often desirable for a Jabber/XMPP application (commonly but not necessarily a client) to take different actions depending on the capabilities of another application from which it receives presence information. Examples include:</p>
|
|
<ul>
|
|
<li>Showing a different set of icons depending on the capabilities of other clients.</li>
|
|
<li>Not sending &xep0071; content to plaintext clients such as cell phones.</li>
|
|
<li>Allowing the initiation of a Voice over IP (VoIP) session only to clients that support &xep0166; and &xep0167;.</li>
|
|
<li>Not showing a "Send a File" button if another user's client does not support &xep0096;.</li>
|
|
</ul>
|
|
<p>Some older Jabber clients send one &xep0030; and one &xep0092; request to each entity from which they received presence after login. That "disco+version flood" results in an excessive use of bandwidth and is impractical on a larger scale, particularly for users or applications with large rosters. Therefore this document proposes a more robust and scalable solution: namely, a presence-based mechanism <note>This proposal is not limited to clients, and can be used by any entity that exchanges presence with another entity, e.g., a gateway. However, this document uses the example of clients throughout.</note> for exchanging information about entity capabilities. Clients SHOULD NOT engage in the older "disco+version flood" behavior and instead SHOULD use Entity Capabilities as specified herein.</p>
|
|
</section2>
|
|
<section2 topic='How It Works' anchor='howitworks'>
|
|
<p>This section provides a friendly, non-normative introduction to the workings of entity capabilities.</p>
|
|
<p>Imagine that you are a Shakespearean character named Juliet and one of your contacts, a handsome fellow named Romeo, becomes available. His client wants to publish its capabilities, and does this by adding a <c/> element to its presence packets. As a result, your client receives the following presence packet:</p>
|
|
<code><![CDATA[
|
|
<presence from='romeo@montague.lit/home'>
|
|
<c xmlns='http://jabber.org/protocol/caps'
|
|
node='http://exodus.jabberstudio.org/caps'
|
|
ver='8RovUdtOmiAjzj+xI7SK5BCw3A8='/>
|
|
</presence>
|
|
]]></code>
|
|
<p>The 'node' attribute represents the client Romeo is using. The 'ver' attribute is a specially-constructed string that represents the identity (see &DISCOCATEGORIES;) and supported features (see &DISCOFEATURES;) of the entity.</p>
|
|
<p>At this point, your client has no idea what the capabilities are of someone with a client string 'http://exodus.jabberstudio.org/caps' and a version string '8RovUdtOmiAjzj+xI7SK5BCw3A8='. Your client therefore sends a service discovery query to Romeo, asking what his client can do (note that the disco#info query is sent to a node of "node#ver"):</p>
|
|
<code><![CDATA[
|
|
<iq type='get' from='juliet@capulet.lit/chamber' to='romeo@montague.lit/home' id='disco1'>
|
|
<query xmlns='http://jabber.org/protocol/disco#info'
|
|
node='http://exodus.jabberstudio.org/caps#8RovUdtOmiAjzj+xI7SK5BCw3A8='/>
|
|
</iq>
|
|
]]></code>
|
|
<p>The response is:</p>
|
|
<code><![CDATA[
|
|
<iq type='result' from='romeo@montague.lit/home' to='juliet@capulet.lit/chamber' id='disco1'>
|
|
<query xmlns='http://jabber.org/protocol/disco#info'
|
|
node='http://exodus.jabberstudio.org/caps#8RovUdtOmiAjzj+xI7SK5BCw3A8='>
|
|
<identity category='client' type='pc'/>
|
|
<feature var='http://jabber.org/protocol/disco#info'/>
|
|
<feature var='http://jabber.org/protocol/disco#items'/>
|
|
<feature var='http://jabber.org/protocol/muc'/>
|
|
</query>
|
|
</iq>
|
|
]]></code>
|
|
<p>At this point, your client knows that anyone advertising a version string of '8RovUdtOmiAjzj+xI7SK5BCw3A8=' has a client that can do MUC. Your client remembers this information, so that it does not need to explicitly query the capabilities of a contact with the same version string. For example, Benvolio may send you the following presence:</p>
|
|
<code><![CDATA[
|
|
<presence from='benvolio@capulet.lit/230193'>
|
|
<c xmlns='http://jabber.org/protocol/caps'
|
|
node='http://exodus.jabberstudio.org/caps'
|
|
ver='8RovUdtOmiAjzj+xI7SK5BCw3A8='/>
|
|
</presence>
|
|
]]></code>
|
|
<p>Now your client automatically knows that Benvolio can do MUC, without needing to ask him explicitly via service discovery.</p>
|
|
<p>On the other hand, for a person with the following presence ...</p>
|
|
<code><![CDATA[
|
|
<presence from='nurse@capulet.lit/chamber'>
|
|
<c xmlns='http://jabber.org/protocol/caps'
|
|
node='http://psi-im.org/caps'
|
|
ver='uCoVCteRe3ty2wU2gHxkMaA7xhs='/>
|
|
</presence>
|
|
]]></code>
|
|
<p>... or the following presence ...</p>
|
|
<code><![CDATA[
|
|
<presence from='bard@shakespeare.lit/globe'>
|
|
<c xmlns='http://jabber.org/protocol/caps'
|
|
node='http://www.chatopus.com/caps'
|
|
ver='zHyEOgxTrkpSdGcQKH8EFPLsriY='/>
|
|
</presence>
|
|
]]></code>
|
|
<p>... you have no information about what this contact's client is capable of (as he is using a different client/version), and you therefore need to query for capabilities explicitly again via service discovery.</p>
|
|
</section2>
|
|
</section1>
|
|
<section1 topic='Assumptions' anchor='assumptions'>
|
|
<p>This document makes several assumptions:</p>
|
|
<ul>
|
|
<li>The type of client I am using is of interest to the people in my roster.</li>
|
|
<li>Clients for the people on my roster might want to make user interface decisions based on my capabilities.</li>
|
|
<li>Different clients may support the same capabilities.</li>
|
|
<li>Members of a community tend to cluster around a small set of clients. More specifically, multiple people in my roster use the same client, and they upgrade versions relatively slowly (commonly a few times a year, perhaps once a week at most, certainly not once a minute).</li>
|
|
<li>Some clients are running against servers without server-to-server connectivity enabled, and without access to the Internet via HTTP.</li>
|
|
<li>Conversations are possible between users who are not on each other's rosters.</li>
|
|
<li>Client capabilities may change over the course of a session, due to features being enabled and disabled.</li>
|
|
</ul>
|
|
</section1>
|
|
|
|
<section1 topic='Requirements' anchor='reqs'>
|
|
<p>The protocol defined herein addresses the following requirements:</p>
|
|
<ol>
|
|
<li>Clients MUST be able to participate even if they support only &xmppcore;, &xmppim;, and <cite>XEP-0030</cite>.</li>
|
|
<li>Clients MUST be able to participate even if they are on networks without connectivity to other XMPP servers, services offering specialized XMPP extensions, or HTTP servers.<note>These first two requirements effectively eliminated &xep0060; as a possible implementation of entity capabilities.</note></li>
|
|
<li>Clients MUST be able to retrieve information without querying each user.</li>
|
|
<li>Since presence is normally broadcasted to many users, the byte size of the proposed extension MUST be as small as possible.</li>
|
|
<li>It MUST be possible to write a &xep0045; implementation that passes the given information along.</li>
|
|
<li>It MUST be possible to publish a change in capabilities within a single session.</li>
|
|
<li>Server infrastructure above and beyond that defined in <cite>XMPP Core</cite> and <cite>XMPP IM</cite> MUST NOT be required for this approach to work, although additional server infrastructure MAY be used for optimization purposes.</li>
|
|
</ol>
|
|
</section1>
|
|
|
|
<section1 topic='Protocol' anchor='protocol'>
|
|
<p>Entity capabilities are encapsulated in a <c/> element qualified by the 'http://jabber.org/protocol/caps' namespace. The attributes of the <c/> element are as follows:</p>
|
|
<table caption='Attributes'>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Definition</th>
|
|
<th>Inclusion</th>
|
|
</tr>
|
|
<tr>
|
|
<td>ext</td>
|
|
<td>A set of nametokens specifying additional feature bundles; this attribute is deprecated.</td>
|
|
<td>OPTIONAL</td>
|
|
</tr>
|
|
<tr>
|
|
<td>hash</td>
|
|
<td>The hashing algorithm used in generated the 'ver' attribute (see &ianahashes;); the value defaults to "sha-1".</td>
|
|
<td>OPTIONAL</td>
|
|
</tr>
|
|
<tr>
|
|
<td>node</td>
|
|
<td>A unique identifier for the software underlying the entity, typically a URL at the website of the project or company that produces the software; required for backward-compatibility.</td>
|
|
<td>REQUIRED</td>
|
|
</tr>
|
|
<tr>
|
|
<td>ver</td>
|
|
<td>A string that specifies the identity and supported features of the entity. <note>Before version 1.4 of this specification, the 'ver' attribute was used to specify the released version of the software.</note></td>
|
|
<td>REQUIRED</td>
|
|
</tr>
|
|
</table>
|
|
</section1>
|
|
|
|
<section1 topic='Generation of ver Attribute' anchor='ver'>
|
|
<p>In order to help prevent poisoning of entity capabilities information, the value of the 'ver' attribute MUST be generated according to the following method.</p>
|
|
<p>Note: All sorting operations MUST be performed using "i;octet" collation as specified in Section 9.3 of &rfc4790;.</p>
|
|
<ol>
|
|
<li>Initialize an empty string S.</li>
|
|
<li>Sort the service discovery identities by category and then by type, formatted as "category" "/" "type".</li>
|
|
<li>For each identity, append the category/type (if it exists) to S, followed by the '<' character.</li>
|
|
<li>Sort the supported features.</li>
|
|
<li>For each feature, append the feature to S, followed by the '<' character.</li>
|
|
<li>Compute ver by hashing S using the SHA-1 algorithm as specified in &rfc3174; (with binary output) and encoding the hash using Base64 as specified in Section 4 of &rfc4648;.</li>
|
|
</ol>
|
|
<p>For example, consider an entity whose service discovery category is "client", whose service discovery type is "pc", and whose supported features are "http://jabber.org/protocol/disco#info", "http://jabber.org/protocol/disco#items", and "http://jabber.org/protocol/muc". The value of the 'ver' attribute would be generated as follows:</p>
|
|
<ol>
|
|
<li>E = ''</li>
|
|
<li>Only one identity: client/pc</li>
|
|
<li>E = 'client/pc<'</li>
|
|
<li>Sort the features: "http://jabber.org/protocol/disco#info", "http://jabber.org/protocol/disco#items", "http://jabber.org/protocol/muc".</li>
|
|
<li>E = 'client/pc<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<<http://jabber.org/protocol/muc<'</li>
|
|
<li>ver = 8RovUdtOmiAjzj+xI7SK5BCw3A8=</li>
|
|
</ol>
|
|
</section1>
|
|
|
|
<section1 topic='Use Cases' anchor='usecases'>
|
|
<section2 topic='Advertising Capabilities' anchor='advertise'>
|
|
<p>Each time a conformant client sends presence, it annotates that presence with a client identifier ('node' attribute) and identity and feature identifier ('ver' attribute). Unless the server optimizations shown later are being used, the client MUST send this with every presence change (except for unavailable presence) to enable existing servers to remember the last presence for use in responding to probes.</p>
|
|
<p>If the supported features change during a client's session (e.g., a user installs an updated version of a client plugin), the application MUST recompute the 'ver' attribute and SHOULD send a new presence broadcast.</p>
|
|
<p>Note: The values of the <strong>'node'</strong> and <strong>'ver'</strong> attributes MUST NOT contain the '#' character, since that character is used as a separator in the <link url="#discover">Discovering Capabilities</link> use case.</p>
|
|
|
|
<example caption='Annotated presence sent'><![CDATA[
|
|
<presence>
|
|
<c xmlns='http://jabber.org/protocol/caps'
|
|
node='http://exodus.jabberstudio.org/caps'
|
|
ver='8RovUdtOmiAjzj+xI7SK5BCw3A8='/>
|
|
</presence>
|
|
]]></example>
|
|
</section2>
|
|
|
|
<section2 topic="Discovering Capabilities" anchor='discover'>
|
|
<p>A contact can learn what features a user's client supports by sending a disco#info request (as defined in <strong>XEP-0030: Service Discovery</strong>) to any client that sent a particular value of the <strong>ver</strong> attribute.</p>
|
|
|
|
<example caption='Disco#info request for client#version'><![CDATA[
|
|
<iq type='get' from='bard@shakespeare.lit/globe' to='someuser@capulet.lit/resource' id='123'>
|
|
<query xmlns='http://jabber.org/protocol/disco#info'/>
|
|
</iq>
|
|
]]></example>
|
|
|
|
<p>The user then returns all of the capabilities supported by software.</p>
|
|
|
|
<example caption='Disco#info response for client#version'><![CDATA[
|
|
<iq type='result' from='someuser@capulet.lit/resource' to='bard@shakespeare.lit/globe' id='123'>
|
|
<query xmlns='http://jabber.org/protocol/disco#info'/>
|
|
<identity category='client' type='pc'/>
|
|
<feature var='http://jabber.org/protocol/disco#info'/>
|
|
<feature var='http://jabber.org/protocol/disco#items'/>
|
|
<feature var='http://jabber.org/protocol/muc'/>
|
|
</query>
|
|
</iq>
|
|
]]></example>
|
|
|
|
<p>The client MUST check the identities and supported features against the 'ver' value by calculating the hash as described under <link url='#ver'>Generating the ver Attribute</link> and making sure that the values match. If the values do not match, the client MUST NOT accept the 'ver' value as reliable and SHOULD check the value of another user who advertises that value (if any). This helps to prevent poisoning of entity capabilities information.</p>
|
|
|
|
</section2>
|
|
|
|
<section2 topic='Stream Feature' anchor='stream'>
|
|
<p>A server MAY include its own entity capabilities in a stream feature element so that connecting clients and peer servers do not need to send service discovery requests each time they connect:</p>
|
|
<example caption='Stream feature element including capabilities'><![CDATA[
|
|
<stream:features>
|
|
<c xmlns='http://jabber.org/protocol/caps'
|
|
node='http://jabberd.org/entity'
|
|
ver='ItBTI0XLDFvVxZ72NQElAzKS9sU='>
|
|
</stream:features>
|
|
]]></example>
|
|
</section2>
|
|
</section1>
|
|
|
|
<section1 topic='Server Optimizations' anchor='optimizations'>
|
|
<p>A server that is managing an entity's session MAY choose to optimize traffic through the server. In this case, the server MAY strip off redundant capabilities annotations. Because of this, receivers of annotations MUST NOT expect an annotation on every presence packet they receive. If the server wants to perform this traffic optimization, it MUST ensure that the first presence each subscriber receives contains the annotation. The server MUST also ensure that any changes in the annotation (typically in the <strong>'ext'</strong> attribute) are sent to all subscribers.</p>
|
|
|
|
<p>A client MAY query the server using <strong>disco#info</strong> to determine if the server supports the <strong>'http://jabber.org/protocol/caps'</strong> feature. If so, the server MUST perform the optimization delineated above, and the client MAY choose to send the capabilities annotation only on the first presence packet, as well as whenever its capabilities change.</p>
|
|
|
|
<example caption='Disco#info request for server optimization'><![CDATA[
|
|
<iq from='juliet@capulet.lit/balcony'
|
|
to='capulet.lit'
|
|
type='get'>
|
|
<query xmlns='http://jabber.org/protocol/disco#info'/>
|
|
</iq>
|
|
|
|
<iq from='capulet.lit'
|
|
to='juliet@capulet.lit/balcony'
|
|
type='result'>
|
|
<query xmlns='http://jabber.org/protocol/disco#info'>
|
|
...
|
|
<feature var='http://jabber.org/protocol/caps'/>
|
|
...
|
|
</query>
|
|
</iq>
|
|
]]></example>
|
|
</section1>
|
|
|
|
<section1 topic='Implementation Notes' anchor='impl'>
|
|
<p>If two entities exchanges messages but they do not normally exchange presence (i.e., via presence subscription), the entities MAY choose to send directed presence to each other, where the presence information SHOULD be annotated with the same capabilities information as each entity sends in broadcasted presence. If capabilities information has not been received from another entity, an application MUST assume that the other entity does not support capabilities.</p>
|
|
</section1>
|
|
|
|
<section1 topic='Error Codes' anchor='error'>
|
|
<p>No application-specific error codes are defined by this document. See <strong>XEP-0030: Service Discovery</strong> for a list of potential service discovery error codes.</p>
|
|
</section1>
|
|
|
|
<section1 topic='Security Considerations' anchor='security'>
|
|
<p>Use of the protocol specified in this document might make some client-specific forms of attack slightly easier, since the attacker could more easily determine the type of client being used. However, since most clients respond to <strong>jabber:iq:version</strong> requests without performing access control checks, there is no new vulnerability. Entities that wish to restrict access to capabilities information SHOULD use &xep0016; to define appropriate communications blocking (e.g., an entity MAY choose to allow IQ requests only from "trusted" entities, such as those with whom it has a subscription of "both").</p>
|
|
<p>Adherence to the algorithm defined in the <link url='#ver'>Generation of ver Attribute</link> sectio of this document helps to guard against poisoning of entity capabilities information by malicious or improperly implemented entities.</p>
|
|
</section1>
|
|
|
|
<section1 topic='IANA Considerations' anchor='iana'>
|
|
<p>This document requires no interaction with &IANA;. </p>
|
|
</section1>
|
|
|
|
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
|
|
<section2 topic='Protocol Namespaces' anchor='ns'>
|
|
<p>The ®ISTRAR; includes 'http://jabber.org/protocol/caps' in its registry of protocol namespaces (see &NAMESPACES;).</p>
|
|
</section2>
|
|
</section1>
|
|
|
|
<section1 topic='XML Schema' anchor='schema'>
|
|
<code><![CDATA[
|
|
<?xml version='1.0' encoding='UTF-8'?>
|
|
|
|
<xs:schema
|
|
xmlns:xs='http://www.w3.org/2001/XMLSchema'
|
|
targetNamespace='http://jabber.org/protocol/caps'
|
|
xmlns='http://jabber.org/protocol/caps'
|
|
elementFormDefault='qualified'>
|
|
|
|
<xs:annotation>
|
|
<xs:documentation>
|
|
The protocol documented by this schema is defined in
|
|
XEP-0115: http://www.xmpp.org/extensions/xep-0115.html
|
|
</xs:documentation>
|
|
</xs:annotation>
|
|
|
|
<xs:element name='c'>
|
|
<xs:complexType>
|
|
<xs:simpleContent>
|
|
<xs:extension base='empty'>
|
|
<xs:attribute name='ext' type='xs:NMTOKENS' use='optional'/>
|
|
<xs:attribute name='hash' type='xs:NMTOKEN' use='optional' default='sha-1'/>
|
|
<xs:attribute name='node' type='xs:string' use='optional'/>
|
|
<xs:attribute name='ver' type='xs:string' use='required'/>
|
|
</xs:extension>
|
|
</xs:simpleContent>
|
|
</xs:complexType>
|
|
</xs:element>
|
|
|
|
<xs:simpleType name='empty'>
|
|
<xs:restriction base='xs:string'>
|
|
<xs:enumeration value=''/>
|
|
</xs:restriction>
|
|
</xs:simpleType>
|
|
|
|
</xs:schema>
|
|
]]></code>
|
|
</section1>
|
|
|
|
<section1 topic='Legacy Format' anchor='legacy'>
|
|
<p>Before Version 1.4 of this specification, the 'node' attribute was required, the 'ver' attribute was generated differently, and the 'ext' attribute was used more extensively. For historical purposes, Version 1.3 of this specification is archived at <<link url='http://www.xmpp.org/extensions/attic/xep-0115-1.3.html'>http://www.xmpp.org/extensions/attic/xep-0115-1.3.html</link>>. For backward-compatibility with the legacy format, the 'node' attribute is REQUIRED and the 'ext' attribute MAY be included.</p>
|
|
</section1>
|
|
|
|
<section1 topic='Acknowledgements' anchor='ack'>
|
|
<p>Thanks to Rachel Blackman, Dave Cridland, Richard Dobson, Sergei Golovan, Justin Karneges, Jacek Konieczny, Ian Paterson, Kevin Smith, Tomasz Sterna, and Michal Vaner for comments and suggestions.</p>
|
|
</section1>
|
|
|
|
</xep>
|