org.jivesoftware.smackx.pubsub.PubSubManager Java Examples

The following examples show how to use org.jivesoftware.smackx.pubsub.PubSubManager. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: XMPPSession.java    From mangosta-android with Apache License 2.0 7 votes vote down vote up
public void createNodeToAllowComments(String blogPostId) {
    String nodeName = PublishCommentExtension.NODE + "/" + blogPostId;

    PubSubManager pubSubManager = PubSubManager.getInstance(XMPPSession.getInstance().getXMPPConnection());
    try {
        // create node
        ConfigureForm configureForm = new ConfigureForm(DataForm.Type.submit);
        configureForm.setPublishModel(PublishModel.open);
        configureForm.setAccessModel(AccessModel.open);
        Node node = pubSubManager.createNode(nodeName, configureForm);

        // subscribe to comments
        String myJIDString = getUser().toString();
        node.subscribe(myJIDString);
    } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | InterruptedException e) {
        e.printStackTrace();
    }
}
 
Example #2
Source File: OpenPgpPubSubUtil.java    From Smack with Apache License 2.0 6 votes vote down vote up
/**
 * Try to get a {@link LeafNode} the traditional way (first query information using disco#info), then query the node.
 * If that fails, query the node directly.
 *
 * @param pm PubSubManager
 * @param nodeName name of the node
 * @return node TODO javadoc me please
 *
 * @throws XMPPException.XMPPErrorException in case of an XMPP protocol error.
 * @throws PubSubException.NotALeafNodeException if the queried node is not a {@link LeafNode}.
 * @throws InterruptedException in case the thread gets interrupted
 * @throws PubSubException.NotAPubSubNodeException in case the queried entity is not a PubSub node.
 * @throws SmackException.NotConnectedException in case the connection is not connected.
 * @throws SmackException.NoResponseException in case the server doesn't respond.
 */
static LeafNode getLeafNode(PubSubManager pm, String nodeName)
        throws XMPPException.XMPPErrorException, PubSubException.NotALeafNodeException, InterruptedException,
        PubSubException.NotAPubSubNodeException, SmackException.NotConnectedException, SmackException.NoResponseException {
    LeafNode node;
    try {
        node = pm.getLeafNode(nodeName);
    } catch (XMPPException.XMPPErrorException e) {
        // It might happen, that the server doesn't allow disco#info queries from strangers.
        // In that case we have to fetch the node directly
        if (e.getStanzaError().getCondition() == StanzaError.Condition.subscription_required) {
            node = getOpenLeafNode(pm, nodeName);
        } else {
            throw e;
        }
    }

    return node;
}
 
Example #3
Source File: PubSubTestCase.java    From Smack with Apache License 2.0 6 votes vote down vote up
protected LeafNode getPubnode(PubSubManager pubMgr, boolean persistItems, boolean deliverPayload, String nodeId) throws XMPPException
{
	LeafNode node = null;

	try
	{
		node = (LeafNode)pubMgr.getNode(nodeId);
	}
	catch (XMPPException e)
	{
		ConfigureForm form = new ConfigureForm(FormType.submit);
		form.setPersistentItems(persistItems);
		form.setDeliverPayloads(deliverPayload);
		form.setAccessModel(AccessModel.open);
		node = (LeafNode)pubMgr.createNode(nodeId, form);
	}
	return node;
}
 
Example #4
Source File: PepManager.java    From Smack with Apache License 2.0 6 votes vote down vote up
public <E extends ExtensionElement> boolean addPepEventListener(String node, Class<E> extensionElementType,
                PepEventListener<E> pepEventListener) {
    PepEventListenerCoupling<E> pepEventListenerCoupling = new PepEventListenerCoupling<>(node,
                    extensionElementType, pepEventListener);

    synchronized (pepEventListeners) {
        if (listenerToCouplingMap.containsKey(pepEventListener)) {
            return false;
        }
        listenerToCouplingMap.put(pepEventListener, pepEventListenerCoupling);
        /*
         * TODO: Replace the above with the below using putIfAbsent() if Smack's minimum required Android SDK level
         * is 24 or higher. PepEventListenerCoupling<?> currentPepEventListenerCoupling =
         * listenerToCouplingMap.putIfAbsent(pepEventListener, pepEventListenerCoupling); if
         * (currentPepEventListenerCoupling != null) { return false; }
         */

        boolean listenerForNodeExisted = pepEventListeners.put(node, pepEventListenerCoupling);
        if (!listenerForNodeExisted) {
            serviceDiscoveryManager.addFeature(node + PubSubManager.PLUS_NOTIFY);
        }
    }
    return true;
}
 
Example #5
Source File: OmemoService.java    From Smack with Apache License 2.0 6 votes vote down vote up
/**
 * Retrieve the OMEMO device list of a contact.
 *
 * @param connection authenticated XMPP connection.
 * @param contact BareJid of the contact of which we want to retrieve the device list from.
 * @return device list
 *
 * @throws InterruptedException if the calling thread was interrupted.
 * @throws PubSubException.NotALeafNodeException if a PubSub leaf node operation was attempted on a non-leaf node.
 * @throws SmackException.NoResponseException if there was no response from the remote entity.
 * @throws SmackException.NotConnectedException if the XMPP connection is not connected.
 * @throws XMPPException.XMPPErrorException if there was an XMPP error returned.
 * @throws PubSubException.NotAPubSubNodeException if a involved node is not a PubSub node.
 */
private static OmemoDeviceListElement fetchDeviceList(XMPPConnection connection, BareJid contact)
        throws InterruptedException, PubSubException.NotALeafNodeException, SmackException.NoResponseException,
        SmackException.NotConnectedException, XMPPException.XMPPErrorException,
        PubSubException.NotAPubSubNodeException {

    PubSubManager pm = PubSubManager.getInstanceFor(connection, contact);
    String nodeName = OmemoConstants.PEP_NODE_DEVICE_LIST;
    LeafNode node = pm.getLeafNode(nodeName);

    if (node == null) {
        return null;
    }

    List<PayloadItem<OmemoDeviceListElement>> items = node.getItems();
    if (items.isEmpty()) {
        return null;
    }

    return items.get(items.size() - 1).getPayload();
}
 
Example #6
Source File: OmemoService.java    From Smack with Apache License 2.0 6 votes vote down vote up
/**
 * Retrieve a users OMEMO bundle.
 *
 * @param connection authenticated XMPP connection.
 * @param contactsDevice device of which we want to retrieve the bundle.
 * @return OmemoBundle of the device or null, if it doesn't exist.
 *
 * @throws SmackException.NotConnectedException if the XMPP connection is not connected.
 * @throws InterruptedException if the calling thread was interrupted.
 * @throws SmackException.NoResponseException if there was no response from the remote entity.
 * @throws XMPPException.XMPPErrorException if there was an XMPP error returned.
 * @throws PubSubException.NotALeafNodeException if a PubSub leaf node operation was attempted on a non-leaf node.
 * @throws PubSubException.NotAPubSubNodeException if a involved node is not a PubSub node.
 */
private static OmemoBundleElement fetchBundle(XMPPConnection connection,
                                              OmemoDevice contactsDevice)
        throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException,
        XMPPException.XMPPErrorException, PubSubException.NotALeafNodeException,
        PubSubException.NotAPubSubNodeException {

    PubSubManager pm = PubSubManager.getInstanceFor(connection, contactsDevice.getJid());
    LeafNode node = pm.getLeafNode(contactsDevice.getBundleNodeName());

    if (node == null) {
        return null;
    }

    List<PayloadItem<OmemoBundleElement>> bundleItems = node.getItems();
    if (bundleItems.isEmpty()) {
        return null;
    }

    return bundleItems.get(bundleItems.size() - 1).getPayload();
}
 
Example #7
Source File: OpenPgpPubSubUtil.java    From Smack with Apache License 2.0 5 votes vote down vote up
/**
 * Publish the users OpenPGP public key to the public key node if necessary.
 * Also announce the key to other users by updating the metadata node.
 *
 * @see <a href="https://xmpp.org/extensions/xep-0373.html#annoucning-pubkey">XEP-0373 §4.1</a>
 *
 * @param pepManager The PEP manager.
 * @param pubkeyElement {@link PubkeyElement} containing the public key
 * @param fingerprint fingerprint of the public key
 *
 * @throws InterruptedException if the thread gets interrupted.
 * @throws PubSubException.NotALeafNodeException if either the metadata node or the public key node is not a
 *                                               {@link LeafNode}.
 * @throws XMPPException.XMPPErrorException in case of an XMPP protocol error.
 * @throws SmackException.NotConnectedException if we are not connected.
 * @throws SmackException.NoResponseException if the server doesn't respond.
 */
public static void publishPublicKey(PepManager pepManager, PubkeyElement pubkeyElement, OpenPgpV4Fingerprint fingerprint)
        throws InterruptedException, PubSubException.NotALeafNodeException,
        XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException {

    String keyNodeName = PEP_NODE_PUBLIC_KEY(fingerprint);
    PubSubManager pm = pepManager.getPepPubSubManager();

    // Check if key available at data node
    // If not, publish key to data node
    LeafNode keyNode = pm.getOrCreateLeafNode(keyNodeName);
    changeAccessModelIfNecessary(keyNode, AccessModel.open);
    List<Item> items = keyNode.getItems(1);
    if (items.isEmpty()) {
        LOGGER.log(Level.FINE, "Node " + keyNodeName + " is empty. Publish.");
        keyNode.publish(new PayloadItem<>(pubkeyElement));
    } else {
        LOGGER.log(Level.FINE, "Node " + keyNodeName + " already contains key. Skip.");
    }

    // Fetch IDs from metadata node
    LeafNode metadataNode = pm.getOrCreateLeafNode(PEP_NODE_PUBLIC_KEYS);
    changeAccessModelIfNecessary(metadataNode, AccessModel.open);
    List<PayloadItem<PublicKeysListElement>> metadataItems = metadataNode.getItems(1);

    PublicKeysListElement.Builder builder = PublicKeysListElement.builder();
    if (!metadataItems.isEmpty() && metadataItems.get(0).getPayload() != null) {
        // Add old entries back to list.
        PublicKeysListElement publishedList = metadataItems.get(0).getPayload();
        for (PublicKeysListElement.PubkeyMetadataElement meta : publishedList.getMetadata().values()) {
            builder.addMetadata(meta);
        }
    }
    builder.addMetadata(new PublicKeysListElement.PubkeyMetadataElement(fingerprint, new Date()));

    // Publish IDs to metadata node
    metadataNode.publish(new PayloadItem<>(builder.build()));
}
 
Example #8
Source File: PubSubTestCase.java    From Smack with Apache License 2.0 5 votes vote down vote up
protected PubSubManager getManager(int idx)
{
	if (manager == null)
	{
		manager = new PubSubManager[getMaxConnections()];

		for(int i=0; i<manager.length; i++)
		{
			manager[i] = new PubSubManager(getConnection(i), getService());
		}
	}
	return manager[idx];
}
 
Example #9
Source File: PubSubTestCase.java    From Smack with Apache License 2.0 5 votes vote down vote up
protected LeafNode getRandomPubnode(PubSubManager pubMgr, boolean persistItems, boolean deliverPayload) throws XMPPException
{
	ConfigureForm form = new ConfigureForm(FormType.submit);
	form.setPersistentItems(persistItems);
	form.setDeliverPayloads(deliverPayload);
	form.setAccessModel(AccessModel.open);
	return (LeafNode)pubMgr.createNode("/test/Pubnode" + System.currentTimeMillis(), form);
}
 
Example #10
Source File: SingleUserTestCase.java    From Smack with Apache License 2.0 4 votes vote down vote up
protected PubSubManager getManager()
{
	return getManager(0);
}
 
Example #11
Source File: XMPPSession.java    From mangosta-android with Apache License 2.0 4 votes vote down vote up
public Jid getPubSubService() throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException {
    return PubSubManager.getPubSubService(getXMPPConnection());
}
 
Example #12
Source File: PepManager.java    From Smack with Apache License 2.0 4 votes vote down vote up
public PubSubManager getPepPubSubManager() {
    return pepPubSubManager;
}
 
Example #13
Source File: OpenPgpPubSubUtil.java    From Smack with Apache License 2.0 4 votes vote down vote up
/**
 * Use reflection magic to get a {@link LeafNode} without doing a disco#info query.
 * This method is useful for fetching nodes that are configured with the access model 'open', since
 * some servers that announce support for that access model do not allow disco#info queries from contacts
 * which are not subscribed to the node owner. Therefore this method fetches the node directly and puts it
 * into the {@link PubSubManager}s node map.
 *
 * Note: Due to the alck of a disco#info query, it might happen, that the node doesn't exist on the server,
 * even though we add it to the node map.
 *
 * @see <a href="https://github.com/processone/ejabberd/issues/2483">Ejabberd bug tracker about the issue</a>
 * @see <a href="https://mail.jabber.org/pipermail/standards/2018-June/035206.html">
 *     Topic on the standards mailing list</a>
 *
 * @param pubSubManager pubsub manager
 * @param nodeName name of the node
 * @return leafNode TODO javadoc me please
 *
 * @throws PubSubException.NotALeafNodeException in case we already have the node cached, but it is not a LeafNode.
 */
@SuppressWarnings("unchecked")
public static LeafNode getOpenLeafNode(PubSubManager pubSubManager, String nodeName)
        throws PubSubException.NotALeafNodeException {

    try {

        // Get access to the PubSubManager's nodeMap
        Field field = pubSubManager.getClass().getDeclaredField("nodeMap");
        field.setAccessible(true);
        Map<String, Node> nodeMap = (Map<String, Node>) field.get(pubSubManager);

        // Check, if the node already exists
        Node existingNode = nodeMap.get(nodeName);
        if (existingNode != null) {

            if (existingNode instanceof LeafNode) {
                // We already know that node
                return (LeafNode) existingNode;

            } else {
                // Throw a new NotALeafNodeException, as the node is not a LeafNode.
                // Again use reflections to access the exceptions constructor.
                Constructor<PubSubException.NotALeafNodeException> exceptionConstructor =
                        PubSubException.NotALeafNodeException.class.getDeclaredConstructor(String.class, BareJid.class);
                exceptionConstructor.setAccessible(true);
                throw exceptionConstructor.newInstance(nodeName, pubSubManager.getServiceJid());
            }
        }

        // Node does not exist. Create the node
        Constructor<LeafNode> constructor;
        constructor = LeafNode.class.getDeclaredConstructor(PubSubManager.class, String.class);
        constructor.setAccessible(true);
        LeafNode node = constructor.newInstance(pubSubManager, nodeName);

        // Add it to the node map
        nodeMap.put(nodeName, node);

        // And return
        return node;

    } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException |
            NoSuchFieldException e) {
        LOGGER.log(Level.SEVERE, "Using reflections to create a LeafNode and put it into PubSubManagers nodeMap failed.", e);
        throw new AssertionError(e);
    }
}
 
Example #14
Source File: XMPPSession.java    From mangosta-android with Apache License 2.0 4 votes vote down vote up
public PubSubManager getPubSubManager() {
    EntityBareJid myJIDString = getUser();
    return PubSubManager.getInstance(mXMPPConnection, myJIDString);
}
 
Example #15
Source File: OpenPgpPubSubUtil.java    From Smack with Apache License 2.0 4 votes vote down vote up
/**
 * Fetch the OpenPGP public key of a {@code contact}, identified by its OpenPGP {@code v4_fingerprint}.
 *
 * @see <a href="https://xmpp.org/extensions/xep-0373.html#discover-pubkey">XEP-0373 §4.3</a>
 *
 * @param connection XMPP connection
 * @param contact {@link BareJid} of the contact we want to fetch a key from.
 * @param v4_fingerprint upper case, hex encoded v4 fingerprint of the contacts key.
 * @return {@link PubkeyElement} containing the requested public key.
 *
 * @throws InterruptedException if the thread gets interrupted.A
 * @throws XMPPException.XMPPErrorException in case of an XMPP protocol error.
 * @throws PubSubException.NotAPubSubNodeException in case the targeted entity is not a PubSub node.
 * @throws PubSubException.NotALeafNodeException in case the fetched node is not a {@link LeafNode}.
 * @throws SmackException.NotConnectedException in case we are not connected.
 * @throws SmackException.NoResponseException if the server doesn't respond.
 */
public static PubkeyElement fetchPubkey(XMPPConnection connection, BareJid contact, OpenPgpV4Fingerprint v4_fingerprint)
        throws InterruptedException, XMPPException.XMPPErrorException, PubSubException.NotAPubSubNodeException,
        PubSubException.NotALeafNodeException, SmackException.NotConnectedException, SmackException.NoResponseException {
    PubSubManager pm = PubSubManager.getInstanceFor(connection, contact);
    String nodeName = PEP_NODE_PUBLIC_KEY(v4_fingerprint);

    LeafNode node = getLeafNode(pm, nodeName);

    List<PayloadItem<PubkeyElement>> list = node.getItems(1);

    if (list.isEmpty()) {
        return null;
    }

    return list.get(0).getPayload();
}
 
Example #16
Source File: OpenPgpPubSubUtil.java    From Smack with Apache License 2.0 3 votes vote down vote up
/**
 * Delete the private backup node.
 *
 * @param pepManager the PEP manager.
 *
 * @throws XMPPException.XMPPErrorException if there is an XMPP protocol related issue
 * @throws SmackException.NotConnectedException if we are not connected
 * @throws InterruptedException if the thread gets interrupted
 * @throws SmackException.NoResponseException if the server sends no response
 * @return <code>true</code> if the node existed and was deleted, <code>false</code> if the node did not exist.
 */
public static boolean deleteSecretKeyNode(PepManager pepManager)
        throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
        SmackException.NoResponseException {
    PubSubManager pm = pepManager.getPepPubSubManager();
    return pm.deleteNode(PEP_NODE_SECRET_KEY);
}
 
Example #17
Source File: OpenPgpPubSubUtil.java    From Smack with Apache License 2.0 3 votes vote down vote up
/**
 * Fetch the latest {@link SecretkeyElement} from the private backup node.
 *
 * @see <a href="https://xmpp.org/extensions/xep-0373.html#synchro-pep">
 *      XEP-0373 §5. Synchronizing the Secret Key with a Private PEP Node</a>
 *
 * @param pepManager the PEP manager.
 * @return the secret key node or null, if it doesn't exist.
 *
 * @throws InterruptedException if the thread gets interrupted
 * @throws PubSubException.NotALeafNodeException if there is an issue with the PubSub node
 * @throws XMPPException.XMPPErrorException if there is an XMPP protocol related issue
 * @throws SmackException.NotConnectedException if we are not connected
 * @throws SmackException.NoResponseException /watch?v=7U0FzQzJzyI
 */
public static SecretkeyElement fetchSecretKey(PepManager pepManager)
        throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException,
        SmackException.NotConnectedException, SmackException.NoResponseException {
    PubSubManager pm = pepManager.getPepPubSubManager();
    LeafNode secretKeyNode = pm.getOrCreateLeafNode(PEP_NODE_SECRET_KEY);
    List<PayloadItem<SecretkeyElement>> list = secretKeyNode.getItems(1);
    if (list.size() == 0) {
        LOGGER.log(Level.INFO, "No secret key published!");
        return null;
    }
    SecretkeyElement secretkeyElement = list.get(0).getPayload();
    return secretkeyElement;
}
 
Example #18
Source File: OpenPgpPubSubUtil.java    From Smack with Apache License 2.0 3 votes vote down vote up
/**
 * Publishes a {@link SecretkeyElement} to the secret key node.
 * The node will be configured to use the whitelist access model to prevent access from subscribers.
 *
 * @see <a href="https://xmpp.org/extensions/xep-0373.html#synchro-pep">
 *     XEP-0373 §5. Synchronizing the Secret Key with a Private PEP Node</a>
 *
 * @param connection {@link XMPPConnection} of the user
 * @param element a {@link SecretkeyElement} containing the encrypted secret key of the user
 *
 * @throws InterruptedException if the thread gets interrupted.
 * @throws PubSubException.NotALeafNodeException if something is wrong with the PubSub node
 * @throws XMPPException.XMPPErrorException in case of an protocol related error
 * @throws SmackException.NotConnectedException if we are not connected
 * @throws SmackException.NoResponseException /watch?v=0peBq89ZTrc
 * @throws SmackException.FeatureNotSupportedException if the Server doesn't support the whitelist access model
 */
public static void depositSecretKey(XMPPConnection connection, SecretkeyElement element)
        throws InterruptedException, PubSubException.NotALeafNodeException,
        XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException,
        SmackException.FeatureNotSupportedException {
    if (!OpenPgpManager.serverSupportsSecretKeyBackups(connection)) {
        throw new SmackException.FeatureNotSupportedException("http://jabber.org/protocol/pubsub#access-whitelist");
    }
    PubSubManager pm = PepManager.getInstanceFor(connection).getPepPubSubManager();
    LeafNode secretKeyNode = pm.getOrCreateLeafNode(PEP_NODE_SECRET_KEY);
    OpenPgpPubSubUtil.changeAccessModelIfNecessary(secretKeyNode, AccessModel.whitelist);

    secretKeyNode.publish(new PayloadItem<>(element));
}
 
Example #19
Source File: OpenPgpPubSubUtil.java    From Smack with Apache License 2.0 3 votes vote down vote up
/**
 * Delete the public key node of the key with fingerprint {@code fingerprint}.
 *
 * @param pepManager The PEP manager.
 * @param fingerprint fingerprint of the key we want to delete
 *
 * @throws XMPPException.XMPPErrorException in case of an XMPP protocol error.
 * @throws SmackException.NotConnectedException if we are not connected.
 * @throws InterruptedException if the thread gets interrupted.
 * @throws SmackException.NoResponseException if the server doesn't respond.
 * @return <code>true</code> if the node existed and was deleted, <code>false</code> if the node did not exist.
 */
public static boolean deletePublicKeyNode(PepManager pepManager, OpenPgpV4Fingerprint fingerprint)
        throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
        SmackException.NoResponseException {
    PubSubManager pm = pepManager.getPepPubSubManager();
    return pm.deleteNode(PEP_NODE_PUBLIC_KEY(fingerprint));
}
 
Example #20
Source File: OpenPgpPubSubUtil.java    From Smack with Apache License 2.0 3 votes vote down vote up
/**
 * Delete our metadata node.
 *
 * @param pepManager The PEP manager.
 *
 * @throws XMPPException.XMPPErrorException in case of an XMPP protocol error.
 * @throws SmackException.NotConnectedException if we are not connected.
 * @throws InterruptedException if the thread is interrupted.
 * @throws SmackException.NoResponseException if the server doesn't respond.
 * @return <code>true</code> if the node existed and was deleted, <code>false</code> if the node did not exist.
 */
public static boolean deletePubkeysListNode(PepManager pepManager)
        throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
        SmackException.NoResponseException {
    PubSubManager pm = pepManager.getPepPubSubManager();
    return pm.deleteNode(PEP_NODE_PUBLIC_KEYS);
}
 
Example #21
Source File: OpenPgpPubSubUtil.java    From Smack with Apache License 2.0 3 votes vote down vote up
/**
 * Consult the public key metadata node of {@code contact} to fetch the list of their published OpenPGP public keys.
 *
 * @see <a href="https://xmpp.org/extensions/xep-0373.html#discover-pubkey-list">
 *     XEP-0373 §4.3: Discovering Public Keys of a User</a>
 *
 * @param connection XMPP connection
 * @param contact {@link BareJid} of the user we want to fetch the list from.
 * @return content of {@code contact}'s metadata node.
 *
 * @throws InterruptedException if the thread gets interrupted.
 * @throws XMPPException.XMPPErrorException in case of an XMPP protocol exception.
 * @throws SmackException.NoResponseException in case the server doesn't respond
 * @throws PubSubException.NotALeafNodeException in case the queried node is not a {@link LeafNode}
 * @throws SmackException.NotConnectedException in case we are not connected
 * @throws PubSubException.NotAPubSubNodeException in case the queried entity is not a PubSub node
 */
public static PublicKeysListElement fetchPubkeysList(XMPPConnection connection, BareJid contact)
        throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NoResponseException,
        PubSubException.NotALeafNodeException, SmackException.NotConnectedException, PubSubException.NotAPubSubNodeException {
    PubSubManager pm = PubSubManager.getInstanceFor(connection, contact);

    LeafNode node = getLeafNode(pm, PEP_NODE_PUBLIC_KEYS);
    List<PayloadItem<PublicKeysListElement>> list = node.getItems(1);

    if (list.isEmpty()) {
        return null;
    }

    return list.get(0).getPayload();
}