/** * Copyright 2013 Georg Lukas * * 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.receipts; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import org.jivesoftware.smack.Connection; import org.jivesoftware.smack.ConnectionCreationListener; import org.jivesoftware.smack.PacketCollector; import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.filter.PacketExtensionFilter; import org.jivesoftware.smack.filter.PacketIDFilter; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smackx.ServiceDiscoveryManager; import org.jivesoftware.smackx.packet.DiscoverInfo; /** * Packet extension for XEP-0184: Message Delivery Receipts. This class implements * the manager for {@link DeliveryReceipt} support, enabling and disabling of * automatic DeliveryReceipt transmission. * * @author Georg Lukas */ public class DeliveryReceiptManager implements PacketListener { private static Map<Connection, DeliveryReceiptManager> instances = Collections.synchronizedMap(new WeakHashMap<Connection, DeliveryReceiptManager>()); static { Connection.addConnectionCreationListener(new ConnectionCreationListener() { public void connectionCreated(Connection connection) { new DeliveryReceiptManager(connection); } }); } private Connection connection; private boolean auto_receipts_enabled = false; private Set<ReceiptReceivedListener> receiptReceivedListeners = Collections .synchronizedSet(new HashSet<ReceiptReceivedListener>()); private DeliveryReceiptManager(Connection connection) { ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection); sdm.addFeature(DeliveryReceipt.NAMESPACE); this.connection = connection; instances.put(connection, this); // register listener for delivery receipts and requests connection.addPacketListener(this, new PacketExtensionFilter(DeliveryReceipt.NAMESPACE)); } /** * Obtain the DeliveryReceiptManager responsible for a connection. * * @param connection the connection object. * * @return the DeliveryReceiptManager instance for the given connection */ synchronized public static DeliveryReceiptManager getInstanceFor(Connection connection) { DeliveryReceiptManager receiptManager = instances.get(connection); if (receiptManager == null) { receiptManager = new DeliveryReceiptManager(connection); } return receiptManager; } /** * Returns true if Delivery Receipts are supported by a given JID * * @param jid * @return true if supported */ public boolean isSupported(String jid) { try { DiscoverInfo result = ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid); return result.containsFeature(DeliveryReceipt.NAMESPACE); } catch (XMPPException e) { return false; } } // handle incoming receipts and receipt requests @Override public void processPacket(Packet packet) { DeliveryReceipt dr = (DeliveryReceipt)packet.getExtension( DeliveryReceipt.ELEMENT, DeliveryReceipt.NAMESPACE); if (dr != null) { // notify listeners of incoming receipt for (ReceiptReceivedListener l : receiptReceivedListeners) { l.onReceiptReceived(packet.getFrom(), packet.getTo(), dr.getId()); } } // if enabled, automatically send a receipt if (auto_receipts_enabled) { DeliveryReceiptRequest drr = (DeliveryReceiptRequest)packet.getExtension( DeliveryReceiptRequest.ELEMENT, DeliveryReceipt.NAMESPACE); if (drr != null) { Message ack = new Message(packet.getFrom(), Message.Type.normal); ack.addExtension(new DeliveryReceipt(packet.getPacketID())); connection.sendPacket(ack); } } } /** * Configure whether the {@link DeliveryReceiptManager} should automatically * reply to incoming {@link DeliveryReceipt}s. By default, this feature is off. * * @param new_state whether automatic transmission of * DeliveryReceipts should be enabled or disabled */ public void setAutoReceiptsEnabled(boolean new_state) { auto_receipts_enabled = new_state; } /** * Helper method to enable automatic DeliveryReceipt transmission. */ public void enableAutoReceipts() { setAutoReceiptsEnabled(true); } /** * Helper method to disable automatic DeliveryReceipt transmission. */ public void disableAutoReceipts() { setAutoReceiptsEnabled(false); } /** * Check if AutoReceipts are enabled on this connection. */ public boolean getAutoReceiptsEnabled() { return this.auto_receipts_enabled; } /** * Get informed about incoming delivery receipts with a {@link ReceiptReceivedListener}. * * @param listener the listener to be informed about new receipts */ public void registerReceiptReceivedListener(ReceiptReceivedListener listener) { receiptReceivedListeners.add(listener); } /** * Stop getting informed about incoming delivery receipts. * * @param listener the listener to be removed */ public void unregisterReceiptReceivedListener(ReceiptReceivedListener listener) { receiptReceivedListeners.remove(listener); } /** * Interface for received receipt notifications. * * Implement this and add a listener to get notified. */ public static interface ReceiptReceivedListener { void onReceiptReceived(String fromJid, String toJid, String receiptId); } /** * Test if a packet requires a delivery receipt. * * @param p Packet object to check for a DeliveryReceiptRequest * * @return true if a delivery receipt was requested */ public static boolean hasDeliveryReceiptRequest(Packet p) { return (p.getExtension(DeliveryReceiptRequest.ELEMENT, DeliveryReceipt.NAMESPACE) != null); } /** * Add a delivery receipt request to an outgoing packet. * * Only message packets may contain receipt requests as of XEP-0184, * therefore only allow Message as the parameter type. * * @param m Message object to add a request to */ public static void addDeliveryReceiptRequest(Message m) { m.addExtension(new DeliveryReceiptRequest()); } }