1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2025-09-13 12:19:40 +02:00

Merge from 3.3 branch

git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@13663 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
rcollier 2013-05-18 16:56:52 +00:00
commit dac68c64a9
163 changed files with 2304 additions and 2366 deletions

View file

@ -299,24 +299,23 @@ public class FormField {
return buf.toString();
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj == this)
return true;
if (obj.getClass() != getClass())
if (!(obj instanceof FormField))
return false;
FormField other = (FormField) obj;
String thisXml = toXML();
String otherXml = other.toXML();
return toXML().equals(other.toXML());
}
if (thisXml.equals(otherXml)) {
return true;
} else {
return false;
}
@Override
public int hashCode() {
return toXML().hashCode();
}
/**
@ -356,6 +355,7 @@ public class FormField {
return value;
}
@Override
public String toString() {
return getLabel();
}
@ -375,6 +375,7 @@ public class FormField {
return buf.toString();
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
@ -396,5 +397,13 @@ public class FormField {
return true;
}
@Override
public int hashCode() {
int result = 1;
result = 37 * result + value.hashCode();
result = 37 * result + (label == null ? 0 : label.hashCode());
return result;
}
}
}

View file

@ -45,7 +45,7 @@ public interface NodeInformationProvider {
*
* @return a list of the Items defined in the node.
*/
public abstract List<DiscoverItems.Item> getNodeItems();
List<DiscoverItems.Item> getNodeItems();
/**
* Returns a list of the features defined in the node. For
@ -55,7 +55,7 @@ public interface NodeInformationProvider {
*
* @return a list of the feature strings defined in the node.
*/
public abstract List<String> getNodeFeatures();
List<String> getNodeFeatures();
/**
* Returns a list of the indentites defined in the node. For
@ -64,12 +64,12 @@ public interface NodeInformationProvider {
*
* @return a list of the Identities defined in the node.
*/
public abstract List<DiscoverInfo.Identity> getNodeIdentities();
List<DiscoverInfo.Identity> getNodeIdentities();
/**
* Returns a list of the packet extensions defined in the node.
*
* @return a list of the packet extensions defined in the node.
*/
public abstract List<PacketExtension> getNodePacketExtensions();
List<PacketExtension> getNodePacketExtensions();
}

View file

@ -513,7 +513,7 @@ public class ServiceDiscoveryManager {
// If the node version is known, store the new entry.
if (nvh != null) {
if (EntityCapsManager.verifyDiscvoerInfoVersion(nvh.getVer(), nvh.getHash(), info))
if (EntityCapsManager.verifyDiscoverInfoVersion(nvh.getVer(), nvh.getHash(), info))
EntityCapsManager.addDiscoverInfoByNode(nvh.getNodeVer(), info);
}

View file

@ -3,7 +3,7 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
* Copyright 2005 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.

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 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

View file

@ -1,139 +0,0 @@
/**
* Copyright 2013 Georg Lukas
*
* 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.carbons;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.forward.Forwarded;
import org.jivesoftware.smackx.packet.DelayInfo;
import org.jivesoftware.smackx.provider.DelayInfoProvider;
import org.xmlpull.v1.XmlPullParser;
/**
* Packet extension for XEP-0280: Message Carbons. This class implements
* the packet extension and a {@link PacketExtensionProvider} to parse
* message carbon copies from a packet. The extension
* <a href="http://xmpp.org/extensions/xep-0280.html">XEP-0280</a> is
* meant to synchronize a message flow to multiple presences of a user.
*
* <p>The {@link Carbon.Provider} must be registered in the
* <b>smack.properties</b> file for the elements <b>sent</b> and
* <b>received</b> with namespace <b>urn:xmpp:carbons:2</b></p> to be used.
*
* @author Georg Lukas
*/
public class Carbon implements PacketExtension {
public static final String NAMESPACE = "urn:xmpp:carbons:2";
private Direction dir;
private Forwarded fwd;
public Carbon(Direction dir, Forwarded fwd) {
this.dir = dir;
this.fwd = fwd;
}
/**
* get the direction (sent or received) of the carbon.
*
* @return the {@link Direction} of the carbon.
*/
public Direction getDirection() {
return dir;
}
/**
* get the forwarded packet.
*
* @return the {@link Forwarded} message contained in this Carbon.
*/
public Forwarded getForwarded() {
return fwd;
}
@Override
public String getElementName() {
return dir.toString();
}
@Override
public String getNamespace() {
return NAMESPACE;
}
@Override
public String toXML() {
StringBuilder buf = new StringBuilder();
buf.append("<").append(getElementName()).append(" xmlns=\"")
.append(getNamespace()).append("\">");
buf.append(fwd.toXML());
buf.append("</").append(getElementName()).append(">");
return buf.toString();
}
/**
* An enum to display the direction of a {@link Carbon} message.
*/
public static enum Direction {
received,
sent
}
public static class Provider implements PacketExtensionProvider {
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
Direction dir = Direction.valueOf(parser.getName());
Forwarded fwd = null;
boolean done = false;
while (!done) {
int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG && parser.getName().equals("forwarded")) {
fwd = (Forwarded)new Forwarded.Provider().parseExtension(parser);
}
else if (eventType == XmlPullParser.END_TAG && dir == Direction.valueOf(parser.getName()))
done = true;
}
if (fwd == null)
throw new Exception("sent/received must contain exactly one <forwarded> tag");
return new Carbon(dir, fwd);
}
}
/**
* Packet extension indicating that a message may not be carbon-copied.
*/
public static class Private implements PacketExtension {
public static final String ELEMENT = "private";
public String getElementName() {
return ELEMENT;
}
public String getNamespace() {
return Carbon.NAMESPACE;
}
public String toXML() {
return "<" + ELEMENT + " xmlns=\"" + Carbon.NAMESPACE + "\"/>";
}
}
}

View file

@ -1,213 +0,0 @@
/**
* Copyright 2013 Georg Lukas
*
* 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.carbons;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.packet.DiscoverInfo;
/**
* Packet extension for XEP-0280: Message Carbons. This class implements
* the manager for registering {@link Carbon} support, enabling and disabling
* message carbons.
*
* You should call enableCarbons() before sending your first undirected
* presence.
*
* @author Georg Lukas
*/
public class CarbonManager {
private static Map<Connection, CarbonManager> instances =
Collections.synchronizedMap(new WeakHashMap<Connection, CarbonManager>());
static {
Connection.addConnectionCreationListener(new ConnectionCreationListener() {
public void connectionCreated(Connection connection) {
new CarbonManager(connection);
}
});
}
private Connection connection;
private volatile boolean enabled_state = false;
private CarbonManager(Connection connection) {
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
sdm.addFeature(Carbon.NAMESPACE);
this.connection = connection;
instances.put(connection, this);
}
/**
* Obtain the CarbonManager responsible for a connection.
*
* @param connection the connection object.
*
* @return a CarbonManager instance
*/
public static CarbonManager getInstanceFor(Connection connection) {
CarbonManager carbonManager = instances.get(connection);
if (carbonManager == null) {
carbonManager = new CarbonManager(connection);
}
return carbonManager;
}
private IQ carbonsEnabledIQ(final boolean new_state) {
IQ setIQ = new IQ() {
public String getChildElementXML() {
return "<" + (new_state? "enable" : "disable") + " xmlns='" + Carbon.NAMESPACE + "'/>";
}
};
setIQ.setType(IQ.Type.SET);
return setIQ;
}
/**
* Returns true if XMPP Carbons are supported by the server.
*
* @return true if supported
*/
public boolean isSupportedByServer() {
try {
DiscoverInfo result = ServiceDiscoveryManager
.getInstanceFor(connection).discoverInfo(connection.getServiceName());
return result.containsFeature(Carbon.NAMESPACE);
}
catch (XMPPException e) {
return false;
}
}
/**
* Notify server to change the carbons state. This method returns
* immediately and changes the variable when the reply arrives.
*
* You should first check for support using isSupportedByServer().
*
* @param new_state whether carbons should be enabled or disabled
*/
public void sendCarbonsEnabled(final boolean new_state) {
IQ setIQ = carbonsEnabledIQ(new_state);
connection.addPacketListener(new PacketListener() {
public void processPacket(Packet packet) {
IQ result = (IQ)packet;
if (result.getType() == IQ.Type.RESULT) {
enabled_state = new_state;
}
connection.removePacketListener(this);
}
}, new PacketIDFilter(setIQ.getPacketID()));
connection.sendPacket(setIQ);
}
/**
* Notify server to change the carbons state. This method blocks
* some time until the server replies to the IQ and returns true on
* success.
*
* You should first check for support using isSupportedByServer().
*
* @param new_state whether carbons should be enabled or disabled
*
* @return true if the operation was successful
*/
public boolean setCarbonsEnabled(final boolean new_state) {
if (enabled_state == new_state)
return true;
IQ setIQ = carbonsEnabledIQ(new_state);
PacketCollector collector =
connection.createPacketCollector(new PacketIDFilter(setIQ.getPacketID()));
connection.sendPacket(setIQ);
IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
collector.cancel();
if (result != null && result.getType() == IQ.Type.RESULT) {
enabled_state = new_state;
return true;
}
return false;
}
/**
* Helper method to enable carbons.
*
* @return true if the operation was successful
*/
public boolean enableCarbons() {
return setCarbonsEnabled(true);
}
/**
* Helper method to disable carbons.
*
* @return true if the operation was successful
*/
public boolean disableCarbons() {
return setCarbonsEnabled(false);
}
/**
* Check if carbons are enabled on this connection.
*/
public boolean getCarbonsEnabled() {
return this.enabled_state;
}
/**
* Obtain a Carbon from a message, if available.
*
* @param msg Message object to check for carbons
*
* @return a Carbon if available, null otherwise.
*/
public static Carbon getCarbon(Message msg) {
Carbon cc = (Carbon)msg.getExtension("received", Carbon.NAMESPACE);
if (cc == null)
cc = (Carbon)msg.getExtension("sent", Carbon.NAMESPACE);
return cc;
}
/**
* Mark a message as "private", so it will not be carbon-copied.
*
* @param msg Message object to mark private
*/
public static void disableCarbons(Message msg) {
msg.addExtension(new Carbon.Private());
}
}

View file

@ -3,7 +3,7 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
* Copyright 2008 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.

View file

@ -506,7 +506,7 @@ public class EntityCapsManager {
* @param info
* @return true if it's valid and should be cache, false if not
*/
public static boolean verifyDiscvoerInfoVersion(String ver, String hash, DiscoverInfo info) {
public static boolean verifyDiscoverInfoVersion(String ver, String hash, DiscoverInfo info) {
// step 3.3 check for duplicate identities
if (info.containsDuplicateIdentities())
return false;
@ -583,7 +583,7 @@ public class EntityCapsManager {
// NAME is not included (in accordance with XEP-0030, the category and
// type MUST be included.
SortedSet<DiscoverInfo.Identity> sortedIdentities = new TreeSet<DiscoverInfo.Identity>();
;
for (Iterator<DiscoverInfo.Identity> it = discoverInfo.getIdentities(); it.hasNext();)
sortedIdentities.add(it.next());
@ -616,7 +616,7 @@ public class EntityCapsManager {
// only use the data form for calculation is it has a hidden FORM_TYPE
// field
// see XEP-0115 5.4 step 3.6
if (extendedInfo != null && extendedInfo.hasHiddenFromTypeField()) {
if (extendedInfo != null && extendedInfo.hasHiddenFormTypeField()) {
synchronized (extendedInfo) {
// 6. If the service discovery information response includes
// XEP-0128 data forms, sort the forms by the FORM_TYPE (i.e.,

View file

@ -24,15 +24,15 @@ public interface EntityCapsPersistentCache {
* @param node
* @param info
*/
abstract void addDiscoverInfoByNodePersistent(String node, DiscoverInfo info);
void addDiscoverInfoByNodePersistent(String node, DiscoverInfo info);
/**
* Replay the Caches data into EntityCapsManager
*/
abstract void replay() throws IOException;
void replay() throws IOException;
/**
* Empty the Cache
*/
abstract void emptyCache();
void emptyCache();
}

View file

@ -27,7 +27,7 @@ import java.io.StringReader;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.util.Base64Encoder;
import org.jivesoftware.smack.util.Base32Encoder;
import org.jivesoftware.smack.util.StringEncoder;
import org.jivesoftware.smackx.entitycaps.EntityCapsManager;
import org.jivesoftware.smackx.packet.DiscoverInfo;
@ -47,19 +47,20 @@ import org.xmlpull.v1.XmlPullParserException;
public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache {
private File cacheDir;
private StringEncoder stringEncoder;
private StringEncoder filenameEncoder;
/**
* Creates a new SimpleDirectoryPersistentCache Object. Make sure that the
* cacheDir exists and that it's an directory.
*
* If your cacheDir is case insensitive then make sure to set the
* StringEncoder to Base32.
* <p>
* Default filename encoder {@link Base32Encoder}, as this will work on all
* filesystems, both case sensitive and case insensitive. It does however
* produce longer filenames.
*
* @param cacheDir
*/
public SimpleDirectoryPersistentCache(File cacheDir) {
this(cacheDir, Base64Encoder.getInstance());
this(cacheDir, Base32Encoder.getInstance());
}
/**
@ -67,26 +68,25 @@ public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache
* cacheDir exists and that it's an directory.
*
* If your cacheDir is case insensitive then make sure to set the
* StringEncoder to Base32.
* StringEncoder to {@link Base32Encoder} (which is the default).
*
* @param cacheDir
* @param stringEncoder
* @param cacheDir The directory where the cache will be stored.
* @param filenameEncoder Encodes the node string into a filename.
*/
public SimpleDirectoryPersistentCache(File cacheDir, StringEncoder stringEncoder) {
public SimpleDirectoryPersistentCache(File cacheDir, StringEncoder filenameEncoder) {
if (!cacheDir.exists())
throw new IllegalStateException("Cache directory \"" + cacheDir + "\" does not exist");
if (!cacheDir.isDirectory())
throw new IllegalStateException("Cache directory \"" + cacheDir + "\" is not a directory");
this.cacheDir = cacheDir;
this.stringEncoder = stringEncoder;
this.filenameEncoder = filenameEncoder;
}
@Override
public void addDiscoverInfoByNodePersistent(String node, DiscoverInfo info) {
String filename = stringEncoder.encode(node);
String filename = filenameEncoder.encode(node);
File nodeFile = new File(cacheDir, filename);
try {
if (nodeFile.createNewFile())
writeInfoToFile(nodeFile, info);
@ -99,7 +99,7 @@ public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache
public void replay() throws IOException {
File[] files = cacheDir.listFiles();
for (File f : files) {
String node = stringEncoder.decode(f.getName());
String node = filenameEncoder.decode(f.getName());
DiscoverInfo info = restoreInfoFromFile(f);
if (info == null)
continue;

View file

@ -1,4 +1,4 @@
/*
/**
* Copyright 2009 Jonas Ådahl.
* Copyright 2011-2013 Florian Schmaus
*

View file

@ -1,125 +0,0 @@
/**
* Copyright 2013 Georg Lukas
*
* 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.forward;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.packet.DelayInfo;
import org.jivesoftware.smackx.provider.DelayInfoProvider;
import org.xmlpull.v1.XmlPullParser;
/**
* Packet extension for XEP-0297: Stanza Forwarding. This class implements
* the packet extension and a {@link PacketExtensionProvider} to parse
* forwarded messages from a packet. The extension
* <a href="http://xmpp.org/extensions/xep-0297.html">XEP-0297</a> is
* a prerequisite for XEP-0280 (Message Carbons).
*
* <p>The {@link Forwarded.Provider} must be registered in the
* <b>smack.properties</b> file for the element <b>forwarded</b> with
* namespace <b>urn:xmpp:forwarded:0</b></p> to be used.
*
* @author Georg Lukas
*/
public class Forwarded implements PacketExtension {
public static final String NAMESPACE = "urn:xmpp:forward:0";
public static final String ELEMENT_NAME = "forwarded";
private DelayInfo delay;
private Packet forwardedPacket;
/**
* Creates a new Forwarded packet extension.
*
* @param delay an optional {@link DelayInfo} timestamp of the packet.
* @param fwdPacket the packet that is forwarded (required).
*/
public Forwarded(DelayInfo delay, Packet fwdPacket) {
this.delay = delay;
this.forwardedPacket = fwdPacket;
}
@Override
public String getElementName() {
return ELEMENT_NAME;
}
@Override
public String getNamespace() {
return NAMESPACE;
}
@Override
public String toXML() {
StringBuilder buf = new StringBuilder();
buf.append("<").append(getElementName()).append(" xmlns=\"")
.append(getNamespace()).append("\">");
if (delay != null)
buf.append(delay.toXML());
buf.append(forwardedPacket.toXML());
buf.append("</").append(getElementName()).append(">");
return buf.toString();
}
/**
* get the packet forwarded by this stanza.
*
* @return the {@link Packet} instance (typically a message) that was forwarded.
*/
public Packet getForwardedPacket() {
return forwardedPacket;
}
/**
* get the timestamp of the forwarded packet.
*
* @return the {@link DelayInfo} representing the time when the original packet was sent. May be null.
*/
public DelayInfo getDelayInfo() {
return delay;
}
public static class Provider implements PacketExtensionProvider {
DelayInfoProvider dip = new DelayInfoProvider();
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
DelayInfo di = null;
Packet packet = null;
boolean done = false;
while (!done) {
int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG) {
if (parser.getName().equals("delay"))
di = (DelayInfo)dip.parseExtension(parser);
else if (parser.getName().equals("message"))
packet = PacketParserUtils.parseMessage(parser);
else throw new Exception("Unsupported forwarded packet type: " + parser.getName());
}
else if (eventType == XmlPullParser.END_TAG && parser.getName().equals(ELEMENT_NAME))
done = true;
}
if (packet == null)
throw new Exception("forwarded extension must contain a packet");
return new Forwarded(di, packet);
}
}
}

View file

@ -202,7 +202,7 @@ public class DataForm implements PacketExtension {
*
* @return
*/
public boolean hasHiddenFromTypeField() {
public boolean hasHiddenFormTypeField() {
boolean found = false;
for (FormField f : fields) {
if (f.getVariable().equals("FORM_TYPE") && f.getType() != null && f.getType().equals("hidden"))

View file

@ -257,13 +257,25 @@ public class DiscoverInfo extends IQ {
* attributes.
*
*/
public static class Identity implements Comparable<Object> {
public static class Identity implements Comparable<Identity> {
private String category;
private String name;
private String type;
private String lang; // 'xml:lang;
/**
* Creates a new identity for an XMPP entity.
*
* @param category the entity's category.
* @param name the entity's name.
* @deprecated As per the spec, the type field is mandatory and the 3 argument constructor should be used instead.
*/
public Identity(String category, String name) {
this.category = category;
this.name = name;
}
/**
* Creates a new identity for an XMPP entity.
* 'category' and 'type' are required by
@ -274,6 +286,9 @@ public class DiscoverInfo extends IQ {
* @param type the entity's type (required as per XEP-30).
*/
public Identity(String category, String name, String type) {
if ((category == null) || (type == null))
throw new IllegalArgumentException("category and type cannot be null");
this.category = category;
this.name = name;
this.type = type;
@ -313,6 +328,7 @@ public class DiscoverInfo extends IQ {
* 'type' attribute refer to <a href="http://www.jabber.org/registrar/disco-categories.html">Jabber::Registrar</a>
*
* @param type the identity's type.
* @deprecated As per the spec, this field is mandatory and the 3 argument constructor should be used instead.
*/
public void setType(String type) {
this.type = type;
@ -374,11 +390,14 @@ public class DiscoverInfo extends IQ {
String otherLang = other.lang == null ? "" : other.lang;
String thisLang = lang == null ? "" : lang;
if (!other.type.equals(type))
return false;
if (!otherLang.equals(thisLang))
return false;
// This safeguard can be removed once the deprecated constructor is removed.
String otherType = other.type == null ? "" : other.type;
String thisType = type == null ? "" : type;
if (!otherType.equals(thisType))
return false;
String otherName = other.name == null ? "" : other.name;
String thisName = name == null ? "" : other.name;
@ -387,23 +406,35 @@ public class DiscoverInfo extends IQ {
return true;
}
@Override
public int hashCode() {
int result = 1;
result = 37 * result + category.hashCode();
result = 37 * result + (lang == null ? 0 : lang.hashCode());
result = 37 * result + (type == null ? 0 : type.hashCode());
result = 37 * result + (name == null ? 0 : name.hashCode());
return result;
}
/**
* Compares and identity with another object. The comparison order is:
* Compares this identity with another one. The comparison order is:
* Category, Type, Lang. If all three are identical the other Identity is considered equal.
* Name is not used for comparision, as defined by XEP-0115
*
* @param obj
* @return
*/
public int compareTo(Object obj) {
DiscoverInfo.Identity other = (DiscoverInfo.Identity) obj;
public int compareTo(DiscoverInfo.Identity other) {
String otherLang = other.lang == null ? "" : other.lang;
String thisLang = lang == null ? "" : lang;
// This can be removed once the deprecated constructor is removed.
String otherType = other.type == null ? "" : other.type;
String thisType = type == null ? "" : type;
if (category.equals(other.category)) {
if (type.equals(other.type)) {
if (thisType.equals(otherType)) {
if (thisLang.equals(otherLang)) {
// Don't compare on name, XEP-30 says that name SHOULD
// be equals for all identities of an entity
@ -412,7 +443,7 @@ public class DiscoverInfo extends IQ {
return thisLang.compareTo(otherLang);
}
} else {
return type.compareTo(other.type);
return thisType.compareTo(otherType);
}
} else {
return category.compareTo(other.category);
@ -436,6 +467,8 @@ public class DiscoverInfo extends IQ {
* @param variable the feature's variable.
*/
public Feature(String variable) {
if (variable == null)
throw new IllegalArgumentException("variable cannot be null");
this.variable = variable;
}
@ -465,5 +498,10 @@ public class DiscoverInfo extends IQ {
DiscoverInfo.Feature other = (DiscoverInfo.Feature) obj;
return variable.equals(other.variable);
}
@Override
public int hashCode() {
return 37 * variable.hashCode();
}
}
}

View file

@ -3,7 +3,7 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
* Copyright 2005 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.

View file

@ -85,7 +85,8 @@ import org.jivesoftware.smack.util.StringUtils;
* @author Kirill Maximov (kir@maxkir.com)
*/
public class VCard extends IQ {
private static final String DEFAULT_MIME_TYPE = "image/jpeg";
/**
* Phone types:
* VOICE?, FAX?, PAGER?, MSG?, CELL?, VIDEO?, BBS?, MODEM?, ISDN?, PCS?, PREF?
@ -93,7 +94,6 @@ public class VCard extends IQ {
private Map<String, String> homePhones = new HashMap<String, String>();
private Map<String, String> workPhones = new HashMap<String, String>();
/**
* Address types:
* POSTAL?, PARCEL?, (DOM | INTL)?, PREF?, POBOX?, EXTADR?, STREET?, LOCALITY?,
@ -357,7 +357,7 @@ public class VCard extends IQ {
* @param bytes the bytes of the avatar, or null to remove the avatar data
*/
public void setAvatar(byte[] bytes) {
setAvatar(bytes, "image/jpeg");
setAvatar(bytes, DEFAULT_MIME_TYPE);
}
/**
@ -390,6 +390,16 @@ public class VCard extends IQ {
photoMimeType = mimeType;
}
/**
* Set the encoded avatar string. This is used by the provider.
*
* @param encodedAvatar the encoded avatar string.
* @deprecated Use {@link #setAvatar(String, String)} instead.
*/
public void setEncodedImage(String encodedAvatar) {
setAvatar(encodedAvatar, DEFAULT_MIME_TYPE);
}
/**
* Return the byte representation of the avatar(if one exists), otherwise returns null if
* no avatar could be found.

View file

@ -17,52 +17,47 @@
package org.jivesoftware.smackx.ping;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.SmackError;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.IQTypeFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.keepalive.KeepAliveManager;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.ping.packet.Ping;
import org.jivesoftware.smack.util.SyncPacketSend;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.packet.DiscoverInfo;
import org.jivesoftware.smackx.ping.packet.Ping;
import org.jivesoftware.smackx.ping.packet.Pong;
/**
* Implements the XMPP Ping as defined by XEP-0199. This protocol offers an
* alternative to the traditional 'white space ping' approach of determining the
* availability of an entity. The XMPP Ping protocol allows ping messages to be
* send in a more XML-friendly approach, which can be used over more than one
* hop in the communication path.
* Implements the XMPP Ping as defined by XEP-0199. The XMPP Ping protocol
* allows one entity to 'ping' any other entity by simply sending a ping to
* the appropriate JID.
* <p>
* NOTE: The {@link KeepAliveManager} already provides a keepalive functionality
* for regularly pinging the server to keep the underlying transport connection
* alive. This class is specifically intended to do manual pings of other
* entities.
*
* @author Florian Schmaus
* @see <a href="http://www.xmpp.org/extensions/xep-0199.html">XEP-0199:XMPP
* Ping</a>
*/
public class PingManager {
public static final String NAMESPACE = "urn:xmpp:ping";
public static final String ELEMENT = "ping";
private static Map<Connection, PingManager> instances =
Collections.synchronizedMap(new WeakHashMap<Connection, PingManager>());
private static Map<Connection, PingManager> instances = Collections
.synchronizedMap(new WeakHashMap<Connection, PingManager>());
static {
Connection.addConnectionCreationListener(new ConnectionCreationListener() {
public void connectionCreated(Connection connection) {
@ -71,273 +66,106 @@ public class PingManager {
});
}
private ScheduledExecutorService periodicPingExecutorService;
private Connection connection;
private int pingInterval = SmackConfiguration.getDefaultPingInterval();
private Set<PingFailedListener> pingFailedListeners = Collections
.synchronizedSet(new HashSet<PingFailedListener>());
private ScheduledFuture<?> periodicPingTask;
protected volatile long lastSuccessfulPingByTask = -1;
// Ping Flood protection
private long pingMinDelta = 100;
private long lastPingStamp = 0; // timestamp of the last received ping
// Timestamp of the last pong received, either from the server or another entity
// Note, no need to synchronize this value, it will only increase over time
private long lastSuccessfulManualPing = -1;
private PingManager(Connection connection) {
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
sdm.addFeature(NAMESPACE);
this.connection = connection;
init();
}
private void init() {
periodicPingExecutorService = new ScheduledThreadPoolExecutor(1);
PacketFilter pingPacketFilter = new PacketTypeFilter(Ping.class);
connection.addPacketListener(new PacketListener() {
/**
* Sends a Pong for every Ping
*/
public void processPacket(Packet packet) {
if (pingMinDelta > 0) {
// Ping flood protection enabled
long currentMillies = System.currentTimeMillis();
long delta = currentMillies - lastPingStamp;
lastPingStamp = currentMillies;
if (delta < pingMinDelta) {
return;
}
}
Pong pong = new Pong((Ping)packet);
connection.sendPacket(pong);
}
}
, pingPacketFilter);
connection.addConnectionListener(new ConnectionListener() {
@Override
public void connectionClosed() {
maybeStopPingServerTask();
}
@Override
public void connectionClosedOnError(Exception arg0) {
maybeStopPingServerTask();
}
@Override
public void reconnectionSuccessful() {
maybeSchedulePingServerTask();
}
@Override
public void reconnectingIn(int seconds) {
}
@Override
public void reconnectionFailed(Exception e) {
}
});
instances.put(connection, this);
maybeSchedulePingServerTask();
}
public static PingManager getInstanceFor(Connection connection) {
/**
* Retrieves a {@link PingManager} for the specified {@link Connection}, creating one if it doesn't already
* exist.
*
* @param connection
* The connection the manager is attached to.
* @return The new or existing manager.
*/
public synchronized static PingManager getInstanceFor(Connection connection) {
PingManager pingManager = instances.get(connection);
if (pingManager == null) {
pingManager = new PingManager(connection);
}
return pingManager;
}
public void setPingIntervall(int pingIntervall) {
this.pingInterval = pingIntervall;
private PingManager(Connection con) {
this.connection = con;
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
// The ServiceDiscoveryManager was not pre-initialized
if (sdm == null)
sdm = new ServiceDiscoveryManager(connection);
sdm.addFeature(Ping.NAMESPACE);
PacketFilter pingPacketFilter = new AndFilter(new PacketTypeFilter(Ping.class), new IQTypeFilter(Type.GET));
connection.addPacketListener(new PacketListener() {
/**
* Sends a Pong for every Ping
*/
public void processPacket(Packet packet) {
IQ pong = IQ.createResultIQ((Ping) packet);
connection.sendPacket(pong);
}
}, pingPacketFilter);
}
public int getPingIntervall() {
return pingInterval;
}
public void registerPingFailedListener(PingFailedListener listener) {
pingFailedListeners.add(listener);
}
public void unregisterPingFailedListener(PingFailedListener listener) {
pingFailedListeners.remove(listener);
}
public void disablePingFloodProtection() {
setPingMinimumInterval(-1);
}
public void setPingMinimumInterval(long ms) {
this.pingMinDelta = ms;
}
public long getPingMinimumInterval() {
return this.pingMinDelta;
/**
* Pings the given jid. This method will return false if an error occurs. The exception
* to this, is a server ping, which will always return true if the server is reachable,
* event if there is an error on the ping itself (i.e. ping not supported).
* <p>
* Use {@link #isPingSupported(String)} to determine if XMPP Ping is supported
* by the entity.
*
* @param jid The id of the entity the ping is being sent to
* @param pingTimeout The time to wait for a reply
* @return true if a reply was received from the entity, false otherwise.
*/
public boolean ping(String jid, long pingTimeout) {
Ping ping = new Ping(jid);
try {
SyncPacketSend.getReply(connection, ping);
}
catch (XMPPException exc) {
return (jid.equals(connection.getServiceName()) && (exc.getSmackError() != SmackError.NO_RESPONSE_FROM_SERVER));
}
return true;
}
/**
* Pings the given jid and returns the IQ response which is either of
* IQ.Type.ERROR or IQ.Type.RESULT. If we are not connected or if there was
* no reply, null is returned.
* Same as calling {@link #ping(String, long)} with the defaultpacket reply
* timeout.
*
* You should use isPingSupported(jid) to determine if XMPP Ping is
* supported by the user.
*
* @param jid
* @param pingTimeout
* @return
* @param jid The id of the entity the ping is being sent to
* @return true if a reply was received from the entity, false otherwise.
*/
public IQ ping(String jid, long pingTimeout) {
// Make sure we actually connected to the server
if (!connection.isAuthenticated())
return null;
Ping ping = new Ping(connection.getUser(), jid);
PacketCollector collector =
connection.createPacketCollector(new PacketIDFilter(ping.getPacketID()));
connection.sendPacket(ping);
IQ result = (IQ) collector.nextResult(pingTimeout);
collector.cancel();
return result;
}
/**
* Pings the given jid and returns the IQ response with the default
* packet reply timeout
*
* @param jid
* @return
*/
public IQ ping(String jid) {
public boolean ping(String jid) {
return ping(jid, SmackConfiguration.getPacketReplyTimeout());
}
/**
* Pings the given Entity.
* Query the specified entity to see if it supports the Ping protocol (XEP-0199)
*
* Note that XEP-199 shows that if we receive a error response
* service-unavailable there is no way to determine if the response was send
* by the entity (e.g. a user JID) or from a server in between. This is
* intended behavior to avoid presence leaks.
*
* Always use isPingSupported(jid) to determine if XMPP Ping is supported
* by the entity.
*
* @param jid
* @return True if a pong was received, otherwise false
* @param jid The id of the entity the query is being sent to
* @return true if it supports ping, false otherwise.
* @throws XMPPException An XMPP related error occurred during the request
*/
public boolean pingEntity(String jid, long pingTimeout) {
IQ result = ping(jid, pingTimeout);
public boolean isPingSupported(String jid) throws XMPPException {
DiscoverInfo result = ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid);
return result.containsFeature(Ping.NAMESPACE);
}
if (result == null || result.getType() == IQ.Type.ERROR) {
return false;
}
pongReceived();
return true;
}
public boolean pingEntity(String jid) {
return pingEntity(jid, SmackConfiguration.getPacketReplyTimeout());
}
/**
* Pings the user's server. Will notify the registered
* pingFailedListeners in case of error.
* Pings the server. This method will return true if the server is reachable. It
* is the equivalent of calling <code>ping</code> with the XMPP domain.
* <p>
* Unlike the {@link #ping(String)} case, this method will return true even if
* {@link #isPingSupported(String)} is false.
*
* If we receive as response, we can be sure that it came from the server.
*
* @return true if successful, otherwise false
*/
public boolean pingMyServer(long pingTimeout) {
IQ result = ping(connection.getServiceName(), pingTimeout);
if (result == null) {
for (PingFailedListener l : pingFailedListeners) {
l.pingFailed();
}
return false;
}
// Maybe not really a pong, but an answer is an answer
pongReceived();
return true;
}
/**
* Pings the user's server with the PacketReplyTimeout as defined
* in SmackConfiguration.
*
* @return true if successful, otherwise false
* @return true if a reply was received from the server, false otherwise.
*/
public boolean pingMyServer() {
return pingMyServer(SmackConfiguration.getPacketReplyTimeout());
}
/**
* Returns true if XMPP Ping is supported by a given JID
*
* @param jid
* @return
*/
public boolean isPingSupported(String jid) {
try {
DiscoverInfo result =
ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid);
return result.containsFeature(NAMESPACE);
}
catch (XMPPException e) {
return false;
}
}
/**
* Returns the time of the last successful Ping Pong with the
* users server. If there was no successful Ping (e.g. because this
* feature is disabled) -1 will be returned.
*
* @return
*/
public long getLastSuccessfulPing() {
return Math.max(lastSuccessfulPingByTask, lastSuccessfulManualPing);
}
protected Set<PingFailedListener> getPingFailedListeners() {
return pingFailedListeners;
}
/**
* Cancels any existing periodic ping task if there is one and schedules a new ping task if pingInterval is greater
* then zero.
*
*/
protected synchronized void maybeSchedulePingServerTask() {
maybeStopPingServerTask();
if (pingInterval > 0) {
periodicPingTask = periodicPingExecutorService.schedule(new ServerPingTask(connection), pingInterval,
TimeUnit.SECONDS);
}
}
private void maybeStopPingServerTask() {
if (periodicPingTask != null) {
periodicPingTask.cancel(true);
periodicPingTask = null;
}
}
private void pongReceived() {
lastSuccessfulManualPing = System.currentTimeMillis();
return ping(connection.getServiceName());
}
}

View file

@ -1,77 +0,0 @@
/**
* Copyright 2012-2013 Florian Schmaus
*
* 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.ping;
import java.lang.ref.WeakReference;
import java.util.Set;
import org.jivesoftware.smack.Connection;
class ServerPingTask implements Runnable {
// This has to be a weak reference because IIRC all threads are roots
// for objects and we have a new thread here that should hold a strong
// reference to connection so that it can be GCed.
private WeakReference<Connection> weakConnection;
private int delta = 1000; // 1 seconds
private int tries = 3; // 3 tries
protected ServerPingTask(Connection connection) {
this.weakConnection = new WeakReference<Connection>(connection);
}
public void run() {
Connection connection = weakConnection.get();
if (connection == null) {
// connection has been collected by GC
// which means we can stop the thread by breaking the loop
return;
}
if (connection.isAuthenticated()) {
PingManager pingManager = PingManager.getInstanceFor(connection);
boolean res = false;
for (int i = 0; i < tries; i++) {
if (i != 0) {
try {
Thread.sleep(delta);
} catch (InterruptedException e) {
// We received an interrupt
// This only happens if we should stop pinging
return;
}
}
res = pingManager.pingMyServer();
// stop when we receive a pong back
if (res) {
pingManager.lastSuccessfulPingByTask = System.currentTimeMillis();
break;
}
}
if (!res) {
Set<PingFailedListener> pingFailedListeners = pingManager.getPingFailedListeners();
for (PingFailedListener l : pingFailedListeners) {
l.pingFailed();
}
} else {
// Ping was successful, wind-up the periodic task again
pingManager.maybeSchedulePingServerTask();
}
}
}
}

View file

@ -1,38 +0,0 @@
/**
* Copyright 2012 Florian Schmaus
*
* 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.ping.packet;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smackx.ping.PingManager;
public class Ping extends IQ {
public Ping() {
}
public Ping(String from, String to) {
setTo(to);
setFrom(from);
setType(IQ.Type.GET);
setPacketID(getPacketID());
}
public String getChildElementXML() {
return "<" + PingManager.ELEMENT + " xmlns=\'" + PingManager.NAMESPACE + "\' />";
}
}

View file

@ -1,45 +0,0 @@
/**
* Copyright 2012 Florian Schmaus
*
* 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.ping.packet;
import org.jivesoftware.smack.packet.IQ;
public class Pong extends IQ {
/**
* Composes a Pong packet from a received ping packet. This basically swaps
* the 'from' and 'to' attributes. And sets the IQ type to result.
*
* @param ping
*/
public Pong(Ping ping) {
setType(IQ.Type.RESULT);
setFrom(ping.getTo());
setTo(ping.getFrom());
setPacketID(ping.getPacketID());
}
/*
* Returns the child element of the Pong reply, which is non-existent. This
* is why we return 'null' here. See e.g. Example 11 from
* http://xmpp.org/extensions/xep-0199.html#e2e
*/
public String getChildElementXML() {
return null;
}
}

View file

@ -1,32 +0,0 @@
/**
* Copyright 2012 Florian Schmaus
*
* 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.ping.provider;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smackx.ping.packet.Ping;
import org.xmlpull.v1.XmlPullParser;
public class PingProvider implements IQProvider {
public IQ parseIQ(XmlPullParser parser) throws Exception {
// No need to use the ping constructor with arguments. IQ will already
// have filled out all relevant fields ('from', 'to', 'id').
return new Ping();
}
}

View file

@ -3,7 +3,7 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
* Copyright 2009 Robin Collier.
*
* 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.
@ -17,9 +17,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Created on 2009-07-13
*/
package org.jivesoftware.smackx.pubsub;
import org.jivesoftware.smack.Connection;

View file

@ -3,7 +3,7 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
* Copyright 2009 Robin Collier.
*
* 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.
@ -17,9 +17,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Created on 2009-07-09
*/
package org.jivesoftware.smackx.pubsub;
import java.util.ArrayList;

View file

@ -3,7 +3,7 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
* Copyright 2009 Robin Collier.
*
* 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.
@ -17,9 +17,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Created on 2009-05-12
*/
package org.jivesoftware.smackx.pubsub;
abstract public class NodeEvent

View file

@ -24,53 +24,86 @@ import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
import org.xmlpull.v1.XmlPullParser;
/**
* Parses an <b>item</b> element as is defined in both the {@link PubSubNamespace#BASIC} and {@link PubSubNamespace#EVENT}
* namespaces. To parse the item contents, it will use whatever {@link PacketExtensionProvider} is registered in
* <b>smack.providers</b> for its element name and namespace. If no provider is registered, it will return a {@link SimplePayload}.
* Parses an <b>item</b> element as is defined in both the {@link PubSubNamespace#BASIC} and
* {@link PubSubNamespace#EVENT} namespaces. To parse the item contents, it will use whatever
* {@link PacketExtensionProvider} is registered in <b>smack.providers</b> for its element name and namespace. If no
* provider is registered, it will return a {@link SimplePayload}.
*
* @author Robin Collier
*/
public class ItemProvider implements PacketExtensionProvider
public class ItemProvider implements PacketExtensionProvider
{
public PacketExtension parseExtension(XmlPullParser parser) throws Exception
{
String id = parser.getAttributeValue(null, "id");
public PacketExtension parseExtension(XmlPullParser parser) throws Exception
{
String id = parser.getAttributeValue(null, "id");
String node = parser.getAttributeValue(null, "node");
String elem = parser.getName();
int tag = parser.next();
if (tag == XmlPullParser.END_TAG)
{
return new Item(id, node);
}
else
{
String payloadElemName = parser.getName();
String payloadNS = parser.getNamespace();
if (ProviderManager.getInstance().getExtensionProvider(payloadElemName, payloadNS) == null)
{
boolean done = false;
StringBuilder payloadText = new StringBuilder();
while (!done)
{
if (tag == XmlPullParser.END_TAG && parser.getName().equals(elem))
done = true;
else if (!((tag == XmlPullParser.START_TAG) && parser.isEmptyElementTag()))
payloadText.append(parser.getText());
if (!done)
tag = parser.next();
}
return new PayloadItem<SimplePayload>(id, node, new SimplePayload(payloadElemName, payloadNS, payloadText.toString()));
}
else
{
return new PayloadItem<PacketExtension>(id, node, PacketParserUtils.parsePacketExtension(payloadElemName, payloadNS, parser));
}
}
}
String elem = parser.getName();
int tag = parser.next();
if (tag == XmlPullParser.END_TAG)
{
return new Item(id, node);
}
else
{
String payloadElemName = parser.getName();
String payloadNS = parser.getNamespace();
if (ProviderManager.getInstance().getExtensionProvider(payloadElemName, payloadNS) == null)
{
boolean done = false;
boolean isEmptyElement = false;
StringBuilder payloadText = new StringBuilder();
while (!done)
{
if (tag == XmlPullParser.END_TAG && parser.getName().equals(elem))
{
done = true;
}
else if (parser.getEventType() == XmlPullParser.START_TAG)
{
payloadText.append("<").append(parser.getName());
if (parser.getName().equals(payloadElemName) && (payloadNS.length() > 0))
payloadText.append(" xmlns=\"").append(payloadNS).append("\"");
int n = parser.getAttributeCount();
for (int i = 0; i < n; i++)
payloadText.append(" ").append(parser.getAttributeName(i)).append("=\"")
.append(parser.getAttributeValue(i)).append("\"");
if (parser.isEmptyElementTag())
{
payloadText.append("/>");
isEmptyElement = true;
}
else
{
payloadText.append(">");
}
}
else if (parser.getEventType() == XmlPullParser.END_TAG)
{
if (isEmptyElement)
isEmptyElement = false;
else
payloadText.append("</").append(parser.getName()).append(">");
}
else if (parser.getEventType() == XmlPullParser.TEXT)
{
payloadText.append(parser.getText());
}
tag = parser.next();
}
return new PayloadItem<SimplePayload>(id, node, new SimplePayload(payloadElemName, payloadNS, payloadText.toString()));
}
else {
return new PayloadItem<PacketExtension>(id, node, PacketParserUtils.parsePacketExtension(
payloadElemName, payloadNS, parser));
}
}
}
}

View file

@ -1,4 +1,4 @@
/*
/**
* 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
@ -42,16 +42,19 @@ public class DeliveryReceipt implements PacketExtension
return id;
}
@Override
public String getElementName()
{
return ELEMENT;
}
@Override
public String getNamespace()
{
return NAMESPACE;
}
@Override
public String toXML()
{
return "<received xmlns='" + NAMESPACE + "' id='" + id + "'/>";

View file

@ -24,20 +24,16 @@ import java.util.WeakHashMap;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketExtensionFilter;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.packet.DiscoverInfo;
/**
* Packet extension for XEP-0184: Message Delivery Receipts. This class implements
* Manager for XEP-0184: Message Delivery Receipts. This class implements
* the manager for {@link DeliveryReceipt} support, enabling and disabling of
* automatic DeliveryReceipt transmission.
*
@ -167,7 +163,7 @@ public class DeliveryReceiptManager implements PacketListener {
*
* @param listener the listener to be informed about new receipts
*/
public void registerReceiptReceivedListener(ReceiptReceivedListener listener) {
public void addReceiptReceivedListener(ReceiptReceivedListener listener) {
receiptReceivedListeners.add(listener);
}
@ -176,20 +172,10 @@ public class DeliveryReceiptManager implements PacketListener {
*
* @param listener the listener to be removed
*/
public void unregisterReceiptReceivedListener(ReceiptReceivedListener listener) {
public void removeReceiptReceivedListener(ReceiptReceivedListener listener) {
receiptReceivedListeners.remove(listener);
}
/**
* Interface for received receipt notifications.
*
* Implement this and add a listener to get notified.
*/
public static interface ReceiptReceivedListener {
void onReceiptReceived(String fromJid, String toJid, String receiptId);
}
/**
* Test if a packet requires a delivery receipt.
*

View file

@ -1,21 +1,26 @@
/**
* Copyright 2012 Florian Schmaus
*
* 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.ping;
public interface PingFailedListener {
void pingFailed();
/**
* Copyright 2013 Georg Lukas
*
* 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.receipts;
/**
* Interface for received receipt notifications.
*
* Implement this and add a listener to get notified.
*/
public interface ReceiptReceivedListener {
void onReceiptReceived(String fromJid, String toJid, String receiptId);
}