mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-26 16:22:06 +01:00
Initial version. SMACK-117
git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@3345 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
parent
237ab44301
commit
9eca04602b
5 changed files with 977 additions and 0 deletions
98
source/org/jivesoftware/smackx/MultipleRecipientInfo.java
Normal file
98
source/org/jivesoftware/smackx/MultipleRecipientInfo.java
Normal file
|
@ -0,0 +1,98 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision: $
|
||||
* $Date: $
|
||||
*
|
||||
* Copyright 2003-2006 Jive Software.
|
||||
*
|
||||
* 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;
|
||||
|
||||
import org.jivesoftware.smackx.packet.MultipleAddresses;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* MultipleRecipientInfo keeps information about the multiple recipients extension included
|
||||
* in a received packet. Among the information we can find the list of TO and CC addresses.
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public class MultipleRecipientInfo {
|
||||
|
||||
MultipleAddresses extension;
|
||||
|
||||
MultipleRecipientInfo(MultipleAddresses extension) {
|
||||
this.extension = extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of {@link org.jivesoftware.smackx.packet.MultipleAddresses.Address}
|
||||
* that were the primary recipients of the packet.
|
||||
*
|
||||
* @return list of primary recipients of the packet.
|
||||
*/
|
||||
public List getTOAddresses() {
|
||||
return extension.getAddressesOfType(MultipleAddresses.TO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of {@link org.jivesoftware.smackx.packet.MultipleAddresses.Address}
|
||||
* that were the secondary recipients of the packet.
|
||||
*
|
||||
* @return list of secondary recipients of the packet.
|
||||
*/
|
||||
public List getCCAddresses() {
|
||||
return extension.getAddressesOfType(MultipleAddresses.CC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JID of a MUC room to which responses should be sent or <tt>null</tt> if
|
||||
* no specific address was provided. When no specific address was provided then the reply
|
||||
* can be sent to any or all recipients. Otherwise, the user should join the specified room
|
||||
* and send the reply to the room.
|
||||
*
|
||||
* @return the JID of a MUC room to which responses should be sent or <tt>null</tt> if
|
||||
* no specific address was provided.
|
||||
*/
|
||||
public String getReplyRoom() {
|
||||
List replyRoom = extension.getAddressesOfType(MultipleAddresses.REPLY_ROOM);
|
||||
return replyRoom.isEmpty() ? null : ((MultipleAddresses.Address) replyRoom.get(0)).getJid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the received packet should not be replied. Use
|
||||
* {@link MultipleRecipientManager#reply(org.jivesoftware.smack.XMPPConnection, org.jivesoftware.smack.packet.Message, org.jivesoftware.smack.packet.Message)}
|
||||
* to send replies.
|
||||
*
|
||||
* @return true if the received packet should not be replied.
|
||||
*/
|
||||
public boolean shouldNotReply() {
|
||||
return !extension.getAddressesOfType(MultipleAddresses.NO_REPLY).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address to which all replies are requested to be sent or <tt>null</tt> if
|
||||
* no specific address was provided. When no specific address was provided then the reply
|
||||
* can be sent to any or all recipients.
|
||||
*
|
||||
* @return the address to which all replies are requested to be sent or <tt>null</tt> if
|
||||
* no specific address was provided.
|
||||
*/
|
||||
public MultipleAddresses.Address getReplyAddress() {
|
||||
List replyTo = extension.getAddressesOfType(MultipleAddresses.REPLY_TO);
|
||||
return replyTo.isEmpty() ? null : (MultipleAddresses.Address) replyTo.get(0);
|
||||
}
|
||||
}
|
353
source/org/jivesoftware/smackx/MultipleRecipientManager.java
Normal file
353
source/org/jivesoftware/smackx/MultipleRecipientManager.java
Normal file
|
@ -0,0 +1,353 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision: $
|
||||
* $Date: $
|
||||
*
|
||||
* Copyright 2003-2006 Jive Software.
|
||||
*
|
||||
* 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;
|
||||
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.packet.Packet;
|
||||
import org.jivesoftware.smack.util.Cache;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smackx.packet.DiscoverInfo;
|
||||
import org.jivesoftware.smackx.packet.DiscoverItems;
|
||||
import org.jivesoftware.smackx.packet.MultipleAddresses;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A MultipleRecipientManager allows to send packets to multiple recipients by making use of
|
||||
* <a href="http://www.jabber.org/jeps/jep-0033.html">JEP-33: Extended Stanza Addressing</a>.
|
||||
* It also allows to send replies to packets that were sent to multiple recipients.
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public class MultipleRecipientManager {
|
||||
|
||||
/**
|
||||
* Create a cache to hold the 100 most recently accessed elements for a period of
|
||||
* 24 hours.
|
||||
*/
|
||||
private static Cache services = new Cache(100, 24 * 60 * 60 * 1000);
|
||||
|
||||
/**
|
||||
* Sends the specified packet to the list of specified recipients using the
|
||||
* specified connection. If the server has support for JEP-33 then only one
|
||||
* packet is going to be sent to the server with the multiple recipient instructions.
|
||||
* However, if JEP-33 is not supported by the server then the client is going to send
|
||||
* the packet to each recipient.
|
||||
*
|
||||
* @param connection the connection to use to send the packet.
|
||||
* @param packet the packet to send to the list of recipients.
|
||||
* @param to the list of JIDs to include in the TO list or <tt>null</tt> if no TO
|
||||
* list exists.
|
||||
* @param cc the list of JIDs to include in the CC list or <tt>null</tt> if no CC
|
||||
* list exists.
|
||||
* @param bcc the list of JIDs to include in the BCC list or <tt>null</tt> if no BCC
|
||||
* list exists.
|
||||
* @throws XMPPException if server does not support JEP-33: Extended Stanza Addressing and
|
||||
* some JEP-33 specific features were requested.
|
||||
*/
|
||||
public static void send(XMPPConnection connection, Packet packet, List to, List cc, List bcc)
|
||||
throws XMPPException {
|
||||
send(connection, packet, to, cc, bcc, null, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the specified packet to the list of specified recipients using the
|
||||
* specified connection. If the server has support for JEP-33 then only one
|
||||
* packet is going to be sent to the server with the multiple recipient instructions.
|
||||
* However, if JEP-33 is not supported by the server then the client is going to send
|
||||
* the packet to each recipient.
|
||||
*
|
||||
* @param connection the connection to use to send the packet.
|
||||
* @param packet the packet to send to the list of recipients.
|
||||
* @param to the list of JIDs to include in the TO list or <tt>null</tt> if no TO
|
||||
* list exists.
|
||||
* @param cc the list of JIDs to include in the CC list or <tt>null</tt> if no CC
|
||||
* list exists.
|
||||
* @param bcc the list of JIDs to include in the BCC list or <tt>null</tt> if no BCC
|
||||
* list exists.
|
||||
* @param replyTo address to which all replies are requested to be sent or <tt>null</tt>
|
||||
* indicating that they can reply to any address.
|
||||
* @param replyRoom JID of a MUC room to which responses should be sent or <tt>null</tt>
|
||||
* indicating that they can reply to any address.
|
||||
* @param noReply true means that receivers should not reply to the message.
|
||||
* @throws XMPPException if server does not support JEP-33: Extended Stanza Addressing and
|
||||
* some JEP-33 specific features were requested.
|
||||
*/
|
||||
public static void send(XMPPConnection connection, Packet packet, List to, List cc, List bcc,
|
||||
String replyTo, String replyRoom, boolean noReply) throws XMPPException {
|
||||
String serviceAddress = getMultipleRecipienServiceAddress(connection);
|
||||
if (serviceAddress != null) {
|
||||
// Send packet to target users using multiple recipient service provided by the server
|
||||
sendThroughService(connection, packet, to, cc, bcc, replyTo, replyRoom, noReply,
|
||||
serviceAddress);
|
||||
}
|
||||
else {
|
||||
// Server does not support JEP-33 so try to send the packet to each recipient
|
||||
if (noReply || (replyTo != null && replyTo.trim().length() > 0) ||
|
||||
(replyRoom != null && replyRoom.trim().length() > 0)) {
|
||||
// Some specified JEP-33 features were requested so throw an exception alerting
|
||||
// the user that this features are not available
|
||||
throw new XMPPException("Extended Stanza Addressing not supported by server");
|
||||
}
|
||||
// Send the packet to each individual recipient
|
||||
sendToIndividualRecipients(connection, packet, to, cc, bcc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a reply to a previously received packet that was sent to multiple recipients. Before
|
||||
* attempting to send the reply message some checkings are performed. If any of those checkings
|
||||
* fail then an XMPPException is going to be thrown with the specific error detail.
|
||||
*
|
||||
* @param connection the connection to use to send the reply.
|
||||
* @param original the previously received packet that was sent to multiple recipients.
|
||||
* @param reply the new message to send as a reply.
|
||||
* @throws XMPPException if the original message was not sent to multiple recipients, or the
|
||||
* original message cannot be replied or reply should be sent to a room.
|
||||
*/
|
||||
public static void reply(XMPPConnection connection, Message original, Message reply)
|
||||
throws XMPPException {
|
||||
MultipleRecipientInfo info = getMultipleRecipientInfo(original);
|
||||
if (info == null) {
|
||||
throw new XMPPException("Original message does not contain multiple recipient info");
|
||||
}
|
||||
if (info.shouldNotReply()) {
|
||||
throw new XMPPException("Original message should not be replied");
|
||||
}
|
||||
if (info.getReplyRoom() != null) {
|
||||
throw new XMPPException("Reply should be sent through a room");
|
||||
}
|
||||
// Any <thread/> element from the initial message MUST be copied into the reply.
|
||||
if (original.getThread() != null) {
|
||||
reply.setThread(original.getThread());
|
||||
}
|
||||
MultipleAddresses.Address replyAddress = info.getReplyAddress();
|
||||
if (replyAddress != null && replyAddress.getJid() != null) {
|
||||
// Send reply to the reply_to address
|
||||
reply.setTo(replyAddress.getJid());
|
||||
connection.sendPacket(reply);
|
||||
}
|
||||
else {
|
||||
// Send reply to multiple recipients
|
||||
List to = new ArrayList();
|
||||
List cc = new ArrayList();
|
||||
for (Iterator it = info.getTOAddresses().iterator(); it.hasNext();) {
|
||||
String jid = ((MultipleAddresses.Address) it.next()).getJid();
|
||||
to.add(jid);
|
||||
}
|
||||
for (Iterator it = info.getCCAddresses().iterator(); it.hasNext();) {
|
||||
String jid = ((MultipleAddresses.Address) it.next()).getJid();
|
||||
cc.add(jid);
|
||||
}
|
||||
// Add original sender as a 'to' address (if not already present)
|
||||
if (!to.contains(original.getFrom()) && !cc.contains(original.getFrom())) {
|
||||
to.add(original.getFrom());
|
||||
}
|
||||
// Remove the sender from the TO/CC list (try with bare JID too)
|
||||
String from = connection.getUser();
|
||||
if (!to.remove(from) && !cc.remove(from)) {
|
||||
String bareJID = StringUtils.parseBareAddress(from);
|
||||
to.remove(bareJID);
|
||||
cc.remove(bareJID);
|
||||
}
|
||||
|
||||
String serviceAddress = getMultipleRecipienServiceAddress(connection);
|
||||
if (serviceAddress != null) {
|
||||
// Send packet to target users using multiple recipient service provided by the server
|
||||
sendThroughService(connection, reply, to, cc, null, null, null, false,
|
||||
serviceAddress);
|
||||
}
|
||||
else {
|
||||
// Server does not support JEP-33 so try to send the packet to each recipient
|
||||
sendToIndividualRecipients(connection, reply, to, cc, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link MultipleRecipientInfo} contained in the specified packet or
|
||||
* <tt>null</tt> if none was found. Only packets sent to multiple recipients will
|
||||
* contain such information.
|
||||
*
|
||||
* @param packet the packet to check.
|
||||
* @return the MultipleRecipientInfo contained in the specified packet or <tt>null</tt>
|
||||
* if none was found.
|
||||
*/
|
||||
public static MultipleRecipientInfo getMultipleRecipientInfo(Packet packet) {
|
||||
MultipleAddresses extension = (MultipleAddresses) packet
|
||||
.getExtension("addresses", "http://jabber.org/protocol/address");
|
||||
return extension == null ? null : new MultipleRecipientInfo(extension);
|
||||
}
|
||||
|
||||
private static void sendToIndividualRecipients(XMPPConnection connection, Packet packet,
|
||||
List to, List cc, List bcc) {
|
||||
if (to != null) {
|
||||
for (Iterator it = to.iterator(); it.hasNext();) {
|
||||
String jid = (String) it.next();
|
||||
packet.setTo(jid);
|
||||
connection.sendPacket(new PacketCopy(packet.toXML()));
|
||||
}
|
||||
}
|
||||
if (cc != null) {
|
||||
for (Iterator it = cc.iterator(); it.hasNext();) {
|
||||
String jid = (String) it.next();
|
||||
packet.setTo(jid);
|
||||
connection.sendPacket(new PacketCopy(packet.toXML()));
|
||||
}
|
||||
}
|
||||
if (bcc != null) {
|
||||
for (Iterator it = bcc.iterator(); it.hasNext();) {
|
||||
String jid = (String) it.next();
|
||||
packet.setTo(jid);
|
||||
connection.sendPacket(new PacketCopy(packet.toXML()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendThroughService(XMPPConnection connection, Packet packet, List to,
|
||||
List cc, List bcc, String replyTo, String replyRoom, boolean noReply,
|
||||
String serviceAddress) {
|
||||
// Create multiple recipient extension
|
||||
MultipleAddresses multipleAddresses = new MultipleAddresses();
|
||||
if (to != null) {
|
||||
for (Iterator it = to.iterator(); it.hasNext();) {
|
||||
String jid = (String) it.next();
|
||||
multipleAddresses.addAddress(MultipleAddresses.TO, jid, null, null, false, null);
|
||||
}
|
||||
}
|
||||
if (cc != null) {
|
||||
for (Iterator it = cc.iterator(); it.hasNext();) {
|
||||
String jid = (String) it.next();
|
||||
multipleAddresses.addAddress(MultipleAddresses.CC, jid, null, null, false, null);
|
||||
}
|
||||
}
|
||||
if (bcc != null) {
|
||||
for (Iterator it = bcc.iterator(); it.hasNext();) {
|
||||
String jid = (String) it.next();
|
||||
multipleAddresses.addAddress(MultipleAddresses.BCC, jid, null, null, false, null);
|
||||
}
|
||||
}
|
||||
if (noReply) {
|
||||
multipleAddresses.setNoReply();
|
||||
}
|
||||
else {
|
||||
if (replyTo != null && replyTo.trim().length() > 0) {
|
||||
multipleAddresses
|
||||
.addAddress(MultipleAddresses.REPLY_TO, replyTo, null, null, false, null);
|
||||
}
|
||||
if (replyRoom != null && replyRoom.trim().length() > 0) {
|
||||
multipleAddresses.addAddress(MultipleAddresses.REPLY_ROOM, replyRoom, null, null,
|
||||
false, null);
|
||||
}
|
||||
}
|
||||
// Set the multiple recipient service address as the target address
|
||||
packet.setTo(serviceAddress);
|
||||
// Add extension to packet
|
||||
packet.addExtension(multipleAddresses);
|
||||
// Send the packet
|
||||
connection.sendPacket(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address of the multiple recipients service. To obtain such address service
|
||||
* discovery is going to be used on the connected server and if none was found then another
|
||||
* attempt will be tried on the server items. The discovered information is going to be
|
||||
* cached for 24 hours.
|
||||
*
|
||||
* @param connection the connection to use for disco. The connected server is going to be
|
||||
* queried.
|
||||
* @return the address of the multiple recipients service or <tt>null</tt> if none was found.
|
||||
*/
|
||||
private static String getMultipleRecipienServiceAddress(XMPPConnection connection) {
|
||||
String serviceName = connection.getServiceName();
|
||||
String serviceAddress = (String) services.get(serviceName);
|
||||
if (serviceAddress == null) {
|
||||
synchronized (services) {
|
||||
serviceAddress = (String) services.get(serviceName);
|
||||
if (serviceAddress == null) {
|
||||
|
||||
// Send the disco packet to the server itself
|
||||
try {
|
||||
DiscoverInfo info = ServiceDiscoveryManager.getInstanceFor(connection)
|
||||
.discoverInfo(serviceName);
|
||||
// Check if the server supports JEP-33
|
||||
if (info.containsFeature("http://jabber.org/protocol/address")) {
|
||||
serviceAddress = serviceName;
|
||||
}
|
||||
else {
|
||||
// Get the disco items and send the disco packet to each server item
|
||||
DiscoverItems items = ServiceDiscoveryManager.getInstanceFor(connection)
|
||||
.discoverItems(serviceName);
|
||||
for (Iterator it = items.getItems(); it.hasNext();) {
|
||||
DiscoverItems.Item item = (DiscoverItems.Item) it.next();
|
||||
info = ServiceDiscoveryManager.getInstanceFor(connection)
|
||||
.discoverInfo(item.getEntityID(), item.getNode());
|
||||
if (info.containsFeature("http://jabber.org/protocol/address")) {
|
||||
serviceAddress = serviceName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// Cache the discovered information
|
||||
services.put(serviceName, serviceAddress == null ? "" : serviceAddress);
|
||||
}
|
||||
catch (XMPPException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "".equals(serviceAddress) ? null : serviceAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet that holds the XML stanza to send. This class is useful when the same packet
|
||||
* is needed to be sent to different recipients. Since using the same packet is not possible
|
||||
* (i.e. cannot change the TO address of a queues packet to be sent) then this class was
|
||||
* created to keep the XML stanza to send.
|
||||
*/
|
||||
private static class PacketCopy extends Packet {
|
||||
|
||||
private String text;
|
||||
|
||||
/**
|
||||
* Create a copy of a packet with the text to send. The passed text must be a valid text to
|
||||
* send to the server, no validation will be done on the passed text.
|
||||
*
|
||||
* @param text the whole text of the packet to send
|
||||
*/
|
||||
public PacketCopy(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public String toXML() {
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
205
source/org/jivesoftware/smackx/packet/MultipleAddresses.java
Normal file
205
source/org/jivesoftware/smackx/packet/MultipleAddresses.java
Normal file
|
@ -0,0 +1,205 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision: $
|
||||
* $Date: $
|
||||
*
|
||||
* Copyright 2003-2006 Jive Software.
|
||||
*
|
||||
* 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.packet;
|
||||
|
||||
import org.jivesoftware.smack.packet.PacketExtension;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Packet extension that contains the list of addresses that a packet should be sent or was sent.
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public class MultipleAddresses implements PacketExtension {
|
||||
|
||||
public static final String BCC = "bcc";
|
||||
public static final String CC = "cc";
|
||||
public static final String NO_REPLY = "noreply";
|
||||
public static final String REPLY_ROOM = "replyroom";
|
||||
public static final String REPLY_TO = "replyto";
|
||||
public static final String TO = "to";
|
||||
|
||||
|
||||
private List addresses = new ArrayList();
|
||||
|
||||
/**
|
||||
* Adds a new address to which the packet is going to be sent or was sent.
|
||||
*
|
||||
* @param type on of the static type (BCC, CC, NO_REPLY, REPLY_ROOM, etc.)
|
||||
* @param jid the JID address of the recipient.
|
||||
* @param node used to specify a sub-addressable unit at a particular JID, corresponding to
|
||||
* a Service Discovery node.
|
||||
* @param desc used to specify human-readable information for this address.
|
||||
* @param delivered true when the packet was already delivered to this address.
|
||||
* @param uri used to specify an external system address, such as a sip:, sips:, or im: URI.
|
||||
*/
|
||||
public void addAddress(String type, String jid, String node, String desc, boolean delivered,
|
||||
String uri) {
|
||||
// Create a new address with the specificed configuration
|
||||
Address address = new Address(type);
|
||||
address.setJid(jid);
|
||||
address.setNode(node);
|
||||
address.setDescription(desc);
|
||||
address.setDelivered(delivered);
|
||||
address.setUri(uri);
|
||||
// Add the new address to the list of multiple recipients
|
||||
addresses.add(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the packet being sent should not be replied.
|
||||
*/
|
||||
public void setNoReply() {
|
||||
// Create a new address with the specificed configuration
|
||||
Address address = new Address(NO_REPLY);
|
||||
// Add the new address to the list of multiple recipients
|
||||
addresses.add(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of addresses that matches the specified type. Examples of address
|
||||
* type are: TO, CC, BCC, etc..
|
||||
*
|
||||
* @param type Examples of address type are: TO, CC, BCC, etc.
|
||||
* @return the list of addresses that matches the specified type.
|
||||
*/
|
||||
public List getAddressesOfType(String type) {
|
||||
List answer = new ArrayList(addresses.size());
|
||||
for (Iterator it = addresses.iterator(); it.hasNext();) {
|
||||
Address address = (Address) it.next();
|
||||
if (address.getType().equals(type)) {
|
||||
answer.add(address);
|
||||
}
|
||||
}
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
public String getElementName() {
|
||||
return "addresses";
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return "http://jabber.org/protocol/address";
|
||||
}
|
||||
|
||||
public String toXML() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("<").append(getElementName());
|
||||
buf.append(" xmlns=\"").append(getNamespace()).append("\">");
|
||||
// Loop through all the addresses and append them to the string buffer
|
||||
for (Iterator i = addresses.iterator(); i.hasNext();) {
|
||||
Address address = (Address) i.next();
|
||||
buf.append(address.toXML());
|
||||
}
|
||||
buf.append("</").append(getElementName()).append(">");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static class Address {
|
||||
|
||||
private String type;
|
||||
private String jid;
|
||||
private String node;
|
||||
private String description;
|
||||
private boolean delivered;
|
||||
private String uri;
|
||||
|
||||
private Address(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getJid() {
|
||||
return jid;
|
||||
}
|
||||
|
||||
private void setJid(String jid) {
|
||||
this.jid = jid;
|
||||
}
|
||||
|
||||
public String getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
private void setNode(String node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
private void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public boolean isDelivered() {
|
||||
return delivered;
|
||||
}
|
||||
|
||||
private void setDelivered(boolean delivered) {
|
||||
this.delivered = delivered;
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
private void setUri(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
private String toXML() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("<address type=\"");
|
||||
// Append the address type (e.g. TO/CC/BCC)
|
||||
buf.append(type).append("\"");
|
||||
if (jid != null) {
|
||||
buf.append(" jid=\"");
|
||||
buf.append(jid).append("\"");
|
||||
}
|
||||
if (node != null) {
|
||||
buf.append(" node=\"");
|
||||
buf.append(node).append("\"");
|
||||
}
|
||||
if (description != null && description.trim().length() > 0) {
|
||||
buf.append(" desc=\"");
|
||||
buf.append(description).append("\"");
|
||||
}
|
||||
if (delivered) {
|
||||
buf.append(" delivered=\"true\"");
|
||||
}
|
||||
if (uri != null) {
|
||||
buf.append(" uri=\"");
|
||||
buf.append(uri).append("\"");
|
||||
}
|
||||
buf.append("/>");
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision: $
|
||||
* $Date: $
|
||||
*
|
||||
* Copyright 2003-2006 Jive Software.
|
||||
*
|
||||
* 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.provider;
|
||||
|
||||
import org.jivesoftware.smack.packet.PacketExtension;
|
||||
import org.jivesoftware.smack.provider.PacketExtensionProvider;
|
||||
import org.jivesoftware.smackx.packet.MultipleAddresses;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
/**
|
||||
* The MultipleAddressesProvider parses {@link MultipleAddresses} packets.
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public class MultipleAddressesProvider implements PacketExtensionProvider {
|
||||
|
||||
/**
|
||||
* Creates a new MultipleAddressesProvider.
|
||||
* ProviderManager requires that every PacketExtensionProvider has a public, no-argument
|
||||
* constructor.
|
||||
*/
|
||||
public MultipleAddressesProvider() {
|
||||
}
|
||||
|
||||
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
|
||||
boolean done = false;
|
||||
MultipleAddresses multipleAddresses = new MultipleAddresses();
|
||||
while (!done) {
|
||||
int eventType = parser.next();
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
if (parser.getName().equals("address")) {
|
||||
String type = parser.getAttributeValue("", "type");
|
||||
String jid = parser.getAttributeValue("", "jid");
|
||||
String node = parser.getAttributeValue("", "node");
|
||||
String desc = parser.getAttributeValue("", "desc");
|
||||
boolean delivered = "true".equals(parser.getAttributeValue("", "delivered"));
|
||||
String uri = parser.getAttributeValue("", "uri");
|
||||
// Add the parsed address
|
||||
multipleAddresses.addAddress(type, jid, node, desc, delivered, uri);
|
||||
}
|
||||
} else if (eventType == XmlPullParser.END_TAG) {
|
||||
if (parser.getName().equals(multipleAddresses.getElementName())) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return multipleAddresses;
|
||||
}
|
||||
}
|
254
test/org/jivesoftware/smackx/MultipleRecipientManagerTest.java
Normal file
254
test/org/jivesoftware/smackx/MultipleRecipientManagerTest.java
Normal file
|
@ -0,0 +1,254 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision: $
|
||||
* $Date: $
|
||||
*
|
||||
* Copyright 2003-2006 Jive Software.
|
||||
*
|
||||
* 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;
|
||||
|
||||
import org.jivesoftware.smack.PacketCollector;
|
||||
import org.jivesoftware.smack.SmackConfiguration;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.filter.MessageTypeFilter;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.packet.Packet;
|
||||
import org.jivesoftware.smack.test.SmackTestCase;
|
||||
import org.jivesoftware.smackx.packet.MultipleAddresses;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Tests that JEP-33 support in Smack is correct.
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public class MultipleRecipientManagerTest extends SmackTestCase {
|
||||
|
||||
public MultipleRecipientManagerTest(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that sending and receiving of packets is ok.
|
||||
*/
|
||||
public void testSending() throws XMPPException {
|
||||
|
||||
PacketCollector collector1 =
|
||||
getConnection(1).createPacketCollector(new MessageTypeFilter(Message.Type.NORMAL));
|
||||
PacketCollector collector2 =
|
||||
getConnection(2).createPacketCollector(new MessageTypeFilter(Message.Type.NORMAL));
|
||||
PacketCollector collector3 =
|
||||
getConnection(3).createPacketCollector(new MessageTypeFilter(Message.Type.NORMAL));
|
||||
|
||||
Message message = new Message();
|
||||
message.setBody("Hola");
|
||||
List to = Arrays.asList(new String[]{getBareJID(1)});
|
||||
List cc = Arrays.asList(new String[]{getBareJID(2)});
|
||||
List bcc = Arrays.asList(new String[]{getBareJID(3)});
|
||||
MultipleRecipientManager.send(getConnection(0), message, to, cc, bcc);
|
||||
|
||||
Packet message1 = collector1.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNotNull("Connection 1 never received the message", message1);
|
||||
MultipleRecipientInfo info1 = MultipleRecipientManager.getMultipleRecipientInfo(message1);
|
||||
assertNotNull("Message 1 does not contain MultipleRecipientInfo", info1);
|
||||
assertFalse("Message 1 should be 'replyable'", info1.shouldNotReply());
|
||||
List addresses1 = info1.getTOAddresses();
|
||||
assertEquals("Incorrect number of TO addresses", 1, addresses1.size());
|
||||
String address1 = ((MultipleAddresses.Address) addresses1.get(0)).getJid();
|
||||
assertEquals("Incorrect TO address", getBareJID(1), address1);
|
||||
addresses1 = info1.getCCAddresses();
|
||||
assertEquals("Incorrect number of CC addresses", 1, addresses1.size());
|
||||
address1 = ((MultipleAddresses.Address) addresses1.get(0)).getJid();
|
||||
assertEquals("Incorrect CC address", getBareJID(2), address1);
|
||||
|
||||
Packet message2 = collector2.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNotNull("Connection 2 never received the message", message2);
|
||||
MultipleRecipientInfo info2 = MultipleRecipientManager.getMultipleRecipientInfo(message2);
|
||||
assertNotNull("Message 2 does not contain MultipleRecipientInfo", info2);
|
||||
assertFalse("Message 2 should be 'replyable'", info2.shouldNotReply());
|
||||
List addresses2 = info2.getTOAddresses();
|
||||
assertEquals("Incorrect number of TO addresses", 1, addresses2.size());
|
||||
String address2 = ((MultipleAddresses.Address) addresses2.get(0)).getJid();
|
||||
assertEquals("Incorrect TO address", getBareJID(1), address2);
|
||||
addresses2 = info2.getCCAddresses();
|
||||
assertEquals("Incorrect number of CC addresses", 1, addresses2.size());
|
||||
address2 = ((MultipleAddresses.Address) addresses2.get(0)).getJid();
|
||||
assertEquals("Incorrect CC address", getBareJID(2), address2);
|
||||
|
||||
Packet message3 = collector3.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNotNull("Connection 3 never received the message", message3);
|
||||
MultipleRecipientInfo info3 = MultipleRecipientManager.getMultipleRecipientInfo(message3);
|
||||
assertNotNull("Message 3 does not contain MultipleRecipientInfo", info3);
|
||||
assertFalse("Message 3 should be 'replyable'", info3.shouldNotReply());
|
||||
List addresses3 = info3.getTOAddresses();
|
||||
assertEquals("Incorrect number of TO addresses", 1, addresses3.size());
|
||||
String address3 = ((MultipleAddresses.Address) addresses3.get(0)).getJid();
|
||||
assertEquals("Incorrect TO address", getBareJID(1), address3);
|
||||
addresses3 = info3.getCCAddresses();
|
||||
assertEquals("Incorrect number of CC addresses", 1, addresses3.size());
|
||||
address3 = ((MultipleAddresses.Address) addresses3.get(0)).getJid();
|
||||
assertEquals("Incorrect CC address", getBareJID(2), address3);
|
||||
|
||||
collector1.cancel();
|
||||
collector2.cancel();
|
||||
collector3.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that replying to packets is ok.
|
||||
*/
|
||||
public void testReplying() throws XMPPException {
|
||||
PacketCollector collector0 =
|
||||
getConnection(0).createPacketCollector(new MessageTypeFilter(Message.Type.NORMAL));
|
||||
PacketCollector collector1 =
|
||||
getConnection(1).createPacketCollector(new MessageTypeFilter(Message.Type.NORMAL));
|
||||
PacketCollector collector2 =
|
||||
getConnection(2).createPacketCollector(new MessageTypeFilter(Message.Type.NORMAL));
|
||||
PacketCollector collector3 =
|
||||
getConnection(3).createPacketCollector(new MessageTypeFilter(Message.Type.NORMAL));
|
||||
|
||||
// Send the intial message with multiple recipients
|
||||
Message message = new Message();
|
||||
message.setBody("Hola");
|
||||
List to = Arrays.asList(new String[]{getBareJID(1)});
|
||||
List cc = Arrays.asList(new String[]{getBareJID(2)});
|
||||
List bcc = Arrays.asList(new String[]{getBareJID(3)});
|
||||
MultipleRecipientManager.send(getConnection(0), message, to, cc, bcc);
|
||||
|
||||
// Get the message and ensure it's ok
|
||||
Message message1 =
|
||||
(Message) collector1.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNotNull("Connection 1 never received the message", message1);
|
||||
MultipleRecipientInfo info = MultipleRecipientManager.getMultipleRecipientInfo(message1);
|
||||
assertNotNull("Message 1 does not contain MultipleRecipientInfo", info);
|
||||
assertFalse("Message 1 should be 'replyable'", info.shouldNotReply());
|
||||
assertEquals("Incorrect number of TO addresses", 1, info.getTOAddresses().size());
|
||||
assertEquals("Incorrect number of CC addresses", 1, info.getCCAddresses().size());
|
||||
|
||||
// Prepare and send the reply
|
||||
Message reply1 = new Message();
|
||||
reply1.setBody("This is my reply");
|
||||
MultipleRecipientManager.reply(getConnection(1), message1, reply1);
|
||||
|
||||
// Get the reply and ensure it's ok
|
||||
reply1 = (Message) collector0.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNotNull("Connection 0 never received the reply", reply1);
|
||||
info = MultipleRecipientManager.getMultipleRecipientInfo(reply1);
|
||||
assertNotNull("Replied message does not contain MultipleRecipientInfo", info);
|
||||
assertFalse("Replied message should be 'replyable'", info.shouldNotReply());
|
||||
assertEquals("Incorrect number of TO addresses", 1, info.getTOAddresses().size());
|
||||
assertEquals("Incorrect number of CC addresses", 1, info.getCCAddresses().size());
|
||||
|
||||
// Send a reply to the reply
|
||||
Message reply2 = new Message();
|
||||
reply2.setBody("This is my reply to your reply");
|
||||
reply2.setFrom(getBareJID(0));
|
||||
MultipleRecipientManager.reply(getConnection(0), reply1, reply2);
|
||||
|
||||
// Get the reply and ensure it's ok
|
||||
reply2 = (Message) collector1.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNotNull("Connection 1 never received the reply", reply2);
|
||||
info = MultipleRecipientManager.getMultipleRecipientInfo(reply2);
|
||||
assertNotNull("Replied message does not contain MultipleRecipientInfo", info);
|
||||
assertFalse("Replied message should be 'replyable'", info.shouldNotReply());
|
||||
assertEquals("Incorrect number of TO addresses", 1, info.getTOAddresses().size());
|
||||
assertEquals("Incorrect number of CC addresses", 1, info.getCCAddresses().size());
|
||||
|
||||
// Check that connection2 recevied 3 messages
|
||||
message1 = (Message) collector2.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNotNull("Connection2 didn't receive the 1 message", message1);
|
||||
message1 = (Message) collector2.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNotNull("Connection2 didn't receive the 2 message", message1);
|
||||
message1 = (Message) collector2.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNotNull("Connection2 didn't receive the 3 message", message1);
|
||||
message1 = (Message) collector2.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNull("Connection2 received 4 messages", message1);
|
||||
|
||||
// Check that connection3 recevied only 1 message (was BCC in the first message)
|
||||
message1 = (Message) collector3.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNotNull("Connection3 didn't receive the 1 message", message1);
|
||||
message1 = (Message) collector3.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNull("Connection2 received 2 messages", message1);
|
||||
|
||||
collector0.cancel();
|
||||
collector1.cancel();
|
||||
collector2.cancel();
|
||||
collector3.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that replying is not allowed when disabled.
|
||||
*/
|
||||
public void testNoReply() throws XMPPException {
|
||||
PacketCollector collector1 =
|
||||
getConnection(1).createPacketCollector(new MessageTypeFilter(Message.Type.NORMAL));
|
||||
PacketCollector collector2 =
|
||||
getConnection(2).createPacketCollector(new MessageTypeFilter(Message.Type.NORMAL));
|
||||
PacketCollector collector3 =
|
||||
getConnection(3).createPacketCollector(new MessageTypeFilter(Message.Type.NORMAL));
|
||||
|
||||
// Send the intial message with multiple recipients
|
||||
Message message = new Message();
|
||||
message.setBody("Hola");
|
||||
List to = Arrays.asList(new String[]{getBareJID(1)});
|
||||
List cc = Arrays.asList(new String[]{getBareJID(2)});
|
||||
List bcc = Arrays.asList(new String[]{getBareJID(3)});
|
||||
MultipleRecipientManager.send(getConnection(0), message, to, cc, bcc, null, null, true);
|
||||
|
||||
// Get the message and ensure it's ok
|
||||
Message message1 =
|
||||
(Message) collector1.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNotNull("Connection 1 never received the message", message1);
|
||||
MultipleRecipientInfo info = MultipleRecipientManager.getMultipleRecipientInfo(message1);
|
||||
assertNotNull("Message 1 does not contain MultipleRecipientInfo", info);
|
||||
assertTrue("Message 1 should be not 'replyable'", info.shouldNotReply());
|
||||
assertEquals("Incorrect number of TO addresses", 1, info.getTOAddresses().size());
|
||||
assertEquals("Incorrect number of CC addresses", 1, info.getCCAddresses().size());
|
||||
|
||||
// Prepare and send the reply
|
||||
Message reply1 = new Message();
|
||||
reply1.setBody("This is my reply");
|
||||
try {
|
||||
MultipleRecipientManager.reply(getConnection(1), message1, reply1);
|
||||
fail("It was possible to send a reply to a not replyable message");
|
||||
}
|
||||
catch (XMPPException e) {
|
||||
// Exception was expected since replying was not allowed
|
||||
}
|
||||
|
||||
// Check that connection2 recevied 1 messages
|
||||
message1 = (Message) collector2.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNotNull("Connection2 didn't receive the 1 message", message1);
|
||||
message1 = (Message) collector2.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNull("Connection2 received 2 messages", message1);
|
||||
|
||||
// Check that connection3 recevied only 1 message (was BCC in the first message)
|
||||
message1 = (Message) collector3.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNotNull("Connection3 didn't receive the 1 message", message1);
|
||||
message1 = (Message) collector3.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
assertNull("Connection2 received 2 messages", message1);
|
||||
|
||||
collector1.cancel();
|
||||
collector2.cancel();
|
||||
collector3.cancel();
|
||||
}
|
||||
|
||||
protected int getMaxConnections() {
|
||||
return 4;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue