diff --git a/resources/releasedocs/changelog.html b/resources/releasedocs/changelog.html index 7ffbe2f85..7e189a858 100644 --- a/resources/releasedocs/changelog.html +++ b/resources/releasedocs/changelog.html @@ -141,6 +141,25 @@ hr {
+

4.1.6 -- 2016-01-23

+ +

Bug +

+ +

4.1.5 -- 2015-11-22

Bug diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java index fd1b64996..54f9dacfa 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java @@ -387,7 +387,7 @@ public final class Socks5Proxy { try { - if (Socks5Proxy.this.serverSocket.isClosed() + if (Socks5Proxy.this.serverSocket == null || Socks5Proxy.this.serverSocket.isClosed() || Thread.currentThread().isInterrupted()) { return; } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceipt.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceipt.java index 87169dbe0..4b8dee7f2 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceipt.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceipt.java @@ -1,6 +1,6 @@ /** * - * Copyright 2013-2014 the original author or authors + * Copyright 2013-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import java.util.Map; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.provider.EmbeddedExtensionProvider; +import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.XmlStringBuilder; /** @@ -42,7 +43,7 @@ public class DeliveryReceipt implements ExtensionElement public DeliveryReceipt(String id) { - this.id = id; + this.id = StringUtils.requireNotNullOrEmpty(id, "id must not be null"); } public String getId() diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceiptManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceiptManager.java index d65258dd9..a6ff3680d 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceiptManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceiptManager.java @@ -20,6 +20,7 @@ import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.CopyOnWriteArraySet; +import java.util.logging.Logger; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException.NotConnectedException; @@ -31,6 +32,7 @@ import org.jivesoftware.smack.XMPPConnectionRegistry; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.MessageTypeFilter; +import org.jivesoftware.smack.filter.MessageWithBodiesFilter; import org.jivesoftware.smack.filter.NotFilter; import org.jivesoftware.smack.filter.StanzaFilter; import org.jivesoftware.smack.filter.StanzaExtensionFilter; @@ -38,6 +40,7 @@ import org.jivesoftware.smack.filter.StanzaTypeFilter; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.roster.Roster; +import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jxmpp.jid.Jid; @@ -74,6 +77,8 @@ public final class DeliveryReceiptManager extends Manager { private static final StanzaFilter MESSAGES_WITH_DELIVERY_RECEIPT = new AndFilter(StanzaTypeFilter.MESSAGE, new StanzaExtensionFilter(DeliveryReceipt.ELEMENT, DeliveryReceipt.NAMESPACE)); + private static final Logger LOGGER = Logger.getLogger(DeliveryReceiptManager.class.getName()); + private static Map instances = new WeakHashMap(); static { @@ -160,6 +165,11 @@ public final class DeliveryReceiptManager extends Manager { final Message messageWithReceiptRequest = (Message) packet; Message ack = receiptMessageFor(messageWithReceiptRequest); + if (ack == null) { + LOGGER.warning("Received message stanza with receipt request from '" + from + + "' without a stanza ID set. Message: " + messageWithReceiptRequest); + return; + } connection.sendStanza(ack); } }, MESSAGES_WITH_DEVLIERY_RECEIPT_REQUEST); @@ -237,13 +247,17 @@ public final class DeliveryReceiptManager extends Manager { /** * A filter for stanzas to request delivery receipts for. Notably those are message stanzas of type normal, chat or - * headline, which do notcontain a delivery receipt, i.e. are ack messages. + * headline, which do notcontain a delivery receipt, i.e. are ack messages, and have a body extension. * * @see XEP-184 § 5.4 Ack Messages */ private static final StanzaFilter MESSAGES_TO_REQUEST_RECEIPTS_FOR = new AndFilter( - MessageTypeFilter.NORMAL_OR_CHAT_OR_HEADLINE, new NotFilter(new StanzaExtensionFilter( - DeliveryReceipt.ELEMENT, DeliveryReceipt.NAMESPACE))); + // @formatter:off + MessageTypeFilter.NORMAL_OR_CHAT_OR_HEADLINE, + new NotFilter(new StanzaExtensionFilter(DeliveryReceipt.ELEMENT, DeliveryReceipt.NAMESPACE)), + MessageWithBodiesFilter.INSTANCE + ); + // @formatter:on private static final StanzaListener AUTO_ADD_DELIVERY_RECEIPT_REQUESTS_LISTENER = new StanzaListener() { @Override @@ -254,7 +268,9 @@ public final class DeliveryReceiptManager extends Manager { }; /** - * Enables automatic requests of delivery receipts for outgoing messages of type 'normal', 'chat' or 'headline. + * Enables automatic requests of delivery receipts for outgoing messages of + * {@link Message.Type#normal}, {@link Message.Type#chat} or {@link Message.Type#headline}, and + * with a {@link Message.Body} extension. * * @since 4.1 * @see #dontAutoAddDeliveryReceiptRequests() @@ -302,14 +318,21 @@ public final class DeliveryReceiptManager extends Manager { /** * Create and return a new message including a delivery receipt extension for the given message. + *

+ * If {@code messageWithReceiptRequest} does not have a Stanza ID set, then {@code null} will be returned. + *

* * @param messageWithReceiptRequest the given message with a receipt request extension. - * @return a new message with a receipt. + * @return a new message with a receipt or null. * @since 4.1 */ public static Message receiptMessageFor(Message messageWithReceiptRequest) { + String stanzaId = messageWithReceiptRequest.getStanzaId(); + if (StringUtils.isNullOrEmpty(stanzaId)) { + return null; + } Message message = new Message(messageWithReceiptRequest.getFrom(), messageWithReceiptRequest.getType()); - message.addExtension(new DeliveryReceipt(messageWithReceiptRequest.getStanzaId())); + message.addExtension(new DeliveryReceipt(stanzaId)); return message; } } diff --git a/smack-sasl-provided/src/main/java/org/jivesoftware/smack/sasl/provided/SASLDigestMD5Mechanism.java b/smack-sasl-provided/src/main/java/org/jivesoftware/smack/sasl/provided/SASLDigestMD5Mechanism.java index e72ba840e..47d0513a0 100644 --- a/smack-sasl-provided/src/main/java/org/jivesoftware/smack/sasl/provided/SASLDigestMD5Mechanism.java +++ b/smack-sasl-provided/src/main/java/org/jivesoftware/smack/sasl/provided/SASLDigestMD5Mechanism.java @@ -152,7 +152,7 @@ public class SASLDigestMD5Mechanism extends SASLMechanism { } else { authzid = ",authzid=\"" + authorizationId + '"'; } - String saslString = "username=\"" + authenticationId + '"' + String saslString = "username=\"" + quoteBackslash(authenticationId) + '"' + authzid + ",realm=\"" + serviceName + '"' + ",nonce=\"" + nonce + '"' @@ -228,4 +228,18 @@ public class SASLDigestMD5Mechanism extends SASLMechanism { return responseValue; } + /** + * Quote the backslash in the given String. Replaces all occurrences of "\" with "\\". + *

+ * According to RFC 2831 § 7.2 a quoted-string consists either of qdtext or quoted-pair. And since quoted-pair is a + * backslash followed by a char, every backslash in qdtext must be quoted, since it otherwise would be treated as + * qdtext. + *

+ * + * @param string the input string. + * @return the input string where the every backslash is quoted. + */ + public static String quoteBackslash(String string) { + return string.replace("\\", "\\\\"); + } } diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java index d8472011a..4883dcf64 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java @@ -396,8 +396,6 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { LOGGER.fine("Stream resumption failed, continuing with normal stream establishment process"); } - bindResourceAndEstablishSession(resource); - List previouslyUnackedStanzas = new LinkedList(); if (unacknowledgedStanzas != null) { // There was a previous connection with SM enabled but that was either not resumable or @@ -410,6 +408,12 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { // after the 'enable' stream element has been sent. dropSmState(); } + + // Now bind the resource. It is important to do this *after* we dropped an eventually + // existing Stream Management state. As otherwise and may end up in + // unacknowledgedStanzas and become duplicated on reconnect. See SMACK-706. + bindResourceAndEstablishSession(resource); + if (isSmAvailable() && useSm) { // Remove what is maybe left from previously stream managed sessions serverHandledStanzasCount = 0;