• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2013 Georg Lukas
3  *
4  * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.jivesoftware.smackx.receipts;
18 
19 import java.util.Collections;
20 import java.util.HashSet;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.WeakHashMap;
24 
25 import org.jivesoftware.smack.Connection;
26 import org.jivesoftware.smack.ConnectionCreationListener;
27 import org.jivesoftware.smack.PacketListener;
28 import org.jivesoftware.smack.XMPPException;
29 import org.jivesoftware.smack.filter.PacketExtensionFilter;
30 import org.jivesoftware.smack.packet.Message;
31 import org.jivesoftware.smack.packet.Packet;
32 import org.jivesoftware.smackx.ServiceDiscoveryManager;
33 import org.jivesoftware.smackx.packet.DiscoverInfo;
34 
35 /**
36  * Manager for XEP-0184: Message Delivery Receipts. This class implements
37  * the manager for {@link DeliveryReceipt} support, enabling and disabling of
38  * automatic DeliveryReceipt transmission.
39  *
40  * @author Georg Lukas
41  */
42 public class DeliveryReceiptManager implements PacketListener {
43 
44     private static Map<Connection, DeliveryReceiptManager> instances =
45             Collections.synchronizedMap(new WeakHashMap<Connection, DeliveryReceiptManager>());
46 
47     static {
Connection.addConnectionCreationListener(new ConnectionCreationListener() { public void connectionCreated(Connection connection) { new DeliveryReceiptManager(connection); } })48         Connection.addConnectionCreationListener(new ConnectionCreationListener() {
49             public void connectionCreated(Connection connection) {
50                 new DeliveryReceiptManager(connection);
51             }
52         });
53     }
54 
55     private Connection connection;
56     private boolean auto_receipts_enabled = false;
57     private Set<ReceiptReceivedListener> receiptReceivedListeners = Collections
58             .synchronizedSet(new HashSet<ReceiptReceivedListener>());
59 
DeliveryReceiptManager(Connection connection)60     private DeliveryReceiptManager(Connection connection) {
61         ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
62         sdm.addFeature(DeliveryReceipt.NAMESPACE);
63         this.connection = connection;
64         instances.put(connection, this);
65 
66         // register listener for delivery receipts and requests
67         connection.addPacketListener(this, new PacketExtensionFilter(DeliveryReceipt.NAMESPACE));
68     }
69 
70     /**
71      * Obtain the DeliveryReceiptManager responsible for a connection.
72      *
73      * @param connection the connection object.
74      *
75      * @return the DeliveryReceiptManager instance for the given connection
76      */
getInstanceFor(Connection connection)77     synchronized public static DeliveryReceiptManager getInstanceFor(Connection connection) {
78         DeliveryReceiptManager receiptManager = instances.get(connection);
79 
80         if (receiptManager == null) {
81             receiptManager = new DeliveryReceiptManager(connection);
82         }
83 
84         return receiptManager;
85     }
86 
87     /**
88      * Returns true if Delivery Receipts are supported by a given JID
89      *
90      * @param jid
91      * @return true if supported
92      */
isSupported(String jid)93     public boolean isSupported(String jid) {
94         try {
95             DiscoverInfo result =
96                 ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid);
97             return result.containsFeature(DeliveryReceipt.NAMESPACE);
98         }
99         catch (XMPPException e) {
100             return false;
101         }
102     }
103 
104     // handle incoming receipts and receipt requests
105     @Override
processPacket(Packet packet)106     public void processPacket(Packet packet) {
107         DeliveryReceipt dr = (DeliveryReceipt)packet.getExtension(
108                 DeliveryReceipt.ELEMENT, DeliveryReceipt.NAMESPACE);
109         if (dr != null) {
110             // notify listeners of incoming receipt
111             for (ReceiptReceivedListener l : receiptReceivedListeners) {
112                 l.onReceiptReceived(packet.getFrom(), packet.getTo(), dr.getId());
113             }
114 
115         }
116 
117         // if enabled, automatically send a receipt
118         if (auto_receipts_enabled) {
119             DeliveryReceiptRequest drr = (DeliveryReceiptRequest)packet.getExtension(
120                     DeliveryReceiptRequest.ELEMENT, DeliveryReceipt.NAMESPACE);
121             if (drr != null) {
122                 Message ack = new Message(packet.getFrom(), Message.Type.normal);
123                 ack.addExtension(new DeliveryReceipt(packet.getPacketID()));
124                 connection.sendPacket(ack);
125             }
126         }
127     }
128 
129     /**
130      * Configure whether the {@link DeliveryReceiptManager} should automatically
131      * reply to incoming {@link DeliveryReceipt}s. By default, this feature is off.
132      *
133      * @param new_state whether automatic transmission of
134      *                  DeliveryReceipts should be enabled or disabled
135      */
setAutoReceiptsEnabled(boolean new_state)136     public void setAutoReceiptsEnabled(boolean new_state) {
137         auto_receipts_enabled = new_state;
138     }
139 
140     /**
141      * Helper method to enable automatic DeliveryReceipt transmission.
142      */
enableAutoReceipts()143     public void enableAutoReceipts() {
144         setAutoReceiptsEnabled(true);
145     }
146 
147     /**
148      * Helper method to disable automatic DeliveryReceipt transmission.
149      */
disableAutoReceipts()150     public void disableAutoReceipts() {
151         setAutoReceiptsEnabled(false);
152     }
153 
154     /**
155      * Check if AutoReceipts are enabled on this connection.
156      */
getAutoReceiptsEnabled()157     public boolean getAutoReceiptsEnabled() {
158         return this.auto_receipts_enabled;
159     }
160 
161     /**
162      * Get informed about incoming delivery receipts with a {@link ReceiptReceivedListener}.
163      *
164      * @param listener the listener to be informed about new receipts
165      */
addReceiptReceivedListener(ReceiptReceivedListener listener)166     public void addReceiptReceivedListener(ReceiptReceivedListener listener) {
167         receiptReceivedListeners.add(listener);
168     }
169 
170     /**
171      * Stop getting informed about incoming delivery receipts.
172      *
173      * @param listener the listener to be removed
174      */
removeReceiptReceivedListener(ReceiptReceivedListener listener)175     public void removeReceiptReceivedListener(ReceiptReceivedListener listener) {
176         receiptReceivedListeners.remove(listener);
177     }
178 
179     /**
180      * Test if a packet requires a delivery receipt.
181      *
182      * @param p Packet object to check for a DeliveryReceiptRequest
183      *
184      * @return true if a delivery receipt was requested
185      */
hasDeliveryReceiptRequest(Packet p)186     public static boolean hasDeliveryReceiptRequest(Packet p) {
187         return (p.getExtension(DeliveryReceiptRequest.ELEMENT,
188                     DeliveryReceipt.NAMESPACE) != null);
189     }
190 
191     /**
192      * Add a delivery receipt request to an outgoing packet.
193      *
194      * Only message packets may contain receipt requests as of XEP-0184,
195      * therefore only allow Message as the parameter type.
196      *
197      * @param m Message object to add a request to
198      */
addDeliveryReceiptRequest(Message m)199     public static void addDeliveryReceiptRequest(Message m) {
200         m.addExtension(new DeliveryReceiptRequest());
201     }
202 }
203