diff --git a/source/org/jivesoftware/smackx/muc/MultiUserChat.java b/source/org/jivesoftware/smackx/muc/MultiUserChat.java index 049e25bec..080084285 100644 --- a/source/org/jivesoftware/smackx/muc/MultiUserChat.java +++ b/source/org/jivesoftware/smackx/muc/MultiUserChat.java @@ -20,10 +20,6 @@ package org.jivesoftware.smackx.muc; -import java.lang.ref.WeakReference; -import java.lang.reflect.*; -import java.util.*; - import org.jivesoftware.smack.*; import org.jivesoftware.smack.filter.*; import org.jivesoftware.smack.packet.*; @@ -32,6 +28,11 @@ import org.jivesoftware.smackx.NodeInformationProvider; import org.jivesoftware.smackx.ServiceDiscoveryManager; import org.jivesoftware.smackx.packet.*; +import java.lang.ref.WeakReference; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; + /** * A MultiUserChat is a conversation that takes place among many users in a virtual * room. A room could have many occupants with different affiliation and roles. @@ -63,6 +64,7 @@ public class MultiUserChat { private PacketFilter presenceFilter; private PacketListener presenceListener; + private List presenceInterceptors = new ArrayList(); private PacketFilter subjectFilter; private PacketListener subjectListener; private PacketFilter messageFilter; @@ -289,6 +291,11 @@ public class MultiUserChat { joinPresence.setTo(room + "/" + nickname); // Indicate the the client supports MUC joinPresence.addExtension(new MUCInitialPresence()); + // Invoke presence interceptors so that extra information can be dynamically added + for (Iterator it = presenceInterceptors.iterator(); it.hasNext();) { + PacketInterceptor packetInterceptor = (PacketInterceptor) it.next(); + packetInterceptor.interceptPacket(joinPresence); + } // Wait for a presence packet back from the server. PacketFilter responseFilter = @@ -423,6 +430,11 @@ public class MultiUserChat { mucInitialPresence.setHistory(history.getMUCHistory()); } joinPresence.addExtension(mucInitialPresence); + // Invoke presence interceptors so that extra information can be dynamically added + for (Iterator it = presenceInterceptors.iterator(); it.hasNext();) { + PacketInterceptor packetInterceptor = (PacketInterceptor) it.next(); + packetInterceptor.interceptPacket(joinPresence); + } // Wait for a presence packet back from the server. PacketFilter responseFilter = @@ -470,6 +482,11 @@ public class MultiUserChat { // field is in the form "roomName@service/nickname" Presence leavePresence = new Presence(Presence.Type.UNAVAILABLE); leavePresence.setTo(room + "/" + nickname); + // Invoke presence interceptors so that extra information can be dynamically added + for (Iterator it = presenceInterceptors.iterator(); it.hasNext();) { + PacketInterceptor packetInterceptor = (PacketInterceptor) it.next(); + packetInterceptor.interceptPacket(leavePresence); + } connection.sendPacket(leavePresence); // Reset occupant information. occupantsMap = new HashMap(); @@ -824,6 +841,28 @@ public class MultiUserChat { } } + /** + * Adds a new {@link PacketInterceptor} that will be invoked every time a new presence + * is going to be sent by this MultiUserChat to the server. Packet interceptors may + * add new extensions to the presence that is going to be sent to the MUC service. + * + * @param presenceInterceptor the new packet interceptor that will intercept presence packets. + */ + public void addPresenceInterceptor(PacketInterceptor presenceInterceptor) { + presenceInterceptors.add(presenceInterceptor); + } + + /** + * Removes a {@link PacketInterceptor} that was being invoked every time a new presence + * was being sent by this MultiUserChat to the server. Packet interceptors may + * add new extensions to the presence that is going to be sent to the MUC service. + * + * @param presenceInterceptor the packet interceptor to remove. + */ + public void removePresenceInterceptor(PacketInterceptor presenceInterceptor) { + presenceInterceptors.remove(presenceInterceptor); + } + /** * Returns the last known room's subject or null if the user hasn't joined the room * or the room does not have a subject yet. In case the room has a subject, as soon as the @@ -903,6 +942,11 @@ public class MultiUserChat { // We don't have to signal the MUC support again Presence joinPresence = new Presence(Presence.Type.AVAILABLE); joinPresence.setTo(room + "/" + nickname); + // Invoke presence interceptors so that extra information can be dynamically added + for (Iterator it = presenceInterceptors.iterator(); it.hasNext();) { + PacketInterceptor packetInterceptor = (PacketInterceptor) it.next(); + packetInterceptor.interceptPacket(joinPresence); + } // Wait for a presence packet back from the server. PacketFilter responseFilter = @@ -951,6 +995,11 @@ public class MultiUserChat { joinPresence.setStatus(status); joinPresence.setMode(mode); joinPresence.setTo(room + "/" + nickname); + // Invoke presence interceptors so that extra information can be dynamically added + for (Iterator it = presenceInterceptors.iterator(); it.hasNext();) { + PacketInterceptor packetInterceptor = (PacketInterceptor) it.next(); + packetInterceptor.interceptPacket(joinPresence); + } // Send join packet. connection.sendPacket(joinPresence); @@ -2590,7 +2639,7 @@ public class MultiUserChat { invitationPacketListener = new PacketListener() { public void processPacket(Packet packet) { // Get the MUCUser extension - MUCUser mucUser = + MUCUser mucUser = (MUCUser) packet.getExtension("x", "http://jabber.org/protocol/muc#user"); // Check if the MUCUser extension includes an invitation if (mucUser.getInvite() != null && diff --git a/test/org/jivesoftware/smackx/muc/MultiUserChatTest.java b/test/org/jivesoftware/smackx/muc/MultiUserChatTest.java index 853d7a416..62c97d68e 100644 --- a/test/org/jivesoftware/smackx/muc/MultiUserChatTest.java +++ b/test/org/jivesoftware/smackx/muc/MultiUserChatTest.java @@ -1796,6 +1796,53 @@ public class MultiUserChatTest extends SmackTestCase { } + /** + * Test that deaf occupants do not get broadcasted messages. Deaf occupants is a Jive + * extension to MUC so it may not work with other servers. + */ + public void testDeafOccupants() { + try { + // User2 joins the room as a "normal" occupant + MultiUserChat muc2 = new MultiUserChat(getConnection(1), room); + muc2.join("testbot2"); + + // User3 joins the room as a "deaf" occupant + MultiUserChat muc3 = new MultiUserChat(getConnection(2), room); + muc3.addPresenceInterceptor(new DeafOccupantInterceptor()); + muc3.join("testbot3"); + + // User1 sends some messages to the room + muc.sendMessage("Message 1"); + muc.sendMessage("Message 2"); + + Thread.sleep(500); + + Message msg; + // Normal occupant gets first message + msg = muc2.nextMessage(1000); + assertNotNull("First message is null", msg); + // Get second message + msg = muc2.nextMessage(1000); + assertNotNull("Second message is null", msg); + // Try to get a third message + msg = muc2.nextMessage(1000); + assertNull("Third message is not null", msg); + + // Deaf occupant tries to get a third message + msg = muc3.nextMessage(1000); + assertNull("Deaf occupant got a broadcast message", msg); + + // User2 leaves the room + muc2.leave(); + // User3 leaves the room + muc3.leave(); + } + catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + private void makeRoomModerated() throws XMPPException { // User1 (which is the room owner) converts the instant room into a moderated room Form form = muc.getConfigurationForm();