1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2024-11-26 00:02:06 +01:00

Improve Message Delivery Receipt (XEP-184) API

add a new AutoReceiptMode enum that specifies how delivery receipt
requests are handled. Default is to send receipts if the requstor is
subscribed to the user's presence.

Also make sure that messages contain an id if a receipt request is
added to it.
This commit is contained in:
Florian Schmaus 2015-01-19 16:23:50 +01:00
parent 293f90c6c6
commit 1bc3e10cff
6 changed files with 130 additions and 33 deletions

View file

@ -35,6 +35,8 @@ public class MessageTypeFilter extends FlexiblePacketTypeFilter<Message> {
public static final PacketFilter HEADLINE = new MessageTypeFilter(Type.headline); public static final PacketFilter HEADLINE = new MessageTypeFilter(Type.headline);
public static final PacketFilter ERROR = new MessageTypeFilter(Type.error); public static final PacketFilter ERROR = new MessageTypeFilter(Type.error);
public static final PacketFilter NORMAL_OR_CHAT = new OrFilter(NORMAL, CHAT); public static final PacketFilter NORMAL_OR_CHAT = new OrFilter(NORMAL, CHAT);
public static final PacketFilter NORMAL_OR_CHAT_OR_HEADLINE = new OrFilter(NORMAL_OR_CHAT,
HEADLINE);
private final Message.Type type; private final Message.Type type;

View file

@ -22,6 +22,7 @@ import java.util.Map;
import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.EmbeddedExtensionProvider; import org.jivesoftware.smack.provider.EmbeddedExtensionProvider;
import org.jivesoftware.smack.util.XmlStringBuilder;
/** /**
* Represents a <b>message delivery receipt</b> entry as specified by * Represents a <b>message delivery receipt</b> entry as specified by
@ -34,7 +35,10 @@ public class DeliveryReceipt implements PacketExtension
public static final String NAMESPACE = "urn:xmpp:receipts"; public static final String NAMESPACE = "urn:xmpp:receipts";
public static final String ELEMENT = "received"; public static final String ELEMENT = "received";
private String id; /// original ID of the delivered message /**
* original ID of the delivered message
*/
private final String id;
public DeliveryReceipt(String id) public DeliveryReceipt(String id)
{ {
@ -59,9 +63,12 @@ public class DeliveryReceipt implements PacketExtension
} }
@Override @Override
public String toXML() public XmlStringBuilder toXML()
{ {
return "<received xmlns='" + NAMESPACE + "' id='" + id + "'/>"; XmlStringBuilder xml = new XmlStringBuilder(this);
xml.attribute("id", id);
xml.closeEmptyElement();
return xml;
} }
/** /**

View file

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2013-2014 Georg Lukas * Copyright 2013-2014 Georg Lukas, 2015 Florian Schmaus
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -30,6 +30,7 @@ import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnectionRegistry; import org.jivesoftware.smack.XMPPConnectionRegistry;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.MessageTypeFilter;
import org.jivesoftware.smack.filter.PacketExtensionFilter; import org.jivesoftware.smack.filter.PacketExtensionFilter;
import org.jivesoftware.smack.filter.PacketFilter; import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter; import org.jivesoftware.smack.filter.PacketTypeFilter;
@ -42,6 +43,24 @@ import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
* the manager for {@link DeliveryReceipt} support, enabling and disabling of * the manager for {@link DeliveryReceipt} support, enabling and disabling of
* automatic DeliveryReceipt transmission. * automatic DeliveryReceipt transmission.
* *
* <p>
* You can send delivery receipt requests and listen for incoming delivery receipts as shown in this example:
* </p>
* <pre>
* deliveryReceiptManager.addReceiptReceivedListener(new ReceiptReceivedListener() {
* void onReceiptReceived(String fromJid, String toJid, String receiptId, Packet receipt) {
* // If the receiving entity does not support delivery receipts,
* // then the receipt received listener may not get invoked.
* }
* });
* Message message =
* DeliveryReceiptRequest.addTo(message);
* connection.sendPacket(message);
* </pre>
*
* DeliveryReceiptManager can be configured to automatically add delivery receipt requests to every
* message with {@link #autoAddDeliveryReceiptRequests()}.
*
* @author Georg Lukas * @author Georg Lukas
* @see <a href="http://xmpp.org/extensions/xep-0184.html">XEP-0184: Message Delivery Receipts</a> * @see <a href="http://xmpp.org/extensions/xep-0184.html">XEP-0184: Message Delivery Receipts</a>
*/ */
@ -62,7 +81,43 @@ public class DeliveryReceiptManager extends Manager {
}); });
} }
private boolean auto_receipts_enabled = false; /**
* Specifies when incoming message delivery receipt requests should be automatically
* acknowledged with an receipt.
*/
public enum AutoReceiptMode {
/**
* Never send deliver receipts
*/
disabled,
/**
* Only send delivery receipts if the requester is subscribed to our presence.
*/
ifIsSubscribed,
/**
* Always send delivery receipts. <b>Warning:</b> this may causes presence leaks. See <a
* href="http://xmpp.org/extensions/xep-0184.html#security">XEP-0184: Message Delivery
* Receipts § 8. Security Considerations</a>
*/
always,
}
private static AutoReceiptMode defaultAutoReceiptMode = AutoReceiptMode.ifIsSubscribed;
/**
* Set the default automatic receipt mode for new connections.
*
* @param autoReceiptMode the default automatic receipt mode.
*/
public static void setDefaultAutoReceiptMode(AutoReceiptMode autoReceiptMode) {
defaultAutoReceiptMode = autoReceiptMode;
}
private AutoReceiptMode autoReceiptMode = defaultAutoReceiptMode;
private final Set<ReceiptReceivedListener> receiptReceivedListeners = new CopyOnWriteArraySet<ReceiptReceivedListener>(); private final Set<ReceiptReceivedListener> receiptReceivedListeners = new CopyOnWriteArraySet<ReceiptReceivedListener>();
private DeliveryReceiptManager(XMPPConnection connection) { private DeliveryReceiptManager(XMPPConnection connection) {
@ -86,13 +141,23 @@ public class DeliveryReceiptManager extends Manager {
connection.addAsyncPacketListener(new PacketListener() { connection.addAsyncPacketListener(new PacketListener() {
@Override @Override
public void processPacket(Packet packet) throws NotConnectedException { public void processPacket(Packet packet) throws NotConnectedException {
// if enabled, automatically send a receipt final String from = packet.getFrom();
if (!auto_receipts_enabled) { final XMPPConnection connection = connection();
switch (autoReceiptMode) {
case disabled:
return; return;
case ifIsSubscribed:
if (!connection.getRoster().isSubscribedToMyPresence(from)) {
return;
}
break;
case always:
break;
} }
Message ack = new Message(packet.getFrom(), Message.Type.normal);
Message ack = new Message(from, Message.Type.normal);
ack.addExtension(new DeliveryReceipt(packet.getPacketID())); ack.addExtension(new DeliveryReceipt(packet.getPacketID()));
connection().sendPacket(ack); connection.sendPacket(ack);
} }
}, MESSAGES_WITH_DEVLIERY_RECEIPT_REQUEST); }, MESSAGES_WITH_DEVLIERY_RECEIPT_REQUEST);
} }
@ -130,34 +195,22 @@ public class DeliveryReceiptManager extends Manager {
/** /**
* Configure whether the {@link DeliveryReceiptManager} should automatically * Configure whether the {@link DeliveryReceiptManager} should automatically
* reply to incoming {@link DeliveryReceipt}s. By default, this feature is off. * reply to incoming {@link DeliveryReceipt}s.
* *
* @param new_state whether automatic transmission of * @param autoReceiptMode the new auto receipt mode.
* DeliveryReceipts should be enabled or disabled * @see AutoReceiptMode
*/ */
public void setAutoReceiptsEnabled(boolean new_state) { public void setAutoReceiptMode(AutoReceiptMode autoReceiptMode) {
auto_receipts_enabled = new_state; this.autoReceiptMode = autoReceiptMode;
} }
/** /**
* Helper method to enable automatic DeliveryReceipt transmission. * Get the currently active auto receipt mode.
*
* @return the currently active auto receipt mode.
*/ */
public void enableAutoReceipts() { public AutoReceiptMode getAutoReceiptMode() {
setAutoReceiptsEnabled(true); return autoReceiptMode;
}
/**
* 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;
} }
/** /**
@ -178,6 +231,35 @@ public class DeliveryReceiptManager extends Manager {
receiptReceivedListeners.remove(listener); receiptReceivedListeners.remove(listener);
} }
private static final PacketListener AUTO_ADD_DELIVERY_RECEIPT_REQUESTS_LISTENER = new PacketListener() {
@Override
public void processPacket(Packet packet) throws NotConnectedException {
Message message = (Message) packet;
DeliveryReceiptRequest.addTo(message);
}
};
/**
* Enables automatic requests of delivery receipts for outgoing messages of type 'normal', 'chat' or 'headline.
*
* @since 4.1
* @see #dontAutoAddDeliveryReceiptRequests()
*/
public void autoAddDeliveryReceiptRequests() {
connection().addPacketSendingListener(AUTO_ADD_DELIVERY_RECEIPT_REQUESTS_LISTENER,
MessageTypeFilter.NORMAL_OR_CHAT_OR_HEADLINE);
}
/**
* Disables automatically requests of delivery receipts for outgoing messages.
*
* @since 4.1
* @see #autoAddDeliveryReceiptRequests()
*/
public void dontAutoAddDeliveryReceiptRequests() {
connection().removePacketSendingListener(AUTO_ADD_DELIVERY_RECEIPT_REQUESTS_LISTENER);
}
/** /**
* Test if a message requires a delivery receipt. * Test if a message requires a delivery receipt.
* *

View file

@ -21,6 +21,7 @@ import java.io.IOException;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.packet.id.StanzaIdUtil;
import org.jivesoftware.smack.provider.PacketExtensionProvider; import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
@ -82,6 +83,9 @@ public class DeliveryReceiptRequest implements PacketExtension
* @return the Message ID which will be used as receipt ID * @return the Message ID which will be used as receipt ID
*/ */
public static String addTo(Message message) { public static String addTo(Message message) {
if (message.getPacketID() == null) {
message.setPacketID(StanzaIdUtil.newStanzaId());
}
message.addExtension(new DeliveryReceiptRequest()); message.addExtension(new DeliveryReceiptRequest());
return message.getPacketID(); return message.getPacketID();
} }

View file

@ -15,5 +15,6 @@
<className>org.jivesoftware.smackx.xdata.XDataManager</className> <className>org.jivesoftware.smackx.xdata.XDataManager</className>
<className>org.jivesoftware.smackx.xdatalayout.XDataLayoutManager</className> <className>org.jivesoftware.smackx.xdatalayout.XDataLayoutManager</className>
<className>org.jivesoftware.smackx.xdatavalidation.XDataValidationManager</className> <className>org.jivesoftware.smackx.xdatavalidation.XDataValidationManager</className>
<className>org.jivesoftware.smackx.receipts.DeliveryReceiptManager</className>
</startupClasses> </startupClasses>
</smack> </smack>

View file

@ -29,6 +29,7 @@ import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.test.util.WaitForPacketListener; import org.jivesoftware.smack.test.util.WaitForPacketListener;
import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.InitExtensions; import org.jivesoftware.smackx.InitExtensions;
import org.jivesoftware.smackx.receipts.DeliveryReceiptManager.AutoReceiptMode;
import org.junit.Test; import org.junit.Test;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
@ -101,8 +102,8 @@ public class DeliveryReceiptTest extends InitExtensions {
c.connect(); c.connect();
DeliveryReceiptManager drm = DeliveryReceiptManager.getInstanceFor(c); DeliveryReceiptManager drm = DeliveryReceiptManager.getInstanceFor(c);
drm.enableAutoReceipts(); drm.setAutoReceiptMode(AutoReceiptMode.always);
assertTrue(drm.getAutoReceiptsEnabled()); assertEquals(AutoReceiptMode.always, drm.getAutoReceiptMode());
// test auto-receipts // test auto-receipts
Message m = new Message("julia@capulet.com", Message.Type.normal); Message m = new Message("julia@capulet.com", Message.Type.normal);