<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep xmlns="">
    <header>
        <title>PEP Native Bookmarks</title>
        <abstract>This specification defines a syntax and storage profile for keeping a list of chatroom bookmarks on the server.</abstract>
        
<legal>
<copyright>This XMPP Extension Protocol is copyright © 1999 – 2024 by the <link url="https://xmpp.org/">XMPP Standards Foundation</link> (XSF).</copyright>
<permissions>Permission is hereby granted, free of charge, to any person obtaining a copy of this specification (the "Specification"), to make use of the Specification without restriction, including without limitation the rights to implement the Specification in a software program, deploy the Specification in a network service, and copy, modify, merge, publish, translate, distribute, sublicense, or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the condition that the foregoing copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. Unless separate permission is granted, modified works that are redistributed shall not contain misleading information regarding the authors, title, number, or publisher of the Specification, and shall not claim endorsement of the modified works by the authors, any organization or project to which the authors belong, or the XMPP Standards Foundation.</permissions>
<warranty>## NOTE WELL: This Specification is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. ##</warranty>
<liability>In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall the XMPP Standards Foundation or any author of this Specification be liable for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising from, out of, or in connection with the Specification or the implementation, deployment, or other use of the Specification (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if the XMPP Standards Foundation or such author has been advised of the possibility of such damages.</liability>
<conformance>This XMPP Extension Protocol has been contributed in full conformance with the XSF's Intellectual Property Rights Policy (a copy of which can be found at &lt;<link url="https://xmpp.org/about/xsf/ipr-policy">https://xmpp.org/about/xsf/ipr-policy</link>&gt; or obtained by writing to XMPP Standards Foundation, P.O. Box 787, Parker, CO 80134 USA).</conformance>
</legal>
        <number>0402</number>
        <status>Draft</status>
        <lastcall>2020-03-03</lastcall>
        <lastcall>2020-02-12</lastcall>
        <type>Standards Track</type>
        <sig>Standards</sig>
        <approver>Council</approver>
        <dependencies>
          <spec>XEP-0223</spec>
        </dependencies>
        <supersedes>
          <spec>XEP-0411</spec>
        </supersedes>
        <supersededby/>
        <shortname>bookmarks2</shortname>
        <registry/>
        <discuss>standards</discuss>
        
    <author>
      <firstname>Dave</firstname>
      <surname>Cridland</surname>
      <email>dave@hellopando.com</email>
      <jid>dwd@dave.cridland.net</jid>
    </author>

        
  <author>
    <firstname>JC</firstname>
    <surname>Brand</surname>
    <email>jc@opkode.com</email>
    <jid>jc@opkode.com</jid>
  </author>

        <revision>
          <version>1.2.0</version>
          <date>2024-08-15</date>
          <initials>mye</initials>
          <remark><p>Encourage clients to immediately leave the room if they receive a bookmark notification with autojoin set to false</p></remark>
        </revision>
        <revision>
          <version>1.1.4</version>
          <date>2023-04-02</date>
          <initials>egp</initials>
          <remark><p>Recommend setting pubsub#max_items to 'max' instead of some arbitrary large number</p></remark>
        </revision>
        <revision>
          <version>1.1.3</version>
          <date>2021-12-27</date>
          <initials>egp</initials>
          <remark><p>Add missing &lt;supersedes/&gt; for XEP-0411</p></remark>
        </revision>
        <revision>
          <version>1.1.2</version>
          <date>2021-02-03</date>
          <initials>egp</initials>
          <remark><p>Add fixed anchors to all sections</p></remark>
        </revision>
        <revision>
          <version>1.1.1</version>
          <date>2020-06-02</date>
          <initials>mb</initials>
          <remark><p>Fix missing minOccurs=0 in schema</p></remark>
        </revision>
        <revision>
          <version>1.1.0</version>
          <date>2020-05-26</date>
          <initials>mb</initials>
          <remark><p>Add schema + other editorial changes</p></remark>
        </revision>
  <revision>
    <version>1.0.0</version>
    <date>2020-03-31</date>
    <initials>XEP Editor (jsc)</initials>
    <remark><p>Advanced to Draft per Council vote from 2020-03-04.</p></remark>
  </revision>
  <revision>
    <version>0.4.0</version>
    <date>2020-02-13</date>
    <initials>dwd</initials>
    <remark><ul>
      <li>Remove sense of humour</li>
        <li>Re-add Password field</li>
        <li>Add metadata container</li>
        <li>Show edit flow</li>
    </ul></remark>
  </revision>
  <revision>
    <version>0.3.0</version>
    <date>2019-09-28</date>
    <initials>egp</initials>
    <remark><ul>
      <li>Fix examples.</li>
      <li>Explain the expected workflow better.</li>
      <li>Encourage clients to set pubsub#send_last_published_item to never and pubsub#max_items to some high value.</li>
      <li>Add examples about notifications and +notify.</li>
      <li>Request clients to add notify='1' on retraction requests, so they do trigger notifications (see <link url="https://xmpp.org/extensions/xep-0060.html#publisher-delete-success-notify">XEP-0060 §7.2.2.1</link> for a rationale).</li>
      <li>Announce a feature when the server supports compat between old <span class="ref"><link url="https://xmpp.org/extensions/xep-0048.html">Bookmark Storage (XEP-0048)</link></span> <note>XEP-0048: Bookmark Storage &lt;<link url="https://xmpp.org/extensions/xep-0048.html">https://xmpp.org/extensions/xep-0048.html</link>&gt;.</note> (version 1.0) and this specification, and another between current <span class="ref"><link url="https://xmpp.org/extensions/xep-0048.html">Bookmark Storage (XEP-0048)</link></span> <note>XEP-0048: Bookmark Storage &lt;<link url="https://xmpp.org/extensions/xep-0048.html">https://xmpp.org/extensions/xep-0048.html</link>&gt;.</note> (version 1.1) and this specification.</li>
    </ul></remark>
  </revision>
  <revision>
    <version>0.2.1</version>
    <date>2018-07-22</date>
    <initials>egp</initials>
    <remark><ul>
      <li>Add missing dependency on XEP-0223.</li>
      <li>Remove extra whitespace at the end of examples.</li>
    </ul></remark>
  </revision>
  <revision>
    <version>0.2.0</version>
    <date>2018-03-28</date>
    <initials>jcb</initials>
    <remark>Remove password element, add examples, update security considerations.</remark>
  </revision>
  <revision>
    <version>0.1.0</version>
    <date>2018-03-28</date>
    <initials>XEP Editor (jwi)</initials>
    <remark>Accepted by vote of Council on 2018-03-21.</remark>
  </revision>
        <revision>
            <version>0.0.1</version>
            <date>2018-03-17</date>
            <initials>dwd/jcb</initials>
            <remark><p>First draft</p></remark>
        </revision>
    </header>
    <section1 topic="Introduction" anchor="intro">
        <p>The original Bookmarks specification (<span class="ref"><link url="https://xmpp.org/extensions/xep-0048.html">Bookmark Storage (XEP-0048)</link></span> <note>XEP-0048: Bookmark Storage &lt;<link url="https://xmpp.org/extensions/xep-0048.html">https://xmpp.org/extensions/xep-0048.html</link>&gt;.</note>) used the widely available
            Private XML Storage (<span class="ref"><link url="https://xmpp.org/extensions/xep-0049.html">Private XML Storage (XEP-0049)</link></span> <note>XEP-0049: Private XML Storage &lt;<link url="https://xmpp.org/extensions/xep-0049.html">https://xmpp.org/extensions/xep-0049.html</link>&gt;.</note>), but stored all bookmarks in a single element.
            When the specification was moved to the Standards Track and Draft, it was also
            updated to use the user's Pubsub service (<span class="ref"><link url="https://xmpp.org/extensions/xep-0223.html">Best Practices for Persistent Storage of Private Data via Publish-Subscribe (XEP-0223)</link></span> <note>XEP-0223: Best Practices for Persistent Storage of Private Data via Publish-Subscribe &lt;<link url="https://xmpp.org/extensions/xep-0223.html">https://xmpp.org/extensions/xep-0223.html</link>&gt;.</note>), but kept this single element
            containing all bookmarks inside a single Pubsub item.</p>
        <p>Most implementations have kept to the original, Private XML Storage based solution, and
            while some newer implementations have used Pubsub, these are limited in capability by the use of
            a single item, which prevents safe atomic updates of individual bookmarks.</p>
        <p>Finally, while some clients used custom XML elements to store additional private metadata about
        bookmarks, this was usually stripped when any bookmark was edited by another client.</p>
        <p>This specification resolves all three issues by providing a new Bookmarks specification to migrate to,
            and takes the opportunity to update the XML namespace in use as well. The URL storage is dropped,
            since it is rarely used. Storage of URL bookmarks is therefore out of scope.</p>
        <p>This specification was originally entitled "Bookmarks 2: This Time It's Serious". Any implication of a sense
            of humour has been removed with the change in title.</p>
    </section1>

    <section1 topic="Outline of use" anchor="usage">
        <p>Clients store each bookmarked chatroom as a Pubsub item within the 'urn:xmpp:bookmarks:1' node. Each
            item SHALL have, as item id, the Room JID of the chatroom (eg, coven@chat.shakespeare.lit). While a client can
        typically assume a chatroom based on <span class="ref"><link url="https://xmpp.org/extensions/xep-0045.html">Multi-User Chat (XEP-0045)</link></span> <note>XEP-0045: Multi-User Chat &lt;<link url="https://xmpp.org/extensions/xep-0045.html">https://xmpp.org/extensions/xep-0045.html</link>&gt;.</note>, clients are free to store chatrooms based on any particular groupchat
        protocol.</p>
        <p>The payload of the item SHALL be a conference element qualified by the 'urn:xmpp:bookmarks:1' namespace, with the following syntax:</p>
        <table caption="Syntax of conference element">
            <tr>
                <th>Element or Attribute</th>
                <th>Definition</th>
                <th>Datatype</th>
                <th>Inclusion</th>
            </tr>
            <tr>
                <td>'autojoin' attribute</td>
                <td>Whether the client should automatically join the conference room on login.</td>
                <td>boolean defaulting to false <note>In accordance with Section 3.2.2.1 of <cite>XML Schema Part 2: Datatypes</cite>, the allowable lexical representations for the xs:boolean datatype are the strings "0" and "false" for the concept 'false' and the strings "1" and "true" for the concept 'true'; implementations MUST support both styles of lexical representation.</note></td>
                <td>OPTIONAL</td>
            </tr>
            <tr>
                <td>'name' attribute</td>
                <td>A friendly name for the bookmark, specified by the user. Clients SHOULD NOT attempt to autogenerate this from the JID.</td>
                <td>string</td>
                <td>OPTIONAL</td>
            </tr>
            <tr>
                <td>&lt;nick/&gt; element</td>
                <td>The user's preferred roomnick for the chatroom, if different to that specified by <span class="ref"><link url="https://xmpp.org/extensions/xep-0172.html">User Nickname (XEP-0172)</link></span> <note>XEP-0172: User Nickname &lt;<link url="https://xmpp.org/extensions/xep-0172.html">https://xmpp.org/extensions/xep-0172.html</link>&gt;.</note>. In the absence of this element being present, the nickname from <span class="ref"><link url="https://xmpp.org/extensions/xep-0172.html">User Nickname (XEP-0172)</link></span> <note>XEP-0172: User Nickname &lt;<link url="https://xmpp.org/extensions/xep-0172.html">https://xmpp.org/extensions/xep-0172.html</link>&gt;.</note> SHOULD be used if present.</td>
                <td>string</td>
                <td>OPTIONAL</td>
            </tr>
            <tr>
                <td>&lt;password/&gt; element</td>
                <td>A password used to access the chatroom. Note this is not intended to be a secure storage.</td>
                <td>string</td>
                <td>OPTIONAL</td>
            </tr>
            <tr>
                <td>&lt;extensions/&gt; element</td>
                <td>A set of child elements (of potentially any namespace). Clients MUST preserve these (particularly preserving unknown elements) when editing items.</td>
                <td>XML Elements</td>
                <td>OPTIONAL</td>
            </tr>
        </table>
        <p>Note: The datatypes are as defined in <span class="ref"><link url="http://www.w3.org/TR/xmlschema11-2/">XML Schema Part 2</link></span> <note>XML Schema Part 2: Datatypes &lt;<link url="http://www.w3.org/TR/xmlschema11-2/">http://www.w3.org/TR/xmlschema11-2/</link>&gt;.</note>.</p>
        <example caption="An example of the conference element"><![CDATA[
<conference xmlns=']]>urn:xmpp:bookmarks:1<![CDATA['
            name='Council of Oberon'
            autojoin='true'>
  <nick>Puck</nick>
</conference>
]]></example>
        <p>This bookmark would be displayed as 'Council of Oberon' and, if activated, would attempt to join the conference room 'council@conference.underhill.org' with nickname 'Puck'.</p>
        <p>Note that a bookmark item MUST contain only one conference room.</p>
        <p>Note also that a conference element has no truly mandatory attributes or child elements, thus the following is legal:</p>
        <example caption="Minimalist conference element"><![CDATA[
<conference xmlns=']]>urn:xmpp:bookmarks:1<![CDATA['/>
]]></example>
    </section1>

    <section1 topic="Workflow" anchor="workflow">

        <section2 topic="Registering to receive notifications" anchor="enable-updates">
            <p>A client interested in bookmarks SHOULD include the 'urn:xmpp:bookmarks:1+notify' feature in its <span class="ref"><link url="https://xmpp.org/extensions/xep-0115.html">Entity Capabilities (XEP-0115)</link></span> <note>XEP-0115: Entity Capabilities &lt;<link url="https://xmpp.org/extensions/xep-0115.html">https://xmpp.org/extensions/xep-0115.html</link>&gt;.</note>, as per <span class="ref"><link url="https://xmpp.org/extensions/xep-0163.html">Personal Eventing Protocol (XEP-0163)</link></span> <note>XEP-0163: Personal Eventing Protocol &lt;<link url="https://xmpp.org/extensions/xep-0163.html">https://xmpp.org/extensions/xep-0163.html</link>&gt;.</note>, so that it receives notifications for updates done by other clients of the user, and reacts accordingly.  The actual notifications are explained in the <link url="#notifications">Bookmark Notifications</link> section of this specification.</p>

            <example caption="Client replies with +notify to a XEP-0030 query from its server"><![CDATA[
<iq from='juliet@capulet.lit/balcony' to='capulet.lit' type='result' id='disco1'>
  <query xmlns='http://jabber.org/protocol/disco#info'>
    <identity category='client' type='pc' name='poezio'/>
    <feature var='http://jabber.org/protocol/disco#info'/>
    <feature var=']]>urn:xmpp:bookmarks:1<![CDATA[+notify'/>
    <!-- … -->
  </query>
</iq>
]]></example>
        </section2>

        <section2 topic="Retrieving all bookmarks" anchor="retrieving-bookmarks">
            <p>Once connected, a client first retrieves the current list of bookmarks.  It then SHOULD join every MUC identified by the items’ 'id' attribute that have an 'autojoin' attribute that is set to "true" or "1".</p>
            <p>NOTE: A future version of this specification might refer to <span class="ref"><link url="https://xmpp.org/extensions/xep-0312.html">PubSub Since (XEP-0312)</link></span> <note>XEP-0312: PubSub Since &lt;<link url="https://xmpp.org/extensions/xep-0312.html">https://xmpp.org/extensions/xep-0312.html</link>&gt;.</note> or a similar protocol to reduce the need for full synchronisation on each connection.</p>
            <example caption="Client retrieves all bookmarks"><![CDATA[
<iq from='juliet@capulet.lit/balcony' type='get' id='retrieve1'>
  <pubsub xmlns='http://jabber.org/protocol/pubsub'>
    <items node=']]>urn:xmpp:bookmarks:1<![CDATA['/>
  </pubsub>
</iq>
]]></example>
            <example caption="Server returns the bookmarks"><![CDATA[
<iq type='result'
    to='juliet@capulet.lit/balcony'
    id='retrieve1'>
  <pubsub xmlns='http://jabber.org/protocol/pubsub'>
    <items node=']]>urn:xmpp:bookmarks:1<![CDATA['>
      <item id='theplay@conference.shakespeare.lit'>
        <conference xmlns=']]>urn:xmpp:bookmarks:1<![CDATA['
                    name='The Play&apos;s the Thing'
                    autojoin='true'>
          <nick>JC</nick>
        </conference>
      </item>
      <item id='orchard@conference.shakespeare.lit'>
        <conference xmlns=']]>urn:xmpp:bookmarks:1<![CDATA['
                    name='The Orcard'
                    autojoin='1'>
          <nick>JC</nick>
          <extensions>
            <state xmlns='http://myclient.example/bookmark/state' minimized='true'/>
          </extensions>
        </conference>
      </item>
    </items>
  </pubsub>
</iq>
]]></example>
        </section2>

        <section2 topic="Adding a bookmark" anchor="adding-a-bookmark">
            <p>Adding a bookmark means publishing a new item, with the bookmark JID as id, to the 'urn:xmpp:bookmarks:1' node.</p>
            <p>publish-options (as defined in <link url="https://xmpp.org/extensions/xep-0060.xml#publisher-publish-options">XEP-0060</link>) MUST be supported by the server in order to check that the node is correctly configured before publishing a new conference.  This is especially important to avoid leaking your bookmarks to your contacts for instance.</p>

            <example caption="Client adds a new bookmark"><![CDATA[
<iq from='juliet@capulet.lit/balcony' type='set' id='pip1'>
  <pubsub xmlns='http://jabber.org/protocol/pubsub'>
    <publish node=']]>urn:xmpp:bookmarks:1<![CDATA['>
      <item id='theplay@conference.shakespeare.lit'>
        <conference xmlns=']]>urn:xmpp:bookmarks:1<![CDATA['
                    name='The Play&apos;s the Thing'
                    autojoin='true'>
          <nick>JC</nick>
        </conference>
      </item>
    </publish>
    <publish-options>
      <x xmlns='jabber:x:data' type='submit'>
        <field var='FORM_TYPE' type='hidden'>
          <value>http://jabber.org/protocol/pubsub#publish-options</value>
        </field>
        <field var='pubsub#persist_items'>
          <value>true</value>
        </field>
        <field var='pubsub#max_items'>
          <value>max</value>
        </field>
        <field var='pubsub#send_last_published_item'>
          <value>never</value>
        </field>
        <field var='pubsub#access_model'>
          <value>whitelist</value>
        </field>
      </x>
    </publish-options>
  </pubsub>
</iq>
]]></example>
            <example caption="Server acknowledges successful storage"><![CDATA[
<iq to='juliet@capulet.lit/balcony' type='result' id='pip1'/>
]]></example>
        </section2>

        <section2 topic="Editing a bookmark" anchor="adding-a-bookmark">
            <p>Editing a bookmark means republishing the item, with the same bookmark JID as id, to the 'urn:xmpp:bookmarks:1' node.</p>
            <p>Note that clients MUST preserve any XML elements they do not understand, particularly including unknown elements, within the &lt;extensions/&gt; element of the bookmark.</p>
            <p>publish-options (as defined in <link url="https://xmpp.org/extensions/xep-0060.xml#publisher-publish-options">XEP-0060</link>) MUST be supported by the server in order to check that the node is correctly configured before publishing a new conference.  This is especially important to avoid leaking your bookmarks to your contacts for instance.</p>

            <example caption="Client corrects typo in name of bookmark"><![CDATA[
<iq from='juliet@capulet.lit/balcony' type='set' id='pip2'>
  <pubsub xmlns='http://jabber.org/protocol/pubsub'>
    <publish node=']]>urn:xmpp:bookmarks:1<![CDATA['>
      <item id='orchard@conference.shakespeare.lit'>
        <conference xmlns=']]>urn:xmpp:bookmarks:1<![CDATA['
                    name='The Orchard'
                    autojoin='true'>
          <nick>JC</nick>
          <extensions>
            <state xmlns='http://myclient.example/bookmark/state' minimized='true'/>
          </extensions>
        </conference>
      </item>
    </publish>
    <publish-options>
      <x xmlns='jabber:x:data' type='submit'>
        <field var='FORM_TYPE' type='hidden'>
          <value>http://jabber.org/protocol/pubsub#publish-options</value>
        </field>
        <field var='pubsub#persist_items'>
          <value>true</value>
        </field>
        <field var='pubsub#max_items'>
          <value>max</value>
        </field>
        <field var='pubsub#send_last_published_item'>
          <value>never</value>
        </field>
        <field var='pubsub#access_model'>
          <value>whitelist</value>
        </field>
      </x>
    </publish-options>
  </pubsub>
</iq>
]]></example>
            <example caption="Server acknowledges successful storage"><![CDATA[
<iq to='juliet@capulet.lit/balcony' type='result' id='pip2'/>
]]></example>
        </section2>

        <section2 topic="Removing a bookmark" anchor="removing-a-bookmark">
            <p>Removing a bookmark means retracting an existing item, identified by the bookmark's JID, form the 'urn:xmpp:bookmarks:1' node.</p>
            <p>This implies that server support for the "delete-items" pubsub feature is REQUIRED.</p>
            <p>A 'notify' attribute SHOULD be included on the &lt;retract/&gt; element in order to inform other online clients of the deletion.</p>

            <example caption="Client removes a new bookmark"><![CDATA[
<iq from='juliet@capulet.lit/balcony' type='set' id='remove-bookmark1'>
  <pubsub xmlns='http://jabber.org/protocol/pubsub'>
    <retract node=']]>urn:xmpp:bookmarks:1<![CDATA[' notify='true'>
      <item id='theplay@conference.shakespeare.lit'/>
    </retract>
  </pubsub>
</iq>
]]></example>
            <example caption="Server acknowledges successful retraction"><![CDATA[
<iq to='juliet@capulet.lit/balcony' type='result' id='remove-bookmark1'/>
]]></example>
        </section2>

    </section1>


    <section1 topic="Bookmark Notifications" anchor="notifications">
        <p>When a client is sent an event from the Pubsub service for the 'urn:xmpp:bookmarks:1' node, it SHOULD join the room immediately if the 'autojoin' attribute is both present and true.</p>

        <example caption="Client receives a new bookmark notification"><![CDATA[
<message from='juliet@capulet.lit' to='juliet@capulet.lit/balcony' type='headline' id='new-room1'>
  <event xmlns='http://jabber.org/protocol/pubsub#event'>
    <items node=']]>urn:xmpp:bookmarks:1<![CDATA['>
      <item id='theplay@conference.shakespeare.lit'>
        <conference xmlns=']]>urn:xmpp:bookmarks:1<![CDATA['
                    name='The Play&apos;s the Thing'
                    autojoin='1'>
          <nick>JC</nick>
        </conference>
      </item>
    </items>
  </event>
</message>
]]></example>

        <p>If the bookmark notification's 'autojoin' attribute is set to false, the client SHOULD leave the room immediately.</p>

        <example caption="Client receives a bookmark notification with autojoin='false' (its default value)"><![CDATA[
<message from='juliet@capulet.lit' to='juliet@capulet.lit/balcony' type='headline' id='unjoined-room1'>
  <event xmlns='http://jabber.org/protocol/pubsub#event'>
    <items node=']]>urn:xmpp:bookmarks:1<![CDATA['>
      <item id='theplay@conference.shakespeare.lit'>
        <conference xmlns=']]>urn:xmpp:bookmarks:1<![CDATA['
                    name='The Play&apos;s the Thing'>
          <nick>JC</nick>
        </conference>
      </item>
    </items>
  </event>
</message>
]]></example>

        <p>On the other hand, if the event is a retract notification, the client SHOULD leave the room immediately.</p>

        <example caption="Client receives a bookmark retraction notification"><![CDATA[
<message from='juliet@capulet.lit' to='juliet@capulet.lit/balcony' type='headline' id='removed-room1'>
  <event xmlns='http://jabber.org/protocol/pubsub#event'>
    <items node=']]>urn:xmpp:bookmarks:1<![CDATA['>
      <retract id='theplay@conference.shakespeare.lit'/>
    </items>
  </event>
</message>
]]></example>
    </section1>

    <section1 topic="Implementation Notes" anchor="impl">
        <section2 topic="Differences to XEP-0048" anchor="diff-0048">
            <ul>
                <li>The conference element does not contain the jid - this is present only in the item id.</li>
                <li>Each conference element is contained within an item.</li>
                <li>The storage MUST be <span class="ref"><link url="https://xmpp.org/extensions/xep-0223.html">Best Practices for Persistent Storage of Private Data via Publish-Subscribe (XEP-0223)</link></span> <note>XEP-0223: Best Practices for Persistent Storage of Private Data via Publish-Subscribe &lt;<link url="https://xmpp.org/extensions/xep-0223.html">https://xmpp.org/extensions/xep-0223.html</link>&gt;.</note></li>
            </ul>
        </section2>
        <section2 topic="Storage" anchor="storage">
            <p><span class="ref"><link url="https://xmpp.org/extensions/xep-0060.html">Publish-Subscribe (XEP-0060)</link></span> <note>XEP-0060: Publish-Subscribe &lt;<link url="https://xmpp.org/extensions/xep-0060.html">https://xmpp.org/extensions/xep-0060.html</link>&gt;.</note> is used for data storage, specifically through the use of private, personal pubsub nodes (described in <span class="ref"><link url="https://xmpp.org/extensions/xep-0223.html">Best Practices for Persistent Storage of Private Data via Publish-Subscribe (XEP-0223)</link></span> <note>XEP-0223: Best Practices for Persistent Storage of Private Data via Publish-Subscribe &lt;<link url="https://xmpp.org/extensions/xep-0223.html">https://xmpp.org/extensions/xep-0223.html</link>&gt;.</note>) hosted at the user's virtual pubsub service (see <span class="ref"><link url="https://xmpp.org/extensions/xep-0163.html">Personal Eventing Protocol (XEP-0163)</link></span> <note>XEP-0163: Personal Eventing Protocol &lt;<link url="https://xmpp.org/extensions/xep-0163.html">https://xmpp.org/extensions/xep-0163.html</link>&gt;.</note>).</p>
        </section2>
        <section2 topic="Compatibility" anchor="compatibility">
            <p>A server MAY choose to unify the bookmarks from both <span class="ref"><link url="https://xmpp.org/extensions/xep-0049.html">Private XML Storage (XEP-0049)</link></span> <note>XEP-0049: Private XML Storage &lt;<link url="https://xmpp.org/extensions/xep-0049.html">https://xmpp.org/extensions/xep-0049.html</link>&gt;.</note> based and the current <span class="ref"><link url="https://xmpp.org/extensions/xep-0048.html">Bookmark Storage (XEP-0048)</link></span> <note>XEP-0048: Bookmark Storage &lt;<link url="https://xmpp.org/extensions/xep-0048.html">https://xmpp.org/extensions/xep-0048.html</link>&gt;.</note>.</p>
            <p>It is encouraged to at least support unification between Private XML Storage because as of 2019 this is still the storage backend that is implemented in the majority of clients.</p>
            <p>A server that supports unifying bookmarks from <span class="ref"><link url="https://xmpp.org/extensions/xep-0049.html">Private XML Storage (XEP-0049)</link></span> <note>XEP-0049: Private XML Storage &lt;<link url="https://xmpp.org/extensions/xep-0049.html">https://xmpp.org/extensions/xep-0049.html</link>&gt;.</note> and <span class="ref"><link url="https://xmpp.org/extensions/xep-0402.html">PEP Native Bookmarks (XEP-0402)</link></span> <note>XEP-0402: PEP Native Bookmarks &lt;<link url="https://xmpp.org/extensions/xep-0402.html">https://xmpp.org/extensions/xep-0402.html</link>&gt;.</note> SHOULD announce the "urn:xmpp:bookmarks:1#compat" feature on the account. Clients may use that feature as an indication that it is safe to store bookmarks using only <span class="ref"><link url="https://xmpp.org/extensions/xep-0402.html">PEP Native Bookmarks (XEP-0402)</link></span> <note>XEP-0402: PEP Native Bookmarks &lt;<link url="https://xmpp.org/extensions/xep-0402.html">https://xmpp.org/extensions/xep-0402.html</link>&gt;.</note> without losing backward compatibility to clients that are only using <span class="ref"><link url="https://xmpp.org/extensions/xep-0049.html">Private XML Storage (XEP-0049)</link></span> <note>XEP-0049: Private XML Storage &lt;<link url="https://xmpp.org/extensions/xep-0049.html">https://xmpp.org/extensions/xep-0049.html</link>&gt;.</note>.</p>
            <p>A server that supports unifying bookmarks between <span class="ref"><link url="https://xmpp.org/extensions/xep-0223.html">Best Practices for Persistent Storage of Private Data via Publish-Subscribe (XEP-0223)</link></span> <note>XEP-0223: Best Practices for Persistent Storage of Private Data via Publish-Subscribe &lt;<link url="https://xmpp.org/extensions/xep-0223.html">https://xmpp.org/extensions/xep-0223.html</link>&gt;.</note> and <span class="ref"><link url="https://xmpp.org/extensions/xep-0402.html">PEP Native Bookmarks (XEP-0402)</link></span> <note>XEP-0402: PEP Native Bookmarks &lt;<link url="https://xmpp.org/extensions/xep-0402.html">https://xmpp.org/extensions/xep-0402.html</link>&gt;.</note> SHOULD announce the "urn:xmpp:bookmarks:1#compat-pep" feature on the account.</p>
            <section3 topic="Publishing via this specification" anchor="publishing">
            <p>When a client publishes a new item, the server MAY collate all items, casting them into the 'storage:bookmarks' namespace and setting the jid attribute to the item id in each case. When contained within a storage element qualified by the 'storage:bookmarks' namespace, this will be the correct format for both current and previous variants of <span class="ref"><link url="https://xmpp.org/extensions/xep-0048.html">Bookmark Storage (XEP-0048)</link></span> <note>XEP-0048: Bookmark Storage &lt;<link url="https://xmpp.org/extensions/xep-0048.html">https://xmpp.org/extensions/xep-0048.html</link>&gt;.</note></p>
            </section3>
            <section3 topic="Publishing via the old specification" anchor="publishing-legacy">
                <p>If a client publishes a replacement list of bookmarks via the older specifications, a server MAY examine the list and update the individual items as required, sending updates or retraction notifications as needed. Servers electing to perform this OPTIONAL behaviour SHOULD NOT send notifications for unchanged items.</p>
            </section3>
        </section2>
    </section1>

    <section1 topic="Determining Support" anchor="support">
        <p>This specification relies fully on a number of others. Most particularly, support for this protocol is available if <span class="ref"><link url="https://xmpp.org/extensions/xep-0223.html">Best Practices for Persistent Storage of Private Data via Publish-Subscribe (XEP-0223)</link></span> <note>XEP-0223: Best Practices for Persistent Storage of Private Data via Publish-Subscribe &lt;<link url="https://xmpp.org/extensions/xep-0223.html">https://xmpp.org/extensions/xep-0223.html</link>&gt;.</note> is supported.</p>
        <p>Server side unification between <span class="ref"><link url="https://xmpp.org/extensions/xep-0049.html">Private XML Storage (XEP-0049)</link></span> <note>XEP-0049: Private XML Storage &lt;<link url="https://xmpp.org/extensions/xep-0049.html">https://xmpp.org/extensions/xep-0049.html</link>&gt;.</note> bookmarks and PEP Native Bookmarks is announced with the feature "urn:xmpp:bookmarks:1#compat" on the account.</p>
        <p>Server side unification between the current use of XEP-0048 bookmarks (PEP) is annouced with the feature "urn:xmpp:bookmarks:1#compat-pep" on the account.</p>
    </section1>

    <section1 topic="Acknowledgements" anchor="ack">
        <p>The authors would like to note that much of the syntax description was copied exactly from <span class="ref"><link url="https://xmpp.org/extensions/xep-0048.html">Bookmark Storage (XEP-0048)</link></span> <note>XEP-0048: Bookmark Storage &lt;<link url="https://xmpp.org/extensions/xep-0048.html">https://xmpp.org/extensions/xep-0048.html</link>&gt;.</note> by Rachel Blackman, Peter Millard, and Peter Saint-Andre. Much of the remainder of this specification is based closely on their work.</p>
    </section1>

    <section1 topic="Security Considerations" anchor="security">
        <p>Security considerations related to object persistence via publish-subscribe are described in <span class="ref"><link url="https://xmpp.org/extensions/xep-0060.html">Publish-Subscribe (XEP-0060)</link></span> <note>XEP-0060: Publish-Subscribe &lt;<link url="https://xmpp.org/extensions/xep-0060.html">https://xmpp.org/extensions/xep-0060.html</link>&gt;.</note> and <cite>XEP-0223</cite>.</p>
        <p>The client needs to make sure that the server actually supports the "http://jabber.org/protocol/pubsub#publish-options" feature, before relying on it. If it's not supported, the client should configure the 'urn:xmpp:bookmarks:1' node first (see <cite>xep-0060</cite>), before adding any bookmarks.</p>
    </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=']]>urn:xmpp:bookmarks:1<![CDATA['
    xmlns=']]>urn:xmpp:bookmarks:1<![CDATA['
    elementFormDefault='qualified'>

  <xs:annotation>
    <xs:documentation>
      The protocol documented by this schema is defined in
      XEP-0402: http://www.xmpp.org/extensions/xep-0402.html
    </xs:documentation>
  </xs:annotation>

  <xs:element name='conference'>
    <xs:complexType>
      <xs:sequence>
        <xs:element name='nick' type='xs:string' minOccurs='0'/>
        <xs:element name='password' type='xs:string' minOccurs='0'/>
        <xs:element ref='extensions' minOccurs='0' />
      </xs:sequence>
      <xs:attribute name='autojoin' type='xs:boolean' use='optional' default='false'/>
      <xs:attribute name='name' type='xs:string' use='optional'/>
    </xs:complexType>
  </xs:element>

  <xs:element name='extensions'>
    <xs:complexType>
      <xs:sequence>
        <xs:any namespace='##other'
                minOccurs='0'
                maxOccurs='unbounded'
                processContents='lax'/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>]]></code>
    </section1>
</xep>
