Home | History | Annotate | Download | only in receipts
      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 {
     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 
     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      */
     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      */
     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
    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      */
    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      */
    143     public void enableAutoReceipts() {
    144         setAutoReceiptsEnabled(true);
    145     }
    146 
    147     /**
    148      * Helper method to disable automatic DeliveryReceipt transmission.
    149      */
    150     public void disableAutoReceipts() {
    151         setAutoReceiptsEnabled(false);
    152     }
    153 
    154     /**
    155      * Check if AutoReceipts are enabled on this connection.
    156      */
    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      */
    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      */
    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      */
    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      */
    199     public static void addDeliveryReceiptRequest(Message m) {
    200         m.addExtension(new DeliveryReceiptRequest());
    201     }
    202 }
    203