From ff72ea320ce95e4c0817bea6208675fd3a75e2e6 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Tue, 12 May 2015 11:54:54 +0200 Subject: [PATCH] Check if MUC room is hosted on a MUC service when trying to enter a room. --- .../smackx/muc/MultiUserChat.java | 38 +++++++++++++++---- .../smackx/muc/MultiUserChatException.java | 19 ++++++++++ .../smackx/muc/MultiUserChatManager.java | 18 +++++++++ .../MucBookmarkAutojoinManager.java | 3 +- 4 files changed, 69 insertions(+), 9 deletions(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java index 646672e36..929c55402 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java @@ -60,6 +60,7 @@ import org.jivesoftware.smackx.iqregister.packet.Registration; import org.jivesoftware.smackx.muc.MultiUserChatException.MucAlreadyJoinedException; import org.jivesoftware.smackx.muc.MultiUserChatException.MucNotJoinedException; import org.jivesoftware.smackx.muc.MultiUserChatException.MissingMucCreationAcknowledgeException; +import org.jivesoftware.smackx.muc.MultiUserChatException.NotAMucServiceException; import org.jivesoftware.smackx.muc.filter.MUCUserStatusCodeFilter; import org.jivesoftware.smackx.muc.packet.Destroy; import org.jivesoftware.smackx.muc.packet.MUCAdmin; @@ -72,11 +73,13 @@ import org.jivesoftware.smackx.xdata.Form; import org.jivesoftware.smackx.xdata.FormField; import org.jivesoftware.smackx.xdata.packet.DataForm; import org.jxmpp.jid.BareJid; +import org.jxmpp.jid.DomainBareJid; import org.jxmpp.jid.FullJid; import org.jxmpp.jid.Jid; import org.jxmpp.jid.JidWithLocalpart; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.parts.Resourcepart; +import org.jxmpp.util.cache.ExpirationCache; /** * A MultiUserChat room (XEP-45), created with {@link MultiUserChatManager#getMultiUserChat(BareJid)}. @@ -98,6 +101,9 @@ import org.jxmpp.jid.parts.Resourcepart; public class MultiUserChat { private static final Logger LOGGER = Logger.getLogger(MultiUserChat.class.getName()); + private static final ExpirationCache KNOWN_MUC_SERVICES = new ExpirationCache<>( + 100, 1000 * 60 * 60 * 24); + private final XMPPConnection connection; private final BareJid room; private final MultiUserChatManager multiUserChatManager; @@ -287,12 +293,21 @@ public class MultiUserChat { * @throws NoResponseException * @throws XMPPErrorException * @throws InterruptedException + * @throws NotAMucServiceException * @see XEP-45 7.2 Entering a Room */ private Presence enter(Resourcepart nickname, String password, DiscussionHistory history, long timeout) throws NotConnectedException, NoResponseException, - XMPPErrorException, InterruptedException { + XMPPErrorException, InterruptedException, NotAMucServiceException { StringUtils.requireNotNullOrEmpty(nickname, "Nickname must not be null or blank."); + final DomainBareJid mucService = room.asDomainBareJid(); + if (!KNOWN_MUC_SERVICES.containsKey(mucService)) { + if (multiUserChatManager.providesMucService(mucService)) { + KNOWN_MUC_SERVICES.put(mucService, null); + } else { + throw new NotAMucServiceException(this); + } + } // We enter a room by sending a presence packet where the "to" // field is in the form "roomName@service/nickname" Presence joinPresence = new Presence(Presence.Type.available); @@ -369,10 +384,11 @@ public class MultiUserChat { * @throws NotConnectedException * @throws MucAlreadyJoinedException * @throws MissingMucCreationAcknowledgeException + * @throws NotAMucServiceException */ public synchronized MucCreateConfigFormHandle create(Resourcepart nickname) throws NoResponseException, XMPPErrorException, InterruptedException, MucAlreadyJoinedException, - NotConnectedException, MissingMucCreationAcknowledgeException { + NotConnectedException, MissingMucCreationAcknowledgeException, NotAMucServiceException { if (joined) { throw new MucAlreadyJoinedException(); } @@ -398,10 +414,11 @@ public class MultiUserChat { * @throws InterruptedException * @throws NotConnectedException * @throws MucAlreadyJoinedException + * @throws NotAMucServiceException * @see #createOrJoin(Resourcepart, String, DiscussionHistory, long) */ public synchronized MucCreateConfigFormHandle createOrJoin(Resourcepart nickname) throws NoResponseException, XMPPErrorException, - InterruptedException, MucAlreadyJoinedException, NotConnectedException { + InterruptedException, MucAlreadyJoinedException, NotConnectedException, NotAMucServiceException { return createOrJoin(nickname, null, null, connection.getPacketReplyTimeout()); } @@ -422,9 +439,10 @@ public class MultiUserChat { * @throws InterruptedException * @throws MucAlreadyJoinedException if the MUC is already joined * @throws NotConnectedException + * @throws NotAMucServiceException */ public synchronized MucCreateConfigFormHandle createOrJoin(Resourcepart nickname, String password, DiscussionHistory history, long timeout) - throws NoResponseException, XMPPErrorException, InterruptedException, MucAlreadyJoinedException, NotConnectedException { + throws NoResponseException, XMPPErrorException, InterruptedException, MucAlreadyJoinedException, NotConnectedException, NotAMucServiceException { if (joined) { throw new MucAlreadyJoinedException(); } @@ -495,9 +513,10 @@ public class MultiUserChat { * @throws XMPPErrorException * @throws NotConnectedException * @throws InterruptedException + * @throws NotAMucServiceException */ public MucCreateConfigFormHandle createOrJoinIfNecessary(Resourcepart nickname, String password) throws NoResponseException, - XMPPErrorException, NotConnectedException, InterruptedException { + XMPPErrorException, NotConnectedException, InterruptedException, NotAMucServiceException { if (isJoined()) { return null; } @@ -527,8 +546,9 @@ public class MultiUserChat { * @throws NoResponseException if there was no response from the server. * @throws NotConnectedException * @throws InterruptedException + * @throws NotAMucServiceException */ - public void join(Resourcepart nickname) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + public void join(Resourcepart nickname) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, NotAMucServiceException { join(nickname, null, null, connection.getPacketReplyTimeout()); } @@ -553,8 +573,9 @@ public class MultiUserChat { * @throws InterruptedException * @throws NotConnectedException * @throws NoResponseException if there was no response from the server. + * @throws NotAMucServiceException */ - public void join(Resourcepart nickname, String password) throws XMPPErrorException, InterruptedException, NoResponseException, NotConnectedException { + public void join(Resourcepart nickname, String password) throws XMPPErrorException, InterruptedException, NoResponseException, NotConnectedException, NotAMucServiceException { join(nickname, password, null, connection.getPacketReplyTimeout()); } @@ -585,13 +606,14 @@ public class MultiUserChat { * @throws NoResponseException if there was no response from the server. * @throws NotConnectedException * @throws InterruptedException + * @throws NotAMucServiceException */ public synchronized void join( Resourcepart nickname, String password, DiscussionHistory history, long timeout) - throws XMPPErrorException, NoResponseException, NotConnectedException, InterruptedException { + throws XMPPErrorException, NoResponseException, NotConnectedException, InterruptedException, NotAMucServiceException { // If we've already joined the room, leave it before joining under a new // nickname. if (joined) { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatException.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatException.java index 5195b3ea4..a7fd10088 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatException.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatException.java @@ -83,4 +83,23 @@ public abstract class MultiUserChatException extends SmackException { super("The MUC configuration '" + configString + "' is not supported by the MUC service"); } } + + /** + * Thrown when trying to enter a MUC room that is not hosted a domain providing a MUC service. + * Try {@link MultiUserChatManager#getServiceNames()} for a list of client-local domains + * providing a MUC service. + */ + public static class NotAMucServiceException extends MultiUserChatException { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public NotAMucServiceException(MultiUserChat multiUserChat) { + super("Can not join '" + multiUserChat.getRoom() + "', because '" + + multiUserChat.getRoom().asDomainBareJid() + + "' does not provide a MUC (XEP-45) service."); + } + } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java index d599bedfb..8224399f3 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java @@ -261,6 +261,24 @@ public final class MultiUserChatManager extends Manager { return sdm.findServices(MUCInitialPresence.NAMESPACE, false, false); } + /** + * Check if the provided domain bare JID provides a MUC service. + * + * @param domainBareJid the domain bare JID to check. + * @return true if the provided JID provides a MUC service, false otherwise. + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + * @see XEP-45 ยง 6.2 Discovering the Features Supported by a MUC Service + * @since 4.2 + */ + public boolean providesMucService(DomainBareJid domainBareJid) throws NoResponseException, + XMPPErrorException, NotConnectedException, InterruptedException { + return ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(domainBareJid, + MUCInitialPresence.NAMESPACE); + } + /** * Returns a List of HostedRooms where each HostedRoom has the XMPP address of the room and the room's name. * Once discovered the rooms hosted by a chat service it is possible to discover more detailed room information or diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/bookmarkautojoin/MucBookmarkAutojoinManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/bookmarkautojoin/MucBookmarkAutojoinManager.java index 6d15de975..d2f6a476c 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/bookmarkautojoin/MucBookmarkAutojoinManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/bookmarkautojoin/MucBookmarkAutojoinManager.java @@ -34,6 +34,7 @@ import org.jivesoftware.smackx.bookmarks.BookmarkManager; import org.jivesoftware.smackx.bookmarks.BookmarkedConference; import org.jivesoftware.smackx.muc.MultiUserChat; import org.jivesoftware.smackx.muc.MultiUserChat.MucCreateConfigFormHandle; +import org.jivesoftware.smackx.muc.MultiUserChatException.NotAMucServiceException; import org.jivesoftware.smackx.muc.MultiUserChatManager; import org.jxmpp.jid.parts.Resourcepart; @@ -136,7 +137,7 @@ public final class MucBookmarkAutojoinManager extends Manager { // abort here break; } - catch (NoResponseException | XMPPErrorException e) { + catch (NotAMucServiceException | NoResponseException | XMPPErrorException e) { // Do no abort, just log, LOGGER.log(Level.WARNING, "Could not autojoin bookmarked MUC", e); }