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'
sourceCompatibility = 1.7
targetCompatibility = sourceCompatibility
version = shortVersion
if (isSnapshot) {
version += '-SNAPSHOT'
@ -97,7 +98,7 @@ import org.apache.tools.ant.filters.ReplaceTokens
task prepareReleasedocs(type: Copy) {
from 'resources/releasedocs'
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]) {

View File

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

View File

@ -154,18 +154,27 @@ hr {
</table>
<p>
Thank you for downloading Smack!
<p>
Thank you for downloading Smack! This version of Smack is compatible
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>
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">
Smack website</a>. If you need help using or would like to make contributions or
fixes to the code, please visit the
<a href="https://community.igniterealtime.org">online forum</a>.
<p><b>About the Distribution</b><p>
</p>
<p><b>About the Distribution</b></p>
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>

View File

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

View File

@ -20,6 +20,7 @@ package org.jivesoftware.smack;
import org.jivesoftware.smack.packet.Session;
import org.jivesoftware.smack.proxy.ProxyInfo;
import org.jivesoftware.smack.util.DNSUtil;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.dns.HostAddress;
import org.jxmpp.util.XmppStringUtils;
@ -191,6 +192,9 @@ public class ConnectionConfiguration implements Cloneable {
}
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.proxy = proxy;
@ -645,6 +649,9 @@ public class ConnectionConfiguration implements Cloneable {
}
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);
HostAddress hostAddress;
hostAddress = new HostAddress(host, port);

View File

@ -48,6 +48,9 @@ public class Java7ZlibInputOutputStream extends XMPPInputOutputStream {
private final static boolean supported;
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 {
Method m = null;
try {
@ -100,25 +103,23 @@ public class Java7ZlibInputOutputStream extends XMPPInputOutputStream {
@Override
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)) {
public void flush() throws IOException {
if (!supported) {
super.flush();
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 {
do {
count = (Integer) method.invoke(def, buf, 0, buf.length, 2);
int count;
while ((count = (Integer) method.invoke(def, buf, 0, buf.length, flushMethodInt)) != 0) {
out.write(buf, 0, count);
} while (count > 0);
}
} catch (IllegalArgumentException e) {
throw new IOException("Can't flush");
} catch (IllegalAccessException e) {

View File

@ -20,6 +20,21 @@ import java.io.InputStream;
import java.io.OutputStream;
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;
public String getCompressionMethod() {
@ -31,4 +46,9 @@ public abstract class XMPPInputOutputStream {
public abstract InputStream getInputStream(InputStream inputStream) 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
* @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) {
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) {

View File

@ -73,7 +73,12 @@ public class Socks5Proxy {
private static Socks5Proxy socks5Server;
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 */
private Socks5ServerProcess serverProcess;
@ -142,6 +147,9 @@ public class Socks5Proxy {
* @param localSocks5ProxyPort the port of the local Socks5 proxy to set
*/
public static void setLocalSocks5ProxyPort(int localSocks5ProxyPort) {
if (Math.abs(localSocks5ProxyPort) > 65535) {
throw new IllegalArgumentException("localSocks5ProxyPort must be within (-65535,65535)");
}
Socks5Proxy.localSocks5ProxyPort = localSocks5ProxyPort;
}

View File

@ -154,20 +154,24 @@ public class OfflineMessageManager {
}
});
PacketCollector messageCollector = connection.createPacketCollector(messageFilter);
connection.createPacketCollectorAndSend(request).nextResultOrThrow();
// Collect the received offline messages
Message message = (Message) messageCollector.nextResult();
while (message != null) {
messages.add(message);
message = (Message) messageCollector.nextResult();
try {
connection.createPacketCollectorAndSend(request).nextResultOrThrow();
// Collect the received offline messages
Message message = (Message) messageCollector.nextResult();
while (message != null) {
messages.add(message);
message = (Message) messageCollector.nextResult();
}
}
finally {
// Stop queuing offline messages
messageCollector.cancel();
}
// Stop queuing offline messages
messageCollector.cancel();
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)}
* to delete the messages.
*
@ -181,17 +185,23 @@ public class OfflineMessageManager {
List<Message> messages = new ArrayList<Message>();
OfflineMessageRequest request = new OfflineMessageRequest();
request.setFetch(true);
connection.createPacketCollectorAndSend(request).nextResultOrThrow();
PacketCollector messageCollector = connection.createPacketCollector(PACKET_FILTER);
// Collect the received offline messages
Message message = (Message) messageCollector.nextResult();
while (message != null) {
messages.add(message);
message = (Message) messageCollector.nextResult();
PacketCollector resultCollector = connection.createPacketCollectorAndSend(request);
try {
// Collect the received offline messages
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;
}

View File

@ -577,12 +577,23 @@ public class ConfigureForm extends Form
* Determines if subscriptions are allowed.
*
* @return true if subscriptions are allowed, false otherwise
* @deprecated use {@link #isSubscribe()} instead
*/
@Deprecated
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.
*

View File

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