001/** 002 * 003 * Copyright 2013-2014 Georg Lukas 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.receipts; 018 019import java.util.Collections; 020import java.util.HashSet; 021import java.util.Map; 022import java.util.Set; 023import java.util.WeakHashMap; 024 025import org.jivesoftware.smack.SmackException; 026import org.jivesoftware.smack.SmackException.NotConnectedException; 027import org.jivesoftware.smack.XMPPConnection; 028import org.jivesoftware.smack.ConnectionCreationListener; 029import org.jivesoftware.smack.Manager; 030import org.jivesoftware.smack.PacketListener; 031import org.jivesoftware.smack.XMPPException; 032import org.jivesoftware.smack.filter.PacketExtensionFilter; 033import org.jivesoftware.smack.packet.Message; 034import org.jivesoftware.smack.packet.Packet; 035import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; 036 037/** 038 * Manager for XEP-0184: Message Delivery Receipts. This class implements 039 * the manager for {@link DeliveryReceipt} support, enabling and disabling of 040 * automatic DeliveryReceipt transmission. 041 * 042 * @author Georg Lukas 043 */ 044public class DeliveryReceiptManager extends Manager implements PacketListener { 045 046 private static Map<XMPPConnection, DeliveryReceiptManager> instances = new WeakHashMap<XMPPConnection, DeliveryReceiptManager>(); 047 048 static { 049 XMPPConnection.addConnectionCreationListener(new ConnectionCreationListener() { 050 public void connectionCreated(XMPPConnection connection) { 051 getInstanceFor(connection); 052 } 053 }); 054 } 055 056 private boolean auto_receipts_enabled = false; 057 private Set<ReceiptReceivedListener> receiptReceivedListeners = Collections 058 .synchronizedSet(new HashSet<ReceiptReceivedListener>()); 059 060 private DeliveryReceiptManager(XMPPConnection connection) { 061 super(connection); 062 ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection); 063 sdm.addFeature(DeliveryReceipt.NAMESPACE); 064 065 // register listener for delivery receipts and requests 066 connection.addPacketListener(this, new PacketExtensionFilter(DeliveryReceipt.NAMESPACE)); 067 } 068 069 /** 070 * Obtain the DeliveryReceiptManager responsible for a connection. 071 * 072 * @param connection the connection object. 073 * 074 * @return the DeliveryReceiptManager instance for the given connection 075 */ 076 public static synchronized DeliveryReceiptManager getInstanceFor(XMPPConnection connection) { 077 DeliveryReceiptManager receiptManager = instances.get(connection); 078 079 if (receiptManager == null) { 080 receiptManager = new DeliveryReceiptManager(connection); 081 instances.put(connection, receiptManager); 082 } 083 084 return receiptManager; 085 } 086 087 /** 088 * Returns true if Delivery Receipts are supported by a given JID 089 * 090 * @param jid 091 * @return true if supported 092 * @throws SmackException if there was no response from the server. 093 * @throws XMPPException 094 */ 095 public boolean isSupported(String jid) throws SmackException, XMPPException { 096 return ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(jid, 097 DeliveryReceipt.NAMESPACE); 098 } 099 100 // handle incoming receipts and receipt requests 101 @Override 102 public void processPacket(Packet packet) throws NotConnectedException { 103 DeliveryReceipt dr = DeliveryReceipt.getFrom(packet); 104 if (dr != null) { 105 // notify listeners of incoming receipt 106 for (ReceiptReceivedListener l : receiptReceivedListeners) { 107 l.onReceiptReceived(packet.getFrom(), packet.getTo(), dr.getId()); 108 } 109 } 110 111 // if enabled, automatically send a receipt 112 if (auto_receipts_enabled) { 113 DeliveryReceiptRequest drr = DeliveryReceiptRequest.getFrom(packet); 114 if (drr != null) { 115 XMPPConnection connection = connection(); 116 Message ack = new Message(packet.getFrom(), Message.Type.normal); 117 ack.addExtension(new DeliveryReceipt(packet.getPacketID())); 118 connection.sendPacket(ack); 119 } 120 } 121 } 122 123 /** 124 * Configure whether the {@link DeliveryReceiptManager} should automatically 125 * reply to incoming {@link DeliveryReceipt}s. By default, this feature is off. 126 * 127 * @param new_state whether automatic transmission of 128 * DeliveryReceipts should be enabled or disabled 129 */ 130 public void setAutoReceiptsEnabled(boolean new_state) { 131 auto_receipts_enabled = new_state; 132 } 133 134 /** 135 * Helper method to enable automatic DeliveryReceipt transmission. 136 */ 137 public void enableAutoReceipts() { 138 setAutoReceiptsEnabled(true); 139 } 140 141 /** 142 * Helper method to disable automatic DeliveryReceipt transmission. 143 */ 144 public void disableAutoReceipts() { 145 setAutoReceiptsEnabled(false); 146 } 147 148 /** 149 * Check if AutoReceipts are enabled on this connection. 150 */ 151 public boolean getAutoReceiptsEnabled() { 152 return this.auto_receipts_enabled; 153 } 154 155 /** 156 * Get informed about incoming delivery receipts with a {@link ReceiptReceivedListener}. 157 * 158 * @param listener the listener to be informed about new receipts 159 */ 160 public void addReceiptReceivedListener(ReceiptReceivedListener listener) { 161 receiptReceivedListeners.add(listener); 162 } 163 164 /** 165 * Stop getting informed about incoming delivery receipts. 166 * 167 * @param listener the listener to be removed 168 */ 169 public void removeReceiptReceivedListener(ReceiptReceivedListener listener) { 170 receiptReceivedListeners.remove(listener); 171 } 172 173 /** 174 * Test if a packet requires a delivery receipt. 175 * 176 * @param p Packet object to check for a DeliveryReceiptRequest 177 * 178 * @return true if a delivery receipt was requested 179 */ 180 public static boolean hasDeliveryReceiptRequest(Packet p) { 181 return (DeliveryReceiptRequest.getFrom(p) != null); 182 } 183 184 /** 185 * Add a delivery receipt request to an outgoing packet. 186 * 187 * Only message packets may contain receipt requests as of XEP-0184, 188 * therefore only allow Message as the parameter type. 189 * 190 * @param m Message object to add a request to 191 * @return the Message ID which will be used as receipt ID 192 */ 193 public static String addDeliveryReceiptRequest(Message m) { 194 m.addExtension(new DeliveryReceiptRequest()); 195 return m.getPacketID(); 196 } 197}