diff --git a/source/org/jivesoftware/smackx/DefaultMessageEventRequestListener.java b/source/org/jivesoftware/smackx/DefaultMessageEventRequestListener.java new file mode 100644 index 000000000..cc795ca53 --- /dev/null +++ b/source/org/jivesoftware/smackx/DefaultMessageEventRequestListener.java @@ -0,0 +1,122 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright (C) 2002-2003 Jive Software. All rights reserved. + * ==================================================================== + * The Jive Software License (based on Apache Software License, Version 1.1) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * Jive Software (http://www.jivesoftware.com)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Smack" and "Jive Software" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please + * contact webmaster@jivesoftware.com. + * + * 5. Products derived from this software may not be called "Smack", + * nor may "Smack" appear in their name, without prior written + * permission of Jive Software. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.jivesoftware.smackx; + +/** + * + * Default implementation of the MessageEventRequestListener interface.

+ * + * This class automatically sends a delivered notification to the sender of the message + * if the sender has requested to be notified when the message is delivered. + * + * @author Gaston Dombiak + */ +public class DefaultMessageEventRequestListener implements MessageEventRequestListener { + + /** + * Called when a request of message delivered notification is received. The default + * behavior is to automatically respond that the message has been delivered. + * + * @param from the user that sent the notification. + * @param packetId the id of the message that was sent. + * @param messageEventManager the messageEventManager that fired the listener. + */ + public void deliveredNotificationRequested( + String from, + String packetID, + MessageEventManager messageEventManager) { + // Send to the message's sender that the message has been delivered + messageEventManager.sendDeliveredNotification(from, packetID); + } + + /** + * Called when a request of message displayed notification is received. + * + * @param from the user that sent the notification. + * @param packetId the id of the message that was sent. + * @param messageEventManager the messageEventManager that fired the listener. + */ + public void displayedNotificationRequested( + String from, + String packetID, + MessageEventManager messageEventManager) { + } + + /** + * Called when a request that the receiver of the message is composing a reply notification is + * received. + * + * @param from the user that sent the notification. + * @param packetId the id of the message that was sent. + * @param messageEventManager the messageEventManager that fired the listener. + */ + public void composingNotificationRequested( + String from, + String packetID, + MessageEventManager messageEventManager) { + } + + /** + * Called when a request that the receiver of the message is offline is received. + * + * @param from the user that sent the notification. + * @param packetId the id of the message that was sent. + * @param messageEventManager the messageEventManager that fired the listener. + */ + public void offlineNotificationRequested( + String from, + String packetID, + MessageEventManager messageEventManager) { + } + +} diff --git a/source/org/jivesoftware/smackx/MessageEventManager.java b/source/org/jivesoftware/smackx/MessageEventManager.java new file mode 100644 index 000000000..42c117dde --- /dev/null +++ b/source/org/jivesoftware/smackx/MessageEventManager.java @@ -0,0 +1,338 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright (C) 2002-2003 Jive Software. All rights reserved. + * ==================================================================== + * The Jive Software License (based on Apache Software License, Version 1.1) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * Jive Software (http://www.jivesoftware.com)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Smack" and "Jive Software" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please + * contact webmaster@jivesoftware.com. + * + * 5. Products derived from this software may not be called "Smack", + * nor may "Smack" appear in their name, without prior written + * permission of Jive Software. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.jivesoftware.smackx; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; + +import org.jivesoftware.smack.*; +import org.jivesoftware.smack.filter.*; +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smackx.packet.*; + +/** + * + * Manages message events requests and notifications. A MessageEventManager provides a high + * level access to request for notifications and send event notifications. It also provides + * an easy way to hook up custom logic when requests or notifications are received. + * + * @author Gaston Dombiak + */ +public class MessageEventManager { + + private List messageEventNotificationListeners = new ArrayList(); + private List messageEventRequestListeners = new ArrayList(); + + private XMPPConnection con; + + private PacketFilter packetFilter = new PacketExtensionFilter("x", "jabber:x:event"); + private PacketListener packetListener; + + /** + * Creates a new roster exchange manager. + * + * @param con an XMPPConnection. + */ + public MessageEventManager(XMPPConnection con) { + this.con = con; + init(); + } + + /** + * Adds to the message the requests to notify to the sender of the message for certain events. + * + * @param message the message to add the requested notifications + * @param offline specifies if the offline event is requested + * @param delivered specifies if the delivered event is requested + * @param displayed specifies if the displayed event is requested + * @param composing specifies if the composing event is requested + */ + public static void addNotificationsRequests( + Message message, + boolean offline, + boolean delivered, + boolean displayed, + boolean composing) { + // Create a MessageEvent Package and add it to the message + MessageEvent messageEvent = new MessageEvent(); + messageEvent.setOffline(offline); + messageEvent.setDelivered(delivered); + messageEvent.setDisplayed(displayed); + messageEvent.setComposing(composing); + message.addExtension(messageEvent); + } + + /** + * Adds a message event request listener. The listener will be fired anytime a request for + * event notification is received. + * + * @param messageEventRequestListener a message event request listener. + */ + public void addMessageEventRequestListener(MessageEventRequestListener messageEventRequestListener) { + synchronized (messageEventRequestListeners) { + if (!messageEventRequestListeners.contains(messageEventRequestListener)) { + messageEventRequestListeners.add(messageEventRequestListener); + } + } + } + + /** + * Removes a message event request listener. The listener will be fired anytime a request for + * event notification is received. + * + * @param messageEventRequestListener a message event request listener. + */ + public void removeMessageEventRequestListener(MessageEventRequestListener messageEventRequestListener) { + synchronized (messageEventRequestListeners) { + messageEventRequestListeners.remove(messageEventRequestListener); + } + } + + /** + * Adds a message event notification listener. The listener will be fired anytime a notification + * event is received. + * + * @param messageEventNotificationListener a message event notification listener. + */ + public void addMessageEventNotificationListener(MessageEventNotificationListener messageEventNotificationListener) { + synchronized (messageEventNotificationListeners) { + if (!messageEventNotificationListeners.contains(messageEventNotificationListener)) { + messageEventNotificationListeners.add(messageEventNotificationListener); + } + } + } + + /** + * Removes a message event notification listener. The listener will be fired anytime a notification + * event is received. + * + * @param messageEventNotificationListener a message event notification listener. + */ + public void removeMessageEventNotificationListener(MessageEventNotificationListener messageEventNotificationListener) { + synchronized (messageEventNotificationListeners) { + messageEventNotificationListeners.remove(messageEventNotificationListener); + } + } + + /** + * Fires message event request listeners. + */ + private void fireMessageEventRequestListeners( + String from, + String packetID, + String methodName) { + MessageEventRequestListener[] listeners = null; + Method method; + synchronized (messageEventRequestListeners) { + listeners = new MessageEventRequestListener[messageEventRequestListeners.size()]; + messageEventRequestListeners.toArray(listeners); + } + try { + method = + MessageEventRequestListener.class.getDeclaredMethod( + methodName, + new Class[] { String.class, String.class, MessageEventManager.class }); + for (int i = 0; i < listeners.length; i++) { + method.invoke(listeners[i], new Object[] { from, packetID, this }); + } + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + /** + * Fires message event notification listeners. + */ + private void fireMessageEventNotificationListeners( + String from, + String packetID, + String methodName) { + MessageEventNotificationListener[] listeners = null; + Method method; + synchronized (messageEventNotificationListeners) { + listeners = + new MessageEventNotificationListener[messageEventNotificationListeners.size()]; + messageEventNotificationListeners.toArray(listeners); + } + try { + method = + MessageEventNotificationListener.class.getDeclaredMethod( + methodName, + new Class[] { String.class, String.class }); + for (int i = 0; i < listeners.length; i++) { + method.invoke(listeners[i], new Object[] { from, packetID }); + } + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + private void init() { + // Listens for all message event packets and fire the proper message event listeners. + packetListener = new PacketListener() { + public void processPacket(Packet packet) { + Message message = (Message) packet; + MessageEvent messageEvent = + (MessageEvent) message.getExtension("x", "jabber:x:event"); + if (messageEvent.isMessageEventRequest()) { + // Fire event for requests of message events + for (Iterator it = messageEvent.getEventTypes(); it.hasNext();) + fireMessageEventRequestListeners( + message.getFrom(), + message.getPacketID(), + ((String) it.next()).concat("NotificationRequested")); + } else + // Fire event for notifications of message events + for (Iterator it = messageEvent.getEventTypes(); it.hasNext();) + fireMessageEventNotificationListeners( + message.getFrom(), + messageEvent.getPacketID(), + ((String) it.next()).concat("Notification")); + + }; + + }; + con.addPacketListener(packetListener, packetFilter); + } + + /** + * Sends the notification that the message was delivered to the sender of the original message + * + * @param to the recipient of the notification. + * @param packetId the id of the message to send. + */ + public void sendDeliveredNotification(String to, String packetID) { + // Create the message to send + Message msg = new Message(to); + // Create a MessageEvent Package and add it to the message + MessageEvent messageEvent = new MessageEvent(); + messageEvent.setDelivered(true); + messageEvent.setPacketID(packetID); + msg.addExtension(messageEvent); + // Send the packet + con.sendPacket(msg); + } + + /** + * Sends the notification that the message was displayed to the sender of the original message + * + * @param to the recipient of the notification. + * @param packetId the id of the message to send. + */ + public void sendDisplayedNotification(String to, String packetID) { + // Create the message to send + Message msg = new Message(to); + // Create a MessageEvent Package and add it to the message + MessageEvent messageEvent = new MessageEvent(); + messageEvent.setDisplayed(true); + messageEvent.setPacketID(packetID); + msg.addExtension(messageEvent); + // Send the packet + con.sendPacket(msg); + } + + /** + * Sends the notification that the receiver of the message is composing a reply + * + * @param to the recipient of the notification. + * @param packetId the id of the message to send. + */ + public void sendComposingNotification(String to, String packetID) { + // Create the message to send + Message msg = new Message(to); + // Create a MessageEvent Package and add it to the message + MessageEvent messageEvent = new MessageEvent(); + messageEvent.setComposing(true); + messageEvent.setPacketID(packetID); + msg.addExtension(messageEvent); + // Send the packet + con.sendPacket(msg); + } + + /** + * Sends the notification that the receiver of the message has cancelled composing a reply + * + * @param to the recipient of the notification. + * @param packetId the id of the message to send. + */ + public void sendCancelledNotification(String to, String packetID) { + // Create the message to send + Message msg = new Message(to); + // Create a MessageEvent Package and add it to the message + MessageEvent messageEvent = new MessageEvent(); + messageEvent.setCancelled(true); + messageEvent.setPacketID(packetID); + msg.addExtension(messageEvent); + // Send the packet + con.sendPacket(msg); + } + + public void destroy() { + if (con != null) + con.removePacketListener(packetListener); + + } + public void finalize() { + destroy(); + } + +} diff --git a/source/org/jivesoftware/smackx/MessageEventNotificationListener.java b/source/org/jivesoftware/smackx/MessageEventNotificationListener.java new file mode 100644 index 000000000..08bc16222 --- /dev/null +++ b/source/org/jivesoftware/smackx/MessageEventNotificationListener.java @@ -0,0 +1,106 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright (C) 2002-2003 Jive Software. All rights reserved. + * ==================================================================== + * The Jive Software License (based on Apache Software License, Version 1.1) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * Jive Software (http://www.jivesoftware.com)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Smack" and "Jive Software" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please + * contact webmaster@jivesoftware.com. + * + * 5. Products derived from this software may not be called "Smack", + * nor may "Smack" appear in their name, without prior written + * permission of Jive Software. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.jivesoftware.smackx; + +/** + * + * A listener that is fired anytime a message event notification is received. + * Message event notifications are received as a consequence of the request + * to receive notifications when sending a message. + * + * @author Gaston Dombiak + */ +public interface MessageEventNotificationListener { + + /** + * Called when a notification of message delivered is received. + * + * @param from the user that sent the notification. + * @param packetId the id of the message that was sent. + */ + public void deliveredNotification(String from, String packetID); + + /** + * Called when a notification of message displayed is received. + * + * @param from the user that sent the notification. + * @param packetId the id of the message that was sent. + */ + public void displayedNotification(String from, String packetID); + + /** + * Called when a notification that the receiver of the message is composing a reply is + * received. + * + * @param from the user that sent the notification. + * @param packetId the id of the message that was sent. + */ + public void composingNotification(String from, String packetID); + + /** + * Called when a notification that the receiver of the message is offline is received. + * + * @param from the user that sent the notification. + * @param packetId the id of the message that was sent. + */ + public void offlineNotification(String from, String packetID); + + /** + * Called when a notification that the receiver of the message cancelled the reply + * is received. + * + * @param from the user that sent the notification. + * @param packetId the id of the message that was sent. + */ + public void cancelledNotification(String from, String packetID); +} diff --git a/source/org/jivesoftware/smackx/MessageEventRequestListener.java b/source/org/jivesoftware/smackx/MessageEventRequestListener.java new file mode 100644 index 000000000..b1dc1dc40 --- /dev/null +++ b/source/org/jivesoftware/smackx/MessageEventRequestListener.java @@ -0,0 +1,124 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright (C) 2002-2003 Jive Software. All rights reserved. + * ==================================================================== + * The Jive Software License (based on Apache Software License, Version 1.1) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * Jive Software (http://www.jivesoftware.com)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Smack" and "Jive Software" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please + * contact webmaster@jivesoftware.com. + * + * 5. Products derived from this software may not be called "Smack", + * nor may "Smack" appear in their name, without prior written + * permission of Jive Software. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.jivesoftware.smackx; + +/** + * + * A listener that is fired anytime a message event request is received. + * Message event requests are received when the received message includes an extension + * like this: + * + * + * + * + * + * + * + * In this example you can see that the sender of the message requests to be notified + * when the user couldn't receive the message because he/she is offline, the message + * was delivered or when the receiver of the message is composing a reply. + * + * @author Gaston Dombiak + */ +public interface MessageEventRequestListener { + + /** + * Called when a request for message delivered notification is received. + * + * @param from the user that sent the notification. + * @param packetId the id of the message that was sent. + * @param messageEventManager the messageEventManager that fired the listener. + */ + public void deliveredNotificationRequested( + String from, + String packetID, + MessageEventManager messageEventManager); + + /** + * Called when a request for message displayed notification is received. + * + * @param from the user that sent the notification. + * @param packetId the id of the message that was sent. + * @param messageEventManager the messageEventManager that fired the listener. + */ + public void displayedNotificationRequested( + String from, + String packetID, + MessageEventManager messageEventManager); + + /** + * Called when a request that the receiver of the message is composing a reply notification is + * received. + * + * @param from the user that sent the notification. + * @param packetId the id of the message that was sent. + * @param messageEventManager the messageEventManager that fired the listener. + */ + public void composingNotificationRequested( + String from, + String packetID, + MessageEventManager messageEventManager); + + /** + * Called when a request that the receiver of the message is offline is received. + * + * @param from the user that sent the notification. + * @param packetId the id of the message that was sent. + * @param messageEventManager the messageEventManager that fired the listener. + */ + public void offlineNotificationRequested( + String from, + String packetID, + MessageEventManager messageEventManager); + +} diff --git a/source/org/jivesoftware/smackx/packet/MessageEvent.java b/source/org/jivesoftware/smackx/packet/MessageEvent.java new file mode 100644 index 000000000..1709908d7 --- /dev/null +++ b/source/org/jivesoftware/smackx/packet/MessageEvent.java @@ -0,0 +1,360 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright (C) 2002-2003 Jive Software. All rights reserved. + * ==================================================================== + * The Jive Software License (based on Apache Software License, Version 1.1) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * Jive Software (http://www.jivesoftware.com)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Smack" and "Jive Software" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please + * contact webmaster@jivesoftware.com. + * + * 5. Products derived from this software may not be called "Smack", + * nor may "Smack" appear in their name, without prior written + * permission of Jive Software. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.jivesoftware.smackx.packet; + +import java.util.*; + +import org.jivesoftware.smack.packet.PacketExtension; + +/** + * Represents message events relating to the delivery, display, composition and cancellation of + * messages. + * + * There are four message events currently defined in this namespace: + * 1.Offline + * Indicates that the message has been stored offline by the intended recipient's server. This + * event is triggered only if the intended recipient's server supports offline storage, has that + * support enabled, and the recipient is offline when the server receives the message for delivery. + * + * 2.Delivered + * Indicates that the message has been delivered to the recipient. This signifies that the message + * has reached the recipient's XMPP client, but does not necessarily mean that the message has + * been displayed. This event is to be raised by the XMPP client. + * + * 3.Displayed + * Once the message has been received by the recipient's XMPP client, it may be displayed to the + * user. This event indicates that the message has been displayed, and is to be raised by the + * XMPP client. Even if a message is displayed multiple times, this event should be raised only + * once. + * + * 4.Composing + * In threaded chat conversations, this indicates that the recipient is composing a reply to a + * message. The event is to be raised by the recipient's XMPP client. A XMPP client is allowed + * to raise this event multiple times in response to the same request, providing the original + * event is cancelled first. + * + * @author Gaston Dombiak + */ +public class MessageEvent implements PacketExtension { + + public static final String OFFLINE = "offline"; + public static final String COMPOSING = "composing"; + public static final String DISPLAYED = "displayed"; + public static final String DELIVERED = "delivered"; + public static final String CANCELLED = "cancelled"; + + private boolean offline = false; + private boolean delivered = false; + private boolean displayed = false; + private boolean composing = false; + private boolean cancelled = true; + + private String packetID = null; + + /** + * Returns the XML element name of the extension sub-packet root element. + * Always returns "x" + * + * @return the XML element name of the packet extension. + */ + public String getElementName() { + return "x"; + } + + /** + * Returns the XML namespace of the extension sub-packet root element. + * According the specification the namespace is always "jabber:x:event" + * + * @return the XML namespace of the packet extension. + */ + public String getNamespace() { + return "jabber:x:event"; + } + + /** + * When the message is a request returns if the sender of the message requests to be notified + * when the receiver is composing a reply. + * When the message is a notification returns if the receiver of the message is composing a + * reply. + * + * @return true if the sender is requesting to be notified when composing or when notifying + * that the receiver of the message is composing a reply + */ + public boolean isComposing() { + return composing; + } + + /** + * When the message is a request returns if the sender of the message requests to be notified + * when the message is delivered. + * When the message is a notification returns if the message was delivered or not. + * + * @return true if the sender is requesting to be notified when delivered or when notifying + * that the message was delivered + */ + public boolean isDelivered() { + return delivered; + } + + /** + * When the message is a request returns if the sender of the message requests to be notified + * when the message is displayed. + * When the message is a notification returns if the message was displayed or not. + * + * @return true if the sender is requesting to be notified when displayed or when notifying + * that the message was displayed + */ + public boolean isDisplayed() { + return displayed; + } + + /** + * When the message is a request returns if the sender of the message requests to be notified + * when the receiver of the message is offline. + * When the message is a notification returns if the receiver of the message was offline. + * + * @return true if the sender is requesting to be notified when offline or when notifying + * that the receiver of the message is offline + */ + public boolean isOffline() { + return offline; + } + + /** + * When the message is a notification returns if the receiver of the message cancelled + * composing a reply. + * + * @return true if the receiver of the message cancelled composing a reply + */ + public boolean isCancelled() { + return cancelled; + } + + /** + * Returns the unique ID of the message that requested to be notified of the event. + * The packet id is not used when the message is a request for notifications + * + * @return the message id that requested to be notified of the event. + */ + public String getPacketID() { + return packetID; + } + + /** + * Returns the types of events. The type of event could be: + * "offline", "composing","delivered","displayed", "offline" + * + * @return an iterator over all the types of events of the MessageEvent. + */ + public Iterator getEventTypes() { + ArrayList allEvents = new ArrayList(); + if (isDelivered()) { + allEvents.add(MessageEvent.DELIVERED); + } + if (isCancelled()) { + allEvents.add(MessageEvent.CANCELLED); + } + if (isComposing()) { + allEvents.add(MessageEvent.COMPOSING); + } + if (isDisplayed()) { + allEvents.add(MessageEvent.DISPLAYED); + } + if (isOffline()) { + allEvents.add(MessageEvent.OFFLINE); + } + return allEvents.iterator(); + } + + /** + * When the message is a request sets if the sender of the message requests to be notified + * when the receiver is composing a reply. + * When the message is a notification sets if the receiver of the message is composing a + * reply. + * + * @param composing sets if the sender is requesting to be notified when composing or when + * notifying that the receiver of the message is composing a reply + */ + public void setComposing(boolean composing) { + this.composing = composing; + setCancelled(false); + } + + /** + * When the message is a request sets if the sender of the message requests to be notified + * when the message is delivered. + * When the message is a notification sets if the message was delivered or not. + * + * @param delivered sets if the sender is requesting to be notified when delivered or when + * notifying that the message was delivered + */ + public void setDelivered(boolean delivered) { + this.delivered = delivered; + setCancelled(false); + } + + /** + * When the message is a request sets if the sender of the message requests to be notified + * when the message is displayed. + * When the message is a notification sets if the message was displayed or not. + * + * @param displayed sets if the sender is requesting to be notified when displayed or when + * notifying that the message was displayed + */ + public void setDisplayed(boolean displayed) { + this.displayed = displayed; + setCancelled(false); + } + + /** + * When the message is a request sets if the sender of the message requests to be notified + * when the receiver of the message is offline. + * When the message is a notification sets if the receiver of the message was offline. + * + * @param offline sets if the sender is requesting to be notified when offline or when + * notifying that the receiver of the message is offline + */ + public void setOffline(boolean offline) { + this.offline = offline; + setCancelled(false); + } + + /** + * When the message is a notification sets if the receiver of the message cancelled + * composing a reply. + * The Cancelled event is never requested explicitly. It is requested implicitly when + * requesting to be notified of the Composing event. + * + * @param cancelled sets if the receiver of the message cancelled composing a reply + */ + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + /** + * Sets the unique ID of the message that requested to be notified of the event. + * The packet id is not used when the message is a request for notifications + * + * @param packetID the message id that requested to be notified of the event. + */ + public void setPacketID(String packetID) { + this.packetID = packetID; + } + + /** + * Returns true if this MessageEvent is a request for notifications. + * Returns false if this MessageEvent is a notification of an event. + * + * @return true if this message is a request for notifications. + */ + public boolean isMessageEventRequest() { + return this.packetID == null; + } + + /** + * Returns the XML representation of a Message Event according the specification. + * + * Usually the XML representation will be inside of a Message XML representation like + * in the following examples: + * + * Request to be notified when displayed: + * + * + * + * + * + * + * Notification of displayed: + * + * + * + * message22 + * + * + * + */ + public String toXML() { + StringBuffer buf = new StringBuffer(); + buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append( + "\">"); + // Note: Cancellation events don't specify any tag. They just send the packetID + + // Add the offline tag if the sender requests to be notified of offline events or if + // the target is offline + if (isOffline()) + buf.append("<").append(MessageEvent.OFFLINE).append("/>"); + // Add the delivered tag if the sender requests to be notified when the message is + // delivered or if the target notifies that the message has been delivered + if (isDelivered()) + buf.append("<").append(MessageEvent.DELIVERED).append("/>"); + // Add the displayed tag if the sender requests to be notified when the message is + // displayed or if the target notifies that the message has been displayed + if (isDisplayed()) + buf.append("<").append(MessageEvent.DISPLAYED).append("/>"); + // Add the composing tag if the sender requests to be notified when the target is + // composing a reply or if the target notifies that he/she is composing a reply + if (isComposing()) + buf.append("<").append(MessageEvent.COMPOSING).append("/>"); + // Add the id tag only if the MessageEvent is a notification message (not a request) + if (getPacketID() != null) + buf.append("").append(getPacketID()).append(""); + buf.append(""); + return buf.toString(); + } + +} diff --git a/source/org/jivesoftware/smackx/provider/MessageEventProvider.java b/source/org/jivesoftware/smackx/provider/MessageEventProvider.java new file mode 100644 index 000000000..9b6b039aa --- /dev/null +++ b/source/org/jivesoftware/smackx/provider/MessageEventProvider.java @@ -0,0 +1,109 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright (C) 2002-2003 Jive Software. All rights reserved. + * ==================================================================== + * The Jive Software License (based on Apache Software License, Version 1.1) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * Jive Software (http://www.jivesoftware.com)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Smack" and "Jive Software" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please + * contact webmaster@jivesoftware.com. + * + * 5. Products derived from this software may not be called "Smack", + * nor may "Smack" appear in their name, without prior written + * permission of Jive Software. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.jivesoftware.smackx.provider; + +import org.jivesoftware.smack.packet.PacketExtension; +import org.jivesoftware.smack.provider.PacketExtensionProvider; +import org.jivesoftware.smackx.packet.MessageEvent; +import org.xmlpull.v1.XmlPullParser; + +/** + * + * The MessageEventProvider parses Message Event packets. +* + * @author Gaston Dombiak + */ +public class MessageEventProvider implements PacketExtensionProvider { + + /** + * Creates a new MessageEventProvider. + * ProviderManager requires that every PacketExtensionProvider has a public, no-argument constructor + */ + public MessageEventProvider() { + } + + /** + * Parses a MessageEvent packet (extension sub-packet). + * + * @param parser the XML parser, positioned at the starting element of the extension. + * @return a PacketExtension. + * @throws Exception if a parsing error occurs. + */ + public PacketExtension parseExtension(XmlPullParser parser) + throws Exception { + MessageEvent messageEvent = new MessageEvent(); + boolean done = false; + while (!done) { + int eventType = parser.next(); + if (eventType == XmlPullParser.START_TAG) { + if (parser.getName().equals("id")) + messageEvent.setPacketID(parser.nextText()); + if (parser.getName().equals(MessageEvent.COMPOSING)) + messageEvent.setComposing(true); + if (parser.getName().equals(MessageEvent.DELIVERED)) + messageEvent.setDelivered(true); + if (parser.getName().equals(MessageEvent.DISPLAYED)) + messageEvent.setDisplayed(true); + if (parser.getName().equals(MessageEvent.OFFLINE)) + messageEvent.setOffline(true); + } else if (eventType == XmlPullParser.END_TAG) { + if (parser.getName().equals("x")) { + done = true; + } + } + } + + return messageEvent; + } + +} diff --git a/test/org/jivesoftware/smackx/MessageEventManagerTest.java b/test/org/jivesoftware/smackx/MessageEventManagerTest.java new file mode 100644 index 000000000..ab62b78fc --- /dev/null +++ b/test/org/jivesoftware/smackx/MessageEventManagerTest.java @@ -0,0 +1,335 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright (C) 2002-2003 Jive Software. All rights reserved. + * ==================================================================== + * The Jive Software License (based on Apache Software License, Version 1.1) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * Jive Software (http://www.jivesoftware.com)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Smack" and "Jive Software" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please + * contact webmaster@jivesoftware.com. + * + * 5. Products derived from this software may not be called "Smack", + * nor may "Smack" appear in their name, without prior written + * permission of Jive Software. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.jivesoftware.smackx; + +import java.util.ArrayList; + +import org.jivesoftware.smack.*; +import org.jivesoftware.smack.packet.*; + +import junit.framework.TestCase; + +/** + * + * Test the MessageEvent extension using the high level API. + * + * @author Gaston Dombiak + */ +public class MessageEventManagerTest extends TestCase { + + /** + * Constructor for MessageEventManagerTest. + * @param name + */ + public MessageEventManagerTest(String name) { + super(name); + } + + /** + * High level API test. + * This is a simple test to use with a XMPP client and check if the client receives the + * message + * 1. User_1 will send a message to user_2 requesting to be notified when any of these events + * occurs: offline, composing, displayed or delivered + */ + public void testSendMessageEventRequest() { + String host = "localhost"; + String server_user1 = "gato3"; + String user1 = "gato3@localhost"; + String pass1 = "gato3"; + + String user2 = "gato4@localhost"; + + XMPPConnection conn1 = null; + + try { + // Connect to the server and log in the users + conn1 = new XMPPConnection(host); + conn1.login(server_user1, pass1); + + // Create a chat for each connection + Chat chat1 = conn1.createChat(user2); + + // Create the message to send with the roster + Message msg = chat1.createMessage(); + msg.setSubject("Any subject you want"); + msg.setBody("An interesting body comes here..."); + // Add to the message all the notifications requests (offline, delivered, displayed, + // composing) + MessageEventManager.addNotificationsRequests(msg, true, true, true, true); + + // Send the message that contains the notifications request + try { + chat1.sendMessage(msg); + } catch (Exception e) { + fail("An error occured sending the message"); + } + } catch (Exception e) { + fail(e.toString()); + } finally { + if (conn1 != null) + conn1.close(); + } + } + + /** + * High level API test. + * This is a simple test to use with a XMPP client, check if the client receives the + * message and display in the console any notification + * 1. User_1 will send a message to user_2 requesting to be notified when any of these events + * occurs: offline, composing, displayed or delivered + * 2. User_2 will use a XMPP client (like Exodus) to display the message and compose a reply + * 3. User_1 will display any notification that receives + */ + public void testSendMessageEventRequestAndDisplayNotifications() { + String host = "localhost"; + String server_user1 = "gato3"; + String user1 = "gato3@localhost"; + String pass1 = "gato3"; + + String user2 = "gato4@localhost"; + + XMPPConnection conn1 = null; + + try { + // Connect to the server and log in the users + conn1 = new XMPPConnection(host); + conn1.login(server_user1, pass1); + + // Create a chat for each connection + Chat chat1 = conn1.createChat(user2); + + MessageEventManager messageEventManager = new MessageEventManager(conn1); + messageEventManager + .addMessageEventNotificationListener(new MessageEventNotificationListener() { + public void deliveredNotification(String from, String packetID) { + System.out.println("From: " + from + " PacketID: " + packetID + "(delivered)"); + } + + public void displayedNotification(String from, String packetID) { + System.out.println("From: " + from + " PacketID: " + packetID + "(displayed)"); + } + + public void composingNotification(String from, String packetID) { + System.out.println("From: " + from + " PacketID: " + packetID + "(composing)"); + } + + public void offlineNotification(String from, String packetID) { + System.out.println("From: " + from + " PacketID: " + packetID + "(offline)"); + } + + public void cancelledNotification(String from, String packetID) { + System.out.println("From: " + from + " PacketID: " + packetID + "(cancelled)"); + } + }); + + // Create the message to send with the roster + Message msg = chat1.createMessage(); + msg.setSubject("Any subject you want"); + msg.setBody("An interesting body comes here..."); + // Add to the message all the notifications requests (offline, delivered, displayed, + // composing) + MessageEventManager.addNotificationsRequests(msg, true, true, true, true); + + // Send the message that contains the notifications request + try { + chat1.sendMessage(msg); + // Wait a few seconds so that the XMPP client can send any event + Thread.sleep(5000); + } catch (Exception e) { + fail("An error occured sending the message"); + } + } catch (Exception e) { + fail(e.toString()); + } finally { + if (conn1 != null) + conn1.close(); + } + } + + /** + * High level API test. + * 1. User_1 will send a message to user_2 requesting to be notified when any of these events + * occurs: offline, composing, displayed or delivered + * 2. User_2 will receive the message + * 3. User_2 will simulate that the message was displayed + * 4. User_2 will simulate that he/she is composing a reply + * 5. User_2 will simulate that he/she has cancelled the reply + */ + public void testRequestsAndNotifications() { + String host = "localhost"; + String server_user1 = "gato3"; + String user1 = "gato3@localhost"; + String pass1 = "gato3"; + + String server_user2 = "gato4"; + String user2 = "gato4@localhost"; + String pass2 = "gato4"; + + XMPPConnection conn1 = null; + XMPPConnection conn2 = null; + + final ArrayList results = new ArrayList(); + ArrayList resultsExpected = new ArrayList(); + resultsExpected.add("deliveredNotificationRequested"); + resultsExpected.add("composingNotificationRequested"); + resultsExpected.add("displayedNotificationRequested"); + resultsExpected.add("offlineNotificationRequested"); + resultsExpected.add("deliveredNotification"); + resultsExpected.add("displayedNotification"); + resultsExpected.add("composingNotification"); + resultsExpected.add("cancelledNotification"); + + try { + // Connect to the server and log in the users + conn1 = new XMPPConnection(host); + conn1.login(server_user1, pass1); + conn2 = new XMPPConnection(host); + conn2.login(server_user2, pass2); + + // Create a chat for each connection + Chat chat1 = conn1.createChat(user2); + + MessageEventManager messageEventManager1 = new MessageEventManager(conn1); + messageEventManager1 + .addMessageEventNotificationListener(new MessageEventNotificationListener() { + public void deliveredNotification(String from, String packetID) { + results.add("deliveredNotification"); + } + + public void displayedNotification(String from, String packetID) { + results.add("displayedNotification"); + } + + public void composingNotification(String from, String packetID) { + results.add("composingNotification"); + } + + public void offlineNotification(String from, String packetID) { + results.add("offlineNotification"); + } + + public void cancelledNotification(String from, String packetID) { + results.add("cancelledNotification"); + } + }); + + MessageEventManager messageEventManager2 = new MessageEventManager(conn2); + messageEventManager2 + .addMessageEventRequestListener(new DefaultMessageEventRequestListener() { + public void deliveredNotificationRequested( + String from, + String packetID, + MessageEventManager messageEventManager) { + super.deliveredNotificationRequested(from, packetID, messageEventManager); + results.add("deliveredNotificationRequested"); + } + + public void displayedNotificationRequested( + String from, + String packetID, + MessageEventManager messageEventManager) { + super.displayedNotificationRequested(from, packetID, messageEventManager); + results.add("displayedNotificationRequested"); + } + + public void composingNotificationRequested( + String from, + String packetID, + MessageEventManager messageEventManager) { + super.composingNotificationRequested(from, packetID, messageEventManager); + results.add("composingNotificationRequested"); + } + + public void offlineNotificationRequested( + String from, + String packetID, + MessageEventManager messageEventManager) { + super.offlineNotificationRequested(from, packetID, messageEventManager); + results.add("offlineNotificationRequested"); + } + }); + + // Create the message to send with the roster + Message msg = chat1.createMessage(); + msg.setSubject("Any subject you want"); + msg.setBody("An interesting body comes here..."); + // Add to the message all the notifications requests (offline, delivered, displayed, + // composing) + MessageEventManager.addNotificationsRequests(msg, true, true, true, true); + + // Send the message that contains the notifications request + try { + chat1.sendMessage(msg); + messageEventManager2.sendDisplayedNotification(user1, msg.getPacketID()); + messageEventManager2.sendComposingNotification(user1, msg.getPacketID()); + messageEventManager2.sendCancelledNotification(user1, msg.getPacketID()); + // Wait half second so that the complete test can run + Thread.sleep(500); + assertTrue("Test failed due to bad results (1)" + resultsExpected, resultsExpected.containsAll(results)); + assertTrue("Test failed due to bad results (2)" + results, results.containsAll(resultsExpected)); + + } catch (Exception e) { + fail("An error occured sending the message"); + } + } catch (Exception e) { + fail(e.toString()); + } finally { + if (conn1 != null) + conn1.close(); + if (conn2 != null) + conn2.close(); + } + } + +} diff --git a/test/org/jivesoftware/smackx/MessageEventTests.java b/test/org/jivesoftware/smackx/MessageEventTests.java new file mode 100644 index 000000000..a0e9d0197 --- /dev/null +++ b/test/org/jivesoftware/smackx/MessageEventTests.java @@ -0,0 +1,76 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright (C) 2002-2003 Jive Software. All rights reserved. + * ==================================================================== + * The Jive Software License (based on Apache Software License, Version 1.1) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * Jive Software (http://www.jivesoftware.com)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Smack" and "Jive Software" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please + * contact webmaster@jivesoftware.com. + * + * 5. Products derived from this software may not be called "Smack", + * nor may "Smack" appear in their name, without prior written + * permission of Jive Software. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.jivesoftware.smackx; + +import org.jivesoftware.smackx.packet.MessageEventTest; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * + * Test suite that runs all the Message Event extension tests + * + * @author Gaston Dombiak + */ +public class MessageEventTests extends RosterExchangeTests { + + public static Test suite() { + TestSuite suite = new TestSuite("High and low level API tests for message event extension"); + //$JUnit-BEGIN$ + suite.addTest(new TestSuite(MessageEventManagerTest.class)); + suite.addTest(new TestSuite(MessageEventTest.class)); + //$JUnit-END$ + return suite; + } +} diff --git a/test/org/jivesoftware/smackx/packet/MessageEventTest.java b/test/org/jivesoftware/smackx/packet/MessageEventTest.java new file mode 100644 index 000000000..742f527a3 --- /dev/null +++ b/test/org/jivesoftware/smackx/packet/MessageEventTest.java @@ -0,0 +1,203 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright (C) 2002-2003 Jive Software. All rights reserved. + * ==================================================================== + * The Jive Software License (based on Apache Software License, Version 1.1) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * Jive Software (http://www.jivesoftware.com)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Smack" and "Jive Software" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please + * contact webmaster@jivesoftware.com. + * + * 5. Products derived from this software may not be called "Smack", + * nor may "Smack" appear in their name, without prior written + * permission of Jive Software. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.jivesoftware.smackx.packet; + +import org.jivesoftware.smack.*; +import org.jivesoftware.smack.filter.*; +import org.jivesoftware.smack.packet.*; + +import junit.framework.TestCase; + +/** + * + * Test the MessageEvent extension using the low level API + * + * @author Gaston Dombiak + */ +public class MessageEventTest extends TestCase { + + /** + * Constructor for MessageEventTest. + * @param name + */ + public MessageEventTest(String name) { + super(name); + } + + /** + * Low level API test. + * This is a simple test to use with a XMPP client and check if the client receives the + * message + * 1. User_1 will send a message to user_2 requesting to be notified when any of these events + * occurs: offline, composing, displayed or delivered + */ + public void testSendMessageEventRequest() { + String host = "localhost"; + String server_user1 = "gato3"; + String user1 = "gato3@localhost"; + String pass1 = "gato3"; + + String user2 = "gato4@localhost"; + + XMPPConnection conn1 = null; + + try { + // Connect to the server and log in the users + conn1 = new XMPPConnection(host); + conn1.login(server_user1, pass1); + + // Create a chat for each connection + Chat chat1 = conn1.createChat(user2); + + // Create the message to send with the roster + Message msg = chat1.createMessage(); + msg.setSubject("Any subject you want"); + msg.setBody("An interesting body comes here..."); + // Create a MessageEvent Package and add it to the message + MessageEvent messageEvent = new MessageEvent(); + messageEvent.setComposing(true); + messageEvent.setDelivered(true); + messageEvent.setDisplayed(true); + messageEvent.setOffline(true); + msg.addExtension(messageEvent); + + // Send the message that contains the notifications request + try { + chat1.sendMessage(msg); + // Wait half second so that the complete test can run + Thread.sleep(500); + } catch (Exception e) { + fail("An error occured sending the message"); + } + } catch (Exception e) { + fail(e.toString()); + } finally { + if (conn1 != null) + conn1.close(); + } + } + + /** + * Low level API test. + * This is a simple test to use with a XMPP client, check if the client receives the + * message and display in the console any notification + * 1. User_1 will send a message to user_2 requesting to be notified when any of these events + * occurs: offline, composing, displayed or delivered + * 2. User_2 will use a XMPP client (like Exodus) to display the message and compose a reply + * 3. User_1 will display any notification that receives + */ + public void testSendMessageEventRequestAndDisplayNotifications() { + String host = "localhost"; + String server_user1 = "gato3"; + String user1 = "gato3@localhost"; + String pass1 = "gato3"; + + String user2 = "gato4@localhost"; + + XMPPConnection conn1 = null; + + try { + // Connect to the server and log in the users + conn1 = new XMPPConnection(host); + conn1.login(server_user1, pass1); + + // Create a chat for each connection + Chat chat1 = conn1.createChat(user2); + + // Create a Listener that listens for Messages with the extension "jabber:x:roster" + // This listener will listen on the conn2 and answer an ACK if everything is ok + PacketFilter packetFilter = new PacketExtensionFilter("x", "jabber:x:event"); + PacketListener packetListener = new PacketListener() { + public void processPacket(Packet packet) { + Message message = (Message) packet; + try { + MessageEvent messageEvent = (MessageEvent) message.getExtension("x", "jabber:x:event"); + assertNotNull("Message without extension \"jabber:x:event\"", messageEvent); + assertTrue("Message event is a request not a notification", !messageEvent.isMessageEventRequest()); + System.out.println(messageEvent.toXML()); + } catch (ClassCastException e) { + fail("ClassCastException - Most probable cause is that smack providers is misconfigured"); + } + } + }; + conn1.addPacketListener(packetListener, packetFilter); + + // Create the message to send with the roster + Message msg = chat1.createMessage(); + msg.setSubject("Any subject you want"); + msg.setBody("An interesting body comes here..."); + // Create a MessageEvent Package and add it to the message + MessageEvent messageEvent = new MessageEvent(); + messageEvent.setComposing(true); + messageEvent.setDelivered(true); + messageEvent.setDisplayed(true); + messageEvent.setOffline(true); + msg.addExtension(messageEvent); + + // Send the message that contains the notifications request + try { + chat1.sendMessage(msg); + // Wait half second so that the complete test can run + Thread.sleep(500); + } catch (Exception e) { + fail("An error occured sending the message"); + } + } catch (Exception e) { + fail(e.toString()); + } finally { + if (conn1 != null) + conn1.close(); + } + } + +}