diff --git a/source/org/jivesoftware/smackx/OfflineMessageHeader.java b/source/org/jivesoftware/smackx/OfflineMessageHeader.java new file mode 100644 index 000000000..c3ff215a1 --- /dev/null +++ b/source/org/jivesoftware/smackx/OfflineMessageHeader.java @@ -0,0 +1,85 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright 2003-2004 Jive Software. + * + * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jivesoftware.smackx; + +import org.jivesoftware.smackx.packet.DiscoverItems; + +/** + * The OfflineMessageHeader holds header information of an offline message. The header + * information was retrieved using the {@link OfflineMessageManager} class.
+ * + * Each offline message is identified by the target user of the offline message and a unique stamp. + * Use {@link OfflineMessageManager#getMessages(java.util.List)} to retrieve the whole message. + * + * @author Gaston Dombiak + */ +public class OfflineMessageHeader { + /** + * Bare JID of the user that was offline when the message was sent. + */ + private String user; + /** + * Full JID of the user that sent the message. + */ + private String jid; + /** + * Stamp that uniquely identifies the offline message. This stamp will be used for + * getting the specific message or delete it. The stamp may be of the form UTC timestamps + * but it is not required to have that format. + */ + private String stamp; + + public OfflineMessageHeader(DiscoverItems.Item item) { + super(); + user = item.getEntityID(); + jid = item.getName(); + stamp = item.getNode(); + } + + /** + * Returns the bare JID of the user that was offline when the message was sent. + * + * @return the bare JID of the user that was offline when the message was sent. + */ + public String getUser() { + return user; + } + + /** + * Returns the full JID of the user that sent the message. + * + * @return the full JID of the user that sent the message. + */ + public String getJid() { + return jid; + } + + /** + * Returns the stamp that uniquely identifies the offline message. This stamp will + * be used for getting the specific message or delete it. The stamp may be of the + * form UTC timestamps but it is not required to have that format. + * + * @return the stamp that uniquely identifies the offline message. + */ + public String getStamp() { + return stamp; + } +} diff --git a/source/org/jivesoftware/smackx/OfflineMessageManager.java b/source/org/jivesoftware/smackx/OfflineMessageManager.java new file mode 100644 index 000000000..ba4331d83 --- /dev/null +++ b/source/org/jivesoftware/smackx/OfflineMessageManager.java @@ -0,0 +1,284 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright 2003-2004 Jive Software. + * + * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jivesoftware.smackx; + +import org.jivesoftware.smack.PacketCollector; +import org.jivesoftware.smack.SmackConfiguration; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.filter.*; +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Packet; +import org.jivesoftware.smackx.packet.DiscoverInfo; +import org.jivesoftware.smackx.packet.DiscoverItems; +import org.jivesoftware.smackx.packet.OfflineMessageInfo; +import org.jivesoftware.smackx.packet.OfflineMessageRequest; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * The OfflineMessageManager helps manage offline messages even before the user has sent an + * available presence. When a user asks for his offline messages before sending an available + * presence then the server will not send a flood with all the offline messages when the user + * becomes online. The server will not send a flood with all the offline messages to the session + * that made the offline messages request or to any other session used by the user that becomes + * online.
+ *
+ * Once the session that made the offline messages request has been closed and the user becomes
+ * offline in all the resources then the server will resume storing the messages offline and will
+ * send all the offline messages to the user when he becomes online. Therefore, the server will
+ * flood the user when he becomes online unless the user uses this class to manage his offline
+ * messages.
+ *
+ * @author Gaston Dombiak
+ */
+public class OfflineMessageManager {
+
+ private final static String namespace = "http://jabber.org/protocol/offline";
+
+ private XMPPConnection connection;
+
+ private PacketFilter packetFilter;
+
+ public OfflineMessageManager(XMPPConnection connection) {
+ this.connection = connection;
+ packetFilter =
+ new AndFilter(new PacketExtensionFilter("offline", namespace),
+ new PacketTypeFilter(Message.class));
+ }
+
+ /**
+ * Returns true if the server supports Flexible Offline Message Retrieval. When the server
+ * supports Flexible Offline Message Retrieval it is possible to get the header of the offline
+ * messages, get specific messages, delete specific messages, etc.
+ *
+ * @return a boolean indicating if the server supports Flexible Offline Message Retrieval.
+ * @throws XMPPException If the user is not allowed to make this request.
+ */
+ public boolean supportsFlexibleRetrieval() throws XMPPException {
+ DiscoverInfo info = ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(null);
+ return info.containsFeature(namespace);
+ }
+
+ /**
+ * Returns the number of offline messages for the user of the connection.
+ *
+ * @return the number of offline messages for the user of the connection.
+ * @throws XMPPException If the user is not allowed to make this request or the server does
+ * not support offline message retrieval.
+ */
+ public int getMessageCount() throws XMPPException {
+ DiscoverInfo info = ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(null,
+ namespace);
+ Form extendedInfo = Form.getFormFrom(info);
+ if (extendedInfo != null) {
+ String value = (String) extendedInfo.getField("number_of_messages").getValues().next();
+ return Integer.parseInt(value);
+ }
+ return 0;
+ }
+
+ /**
+ * Returns an iterator on OfflineMessageHeader that keep information about the
+ * offline message. The OfflineMessageHeader includes a stamp that could be used to retrieve
+ * the complete message or delete the specific message.
+ *
+ * @return an iterator on OfflineMessageHeader that keep information about the offline
+ * message.
+ * @throws XMPPException If the user is not allowed to make this request or the server does
+ * not support offline message retrieval.
+ */
+ public Iterator getHeaders() throws XMPPException {
+ List answer = new ArrayList();
+ DiscoverItems items = ServiceDiscoveryManager.getInstanceFor(connection).discoverItems(
+ null, namespace);
+ for (Iterator it = items.getItems(); it.hasNext();) {
+ DiscoverItems.Item item = (DiscoverItems.Item) it.next();
+ answer.add(new OfflineMessageHeader(item));
+ }
+ return answer.iterator();
+ }
+
+ /**
+ * Returns an Iterator with the offline Messages whose stamp matches the specified
+ * request. The request will include the list of stamps that uniquely identifies
+ * the offline messages to retrieve. The returned offline messages will not be deleted
+ * from the server. Use {@link #deleteMessages(java.util.List)} to delete the messages.
+ *
+ * @param nodes the list of stamps that uniquely identifies offline message.
+ * @return an Iterator with the offline Messages that were received as part of
+ * this request.
+ * @throws XMPPException If the user is not allowed to make this request or the server does
+ * not support offline message retrieval.
+ */
+ public Iterator getMessages(final List nodes) throws XMPPException {
+ List messages = new ArrayList();
+ OfflineMessageRequest request = new OfflineMessageRequest();
+ for (Iterator it = nodes.iterator(); it.hasNext();) {
+ OfflineMessageRequest.Item item = new OfflineMessageRequest.Item((String) it.next());
+ item.setAction("view");
+ request.addItem(item);
+ }
+ // Filter packets looking for an answer from the server.
+ PacketFilter responseFilter = new PacketIDFilter(request.getPacketID());
+ PacketCollector response = connection.createPacketCollector(responseFilter);
+ // Filter offline messages that were requested by this request
+ PacketFilter messageFilter = new AndFilter(packetFilter, new PacketFilter() {
+ public boolean accept(Packet packet) {
+ OfflineMessageInfo info = (OfflineMessageInfo) packet.getExtension("offline",
+ namespace);
+ return nodes.contains(info.getNode());
+ }
+ });
+ PacketCollector messageCollector = connection.createPacketCollector(messageFilter);
+ // Send the retrieval request to the server.
+ connection.sendPacket(request);
+ // Wait up to a certain number of seconds for a reply.
+ IQ answer = (IQ) response.nextResult(SmackConfiguration.getPacketReplyTimeout());
+ // Stop queuing results
+ response.cancel();
+
+ if (answer == null) {
+ throw new XMPPException("No response from server.");
+ } else if (answer.getError() != null) {
+ throw new XMPPException(answer.getError());
+ }
+
+ // Collect the received offline messages
+ Message message = (Message) messageCollector.nextResult(
+ SmackConfiguration.getPacketReplyTimeout());
+ while (message != null) {
+ messages.add(message);
+ message =
+ (Message) messageCollector.nextResult(
+ SmackConfiguration.getPacketReplyTimeout());
+ }
+ // Stop queuing offline messages
+ messageCollector.cancel();
+ return messages.iterator();
+ }
+
+ /**
+ * Returns an Iterator with all the offline Messages of the user. The returned offline
+ * messages will not be deleted from the server. Use {@link #deleteMessages(java.util.List)}
+ * to delete the messages.
+ *
+ * @return an Iterator with all the offline Messages of the user.
+ * @throws XMPPException If the user is not allowed to make this request or the server does
+ * not support offline message retrieval.
+ */
+ public Iterator getMessages() throws XMPPException {
+ List messages = new ArrayList();
+ OfflineMessageRequest request = new OfflineMessageRequest();
+ request.setFetch(true);
+ // Filter packets looking for an answer from the server.
+ PacketFilter responseFilter = new PacketIDFilter(request.getPacketID());
+ PacketCollector response = connection.createPacketCollector(responseFilter);
+ // Filter offline messages that were requested by this request
+ PacketCollector messageCollector = connection.createPacketCollector(packetFilter);
+ // Send the retrieval request to the server.
+ connection.sendPacket(request);
+ // Wait up to a certain number of seconds for a reply.
+ IQ answer = (IQ) response.nextResult(SmackConfiguration.getPacketReplyTimeout());
+ // Stop queuing results
+ response.cancel();
+
+ if (answer == null) {
+ throw new XMPPException("No response from server.");
+ } else if (answer.getError() != null) {
+ throw new XMPPException(answer.getError());
+ }
+
+ // Collect the received offline messages
+ Message message = (Message) messageCollector.nextResult(
+ SmackConfiguration.getPacketReplyTimeout());
+ while (message != null) {
+ messages.add(message);
+ message =
+ (Message) messageCollector.nextResult(
+ SmackConfiguration.getPacketReplyTimeout());
+ }
+ // Stop queuing offline messages
+ messageCollector.cancel();
+ return messages.iterator();
+ }
+
+ /**
+ * Deletes the specified list of offline messages. The request will include the list of
+ * stamps that uniquely identifies the offline messages to delete.
+ *
+ * @param nodes the list of stamps that uniquely identifies offline message.
+ * @throws XMPPException If the user is not allowed to make this request or the server does
+ * not support offline message retrieval.
+ */
+ public void deleteMessages(List nodes) throws XMPPException {
+ OfflineMessageRequest request = new OfflineMessageRequest();
+ for (Iterator it = nodes.iterator(); it.hasNext();) {
+ OfflineMessageRequest.Item item = new OfflineMessageRequest.Item((String) it.next());
+ item.setAction("remove");
+ request.addItem(item);
+ }
+ // Filter packets looking for an answer from the server.
+ PacketFilter responseFilter = new PacketIDFilter(request.getPacketID());
+ PacketCollector response = connection.createPacketCollector(responseFilter);
+ // Send the deletion request to the server.
+ connection.sendPacket(request);
+ // Wait up to a certain number of seconds for a reply.
+ IQ answer = (IQ) response.nextResult(SmackConfiguration.getPacketReplyTimeout());
+ // Stop queuing results
+ response.cancel();
+
+ if (answer == null) {
+ throw new XMPPException("No response from server.");
+ } else if (answer.getError() != null) {
+ throw new XMPPException(answer.getError());
+ }
+ }
+
+ /**
+ * Deletes all offline messages of the user.
+ *
+ * @throws XMPPException If the user is not allowed to make this request or the server does
+ * not support offline message retrieval.
+ */
+ public void deleteMessages() throws XMPPException {
+ OfflineMessageRequest request = new OfflineMessageRequest();
+ request.setPurge(true);
+ // Filter packets looking for an answer from the server.
+ PacketFilter responseFilter = new PacketIDFilter(request.getPacketID());
+ PacketCollector response = connection.createPacketCollector(responseFilter);
+ // Send the deletion request to the server.
+ connection.sendPacket(request);
+ // Wait up to a certain number of seconds for a reply.
+ IQ answer = (IQ) response.nextResult(SmackConfiguration.getPacketReplyTimeout());
+ // Stop queuing results
+ response.cancel();
+
+ if (answer == null) {
+ throw new XMPPException("No response from server.");
+ } else if (answer.getError() != null) {
+ throw new XMPPException(answer.getError());
+ }
+ }
+}
diff --git a/source/org/jivesoftware/smackx/packet/OfflineMessageInfo.java b/source/org/jivesoftware/smackx/packet/OfflineMessageInfo.java
new file mode 100644
index 000000000..90c1ead71
--- /dev/null
+++ b/source/org/jivesoftware/smackx/packet/OfflineMessageInfo.java
@@ -0,0 +1,128 @@
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2004 Jive Software.
+ *
+ * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jivesoftware.smackx.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * OfflineMessageInfo is an extension included in the retrieved offline messages requested by
+ * the {@link org.jivesoftware.smackx.OfflineMessageManager}. This extension includes a stamp
+ * that uniquely identifies the offline message. This stamp may be used for deleting the offline
+ * message. The stamp may be of the form UTC timestamps but it is not required to have that format.
+ *
+ * @author Gaston Dombiak
+ */
+public class OfflineMessageInfo implements PacketExtension {
+
+ private String node = null;
+
+ /**
+ * Returns the XML element name of the extension sub-packet root element.
+ * Always returns "offline"
+ *
+ * @return the XML element name of the packet extension.
+ */
+ public String getElementName() {
+ return "offline";
+ }
+
+ /**
+ * Returns the XML namespace of the extension sub-packet root element.
+ * According the specification the namespace is always "http://jabber.org/protocol/offline"
+ *
+ * @return the XML namespace of the packet extension.
+ */
+ public String getNamespace() {
+ return "http://jabber.org/protocol/offline";
+ }
+
+ /**
+ * Returns the stamp that uniquely identifies the offline message. This stamp may
+ * be used for deleting the offline message. The stamp may be of the form UTC timestamps
+ * but it is not required to have that format.
+ *
+ * @return the stamp that uniquely identifies the offline message.
+ */
+ public String getNode() {
+ return node;
+ }
+
+ /**
+ * Sets the stamp that uniquely identifies the offline message. This stamp may
+ * be used for deleting the offline message. The stamp may be of the form UTC timestamps
+ * but it is not required to have that format.
+ *
+ * @param node the stamp that uniquely identifies the offline message.
+ */
+ public void setNode(String node) {
+ this.node = node;
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append(
+ "\">");
+ if (getNode() != null)
+ buf.append("