diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/VersionManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/VersionManager.java index b190efce2..fc33e39be 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/VersionManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/VersionManager.java @@ -20,10 +20,15 @@ package org.jivesoftware.smackx.iqversion; import java.util.Map; import java.util.WeakHashMap; +import org.jivesoftware.smack.SmackConfiguration; +import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NotConnectedException; +import org.jivesoftware.smack.ConnectionCreationListener; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.XMPPConnectionRegistry; +import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.IQTypeFilter; import org.jivesoftware.smack.filter.PacketFilter; @@ -53,7 +58,27 @@ public class VersionManager extends Manager { private static final PacketFilter PACKET_FILTER = new AndFilter(new PacketTypeFilter(Version.class), IQTypeFilter.GET); - private Version own_version; + private static Version defaultVersion; + + private Version ourVersion = defaultVersion; + + public static void setDefaultVersion(String name, String version) { + setDefaultVersion(name, version, null); + } + + public static void setDefaultVersion(String name, String version, String os) { + defaultVersion = generateVersionFrom(name, version, os); + } + + private static boolean autoAppendSmackVersion = true; + + static { + XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() { + public void connectionCreated(XMPPConnection connection) { + VersionManager.getInstanceFor(connection); + } + }); + } private VersionManager(final XMPPConnection connection) { super(connection); @@ -67,13 +92,10 @@ public class VersionManager extends Manager { * @throws NotConnectedException */ public void processPacket(Packet packet) throws NotConnectedException { - if (own_version == null) + if (ourVersion == null) return; - Version reply = new Version(own_version); - reply.setPacketID(packet.getPacketID()); - reply.setTo(packet.getFrom()); - connection().sendPacket(reply); + connection().sendPacket(Version.createResultFor(packet, ourVersion)); } } , PACKET_FILTER); @@ -90,7 +112,49 @@ public class VersionManager extends Manager { return versionManager; } - public void setVersion(Version v) { - own_version = v; + public static void setAutoAppendSmackVersion(boolean autoAppendSmackVersion) { + VersionManager.autoAppendSmackVersion = autoAppendSmackVersion; + } + + public void setVersion(String name, String version) { + setVersion(name, version, null); + } + + public void setVersion(String name, String version, String os) { + ourVersion = generateVersionFrom(name, version, os); + } + + public void unsetVersion() { + ourVersion = null; + } + + public boolean isSupported(String jid) throws NoResponseException, XMPPErrorException, + NotConnectedException { + return ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(jid, + Version.NAMESPACE); + } + + /** + * Request version information from a given JID. + * + * @param jid + * @return the version information or {@code null} if not supported by JID + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + */ + public Version getVersion(String jid) throws NoResponseException, XMPPErrorException, + NotConnectedException { + if (!isSupported(jid)) { + return null; + } + return connection().createPacketCollectorAndSend(new Version(jid)).nextResultOrThrow(); + } + + private static Version generateVersionFrom(String name, String version, String os) { + if (autoAppendSmackVersion) { + name += " (Smack " + SmackConfiguration.getVersion() + ')'; + } + return new Version(name, version, os); } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/packet/Version.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/packet/Version.java index 6267ca761..5d1627cc4 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/packet/Version.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/packet/Version.java @@ -19,7 +19,8 @@ package org.jivesoftware.smackx.iqversion.packet; import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smack.packet.Packet; +import org.jivesoftware.smack.util.XmlStringBuilder; /** * A Version IQ packet, which is used by XMPP clients to discover version information @@ -50,10 +51,30 @@ import org.jivesoftware.smack.util.StringUtils; public class Version extends IQ { public static final String NAMESPACE = "jabber:iq:version"; - private String name; - private String version; + private final String name; + private final String version; private String os; + public Version() { + name = null; + version = null; + setType(Type.get); + } + + /** + * Request version IQ + * + * @param to the jid where to request version from + */ + public Version(String to) { + this(); + setTo(to); + } + + public Version(String name, String version) { + this(name, version, null); + } + /** * Creates a new Version object with given details. * @@ -62,6 +83,13 @@ public class Version extends IQ { * @param os The operating system of the queried entity. This element is OPTIONAL. */ public Version(String name, String version, String os) { + if (name == null) + { + throw new IllegalArgumentException("name must not be null"); + } + if (version == null) { + throw new IllegalArgumentException("version must not be null"); + } this.setType(IQ.Type.result); this.name = name; this.version = version; @@ -82,16 +110,6 @@ public class Version extends IQ { return name; } - /** - * Sets the natural-language name of the software. This message should only be - * invoked when parsing the XML and setting the property to a Version instance. - * - * @param name the natural-language name of the software. - */ - public void setName(String name) { - this.name = name; - } - /** * Returns the specific version of the software. This property will always be * present in a result. @@ -102,16 +120,6 @@ public class Version extends IQ { return version; } - /** - * Sets the specific version of the software. This message should only be - * invoked when parsing the XML and setting the property to a Version instance. - * - * @param version the specific version of the software. - */ - public void setVersion(String version) { - this.version = version; - } - /** * Returns the operating system of the queried entity. This property will always be * present in a result. @@ -132,21 +140,23 @@ public class Version extends IQ { this.os = os; } - public String getChildElementXML() { - StringBuilder buf = new StringBuilder(); - buf.append(""); - if (name != null) { - buf.append("").append(StringUtils.escapeForXML(name)).append(""); - } - if (version != null) { - buf.append("").append(StringUtils.escapeForXML(version)).append(""); - } - if (os != null) { - buf.append("").append(StringUtils.escapeForXML(os)).append(""); - } - buf.append(""); - return buf.toString(); + @Override + public XmlStringBuilder getChildElementXML() { + XmlStringBuilder xml = new XmlStringBuilder(); + xml.halfOpenElement(IQ.QUERY_ELEMENT).xmlnsAttribute(NAMESPACE).rightAngelBracket(); + // Although not really optional elements, 'name' and 'version' are not set when sending a + // version request. So we must handle the case that those are 'null' here. + xml.optElement("name", name); + xml.optElement("version", version); + xml.optElement("os", os); + xml.closeElement(IQ.QUERY_ELEMENT); + return xml; + } + + public static Version createResultFor(Packet request, Version version) { + Version result = new Version(version); + result.setPacketID(request.getPacketID()); + result.setTo(request.getFrom()); + return result; } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/provider/VersionProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/provider/VersionProvider.java index 8db31bb8c..350dcb24c 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/provider/VersionProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/provider/VersionProvider.java @@ -24,26 +24,36 @@ import org.xmlpull.v1.XmlPullParser; public class VersionProvider implements IQProvider { public IQ parseIQ(XmlPullParser parser) throws Exception { + assert (parser.getEventType() == XmlPullParser.START_TAG); + final int initalDepth = parser.getDepth(); String name = null, version = null, os = null; - boolean done = false; - while (!done) { + outerloop: while (true) { int eventType = parser.next(); - String tagName = parser.getName(); - if (eventType == XmlPullParser.START_TAG) { - if (tagName.equals("name")) { + switch (eventType) { + case XmlPullParser.START_TAG: + String tagName = parser.getName(); + switch (tagName) { + case "name": name = parser.nextText(); - } - else if (tagName.equals("version")) { + break; + case "version": version = parser.nextText(); - } - else if (tagName.equals("os")) { + break; + case "os": os = parser.nextText(); + break; + } + break; + case XmlPullParser.END_TAG: + if (parser.getDepth() == initalDepth && parser.getName().equals(IQ.QUERY_ELEMENT)) { + break outerloop; } - } else if (eventType == XmlPullParser.END_TAG && tagName.equals("query")) { - done = true; } } + if (name == null && version == null && os == null) { + return new Version(); + } return new Version(name, version, os); } } diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/iqversion/VersionTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/iqversion/VersionTest.java index ad6e4c679..cec0a5bcb 100644 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/iqversion/VersionTest.java +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/iqversion/VersionTest.java @@ -37,7 +37,8 @@ public class VersionTest { DummyConnection con = new DummyConnection(); // Enable version replys for this connection - VersionManager.getInstanceFor(con).setVersion(new Version("Test", "0.23", "DummyOS")); + VersionManager.setAutoAppendSmackVersion(false); + VersionManager.getInstanceFor(con).setVersion("Test", "0.23", "DummyOS"); IQ versionRequest = (IQ) PacketParserUtils.parseStanza(control); assertTrue(versionRequest instanceof Version);