1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2025-09-09 09:09:38 +02:00

Migrate markdown documentation to javadoc

While markdown is easier to write, Smack's markdown documentation was
never tightly coupled with the source. For example, the markdown
documentation never provided links to the actual Java classes and
methods. This poses the risk that the documentation and the code
diverge over time. Furthermore, javadoc is constantly improving (for
example @snippet annotations) and I expect that one will be able to
write javadoc in markdown.

Fixes SMACK-928.
This commit is contained in:
Florian Schmaus 2023-02-03 09:36:54 +01:00
parent f65cf45b5c
commit c9a9982cef
101 changed files with 4441 additions and 5754 deletions

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2016-2017 Fernando Ramirez, 2016-2020 Florian Schmaus
* Copyright 2016-2017 Fernando Ramirez, 2016-2022 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -44,7 +44,15 @@ import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jxmpp.jid.Jid;
/**
* Blocking command manager class.
* Block communications with contancts and other entities using XEP-0191.
* Allows to
* <ul>
* <li>Check push notifications support</li>
* <li>Get blocking list</li>
* <li>Block contact</li>
* <li>Unblock conact</li>
* <li>Unblock all</li>
* </ul>
*
* @author Fernando Ramirez
* @author Florian Schmaus

View file

@ -1,6 +1,6 @@
/**
*
* Copyright © 2009 Jonas Ådahl, 2011-2021 Florian Schmaus
* Copyright © 2009 Jonas Ådahl, 2011-2022 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -77,7 +77,41 @@ import org.jxmpp.jid.Jid;
import org.jxmpp.util.cache.LruCache;
/**
* Keeps track of entity capabilities.
* Manages own and others Entity Capabilities (XEP-0115).
* <p>
* Entity Capabilities is an XMPP extension which, in order to minimize network impact, caches the capabilities of
* remote XMPP entities. Those capabilities are determine with the help of the Service Discovery Protocol
* (<a href="https://xmpp.org/extensions/xep-0030.html">XEP-0030</a>, {@link ServiceDiscoveryManager}).
* </p>
*
* <h2>Usage</h2>
* <p>
* Entity Capabilities work silently in the background when enabled. If the remote XMPP entity does not support XEP-0115
* but XEP-0030 then XEP-0030 mechanisms are transparently used.
* </p>
* <p>
* The caches used by Smack for Entity Capabilities is non-persisent per default. However, it is is also possible to set
* a persistent Entity Capabilities cache, which is recommended.
* </p>
* <h2>Examples</h2>
*
* <h3>Enable Entity Capabilities</h3>
* <pre>{@code
* // Get an instance of entity caps manager for the specified connection
* EntityCapsManager mgr = EntityCapsManager.getInstanceFor(connection);
* // Enable entity capabilities
* mgr.enableEntityCaps();
* }</pre>
*
* <h3>Configure a persistent cache for Entity Capabilities</h3>
* <pre>{@code
* // Get an instance of entity caps manager for the specified connection
* EntityCapsManager mgr = EntityCapsManager.getInstanceFor(connection);
* // Create an cache, see smackx.entitycaps.cache for pre-defined cache implementations
* EntityCapsPersistentCache cache = new SimpleDirectoryPersistentCache(new File("/foo/cachedir"));
* // Set the cache
* mgr.setPersistentCache(cache);
* }</pre>
*
* @author Florian Schmaus
* @see <a href="http://www.xmpp.org/extensions/xep-0115.html">XEP-0115: Entity Capabilities</a>

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2022 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,6 @@
*/
/**
* Smacks implementation of XEP-0115: Entity Capabilities.
* Smacks implementation of XEP-0115: Entity Capabilities, see {@link EntityCapsManager} for more information.
*/
package org.jivesoftware.smackx.caps;

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2022 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,193 @@
*/
/**
* Smacks implementation of XEP-0030: Service Discovery.
* Smack's API for Service Discovery (XEP-0030). The service discovery extension allows one to discover items
* and information about XMPP entities.
* <h2>Manage XMPP entity features</h2>
* <h3>Description</h3>
* <p>
* Any XMPP entity may receive a discovery request and must answer with its associated items or information. Therefore,
* your Smack client may receive a discovery request that must respond to (i.e., if your client supports XHTML- IM).
* This extension automatically responds to a discovery request with the information that you previously configured.
* </p>
* <h3>Usage</h3>
* <p>
* In order to configure the supported features by your client you should first obtain the ServiceDiscoveryManager
* associated with your XMPPConnection. To get your ServiceDiscoveryManager send **getInstanceFor(connection)** to the
* class _**ServiceDiscoveryManager**_ where connection is your XMPPConnection.
* </p>
* <p>
* Once you have your ServiceDiscoveryManager you will be able to manage the supported features. To register a new
* feature send **addFeature(feature)** to your _**ServiceDiscoveryManager**_ where feature is a String that represents
* the supported feature. To remove a supported feature send removeFeature(feature)** to your
* _**ServiceDiscoveryManager**_ where feature is a String that represents the feature to remove.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to add and remove supported features:
* </p>
*
* <pre>{@code
* // Obtain the ServiceDiscoveryManager associated with my XMPP connection
* ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection);
* // Register that a new feature is supported by this XMPP entity
* discoManager.addFeature(namespace1);
* // Remove the specified feature from the supported features
* discoManager.removeFeature(namespace2);
* }</pre>
*
* <h2>Provide node information</h2>
* <h3>Description</h3>
* <p>
* Your XMPP entity may receive a discovery request for items non-addressable as a JID such as the MUC rooms where you
* are joined. In order to answer the correct information it is necessary to configure the information providers
* associated to the items/nodes within the Smack client.
* </p>
* <h3>Usage</h3>
* <p>
* In order to configure the associated nodes within the Smack client you will need to create a NodeInformationProvider
* and register it with the _**ServiceDiscoveryManager**_. To get your ServiceDiscoveryManager send
** getInstanceFor(connection)** to the class _**ServiceDiscoveryManager**_ where connection is your XMPPConnection.
* </p>
* <p>
* Once you have your ServiceDiscoveryManager you will be able to register information providers for the XMPP entity's
* nodes. To register a new node information provider send **setNodeInformationProvider(String node,
* NodeInformationProvider listener)** to your _**ServiceDiscoveryManager**_ where node is the item non-addressable as a
* JID and listener is the _**NodeInformationProvider**_ to register. To unregister a _**NodeInformationProvider**_ send
* **removeNodeInformationProvider(String node)** to your _**ServiceDiscoveryManager**_ where node is the item non-
* addressable as a JID whose information provider we want to unregister.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to register a NodeInformationProvider with a ServiceDiscoveryManager that will provide
* information concerning a node named "http://jabber.org/protocol/muc#rooms":
* </p>
*
* <pre>{@code
* // Obtain the ServiceDiscoveryManager associated with my XMPPConnection
* ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection);
* // Get the items of a given XMPP entity
* // This example gets the items associated with online catalog service
* DiscoverItems discoItems = discoManager.discoverItems("plays.shakespeare.lit");
* // Get the discovered items of the queried XMPP entity
* Iterator it = discoItems.getItems().iterator();
* // Display the items of the remote XMPP entity
* while (it.hasNext()) {
* DiscoverItems.Item item = (DiscoverItems.Item) it.next();
* System.out.println(item.getEntityID());
* System.out.println(item.getNode());
* System.out.println(item.getName());
* }
* }</pre>
*
* <h2>Discover items associated with an XMPP entity</h2>
* <h3>Description</h3>
* <p>
* In order to obtain information about a specific item you have to first discover the items available in an XMPP
* entity.
* </p>
* <h3>Usage</h3>
* <p>
* Once you have your ServiceDiscoveryManager you will be able to discover items associated with an XMPP entity. To
* discover the items of a given XMPP entity send **discoverItems(entityID)** to your _**ServiceDiscoveryManager**_
* where entityID is the ID of the entity. The message **discoverItems(entityID)** will answer an instance of
* _**DiscoverItems**_ that contains the discovered items.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to discover the items associated with an online catalog service:
* </p>
*
* <pre>{@code
* // Obtain the ServiceDiscoveryManager associated with my XMPPConnection
* ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection);
* // Get the items of a given XMPP entity
* // This example gets the items associated with online catalog service
* DiscoverItems discoItems = discoManager.discoverItems("plays.shakespeare.lit");
* // Get the discovered items of the queried XMPP entity
* Iterator it = discoItems.getItems().iterator();
* // Display the items of the remote XMPP entity
* while (it.hasNext()) {
* DiscoverItems.Item item = (DiscoverItems.Item) it.next();
* System.out.println(item.getEntityID());
* System.out.println(item.getNode());
* System.out.println(item.getName());
* }
* }</pre>
*
* <h2>Discover information about an XMPP entity</h2>
* <h3>Description</h3>
* <p>
* Once you have discovered the entity ID and name of an item, you may want to find out more about the item. The
* information desired generally is of two kinds: 1) The item's identity and 2) The features offered by the item.
* </p>
* <p>
* This information helps you determine what actions are possible with regard to this item (registration, search, join,
* etc.) as well as specific feature types of interest, if any (e.g., for the purpose of feature negotiation).
* </p>
* <h3>Usage</h3>
* <p>
* Once you have your ServiceDiscoveryManager you will be able to discover information associated with an XMPP entity.
* To discover the information of a given XMPP entity send **discoverInfo(entityID)** to your
* _**ServiceDiscoveryManager**_ where entityID is the ID of the entity. The message **discoverInfo(entityID)** will
* answer an instance of _**DiscoverInfo**_ that contains the discovered information.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to discover the information of a conference room:
* </p>
*
* <pre>{@code
* // Obtain the ServiceDiscoveryManager associated with my XMPPConnection
* ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection);
* // Get the information of a given XMPP entity
* // This example gets the information of a conference room
* DiscoverInfo discoInfo = discoManager.discoverInfo("balconyscene@plays.shakespeare.lit");
* // Get the discovered identities of the remote XMPP entity
* Iterator it = discoInfo.getIdentities().iterator();
* // Display the identities of the remote XMPP entity
* while (it.hasNext()) {
* DiscoverInfo.Identity identity = (DiscoverInfo.Identity) it.next();
* System.out.println(identity.getName());
* System.out.println(identity.getType());
* System.out.println(identity.getCategory());
* }
* // Check if room is password protected
* discoInfo.containsFeature("muc_passwordprotected");
* }</pre>
*
* <h2>Publish publicly available items</h2>
* <h3>Description</h3>
* <p>
* Publish your entity items to some kind of persistent storage. This enables other entities to query that entity using
* the disco#items namespace and receive a result even when the entity being queried is not online (or available).
* </p>
* <h3>Usage</h3>
* <p>
* Once you have your ServiceDiscoveryManager you will be able to publish items to some kind of persistent storage. To
* publish the items of a given XMPP entity you have to first create an instance of _**DiscoverItems**_ and configure it
* with the items to publish. Then you will have to send publishItems(Jid entityID, DiscoverItems discoverItems)** to
* your _**ServiceDiscoveryManager**_ where entityID is the address of the XMPP entity that will persist the items and
* discoverItems contains the items to publish.
* </p>
* <h3>Examples</h3> In this example we can see how to publish new items:
*
* <pre>{@code
* // Obtain the ServiceDiscoveryManager associated with my XMPPConnection
* ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection);
* // Create a DiscoverItems with the items to publish
* DiscoverItems itemsToPublish = new DiscoverItems();
* Jid jid = JidCreate.from("pubsub.shakespeare.lit");
* DiscoverItems.Item itemToPublish = new DiscoverItems.Item(jid);
* itemToPublish.setName("Avatar");
* itemToPublish.setNode("romeo/avatar");
* itemToPublish.setAction(DiscoverItems.Item.UPDATE_ACTION);
* itemsToPublish.addItem(itemToPublish);
* // Publish the new items by sending them to the server
* Jid jid2 = JidCreate.from("host");
* discoManager.publishItems(jid2, itemsToPublish);
* }</pre>
*
* @see <a href="https://www.xmpp.org/extensions/xep-0030.html">XEP-0030: Service Discovery</a>
*/
package org.jivesoftware.smackx.disco;

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2022 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,156 @@
*/
/**
* File Transfers via XEP-0095: Stream Initialization.
* Smack's API for File Transfers. The file transfer extension allows the user to transmit and receive files.
* <ul>
* <li>Send a file to another user</li>
* <li>Receiving a file from another user</li>
* <li>Monitoring the progress of a file transfer</li>
* </ul>
* <h2>Send a file to another user</h2>
* <h3>Description</h3>
* <p>
* A user may wish to send a file to another user. The other user has the option of accepting, rejecting, or ignoring
* the users request. Smack provides a simple interface in order to enable the user to easily send a file.
* </p>
* <h3>Usage</h3>
* <p>
* In order to send a file you must first construct an instance of the _FileTransferManager_** class. In order to
* instantiate the manager you should call _FileTransferManager.getInstanceFor(connection)_, where connection is an
* XMPPConnection instance.
* </p>
* <p>
* Once you have your **_FileTransferManager_** you will need to create an outgoing file transfer to send a file. The
* method to use on the _FileTransferManager_** is the **createOutgoingFileTransfer(userID)** method. The userID you
* provide to this method is the fully-qualified jabber ID of the user you wish to send the file to. A fully-qualified
* jabber ID consists of a node, a domain, and a resource. The user must be connected to the resource in order to be
* able to receive the file transfer.
* </p>
* <p>
* Now that you have your **_OutgoingFileTransfer_** instance you will want to send the file. The method to send a file
* is **sendFile(file, description)**. The file you provide to this method should be a readable file on the local file
* system, and the description is a short description of the file to help the user decide whether or not they would like
* to receive the file.
* </p>
* <p>
* For information on monitoring the progress of a file transfer see the monitoring progress section of this document.
* </p>
* <p>
* Other means to send a file are also provided as part of the _OutgoingFileTransfer_**. Please consult the Javadoc for
* more information.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to send a file:
* </p>
*
* <pre>{@code
* // Create the file transfer manager
* FileTransferManager manager = FileTransferManager.getInstanceFor(connection);
* // Create the outgoing file transfer
* OutgoingFileTransfer transfer = manager.createOutgoingFileTransfer(entityFullJid);
* // Send the file
* transfer.sendFile(new File("shakespeare_complete_works.txt"), "You won't believe this!");
* }</pre>
*
* <h2>Receiving a file from another user</h2>
* <h3>Description</h3>
* <p>
* The user may wish to receive files from another user. The process of receiving a file is event driven, new file
* transfer requests are received from other users via a listener registered with the file transfer manager.
* </p>
* <h3>Usage</h3>
* <p>
* In order to receive a file you must first construct an instance of the _FileTransferManager_** class. This class has
* one static factory method with one parameter which is your XMPPConnection. In order to instantiate the manager you
* should call _FileTransferManager.getInstanceFor(connection)_.
* </p>
* <p>
* Once you have your **_FileTransferManager_** you will need to register a listener with it. The FileTransferListener
* interface has one method, fileTransferRequest(request)**. When a request is received through this method, you can
* either accept or reject the request. To help you make your decision there are several methods in the
* **_FileTransferRequest_** class that return information about the transfer request.
* </p>
* <p>
* To accept the file transfer, call the **accept()** method. This method will create an _IncomingFileTransfer_**. After
* you have the file transfer you may start to transfer the file by calling the **recieveFile(file)** method. The file
* provided to this method will be where the data from the file transfer is saved.
* </p>
* <p>
* Finally, to reject the file transfer the only method you need to call is reject()** on the **_FileTransferRequest_**.
* </p>
* <p>
* For information on monitoring the progress of a file transfer see the monitoring progress section of this document.
* </p>
* <p>
* Other means to receive a file are also provided as part of the _IncomingFileTransfer_**. Please consult the Javadoc
* for more information.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to approve or reject a file transfer request:
* </p>
*
* <pre>{@code
* // Create the file transfer manager
* final FileTransferManager manager = FileTransferManager.getInstanceFor(connection);
* // Create the listener
* manager.addFileTransferListener(new FileTransferListener() {
* public void fileTransferRequest(FileTransferRequest request) {
* // Check to see if the request should be accepted
* if (shouldAccept(request)) {
* // Accept it
* IncomingFileTransfer transfer = request.accept();
* transfer.recieveFile(new File("shakespeare_complete_works.txt"));
* } else {
* // Reject it
* request.reject();
* }
* }
* });
* }</pre>
*
* <h2>Monitoring the progress of a file transfer</h2>
* <h3>Description</h3>
* <p>
* While a file transfer is in progress you may wish to monitor the progress of a file transfer.
* </p>
* <h3>Usage</h3>
* <p>
* Both the **_IncomingFileTransfer_** and the **_OutgoingFileTransfer_** extend the **_FileTransfer_** class which
* provides several methods to monitor how a file transfer is progressing:
* </p>
* <ul>
* <li>**getStatus()** - The file transfer can be in several states, negotiating, rejected, cancelled, in progress,
* error, and complete. This method will return which state the file transfer is currently in.</li>
* <li>**getProgress()** - If the status of the file transfer is in progress this method will return a number between 0
* and 1, 0 being the transfer has not yet started and 1 being the transfer is complete. It may also return a -1 if the
* transfer is not in progress.</li>
* <li>**isDone()** - Similar to getProgress() except it returns a _boolean_. If the state is rejected, canceled, error,
* or complete then true will be returned and false otherwise.</li>
* <li>**getError()** - If there is an error during the file transfer this method will return the type of error that
* occured.</li>
* </ul>
* <h3>Examples</h3>
* <p>
* In this example we can see how to monitor a file transfer:
* </p>
*
* <pre>{@code
* while (!transfer.isDone()) {
* if (transfer.getStatus().equals(Status.error)) {
* System.out.println("ERROR!!! " + transfer.getError());
* } else {
* System.out.println(transfer.getStatus());
* System.out.println(transfer.getProgress());
* }
* sleep(1000);
* }
* }</pre>
*
* @see <a href="https://xmpp.org/extensions/xep-0047.html">XEP-0047: In-Band Bytestreams</a>
* @see <a href="https://xmpp.org/extensions/xep-0065.html">XEP-0065: SOCKS5 Bytestreams</a> *
* @see <a href="https://xmpp.org/extensions/xep-0095.html">XEP-0095: Stream Initiation</a> *
* @see <a href="https://xmpp.org/extensions/xep-0096.html">XEP-0096: SI File Transfer</a> *
*/
package org.jivesoftware.smackx.filetransfer;

View file

@ -17,5 +17,19 @@
/**
* Smacks implementation of XEP-0049: Private XML Storage.
* <p>
* Manages private data, which is a mechanism to allow users to store arbitrary XML data on an XMPP server. Each private
* data chunk is defined by a element name and XML namespace. Example private data:
* </p>
*
* <pre>
* <code>
* &lt;color xmlns=&quot;http://example.com/xmpp/color&quot;&gt;
* &lt;favorite&gt;blue&lt;/blue&gt;
* &lt;leastFavorite&gt;puce&lt;/leastFavorite&gt;
* &lt;/color&gt;
* </code>
* </pre>
* @see <a href="https://xmpp.org/extensions/xep-0049.html">XEP-0049: Private XML Storage</a>
*/
package org.jivesoftware.smackx.iqprivate;

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2003-2007 Jive Software, 2014-2021 Florian Schmaus
* Copyright 2003-2007 Jive Software, 2014-2022 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -34,6 +34,72 @@ import org.jxmpp.jid.FullJid;
/**
* The Jingle element.
*
* <h2>Jingle Element Structure</h2>
* <pre>{@code
* jingle
* action (REQUIRED, XEP-0166 § 7.2)
* | content-accept
* | content-add
* | content-modify
* | content-reject
* | content-remove
* | description-info
* | security-info
* | session-accept
* | session-info
* | session-initiate
* | transport-accept
* | transport-info
* | transport-reject
* | transport-replace
* initator (RECOMMENDED for session initiate, NOT RECOMMENDED otherwise, full JID, XEP-0166 § 7.1)
* responder (RECOMMENDED for session accept, NOT RECOMMENDED otherwise, full JID. XEP-0166 § 7.1)
* sid (REQUIRED, SHOULD match XML Nmtoken production)
*
* <reason/> (optional, XEP-0166 § 7.4)
*
* (alternativesessionbusy..)
*
* <content/> (one or more, XEP-0166 § 7.3)
* creator (REQUIRED, must be one of)
* | initiator
* | responder
* disposition (OPTIONAL)
* name (REQUIRED)
* senders (OPTIONAL, except when content-modify then REQUIRED)
* | both (default)
* | initiator
* | none
* | responder
*
* description
* media
* xmlns
*
* payloadtype
*
* file (XEP0234)
*
* transport
* xmlns
* pwd (OPTIONAL, XEP-0176 Jingle ICE)
* ufrag (OPTIONAL, XEP-0176 Jingle ICE)
* mode (XEP-0234 Jingle File Transfer)
* sid (XEP-0234 Jingle File Transfer)
*
* candidate
* component
* foundation
* generation
* id
* ip
* network
* port
* priority
* protocol
* type
* }</pre>
*
* @author Florian Schmaus
*/
public final class Jingle extends IQ {

View file

@ -18,5 +18,89 @@
/**
* Smacks implementation for attaching arbitrary properties to packets according to
* https://docs.jivesoftware.com/smack/latest/documentation/properties.html.
* <p>
* Smack provides an easy mechanism for attaching arbitrary properties to packets. Each property has a String name, and
* a value that is a Java primitive (int, long, float, double, boolean) or any Serializable object (a Java object is
* Serializable when it implements the Serializable interface).
* </p>
* <h2 id="using-the-api">Using the API</h2>
* <p>
* All major objects have property support, such as Message objects. The following code demonstrates how to set
* properties:
* </p>
*
* <pre>
* <code>Message message = chat.createMessage();
JivePropertiesExtension jpe = new JivePropertiesExtension();
// Add a Color object as a property._
jpe.setProperty(&quot;favoriteColor&quot;, new Color(0, 0, 255));
// Add an int as a property._
jpe.setProperty(&quot;favoriteNumber&quot;, 4);
// Add the JivePropertiesExtension to the message packet_
message.addStanzaExtension(jpe);
chat.sendMessage(message);</code>
* </pre>
* <p>
* Getting those same properties would use the following code:
* </p>
*
* <pre>
* <code>
* Message message = chat.nextMessage();
* // Get the JivePropertiesExtension_
* JivePropertiesExtension jpe = message.getExtension(JivePropertiesExtension.NAMESPACE);
* // Get a Color object property._
* Color favoriteColor = (Color)jpe.getProperty(&quot;favoriteColor&quot;);
* // Get an int property. Note that properties are always returned as
* // Objects, so we must cast the value to an Integer, then convert
* // it to an int._
* int favoriteNumber = ((Integer)jpe.getProperty(&quot;favoriteNumber&quot;)).intValue();
* </code>
* </pre>
* <p>
* For convenience <code>JivePropertiesManager</code> contains two helper methods namely
* <code>addProperty(Stanza packet, String name, Object value)</code> and
* <code>getProperty(Stanza packet, String name)</code>.
* </p>
* <h2 id="objects-as-properties">Objects as Properties</h2>
* <p>
* Using objects as property values is a very powerful and easy way to exchange data. However, you should keep the
* following in mind:
* </p>
* <ul>
* <li>When you send a Java object as a property, only clients running Java will be able to interpret the data. So,
* consider using a series of primitive values to transfer data instead.</li>
* <li>Objects sent as property values must implement Serialiable. Additionally, both the sender and receiver must have
* identical versions of the class, or a serialization exception will occur when de-serializing the object.</li>
* <li>Serialized objects can potentially be quite large, which will use more bandwidth and server resources.</li>
* </ul>
* <h2 id="xml-format">XML Format</h2>
* <p>
* The current XML format used to send property data is not a standard, so will likely not be recognized by clients not
* using Smack. The XML looks like the following (comments added for clarity):
* </p>
*
* <pre>
* <code>
* &lt;!-- All properties are in a x block. --&gt;
* &lt;properties xmlns=&quot;http://www.jivesoftware.com/xmlns/xmpp/properties&quot;&gt;
* &lt;!-- First, a property named &quot;prop1&quot; that&#39;s an integer. --&gt;
* &lt;property&gt;
* &lt;name&gt;prop1&lt;/name&gt;
* &lt;value type=&quot;integer&quot;&gt;123&lt;/value&gt;
* &lt;property&gt;
* &lt;!-- Next, a Java object that&#39;s been serialized and then converted
* from binary data to base-64 encoded text. --&gt;
* &lt;property&gt;
* &lt;name&gt;blah2&lt;/name&gt;
* &lt;value type=&quot;java-object&quot;&gt;adf612fna9nab&lt;/value&gt;
* &lt;property&gt;
* &lt;/properties&gt;
* </code>
* </pre>
* <p>
* The currently supported types are: <code>integer</code>, <code>long</code>, <code>float</code>, <code>double</code>,
* <code>boolean</code>, <code>string</code>, and <code>java-object</code>.
* </p>
*/
package org.jivesoftware.smackx.jiveproperties;

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2023 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,674 @@
*/
/**
* Classes and Interfaces that implement Multi-User Chat (MUC) as defined in XEP-0045.
* Smack API for Multi-User Chat (MUC, XEP-0045). This API allows configuration of, participation in, and administration
* of individual text-based conference rooms. The two key API classes are {@link MultiUserChatManager} and
* {@link MultiUserChat}.
* <h2>Create a new Room</h2>
* <h3>Description</h3>
* <p>
* Allowed users may create new rooms. There are two types of rooms that you can create. **Instant rooms** which are
* available for immediate access and are automatically created based on some default configuration and **Reserved
* rooms** which are manually configured by the room creator before anyone is allowed to enter.
* </p>
* <h3>Usage</h3>
* <p>
* In order to create a room you will need to first create an instance of _* *MultiUserChat**_. In order to do so, get a
* instance of `MultiUserChatManager` and call `getMultiUserChat(String)` to retrieve a `MultiUserChat` instance. The
* next step is to send **create(String nickname)** to the _**MultiUserChat**_ instance where nickname is the nickname
* to use when joining the room. Depending on the type of room that you want to create you will have to use different
* configuration forms. In order to create an Instant room just use `MucCreateConfigFormHandle.makeInstant()`. But if
* you want to create a Reserved room then you should first get the room's configuration form, complete the form and
* finally send it back to the server.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to create an instant room:
* </p>
*
* <pre>{@code
* // Get the MultiUserChatManager
* MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
* // Get a MultiUserChat using MultiUserChatManager
* MultiUserChat muc = manager.getMultiUserChat(mucJid);
* // Create the room and send an empty configuration form to make this an instant room
* muc.create(nickname).makeInstant();
* }</pre>
* <p>
* In this example we can see how to create a reserved room. The form is completed with default values:
* </p>
*
* <pre>{@code
* // Get the MultiUserChatManager
* MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
* // Create a MultiUserChat using an XMPPConnection for a room
* MultiUserChat muc = manager.getMultiUserChat(mucJid);
* // Prepare a list of owners of the new room
* Set<Jid> owners = JidUtil.jidSetFrom(new String[] { "me@example.org", "juliet@example.org" });
* // Create the room
* muc.create(nickname).getConfigFormManger().setRoomOwners(owners).submitConfigurationForm();
* }</pre>
*
* <h2>Join a room</h2>
* <h3>Description</h3>
* <p>
* Your usual first step in order to send messages to a room is to join the room. Multi User Chat allows to specify
* several parameter while joining a room. Basically you can control the amount of history to receive after joining the
* room as well as provide your nickname within the room and a password if the room is password protected.
* </p>
* <h3>Usage</h3>
* <p>
* In order to join a room you will need to first get an instance of _**MultiUserChat**_. In order to do so, get a
* instance of `MultiUserChatManager` and call `getMultiUserChat(String)` to retrieve a `MultiUserChat` instance. The
* next step is to send **join(...)** to the _**MultiUserChat**_ instance. But first you will have to decide which join
* message to send. If you want to just join the room without a password and without specifying the amount of history to
* receive then you could use join(String nickname)** where nickname if your nickname in the room. In case the room
* requires a password in order to join you could then use **join(String nickname, String password)**. And finally, the
* most complete way to join a room is to send **join(String nickname, String password, DiscussionHistory history, long
* timeout)** where nickname is your nickname in the room, , password is your password to join the room, history is an
* object that specifies the amount of history to receive and timeout is the milliseconds to wait for a response from
* the server.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to join a room with a given nickname:
* </p>
*
* <pre>{@code
* // Get the MultiUserChatManager
* MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
* // Create a MultiUserChat using an XMPPConnection for a room
* MultiUserChat muc2 = manager.getMultiUserChat(mucJid);
* // User2 joins the new room
* // The room service will decide the amount of history to send
* muc2.join(nickname);
* }</pre>
* <p>
* In this example we can see how to join a room with a given nickname and password:
* </p>
*
* <pre>{@code
* // Get the MultiUserChatManager
* MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
* // Create a MultiUserChat using an XMPPConnection for a room
* MultiUserChat muc2 = manager.getMultiUserChat(mucJid);
* // User2 joins the new room using a password
* // The room service will decide the amount of history to send
* muc2.join(nickname, "password");
* }</pre>
* <p>
* In this example we can see how to join a room with a given nickname specifying the amount of history to receive:
* </p>
*
* <pre>{@code
* // Get the MultiUserChatManager
* MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
*
* // Create a MultiUserChat using an XMPPConnection for a room
* MultiUserChat muc2 = manager.getMultiUserChat(mucJid);
*
* // User2 joins the new room using a password and specifying
* // the amount of history to receive. In this example we are requesting the last 5 messages.
* DiscussionHistory history = new DiscussionHistory();
* history.setMaxStanzas(5);
* muc2.join(nickname, "password", history, conn1.getPacketReplyTimeout());
* }</pre>
*
* <h2>Manage room invitations</h2>
* <h3>Description</h3>
* <p>
* It can be useful to invite another user to a room in which one is an occupant. Depending on the room's type the
* invitee could receive a password to use to join the room and/or be added to the member list if the room is of type
* members-only. Smack allows to send room invitations and let potential invitees to listening for room invitations and
* inviters to listen for invitees' rejections.
* </p>
* <h3>Usage</h3>
* <p>
* In order to invite another user to a room you must be already joined to the room. Once you are joined just send
* **invite(String participant, String reason)** to the _**MultiUserChat**_ where participant is the user to invite to
* the room (e.g. hecate@shakespeare.lit) and reason is the reason why the user is being invited.
* </p>
* <p>
* If potential invitees want to listen for room invitations then the invitee must add an _**InvitationListener**_ to
* the _**MultiUserChatManager**_ class. Since the _**InvitationListener**_ is an _interface_, it is necessary to create
* a class that implements this _interface_. If an inviter wants to listen for room invitation rejections, just add an
* _**InvitationRejectionListener**_ to the _**MultiUserChat**_. _**InvitationRejectionListener**_ is also an interface
* so you will need to create a class that implements this interface.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to invite another user to the room and lister for possible rejections:
* </p>
*
* <pre>{@code
* // Get the MultiUserChatManager
* MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
*
* // Create a MultiUserChat using an XMPPConnection for a room
* MultiUserChat muc2 = manager.getMultiUserChat(mucJid);
*
* muc2.join(nickname);
* // User2 listens for invitation rejections
* muc2.addInvitationRejectionListener(new InvitationRejectionListener() {
* public void invitationDeclined(String invitee, String reason) {
* // Do whatever you need here...
* }
* });
* // User2 invites user3 to join to the room
* muc2.invite(otherJid, "Meet me in this excellent room");
* }</pre>
* <p>
* In this example we can see how to listen for room invitations and decline invitations:
* </p>
*
* <pre>{@code
* // User3 listens for MUC invitations
* MultiUserChatManager.getInstanceFor(connection).addInvitationListener(new InvitationListener() {
* public void invitationReceived(XMPPConnection conn, String room, EntityFullJid inviter, String reason,
* String password) {
* // Reject the invitation
* MultiUserChat.decline(conn, room, inviter.asBareJid(), "I'm busy right now");
* }
* });
* }</pre>
*
* <h2>Discover MUC support</h2>
* <h3>Description</h3>
* <p>
* A user may want to discover if one of the user's contacts supports the Multi-User Chat protocol.
* </p>
* <h3>Usage</h3>
* <p>
* In order to discover if one of the user's contacts supports MUC just send isServiceEnabled(String user)** to the
* _**MultiUserChatManager**_ class where user is a fully qualified XMPP ID, e.g. jdoe@example.com. You will receive a
* boolean indicating whether the user supports MUC or not.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to discover support of MUC:
* </p>
*
* <pre>{@code
* // Discover whether user3@host.org supports MUC or not
* boolean supportsMuc = MultiUserChatManager.getInstanceFor(connection).isServiceEnabled(otherJid);
* }</pre>
*
* <h2>Discover joined rooms</h2>
* <h3>Description</h3>
* <p>
* A user may also want to query a contact regarding which rooms the contact is in.
* </p>
* <h3>Usage</h3>
* <p>
* In order to get the rooms where a user is in just send getJoinedRooms(String user)** to the
* _**MultiUserChatManager**_ class where user is a fully qualified XMPP ID, e.g. jdoe@example.com. You will get an
* Iterator of Strings as an answer where each String represents a room name.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to get the rooms where a user is in:
* </p>
*
* <pre>{@code
* // Get the MultiUserChatManager
* MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
*
* // Get the rooms where user3@host.org has joined
* List<String> joinedRooms = manager.getJoinedRooms("user3@host.org/Smack");
* }</pre>
*
* <h2>Discover room information</h2>
* <h3>Description</h3>
* <p>
* A user may need to discover information about a room without having to actually join the room. The server will
* provide information only for public rooms.
* </p>
* <h3>Usage</h3>
* <p>
* In order to discover information about a room just send getRoomInfo(String room)** to the _**MultiUserChatManager**_
* class where room is the XMPP ID of the room, e.g. roomName@conference.myserver. You will get a RoomInfo object that
* contains the discovered room information.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to discover information about a room:
* </p>
*
* <pre>{@code
* // Get the MultiUserChatManager
* MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
*
* // Discover information about the room roomName@conference.myserver
* RoomInfo info = manager.getRoomInfo("roomName@conference.myserver");
* System.out.println("Number of occupants:" + info.getOccupantsCount());
* System.out.println("Room Subject:" + info.getSubject());
* }</pre>
*
* <h2>Start a private chat</h2>
* <h3>Description</h3>
* <p>
* A room occupant may want to start a private chat with another room occupant even though they don't know the fully
* qualified XMPP address (e.g. jdoe@example.com) of each other.
* </p>
* <h3>Usage</h3>
* <p>
* To create a private chat with another room occupant just send createPrivateChat(String participant)** to the
* _**MultiUserChat**_ that you used to join the room. The parameter participant is the occupant unique room JID (e.g.
* 'darkcave@macbeth.shakespeare.lit/Paul'). You will receive a regular _**Chat**_ object that you can use to chat with
* the other room occupant.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to start a private chat with another room occupant:
* </p>
*
* <pre>{@code
* // Start a private chat with another participant
* Chat chat = muc2.createPrivateChat("myroom@conference.jabber.org/johndoe");
* chat.sendMessage("Hello there");
* }</pre>
*
* <h2>Manage changes on room subject</h2>
* <h3>Description</h3>
* <p>
* A common feature of multi-user chat rooms is the ability to change the subject within the room. As a default, only
* users with a role of "moderator" are allowed to change the subject in a room. Although some rooms may be configured
* to allow a mere participant or even a visitor to change the subject.
* </p>
* <p>
* Every time the room's subject is changed you may want to be notified of the modification. The new subject could be
* used to display an in-room message.
* </p>
* <h3>Usage</h3>
* <p>
* In order to modify the room's subject just send **changeSubject(String subject)** to the _**MultiUserChat**_ that you
* used to join the room where subject is the new room's subject. On the other hand, if you want to be notified whenever
* the room's subject is modified you should add a _**SubjectUpdatedListener**_ to the _**MultiUserChat**_ by sending
** addSubjectUpdatedListener(SubjectUpdatedListener listener)** to the _**MultiUserChat**_. Since the
* _**SubjectUpdatedListener**_ is an _interface_, it is necessary to create a class that implements this _interface_.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to change the room's subject and react whenever the room's subject is modified:
* </p>
*
* <pre>{@code
* // An occupant wants to be notified every time the room's subject is changed
* muc3.addSubjectUpdatedListener(new SubjectUpdatedListener() {
* public void subjectUpdated(String subject, String from) {
* ....
* }
* });
* // A room's owner changes the room's subject
* muc2.changeSubject("New Subject");
* }</pre>
*
* <h2></h2>
* <h3>Description</h3>
* <p>
* There are four defined roles that an occupant can have:
* </p>
* <ol>
* <li>Moderator</li>
* <li>Participant</li>
* <li>Visitor</li>
* <li>None (the absence of a role)</li>
* </ol>
* <p>
* These roles are temporary in that they do not persist across a user's visits to the room and can change during the
* course of an occupant's visit to the room.
* </p>
* <p>
* A moderator is the most powerful occupant within the context of the room, and can to some extent manage other
* occupants' roles in the room. A participant has fewer privileges than a moderator, although he or she always has the
* right to speak. A visitor is a more restricted role within the context of a moderated room, since visitors are not
* allowed to send messages to all occupants.
* </p>
* <p>
* Roles are granted, revoked, and maintained based on the occupant's room nickname or full JID. Whenever an occupant's
* role is changed Smack will trigger specific events.
* </p>
* <h3>Usage</h3>
* <p>
* In order to grant voice (i.e. make someone a _participant_) just send the message **grantVoice(String nickname)** to
* _**MultiUserChat**_. Use revokeVoice(String nickname)** to revoke the occupant's voice (i.e. make the occupant a
* _visitor_).
* </p>
* <p>
* In order to grant moderator privileges to a participant or visitor just send the message **grantModerator(String
* nickname)** to _**MultiUserChat**_. Use revokeModerator(String nickname)** to revoke the moderator privilege from the
* occupant thus making the occupant a participant.
* </p>
* <p>
* Smack allows you to listen for role modification events. If you are interested in listening role modification events
* of any occupant then use the listener _ParticipantStatusListener_**. But if you are interested in listening for your
* own role modification events, use the listener **_UserStatusListener_**. Both listeners should be added to the
* _**MultiUserChat**_ by using addParticipantStatusListener(ParticipantStatusListener listener)** or
** addUserStatusListener(UserStatusListener listener)** respectively. These listeners include several notification
* events but you may be interested in just a few of them. Smack provides default implementations for these listeners
* avoiding you to implement all the interfaces' methods. The default implementations are
* **_DefaultUserStatusListener_** and _DefaultParticipantStatusListener_**. Below you will find the sent messages to
* the listeners whenever an occupant's role has changed.
* </p>
* <p>
* These are the triggered events when the role has been upgraded:
* </p>
* <table border="1">
* <caption>Role Upgrade paths</caption>
* <tr>
* <th>Old</th>
* <th>New</th>
* <th>Events</th>
* </tr>
* <tr>
* <td>None</td>
* <td>Visitor</td>
* <td>--</td>
* </tr>
* <tr>
* <td>Visitor</td>
* <td>Participant</td>
* <td>voiceGranted</td>
* </tr>
* <tr>
* <td>Participant</td>
* <td>Moderator</td>
* <td>moderatorGranted</td>
* </tr>
* <tr>
* <td>None</td>
* <td>Participant</td>
* <td>voiceGranted</td>
* </tr>
* <tr>
* <td>None</td>
* <td>Moderator</td>
* <td>voiceGranted + moderatorGranted</td>
* </tr>
* <tr>
* <td>Visitor</td>
* <td>Moderator</td>
* <td>voiceGranted + moderatorGranted</td>
* </tr>
* </table>
* <p>
* These are the triggered events when the role has been downgraded:
* </p>
* <table border="1">
* <caption>Role Downgrade paths</caption>
* <tr>
* <th>Old</th>
* <th>New</th>
* <th>Events</th>
* </tr>
* <tr>
* <td>Moderator</td>
* <td>Participant</td>
* <td>moderatorRevoked</td>
* </tr>
* <tr>
* <td>Participant</td>
* <td>Vistor</td>
* <td>voiceRevoked</td>
* </tr>
* <tr>
* <td>Visitor</td>
* <td>None</td>
* <td>kicked</td>
* </tr>
* <tr>
* <td>Moderator</td>
* <td>Visitor</td>
* <td>voiceRevoked + moderatorRevoked</td>
* </tr>
* <tr>
* <td>Moderator</td>
* <td>None</td>
* <td>kicked</td>
* </tr>
* <tr>
* <td>Participant</td>
* <td>None</td>
* <td>kicked</td>
* </tr>
* </table>
* <h3>Examples</h3>
* <p>
* In this example we can see how to grant voice to a visitor and listen for the notification events:
* </p>
*
* <pre>{@code
* // User1 creates a room
* muc = manager.getMultiUserChat("myroom@conference.jabber.org");
* muc.create("testbot");
* // User1 (which is the room owner) configures the room as a moderated room
* Form form = muc.getConfigurationForm();
* FillableForm answerForm = configForm.getFillableForm();
* answerForm.setAnswer("muc#roomconfig_moderatedroom", "1");
* muc.sendConfigurationForm(answerForm);
*
* // User2 joins the new room (as a visitor)
* MultiUserChat muc2 = manager2.getMultiUserChat("myroom@conference.jabber.org");
* muc2.join("testbot2");
* // User2 will listen for his own "voice" notification events
* muc2.addUserStatusListener(new DefaultUserStatusListener() {
* public void voiceGranted() {
* super.voiceGranted();
* ...
* }
* public void voiceRevoked() {
* super.voiceRevoked();
* ...
* }
* });
*
* // User3 joins the new room (as a visitor)
* MultiUserChat muc3 = manager3.getMultiUserChat("myroom@conference.jabber.org");
* muc3.join("testbot3");
* // User3 will lister for other occupants "voice" notification events
* muc3.addParticipantStatusListener(new DefaultParticipantStatusListener() {
* public void voiceGranted(String participant) {
* super.voiceGranted(participant);
* ...
* }
* public void voiceRevoked(String participant) {
* super.voiceRevoked(participant);
* ...
* }
* });
*
* // The room's owner grants voice to user2
* muc.grantVoice("testbot2");
* }</pre>
*
* <h2>Manage affiliation modifications</h2>
* <h3>Description</h3>
* <p>
* There are five defined affiliations that a user can have in relation to a room:
* </p>
* <ol>
* <li>Owner</li>
* <li>Admin</li>
* <li>Member</li>
* <li>Outcast</li>
* <li>None (the absence of an affiliation)</li>
* </ol>
* <p>
* These affiliations are semi-permanent in that they persist across a user's visits to the room and are not affected by
* happenings in the room. Affiliations are granted, revoked, and maintained based on the user's bare JID.
* </p>
* <p>
* If a user without a defined affiliation enters a room, the user's affiliation is defined as "none"; however, this
* affiliation does not persist across visits.
* </p>
* <p>
* Owners and admins are by definition immune from certain actions. Specifically, an owner or admin cannot be kicked
* from a room and cannot be banned from a room. An admin must first lose his or her affiliation (i.e., have an
* affiliation of "none" or "member") before such actions could be performed on them.
* </p>
* <p>
* The member affiliation provides a way for a room owner or admin to specify a "whitelist" of users who are allowed to
* enter a members-only room. When a member enters a members-only room, his or her affiliation does not change, no
* matter what his or her role is. The member affiliation also provides a way for users to effectively register with an
* open room and thus be permanently associated with that room in some way (one result may be that the user's nickname
* is reserved in the room).
* </p>
* <p>
* An outcast is a user who has been banned from a room and who is not allowed to enter the room. Whenever a user's
* affiliation is changed Smack will trigger specific events.
* </p>
* <h3>Usage</h3>
* <p>
* In order to grant membership to a room, administrator privileges or owner priveliges just send
* **grantMembership(String jid)**, **grantAdmin(String jid)** or **grantOwnership(String jid)** to _**MultiUserChat**_
* respectively. Use **revokeMembership(String jid)**, **revokeAdmin(String jid)** or revokeOwnership(String jid)** to
* revoke the membership to a room, administrator privileges or owner priveliges respectively.
* </p>
* <p>
* In order to ban a user from the room just send the message **banUser(String jid, String reason)** to
* _**MultiUserChat**_.
* </p>
* <p>
* Smack allows you to listen for affiliation modification events. If you are interested in listening affiliation
* modification events of any user then use the listener **_ParticipantStatusListener_**. But if you are interested in
* listening for your own affiliation modification events, use the listener _UserStatusListener_**. Both listeners
* should be added to the _**MultiUserChat**_ by using addParticipantStatusListener(ParticipantStatusListener
* listener)** or addUserStatusListener(UserStatusListener listener)** respectively. These listeners include several
* notification events but you may be interested in just a few of them. Smack provides default implementations for these
* listeners avoiding you to implement all the interfaces' methods. The default implementations are
* **_DefaultUserStatusListener_** and _DefaultParticipantStatusListener_**. Below you will find the sent messages to
* the listeners whenever a user's affiliation has changed.
* </p>
* <p>
* These are the triggered events when the affiliation has been upgraded:
* </p>
* <table border="1">
* <caption>Affiliation Upgrade paths</caption>
* <tr>
* <th>Old</th>
* <th>New</th>
* <th>Events</th>
* </tr>
* <tr>
* <td>None</td>
* <td>Member</td>
* <td>membershipGranted</td>
* </tr>
* <tr>
* <td>Member</td>
* <td>Admin</td>
* <td>membershipRevoked + adminGranted</td>
* </tr>
* <tr>
* <td>Admin</td>
* <td>Owner</td>
* <td>adminRevoked + ownershipGranted</td>
* </tr>
* <tr>
* <td>None</td>
* <td>Admin</td>
* <td>adminGranted</td>
* </tr>
* <tr>
* <td>None</td>
* <td>Owner</td>
* <td>ownershipGranted</td>
* </tr>
* <tr>
* <td>Member</td>
* <td>Owner</td>
* <td>membershipRevoked + ownershipGranted</td>
* </tr>
* </table>
* <p>
* These are the triggered events when the affiliation has been downgraded:
* </p>
* <table border="1">
* <caption>Affiliation Downgrade paths</caption>
* <tr>
* <th>Owner</th>
* <th>Admin</th>
* <th>ownershipRevoked + adminGranted</th>
* </tr>
* <tr>
* <td>Admin</td>
* <td>Member</td>
* <td>adminRevoked + membershipGranted</td>
* </tr>
* <tr>
* <td>Member</td>
* <td>None</td>
* <td>membershipRevoked</td>
* </tr>
* <tr>
* <td>Owner</td>
* <td>Member</td>
* <td>ownershipRevoked + membershipGranted</td>
* </tr>
* <tr>
* <td>Owner</td>
* <td>None</td>
* <td>ownershipRevoked</td>
* </tr>
* <tr>
* <td>Admin</td>
* <td>None</td>
* <td>adminRevoked</td>
* </tr>
* <tr>
* <td>Anyone</td>
* <td>Outcast</td>
* <td>banned</td>
* </tr>
* </table>
* <h3>Examples</h3>
* <p>
* In this example we can see how to grant admin privileges to a user and listen for the notification events:
* </p>
*
* <pre>{@code
* // User1 creates a room
* muc = manager.getMultiUserChat("myroom@conference.jabber.org");
* muc.create("testbot");
* // User1 (which is the room owner) configures the room as a moderated room
* Form form = muc.getConfigurationForm();
* FillableForm answerForm = configForm.getFillableForm();
* answerForm.setAnswer("muc#roomconfig_moderatedroom", "1");
* muc.sendConfigurationForm(answerForm);
*
* // User2 joins the new room (as a visitor)
* MultiUserChat muc2 = manager2.getMultiUserChat("myroom@conference.jabber.org");
* muc2.join("testbot2");
* // User2 will listen for his own admin privileges
* muc2.addUserStatusListener(new DefaultUserStatusListener() {
* public void membershipRevoked() {
* super.membershipRevoked();
* ...
* }
* public void adminGranted() {
* super.adminGranted();
* ...
* }
* });
*
* // User3 joins the new room (as a visitor)
* MultiUserChat muc3 = manager3.getMultiUserChat("myroom@conference.jabber.org");
* muc3.join("testbot3");
* // User3 will lister for other users admin privileges
* muc3.addParticipantStatusListener(new DefaultParticipantStatusListener() {
* public void membershipRevoked(String participant) {
* super.membershipRevoked(participant);
* ...
* }
* public void adminGranted(String participant) {
* super.adminGranted(participant);
* ...
* }
* });
* // The room's owner grants admin privileges to user2
* muc.grantAdmin("user2@jabber.org");
* }</pre>
*
* @see <a href="https://xmpp.org/extensions/xep-0045.html">XEP-0045: Multi-User Chat</a>
*/
package org.jivesoftware.smackx.muc;

View file

@ -1,21 +0,0 @@
/**
*
* Copyright 2015 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Integration tests.
*/
package org.jivesoftware.smackx;

View file

@ -17,5 +17,163 @@
/**
* Smacks implementation of XEP-0016: Privacy Lists.
* <h2 id="what-is-it">What is it?</h2>
* <p>
* <code>Privacy</code> is a method for users to block communications from particular other users. In XMPP this is done
* by managing ones privacy lists.
* </p>
* <p>
* Server-side privacy lists enable successful completion of the following use cases:
* </p>
* <ul>
* <li>Retrieving ones privacy lists.</li>
* <li>Adding, removing, and editing ones privacy lists.</li>
* <li>Setting, changing, or declining active lists.</li>
* <li>Setting, changing, or declining the default list (i.e., the list that is active by default).</li>
* <li>Allowing or blocking messages based on JID, group, or subscription type (or globally).</li>
* <li>Allowing or blocking inbound presence notifications based on JID, group, or subscription type (or globally).</li>
* <li>Allowing or blocking outbound presence notifications based on JID, group, or subscription type (or
* globally).</li>
* <li>Allowing or blocking IQ stanzas based on JID, group, or subscription type (or globally).</li>
* <li>Allowing or blocking all communications based on JID, group, or subscription type (or globally).</li>
* </ul>
* <h2 id="how-can-i-use-it">How can I use it?</h2>
* <p>
* The API implementation releases three main public classes:
* </p>
* <ul>
* <li><code>PrivacyListManager</code>: this is the main API class to retrieve and handle server privacy lists.</li>
* <li><code>PrivacyList</code>: witch represents one privacy list, with a name, a set of privacy items. For example,
* the list with visible or invisible.</li>
* <li><code>PrivacyItem</code>: block or allow one aspect of privacy. For example, to allow my friend to see my
* presence.</li>
* </ul>
* <ol type="1">
* <li>Right from the start, a client MAY <strong>get his/her privacy list</strong> that is stored in the server:</li>
* </ol>
*
* <pre>
* <code>
* // Create a privacy manager for the current connection._
* PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection);
* // Retrieve server privacy lists_
* PrivacyList[] lists = privacyManager.getPrivacyLists();
* </code>
* </pre>
* <p>
* Now the client is able to show every <code>PrivacyItem</code> of the server and also for every list if it is active,
* default or none of them. The client is a listener of privacy changes.
* </p>
* <ol start="2" type="1">
* <li>In order to <strong>add a new list in the server</strong>, the client MAY implement something like:</li>
* </ol>
*
* <pre>
* <code>
* // Set the name of the list_
* String listName = &quot;newList&quot;;
*
* // Create the list of PrivacyItem that will allow or deny some privacy aspect_
* String user = &quot;tybalt@example.com&quot;;
* String groupName = &quot;enemies&quot;;
* ArrayList privacyItems = new ArrayList();
*
* PrivacyItem item = new PrivacyItem(PrivacyItem.Type.jid, user, true, 1);
* privacyItems.add(item);
*
* item = new PrivacyItem(PrivacyItem.Type.subscription, PrivacyItem.SUBSCRIPTION_BOTH, true, 2);
* privacyItems.add(item);
*
* item = new PrivacyItem(PrivacyItem.Type.group, groupName, false, 3);
* item.setFilterMessage(true);
* privacyItems.add(item);
*
* // Get the privacy manager for the current connection._
* PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection);
* // Create the new list._
* privacyManager.createPrivacyList(listName, privacyItems);
* </code>
* </pre>
* <ol start="3" type="1">
* <li>To <strong>modify an existent list</strong>, the client code MAY be like:</li>
* </ol>
*
* <pre>
* <code>
* // Set the name of the list_
* String listName = &quot;existingList&quot;;
* // Get the privacy manager for the current connection._
* PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection);
* // Sent the new list to the server._
* privacyManager.updatePrivacyList(listName, items);
* </code>
* </pre>
* <p>
* Notice <code>items</code> was defined at the example 2 and MUST contain all the elements in the list (not the
* delta).
* </p>
* <ol start="4" type="1">
* <li>In order to <strong>delete an existing list</strong>, the client MAY perform something like:</li>
* </ol>
*
* <pre>
* <code>
* // Set the name of the list_
* String listName = &quot;existingList&quot;;
* // Get the privacy manager for the current connection._
* PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection);
* // Remove the list._
* privacyManager.deletePrivacyList(listName);
* </code>
* </pre>
* <ol start="5" type="1">
* <li>In order to <strong>decline the use of an active list</strong>, the client MAY perform something like:</li>
* </ol>
*
* <pre>
* <code>
* // Get the privacy manager for the current connection._
* PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection);
* // Decline the use of the active list._
* privacyManager.declineActiveList();
* </code>
* </pre>
* <ol start="6" type="1">
* <li>In order to <strong>decline the use of a default list</strong>, the client MAY perform something like:</li>
* </ol>
*
* <pre>
* <code>
* // Get the privacy manager for the current connection._
* PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection);
* // Decline the use of the default list._
* privacyManager.declineDefaultList();
* </code>
* </pre>
* <p>
* Listening for Privacy Changes
* </p>
* <p>
* In order to handle privacy changes, clients SHOULD listen managers updates. When a list is changed the manager
* notifies every added listener. Listeners MUST implement the <code>PrivacyListListener</code> interface. Clients may
* need to react when a privacy list is modified. The <code>PrivacyListManager</code> lets you add listerners that will
* be notified when a list has been changed. Listeners should implement the <code>PrivacyListListener</code> interface.
* </p>
* <p>
* The most important notification is <code>updatedPrivacyList</code> that is performed when a privacy list changes its
* privacy items.
* </p>
* <p>
* The listener becomes notified after performing:
* </p>
*
* <pre>
* <code>
* // Get the privacy manager for the current connection._
* PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection);
* // Add the listener (this) to get notified_
* privacyManager.addListener(this);
* </code>
* </pre>
*/
package org.jivesoftware.smackx.privacy;

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2023 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,390 @@
*/
/**
* Smack's API for XEP-0060: Publish-Subscribe.
* Smack's API for XEP-0060: Publish-Subscribe. XMPP based
* <a href="https://en.wikipedia.org/wiki/Publish/subscribe">publish and subscribe</a> is based around nodes to which
* items can be published. Subscribers of those nodes will be notified about new items.
* <h2>Node creation and configuration</h2>
* <h3>Description</h3>
* <p>
* Allowed users may create and configure pubsub nodes. There are two types of nodes that can be created, leaf nodes and
* collection nodes.
* </p>
* <ul>
* <li>Leaf Nodes - contains only messages</li>
* <li>Collection Nodes - contains only nodes (both Leaf and Collection are allowed), but no messages The current
* version of this API only supports Leaf Nodes. There are many configuration options available for nodes, but the two
* main options are whether the node is **persistent** or not and whether it will deliver payload or not.</li>
* </ul>
* <h3>Usage</h3>
* <p>
* In order to create a node you will need to first create an instance of _**PubSubManager**_. There are several options
* for node creation which range from creating an instant node, default configuration, or a fully configured node.
* </p>
* <h3>Examples</h3>
* <p>
* Create an instant node:
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = new PubSubManager(con);
*
* // Create the node
* LeafNode leaf = mgr.createNode();
* }</pre>
* <p>
* Create a node with default configuration and then configure it:
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
*
* // Create the node
* LeafNode leaf = mgr.createNode("testNode");
* ConfigureForm form = new ConfigureForm(FormType.submit);
* form.setAccessModel(AccessModel.open);
* form.setDeliverPayloads(false);
* form.setNotifyRetract(true);
* form.setPersistentItems(true);
* form.setPublishModel(PublishModel.open);
*
* leaf.sendConfigurationForm(form);
* }</pre>
* <p>
* Create and configure a node:
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
*
* // Create the node
* ConfigureForm form = new ConfigureForm(FormType.submit);
* form.setAccessModel(AccessModel.open);
* form.setDeliverPayloads(false);
* form.setNotifyRetract(true);
* form.setPersistentItems(true);
* form.setPublishModel(PublishModel.open);
* LeafNode leaf = mgr.createNode("testNode", form);
* }</pre>
*
* <h2>Publishing to a node</h2>
* <h3>Description</h3>
* <p>
* This section deals with the **publish** portion of pubsub. Usage of a node typically involves either sending or
* receiving data, referred to as items. Depending on the context of the nodes usage, the item being sent to it can have
* different properties. It can contain application data known as payload, or the publisher may choose to supply
* meaningful unique id's. Determination of an items acceptable properties is defined by a combination of node
* configuration and its purpose.
* </p>
* <h3>Usage</h3>
* <p>
* To publish to a node, you will have to either create or retrieve an existing node and then create and send items to
* that node. The ability for any given person to publish to the node will be dependent on its configuration.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we publish an item to a node that does not take payload:
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
*
* // Get the node
* LeafNode node = mgr.getNode("testNode");
*
* // Publish an Item, let service set the id
* node.send(new Item());
*
* // Publish an Item with the specified id
* node.send(new Item("123abc"));
* }</pre>
* <p>
* In this example we publish an item to a node that does take payload:
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
*
* // Get the node
* LeafNode node = mgr.getNode("testNode");
*
* // Publish an Item with payload
* node.send(new PayloadItem("test" + System.currentTimeMillis(),
* new SimplePayload("book", "pubsub:test:book", "Two Towers")));
* }</pre>
*
* <h2>Receiving pubsub messages</h2>
* <h3>Description</h3>
* <p>
* This section deals with the **subscribe** portion of pubsub. As mentioned in the last section, usage of a node
* typically involves either sending or receiving items. Subscribers are interested in being notified when items are
* published to the pubsub node. These items may or may not have application specific data (payload), as that is
* dependent on the context in which the node is being used.
* </p>
* <h3>Usage</h3>
* <p>
* To get messages asynchronously when items are published to a node, you will have to
* </p>
* <ul>
* <li>Get a node.</li>
* <li>Create and register a listener.</li>
* <li>Subscribe to the node.</li>
* </ul>
* <p>
* Please note that you should register the listener before subscribing so that all messages sent after subscribing are
* received. If done in the reverse order, messages that are sent after subscribing but before registering a listener
* may not be processed as expected.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to create a listener and register it and then subscribe for messages.
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
*
* // Get the node
* LeafNode node = mgr.getNode("testNode");
*
* node.addItemEventListener(new ItemEventCoordinator<Item>());
* node.subscribe(myJid);
* }</pre>
* <p>
* Where the listener is defined like so:
* </p>
*
* <pre><code>
* class ItemEventCoordinator implements ItemEventListener {
* {@literal @}@Override
* public void handlePublishedItems(ItemPublishEvent items) {
* System.out.println("Item count: " + System.out.println(items));
* }
* }
* </code></pre>
* <p>
* In addition to receiving published items, there are notifications for several other events that occur on a node as
* well.
* </p>
* <ul>
* <li>Deleting items or purging all items from a node</li>
* <li>Changing the node configuration</li>
* </ul>
* <p>
* In this example we can see how to create a listener, register it and then subscribe for item deletion messages.
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
*
* // Get the node
* LeafNode node = mgr.getNode("testNode");
*
* node.addItemDeleteListener(new ItemDeleteCoordinator<Item>());
* node.subscribe(myJid);
* node.deleteItem("id_one");
* }</pre>
* <p>
* Where the handler is defined like so:
* </p>
*
* <pre><code>
* class ItemDeleteCoordinator implements ItemDeleteListener {
* {@literal @}Override
* public void handleDeletedItems(ItemDeleteEvent items) {
* System.out.println("Item count: " + items.getItemIds().size());
* System.out.println(items);
* }
*
* {@literal @}Override
* public void handlePurge() {
* System.out.println("All items have been deleted from node");
* }
* }
* </code></pre>
* <p>
* In this example we can see how to create a listener, register it and then subscribe for node configuration messages.
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
*
* // Get the node
* Node node = mgr.getNode("testNode");
*
* node.addConfigurationListener(new NodeConfigCoordinator());
* node.subscribe(myJid);
*
* ConfigureForm form = new ConfigureForm(FormType.submit);
* form.setAccessModel(AccessModel.open);
* form.setDeliverPayloads(false);
* form.setNotifyRetract(true);
* form.setPersistentItems(true);
* form.setPublishModel(PublishModel.open);
*
* node.sendConfigurationForm(form);
* }</pre>
* <p>
* In this example we can see how to create a listener, register it and then subscribe for node configuration messages.
* </p>
*
* <pre><code>
* class NodeConfigCoordinator implements NodeConfigListener {
* {@literal @}Override
* public void handleNodeConfiguration(ConfigurationEvent config) {
* System.out.println("New configuration");
* System.out.println(config.getConfiguration());
* }
* </code></pre>
*
* <h2>Retrieving persisted pubsub messages</h2>
* <h3>Description</h3>
* <p>
* When persistent nodes are used, the subscription and registration methods described in the last section will not
* enable the retrieval of items that already exist in the node. This section deals with the specific methods for
* retrieving these items. There are several means of retrieving existing items. You can retrieve all items at once, the
* last N items, or the items specified by a collection of id's. Please note that the service may, according to the
* pubsub specification, reply with a list of items that contains only the item id's (no payload) to save on bandwidth.
* This will not occur when the id's are specified since this is the means of guaranteeing retrieval of payload.
* </p>
* <h3>Usage</h3>
* <p>
* To synchronously retrieve existing items from a persistent node, you will have to get an instance of a _**LeafNode**_
* and call one of the retrieve methods.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to retrieve the existing items from a node:
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
*
* // Get the node
* LeafNode node = mgr.getNode("testNode");
*
* Collection<? extends Item> items = node.getItems();
* }</pre>
* <p>
* In this example we can see how to retrieve the last N existing items:
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
*
* // Get the node
* LeafNode node = mgr.getNode("testNode");
*
* List<? extends Item> items = node.getItems(100);
* }</pre>
* <p>
* In this example we can see how to retrieve the specified existing items:
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
*
* // Get the node
* LeafNode node = mgr.getNode("testNode");
* Collection<String> ids = new ArrayList<String>(3);
* ids.add("1");
* ids.add("3");
* ids.add("4");
*
* List<? extends Item> items = node.getItems(ids);
* }</pre>
*
* <h2>Discover pubsub information</h2>
* <h3>Description</h3>
* <p>
* A user may want to query a server or node for a variety of pubsub related information.
* </p>
* <h3>Usage</h3>
* <p>
* To retrieve information, a user will simply use either the _**PubSubManager**_ or _**Node**_ classes depending on
* what type of information is required.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to get pubsub capabilities:
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
*
* // Get the pubsub features that are supported
* DiscoverInfo supportedFeatures = mgr.getSupportedFeatures();
* }</pre>
* <p>
* In this example we can see how to get pubsub subscriptions for all nodes:
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
*
* // Get all the subscriptions in the pubsub service
* List<Subscription> subscriptions = mgr.getSubscriptions();
* }</pre>
* <p>
* In this example we can see how to get all affiliations for the users bare JID on the pubsub service:
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
*
* // Get the affiliations for the users bare JID
* List<Affiliation> affiliations = mgr.getAffiliations();
* }</pre>
* <p>
* In this example we can see how to get information about the node:
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
* Node node = mgr.getNode("testNode");
*
* // Get the node information
* DiscoverInfo nodeInfo = node.discoverInfo();
* }</pre>
* <p>
* In this example we can see how to discover the node items:
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
* Node node = mgr.getNode("testNode");
*
* // Discover the node items
* DiscoverItems nodeItems = node.discoverItems();
* }</pre>
* <p>
* In this example we can see how to get node subscriptions:
* </p>
*
* <pre>{@code
* // Create a pubsub manager using an existing XMPPConnection
* PubSubManager mgr = PubSubManager.getInstanceFor(con);
* Node node = mgr.getNode("testNode");
*
* // Discover the node subscriptions
* List<Subscription> subscriptions = node.getSubscriptions();
* }</pre>
*
* @see <a href="https://xmpp.org/extensions/xep-0060.html">XEP-0060: Publish-Subscribe</a>
*/
package org.jivesoftware.smackx.pubsub;

View file

@ -17,5 +17,9 @@
/**
* Smacks implementation of XEP-0202: Entity Time.
* <p>
* Supports a protocol that XMPP clients use to exchange their respective local times and time zones.
* </p>
* @see <a href="https://xmpp.org/extensions/xep-0090.html">XEP-0090: Legacy Entity Time</a>
*/
package org.jivesoftware.smackx.time;

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2022 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,31 @@
*/
/**
* Smacks implementation of XEP-0004: Data Forms.
* Smacks API for Data Forms (XEP-0004).
* <p>
* XMPP data forms allow the exchange of structured data between users and applications for common tasks such as
* registration, searching user forms, or answering a questionnaire.
* </p>
* <h2>Create a Form to fill out</h2>
* <h3>Description</h3>
* <p>
* An XMPP entity may need to gather data from another XMPP entity. Therefore, the data-gathering entity will need to
* create a new Form, specify the fields that will conform to the Form and finally send the Form to the data-providing
* entity.
* </p>
* <h3>Usage</h3> TODO
* <h3>Example</h3>
*
* <h2>Answer a Form</h2>
* <h3>Description</h3>
* <p>
* Under many situations an XMPP entity could receive a form to fill out. For example, some hosts may require to fill
* out a form in order to register new users. Smack lets the data-providing entity to complete the form in an easy way
* and send it back to the data-gathering entity.
* </p>
* <h3>Usage</h3> TODO
* <h3>Example</h3>
*
* @see <a href="https://xmpp.org/extensions/xep-0004.html">XEP-0004: Data Forms</a>
*/
package org.jivesoftware.smackx.xdata;

View file

@ -16,6 +16,174 @@
*/
/**
* Smacks implementation of XEP-0071: XHTML-IM.
* Smacks implementation of XHTML-IM (XEP-0071), which provides the ability to send and receive formatted messages using
* XHTML.
* <h2></h2>
* <h3>Description</h3>
* <p>
* The first step in order to send an XHTML message is to compose it. Smack provides a special class that helps to build
* valid XHTML messages hiding any low level complexity. For special situations, advanced users may decide not to use
* the helper class and generate the XHTML by themselves. Even for these situations Smack provides a well defined entry
* point in order to add the generated XHTML content to a given message.
* </p>
* <p>
* Note: not all clients are able to view XHTML formatted messages. Therefore, it's recommended that you include a
* normal body in that message that is either an unformatted version of the text or a note that XHTML support is
* required to view the message contents.
* </p>
* <h3>Usage</h3>
* <p>
* Create an instance of _**XHTMLText**_ specifying the style and language of the body. You can add several XHTML bodies
* to the message but each body should be for a different language. Once you have an XHTMLText you can start to append
* tags and text to it. In order to append tags there are several messages that you can use. For each XHTML defined tag
* there is a message that you can send. In order to add text you can send the message **#append(String textToAppend)**.
* </p>
* <p>
* After you have configured the XHTML text, the last step you have to do is to add the XHTML text to the message you
* want to send. If you decided to create the XHTML text by yourself, you will have to follow this last step too. In
* order to add the XHTML text to the message send the message **#addBody(Message message, String body)** to the
* _**XHTMLManager**_ class where _message_ is the message that will receive the XHTML body and _body_ is the string to
* add as an XHTML body to the message.**
* </p>
* <h3>Example</h3>
* <p>
* In this example we can see how to compose the following XHTML message:
* </p>
*
* <pre>{@code
* <body>
* <p style='font-size:large'>Hey John, this is my new
* <span style='color:green'>green</span>
* <em>!!!!</em>
* </p>
* </body>
* }</pre>
*
* <pre>{@code
* // Create a message to send
* Message msg = chat.createMessage();
* msg.setSubject("Any subject you want");
* msg.setBody("Hey John, this is my new green!!!!");
*
* // Create an XHTMLText to send with the message
* XHTMLText xhtmlText = new XHTMLText(null, null);
* xhtmlText.appendOpenParagraphTag("font-size:large");
* xhtmlText.append("Hey John, this is my new ");
* xhtmlText.appendOpenSpanTag("color:green");
* xhtmlText.append("green");
* xhtmlText.appendCloseSpanTag();
* xhtmlText.appendOpenEmTag();
* xhtmlText.append("!!!!");
* xhtmlText.appendCloseEmTag();
* xhtmlText.appendCloseParagraphTag();
* xhtmlText.appendCloseBodyTag();
*
* // Add the XHTML text to the message
* XHTMLManager.addBody(msg, xhtmlText);
* }</pre>
*
* <h2>Send an XHTML Message</h2>
* <h3>Description</h3>
* <p>
* After you have composed an XHTML message you will want to send it. Once you have added the XHTML content to the
* message you want to send you are almost done. The last step is to send the message as you do with any other message.
* </p>
* <h3>Usage</h3>
* <p>
* An XHTML message is like any regular message, therefore to send the message you can follow the usual steps you do in
* order to send a message. For example, to send a message as part of a chat just use the message
* **#sendMessage(Message)** of _**Chat**_ or you can use the message **#sendStanza(Stanza)** of _**XMPPConnection**_.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to send a message with XHTML content as part of a chat.
* </p>
*
* <pre>{@code
* // Create a message to send
* Message msg = chat.createMessage();
* // Obtain the XHTML text to send from somewhere
* XHTMLText xhtmlBody = getXHTMLTextToSend();
*
* // Add the XHTML text to the message
* XHTMLManager.addBody(msg, xhtmlBody);
*
* // Send the message that contains the XHTML
* chat.sendMessage(msg);
* }</pre>
*
* <h2>Receive an XHTML Message</h2>
* <h3>Description</h3>
* <p>
* It is also possible to obtain the XHTML content from a received message. Remember that the specification defines that
* a message may contain several XHTML bodies where each body should be for a different language.
* </p>
* <h3>Usage</h3>
* <p>
* To get the XHTML bodies of a given message just send the message #getBodies(Message)** to the class
* _**XHTMLManager**_. The answer of this message will be an _**List**_ with the different XHTML bodies of the message
* or null if none.
* </p>
* <h3>Example</h3>
* <p>
* In this example we can see how to create a PacketListener that obtains the XHTML bodies of any received message.
* </p>
* <pre>{@code
* // Create a listener for the chat and display any XHTML content
* IncomingChatMessageListener listener = new IncomingChatMessageListener() {
* public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
* // Obtain the XHTML bodies of the message
* List&lt;CharSequence&gt; bodies = XHTMLManager.getBodies(message);
* if (bodies == null) {
* return;
*
* // Display the bodies on the console
* for (CharSequence body : bodies) {
* System.out.println(body);
* }
* }
* };
* chatManager.addListener(listener);
* }
* }</pre>
* <h2>Discover support for XHTML Messages</h2>
* <h3>Description</h3>
* <p>
* Before you start to send XHTML messages to a user you should discover if the user supports XHTML messages. There are
* two ways to achieve the discovery, explicitly and implicitly. Explicit is when you first try to discover if the user
* supports XHTML before sending any XHTML message. Implicit is when you send XHTML messages without first discovering
* if the conversation partner's client supports XHTML and depenging on the answer (normal message or XHTML message) you
* find out if the user supports XHTML messages or not. This section explains how to explicitly discover for XHTML
* support.
* </p>
* <h3>Usage</h3>
* <p>
* In order to discover if a remote user supports XHTML messages send #isServiceEnabled(XMPPConnection connection,
* String userID)** to the class _**XHTMLManager**_ where connection is the connection to use to perform the service
* discovery and userID is the user to check (A fully qualified xmpp ID, e.g. jdoe@example.com). This message will
* return true if the specified user handles XHTML messages.
* </p>
* <h3>Examples</h3>
* <p>
* In this example we can see how to discover if a remote user supports XHTML Messages.
* </p>
*
* <pre>{@code
* Message msg = chat.createMessage();
* // Include a normal body in the message
* msg.setBody(getTextToSend());
* // Check if the other user supports XHTML messages
* if (XHTMLManager.isServiceEnabled(connection, chat.getParticipant())) {
* // Obtain the XHTML text to send from somewhere
* String xhtmlBody = getXHTMLTextToSend();
* // Include an XHTML body in the message
* qHTMLManager.addBody(msg, xhtmlBody);
* }
*
* // Send the message
* chat.sendMessage(msg);
* }</pre>
*
* @see <a href="https://www.xmpp.org/extensions/xep-0071.html">XEP-0071: XHTML-IM</a>
*/
package org.jivesoftware.smackx.xhtmlim;