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("").append(getElementName()).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();
+ }
+ }
+
+}