1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2024-11-22 20:12:07 +01:00

Merge branch '4.0'

Also slightly improve OfflineMessageManager.getMessages()

Conflicts:
	build.gradle
	smack-extensions/src/main/java/org/jivesoftware/smackx/offline/OfflineMessageManager.java
This commit is contained in:
Florian Schmaus 2014-08-07 16:51:03 +02:00
commit 92a6d01507
12 changed files with 123 additions and 46 deletions

View file

@ -26,6 +26,7 @@ allprojects {
} }
group = 'org.igniterealtime.smack' group = 'org.igniterealtime.smack'
sourceCompatibility = 1.7 sourceCompatibility = 1.7
targetCompatibility = sourceCompatibility
version = shortVersion version = shortVersion
if (isSnapshot) { if (isSnapshot) {
version += '-SNAPSHOT' version += '-SNAPSHOT'
@ -97,7 +98,7 @@ import org.apache.tools.ant.filters.ReplaceTokens
task prepareReleasedocs(type: Copy) { task prepareReleasedocs(type: Copy) {
from 'resources/releasedocs' from 'resources/releasedocs'
into releasedocsDir into releasedocsDir
filter(ReplaceTokens, tokens: [version: version, releasedate: buildDate]) filter(ReplaceTokens, tokens: [version: version, releasedate: buildDate, targetCompatibility: targetCompatibility.toString()])
} }
task distributionZip(type: Zip, dependsOn: [javadocAll, prepareReleasedocs]) { task distributionZip(type: Zip, dependsOn: [javadocAll, prepareReleasedocs]) {

View file

@ -23,10 +23,8 @@ important classes and concepts.
JAR Files and Requirements JAR Files and Requirements
</p> </p>
Smack is meant to be easily embedded into any existing JDK 1.5 or later Java application. Smack is meant to be easily embedded into any existing Java application.
It has no external dependencies (except for the Jingle voice chat functionality) and is optimized The library ships as several JAR files to provide more flexibility over which features applications require:
to be as small as possible. The library ships as several JAR files to provide more flexibility
over which features applications require:
<ul> <ul>
<li><tt>smack-core.jar</tt> -- provides core XMPP functionality. All XMPP features that are <li><tt>smack-core.jar</tt> -- provides core XMPP functionality. All XMPP features that are

View file

@ -154,18 +154,27 @@ hr {
</table> </table>
<p> <p>
Thank you for downloading Smack! Thank you for downloading Smack! This version of Smack is compatible
<p> with JVMs @targetCompatibility@ or higher. If you dont' use a
dependency resolution system, like gradle or maven, then you will need
to download at least
the <a href="http://www.extreme.indiana.edu/xgws/xsoap/xpp/mxp1/">Xml
Pull Parser 3rd Edition (XPP3) library</a> or any other library that
implements the XmlPullParser interface
(like <a href="http://kxml.org/">kXML</a>).
</p>
<p>
Start off by viewing the <a href="documentation/index.html">documentation</a> Start off by viewing the <a href="documentation/index.html">documentation</a>
that can be found in the "documentation" directory included with this distribution. that can be found in the "documentation" directory included with this distribution.
<p> </p>
Further information can be found on the <a href="http://www.igniterealtime.org/projects/smack"> Further information can be found on the <a href="http://www.igniterealtime.org/projects/smack">
Smack website</a>. If you need help using or would like to make contributions or Smack website</a>. If you need help using or would like to make contributions or
fixes to the code, please visit the fixes to the code, please visit the
<a href="https://community.igniterealtime.org">online forum</a>. <a href="https://community.igniterealtime.org">online forum</a>.
</p>
<p><b>About the Distribution</b><p> <p><b>About the Distribution</b></p>
The <tt>smack-core.jar</tt> file in the main distribution folder. The optional The <tt>smack-core.jar</tt> file in the main distribution folder. The optional
<tt>smack-extensions.jar</tt> contains the <a href="documentation/extensions/index.html">Smack extensions</a> <tt>smack-extensions.jar</tt> contains the <a href="documentation/extensions/index.html">Smack extensions</a>

View file

@ -58,7 +58,9 @@ public class JzlibInputOutputStream extends XMPPInputOutputStream {
@Override @Override
public OutputStream getOutputStream(OutputStream outputStream) throws IOException { public OutputStream getOutputStream(OutputStream outputStream) throws IOException {
final DeflaterOutputStream os = new DeflaterOutputStream(outputStream); final DeflaterOutputStream os = new DeflaterOutputStream(outputStream);
os.setSyncFlush(true); if (flushMethod == FlushMethod.SYNC_FLUSH) {
os.setSyncFlush(true);
}
return os; return os;
} }

View file

@ -20,6 +20,7 @@ package org.jivesoftware.smack;
import org.jivesoftware.smack.packet.Session; import org.jivesoftware.smack.packet.Session;
import org.jivesoftware.smack.proxy.ProxyInfo; import org.jivesoftware.smack.proxy.ProxyInfo;
import org.jivesoftware.smack.util.DNSUtil; import org.jivesoftware.smack.util.DNSUtil;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.dns.HostAddress; import org.jivesoftware.smack.util.dns.HostAddress;
import org.jxmpp.util.XmppStringUtils; import org.jxmpp.util.XmppStringUtils;
@ -191,6 +192,9 @@ public class ConnectionConfiguration implements Cloneable {
} }
protected void init(String serviceName, ProxyInfo proxy) { protected void init(String serviceName, ProxyInfo proxy) {
if (StringUtils.isEmpty(serviceName)) {
throw new IllegalArgumentException("serviceName must not be the empty String");
}
this.serviceName = serviceName; this.serviceName = serviceName;
this.proxy = proxy; this.proxy = proxy;
@ -645,6 +649,9 @@ public class ConnectionConfiguration implements Cloneable {
} }
private void initHostAddresses(String host, int port) { private void initHostAddresses(String host, int port) {
if (StringUtils.isEmpty(host)) {
throw new IllegalArgumentException("host must not be the empty String");
}
hostAddresses = new ArrayList<HostAddress>(1); hostAddresses = new ArrayList<HostAddress>(1);
HostAddress hostAddress; HostAddress hostAddress;
hostAddress = new HostAddress(host, port); hostAddress = new HostAddress(host, port);

View file

@ -48,6 +48,9 @@ public class Java7ZlibInputOutputStream extends XMPPInputOutputStream {
private final static boolean supported; private final static boolean supported;
private final static int compressionLevel = Deflater.DEFAULT_COMPRESSION; private final static int compressionLevel = Deflater.DEFAULT_COMPRESSION;
private static final int SYNC_FLUSH_INT = 2;
private static final int FULL_FLUSH_INT = 3;
static { static {
Method m = null; Method m = null;
try { try {
@ -100,25 +103,23 @@ public class Java7ZlibInputOutputStream extends XMPPInputOutputStream {
@Override @Override
public OutputStream getOutputStream(OutputStream outputStream) { public OutputStream getOutputStream(OutputStream outputStream) {
final int flushMethodInt;
if (flushMethod == FlushMethod.SYNC_FLUSH) {
flushMethodInt = SYNC_FLUSH_INT;
} else {
flushMethodInt = FULL_FLUSH_INT;
}
return new DeflaterOutputStream(outputStream, new Deflater(compressionLevel)) { return new DeflaterOutputStream(outputStream, new Deflater(compressionLevel)) {
public void flush() throws IOException { public void flush() throws IOException {
if (!supported) { if (!supported) {
super.flush(); super.flush();
return; return;
} }
int count = 0;
if (!def.needsInput()) {
do {
count = def.deflate(buf, 0, buf.length);
out.write(buf, 0, count);
} while (count > 0);
out.flush();
}
try { try {
do { int count;
count = (Integer) method.invoke(def, buf, 0, buf.length, 2); while ((count = (Integer) method.invoke(def, buf, 0, buf.length, flushMethodInt)) != 0) {
out.write(buf, 0, count); out.write(buf, 0, count);
} while (count > 0); }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw new IOException("Can't flush"); throw new IOException("Can't flush");
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {

View file

@ -20,6 +20,21 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
public abstract class XMPPInputOutputStream { public abstract class XMPPInputOutputStream {
protected static FlushMethod flushMethod;
/**
* Set the used flushed method when compressing data. The default is full flush which may not
* achieve the best compression ratio, but provides better security against certain attacks.
* Only use sync flush if you fully understand the implications.
*
* @see <a href="https://blog.thijsalkema.de/blog/2014/08/07/https-attacks-and-xmpp-2-crime-and-breach/">Attacks against XMPP when using compression</a>
* @param flushMethod
*/
public static void setFlushMethod(FlushMethod flushMethod) {
XMPPInputOutputStream.flushMethod = flushMethod;
}
protected String compressionMethod; protected String compressionMethod;
public String getCompressionMethod() { public String getCompressionMethod() {
@ -31,4 +46,9 @@ public abstract class XMPPInputOutputStream {
public abstract InputStream getInputStream(InputStream inputStream) throws Exception; public abstract InputStream getInputStream(InputStream inputStream) throws Exception;
public abstract OutputStream getOutputStream(OutputStream outputStream) throws Exception; public abstract OutputStream getOutputStream(OutputStream outputStream) throws Exception;
public enum FlushMethod {
FULL_FLUSH,
SYNC_FLUSH,
}
} }

View file

@ -279,13 +279,23 @@ public class StringUtils {
} }
/** /**
* Returns true if the given CharSequence is not null or empty. * Returns true if the given CharSequence is null or empty.
* *
* @param cs * @param cs
* @return true if the given CharSequence is not null or empty * @return true if the given CharSequence is null or empty
*/ */
public static boolean isNullOrEmpty(CharSequence cs) { public static boolean isNullOrEmpty(CharSequence cs) {
return cs == null || cs.length() == 0; return cs == null || isEmpty(cs);
}
/**
* Returns true if the given CharSequence is empty
*
* @param cs
* @return true if the given CharSequence is empty
*/
public static boolean isEmpty(CharSequence cs) {
return cs.length() == 0;
} }
public static String collectionToString(Collection<String> collection) { public static String collectionToString(Collection<String> collection) {

View file

@ -73,7 +73,12 @@ public class Socks5Proxy {
private static Socks5Proxy socks5Server; private static Socks5Proxy socks5Server;
private static boolean localSocks5ProxyEnabled = true; private static boolean localSocks5ProxyEnabled = true;
private static int localSocks5ProxyPort = 7777;
/**
* The port of the local Socks5 Proxy. If this value is negative, the next ports will be tried
* until a unused is found.
*/
private static int localSocks5ProxyPort = -7777;
/* reusable implementation of a SOCKS5 proxy server process */ /* reusable implementation of a SOCKS5 proxy server process */
private Socks5ServerProcess serverProcess; private Socks5ServerProcess serverProcess;
@ -142,6 +147,9 @@ public class Socks5Proxy {
* @param localSocks5ProxyPort the port of the local Socks5 proxy to set * @param localSocks5ProxyPort the port of the local Socks5 proxy to set
*/ */
public static void setLocalSocks5ProxyPort(int localSocks5ProxyPort) { public static void setLocalSocks5ProxyPort(int localSocks5ProxyPort) {
if (Math.abs(localSocks5ProxyPort) > 65535) {
throw new IllegalArgumentException("localSocks5ProxyPort must be within (-65535,65535)");
}
Socks5Proxy.localSocks5ProxyPort = localSocks5ProxyPort; Socks5Proxy.localSocks5ProxyPort = localSocks5ProxyPort;
} }

View file

@ -154,20 +154,24 @@ public class OfflineMessageManager {
} }
}); });
PacketCollector messageCollector = connection.createPacketCollector(messageFilter); PacketCollector messageCollector = connection.createPacketCollector(messageFilter);
connection.createPacketCollectorAndSend(request).nextResultOrThrow(); try {
// Collect the received offline messages connection.createPacketCollectorAndSend(request).nextResultOrThrow();
Message message = (Message) messageCollector.nextResult(); // Collect the received offline messages
while (message != null) { Message message = (Message) messageCollector.nextResult();
messages.add(message); while (message != null) {
message = (Message) messageCollector.nextResult(); messages.add(message);
message = (Message) messageCollector.nextResult();
}
}
finally {
// Stop queuing offline messages
messageCollector.cancel();
} }
// Stop queuing offline messages
messageCollector.cancel();
return messages; return messages;
} }
/** /**
* Returns an Iterator with all the offline <tt>Messages</tt> of the user. The returned offline * Returns a List of Messages with all the offline <tt>Messages</tt> of the user. The returned offline
* messages will not be deleted from the server. Use {@link #deleteMessages(java.util.List)} * messages will not be deleted from the server. Use {@link #deleteMessages(java.util.List)}
* to delete the messages. * to delete the messages.
* *
@ -181,17 +185,23 @@ public class OfflineMessageManager {
List<Message> messages = new ArrayList<Message>(); List<Message> messages = new ArrayList<Message>();
OfflineMessageRequest request = new OfflineMessageRequest(); OfflineMessageRequest request = new OfflineMessageRequest();
request.setFetch(true); request.setFetch(true);
connection.createPacketCollectorAndSend(request).nextResultOrThrow();
PacketCollector messageCollector = connection.createPacketCollector(PACKET_FILTER); PacketCollector messageCollector = connection.createPacketCollector(PACKET_FILTER);
// Collect the received offline messages PacketCollector resultCollector = connection.createPacketCollectorAndSend(request);
Message message = (Message) messageCollector.nextResult();
while (message != null) { try {
messages.add(message); // Collect the received offline messages
message = (Message) messageCollector.nextResult(); Message message = (Message) messageCollector.nextResult();
while (message != null) {
messages.add(message);
message = (Message) messageCollector.nextResult();
}
resultCollector.nextResultOrThrow();
}
finally {
messageCollector.cancel();
resultCollector.cancel();
} }
// Stop queuing offline messages
messageCollector.cancel();
return messages; return messages;
} }

View file

@ -577,12 +577,23 @@ public class ConfigureForm extends Form
* Determines if subscriptions are allowed. * Determines if subscriptions are allowed.
* *
* @return true if subscriptions are allowed, false otherwise * @return true if subscriptions are allowed, false otherwise
* @deprecated use {@link #isSubscribe()} instead
*/ */
@Deprecated
public boolean isSubscibe() public boolean isSubscibe()
{ {
return parseBoolean(getFieldValue(ConfigureNodeFields.subscribe)); return isSubscribe();
} }
/**
* Determines if subscriptions are allowed.
*
* @return true if subscriptions are allowed, false otherwise
*/
public boolean isSubscribe() {
return parseBoolean(getFieldValue(ConfigureNodeFields.subscribe));
}
/** /**
* Sets whether subscriptions are allowed. * Sets whether subscriptions are allowed.
* *

View file

@ -313,7 +313,7 @@ public class FormField {
*/ */
public static class Option { public static class Option {
public static final String ELEMNT = "option"; public static final String ELEMENT = "option";
private final String value; private final String value;
private String label; private String label;
@ -352,7 +352,7 @@ public class FormField {
public XmlStringBuilder toXML() { public XmlStringBuilder toXML() {
XmlStringBuilder xml = new XmlStringBuilder(); XmlStringBuilder xml = new XmlStringBuilder();
xml.halfOpenElement(ELEMNT); xml.halfOpenElement(ELEMENT);
// Add attribute // Add attribute
xml.optAttribute("label", getLabel()); xml.optAttribute("label", getLabel());
xml.rightAngelBracket(); xml.rightAngelBracket();