mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-25 15:52:06 +01:00
Merge branch '4.2'
This commit is contained in:
commit
384c285fbc
20 changed files with 303 additions and 79 deletions
|
@ -396,6 +396,12 @@ subprojects {
|
|||
}
|
||||
|
||||
clirr {
|
||||
// 2018-08-14: Disabled Clirr because
|
||||
// - It reports an breaking change in android.jar (seems right, but there is nothing we can do about it)
|
||||
// - Only the first smack-* projects are correctly checked,
|
||||
// the other ones have the output of a clirr report from a previous project
|
||||
// (Look at the clirr reports).
|
||||
enabled false
|
||||
semver false
|
||||
}
|
||||
}
|
||||
|
|
18
repl
18
repl
|
@ -3,15 +3,29 @@ set -e
|
|||
set -u
|
||||
set -o pipefail
|
||||
|
||||
JDWP=false
|
||||
JDWP_PORT=8000
|
||||
|
||||
while getopts d OPTION "$@"; do
|
||||
while getopts djp: OPTION "$@"; do
|
||||
case $OPTION in
|
||||
d)
|
||||
set -x
|
||||
;;
|
||||
j)
|
||||
JDWP=true
|
||||
;;
|
||||
p)
|
||||
JDWP_PORT=$OPTARG
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
EXTRA_JAVA_ARGS=()
|
||||
if $JDWP; then
|
||||
EXTRA_JAVA_ARGS+=("-Xdebug")
|
||||
EXTRA_JAVA_ARGS+=("-Xrunjdwp:server=y,transport=dt_socket,address=${JDWP_PORT},suspend=n")
|
||||
fi
|
||||
|
||||
PROJECT_ROOT=$(dirname "${BASH_SOURCE[0]}")
|
||||
cd "${PROJECT_ROOT}"
|
||||
|
||||
|
@ -27,7 +41,7 @@ GRADLE_CLASSPATH="$(gradle :smack-repl:printClasspath --quiet |\
|
|||
tail -n1)"
|
||||
echo "Finished, starting REPL"
|
||||
|
||||
java \
|
||||
java "${EXTRA_JAVA_ARGS[@]}" \
|
||||
-Dscala.usejavacp=true \
|
||||
-classpath "${GRADLE_CLASSPATH}" \
|
||||
ammonite.Main \
|
||||
|
|
|
@ -43,7 +43,10 @@ import org.jivesoftware.smack.util.Async;
|
|||
* </ol>
|
||||
*
|
||||
* {@link ReconnectionPolicy#FIXED_DELAY} - The reconnection mechanism will try to reconnect after a fixed delay
|
||||
* independently from the number of reconnection attempts already performed
|
||||
* independently from the number of reconnection attempts already performed.
|
||||
* <p>
|
||||
* Interrupting the reconnection thread will abort the reconnection mechanism.
|
||||
* </p>
|
||||
*
|
||||
* @author Francisco Vives
|
||||
* @author Luca Stucchi
|
||||
|
@ -163,7 +166,7 @@ public final class ReconnectionManager {
|
|||
private ReconnectionManager(AbstractXMPPConnection connection) {
|
||||
weakRefConnection = new WeakReference<AbstractXMPPConnection>(connection);
|
||||
|
||||
reconnectionRunnable = new Thread() {
|
||||
reconnectionRunnable = new Runnable() {
|
||||
|
||||
/**
|
||||
* Holds the current number of reconnection attempts
|
||||
|
@ -211,6 +214,10 @@ public final class ReconnectionManager {
|
|||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset attempts to zero since a new reconnection cycle is started once this runs.
|
||||
attempts = 0;
|
||||
|
||||
// The process will try to reconnect until the connection is established or
|
||||
// the user cancel the reconnection process AbstractXMPPConnection.disconnect().
|
||||
while (isReconnectionPossible(connection)) {
|
||||
|
@ -219,7 +226,10 @@ public final class ReconnectionManager {
|
|||
// Sleep until we're ready for the next reconnection attempt. Notify
|
||||
// listeners once per second about how much time remains before the next
|
||||
// reconnection attempt.
|
||||
while (isReconnectionPossible(connection) && remainingSeconds > 0) {
|
||||
while (remainingSeconds > 0) {
|
||||
if (!isReconnectionPossible(connection)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
remainingSeconds--;
|
||||
|
@ -228,8 +238,9 @@ public final class ReconnectionManager {
|
|||
}
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOGGER.log(Level.FINE, "waiting for reconnection interrupted", e);
|
||||
break;
|
||||
LOGGER.log(Level.FINE, "Reconnection Thread was interrupted, aborting reconnection mechanism", e);
|
||||
// Exit the reconnection thread in case it was interrupted.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,37 +248,40 @@ public final class ReconnectionManager {
|
|||
listener.reconnectingIn(0);
|
||||
}
|
||||
|
||||
if (!isReconnectionPossible(connection)) {
|
||||
return;
|
||||
}
|
||||
// Makes a reconnection attempt
|
||||
try {
|
||||
if (isReconnectionPossible(connection)) {
|
||||
try {
|
||||
connection.connect();
|
||||
} catch (SmackException.AlreadyConnectedException e) {
|
||||
}
|
||||
catch (SmackException.AlreadyConnectedException e) {
|
||||
LOGGER.log(Level.FINER, "Connection was already connected on reconnection attempt", e);
|
||||
}
|
||||
}
|
||||
// TODO Starting with Smack 4.2, connect() will no
|
||||
// longer login automatically. So change this and the
|
||||
// previous lines to connection.connect().login() in the
|
||||
// 4.2, or any later, branch.
|
||||
if (!connection.isAuthenticated()) {
|
||||
connection.login();
|
||||
}
|
||||
// Successfully reconnected.
|
||||
attempts = 0;
|
||||
}
|
||||
catch (SmackException.AlreadyLoggedInException e) {
|
||||
// This can happen if another thread concurrently triggers a reconnection
|
||||
// and/or login. Obviously it should not be handled as a reconnection
|
||||
// failure. See also SMACK-725.
|
||||
LOGGER.log(Level.FINER, "Reconnection not required, was already logged in", e);
|
||||
}
|
||||
catch (SmackException | IOException | XMPPException | InterruptedException e) {
|
||||
catch (SmackException | IOException | XMPPException e) {
|
||||
// Fires the failed reconnection notification
|
||||
for (ConnectionListener listener : connection.connectionListeners) {
|
||||
listener.reconnectionFailed(e);
|
||||
}
|
||||
// Failed to reconnect, try again.
|
||||
continue;
|
||||
} catch (InterruptedException e) {
|
||||
LOGGER.log(Level.FINE, "Reconnection Thread was interrupted, aborting reconnection mechanism", e);
|
||||
// Exit the reconnection thread in case it was interrupted.
|
||||
return;
|
||||
}
|
||||
|
||||
// Successfully reconnected .
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -314,7 +328,7 @@ public final class ReconnectionManager {
|
|||
*
|
||||
* @return true, if the reconnection mechanism is enabled.
|
||||
*/
|
||||
public boolean isAutomaticReconnectEnabled() {
|
||||
public synchronized boolean isAutomaticReconnectEnabled() {
|
||||
return automaticReconnectEnabled;
|
||||
}
|
||||
|
||||
|
@ -348,6 +362,20 @@ public final class ReconnectionManager {
|
|||
"Smack Reconnection Manager (" + connection.getConnectionCounter() + ')');
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort a possibly running reconnection mechanism.
|
||||
*
|
||||
* @since 4.2.2
|
||||
*/
|
||||
public synchronized void abortPossiblyRunningReconnection() {
|
||||
if (reconnectionThread == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
reconnectionThread.interrupt();
|
||||
reconnectionThread = null;
|
||||
}
|
||||
|
||||
private final ConnectionListener connectionListener = new AbstractConnectionListener() {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -339,7 +339,7 @@ public final class SmackConfiguration {
|
|||
return defaultHostnameVerififer;
|
||||
}
|
||||
|
||||
enum UnknownIqRequestReplyMode {
|
||||
public enum UnknownIqRequestReplyMode {
|
||||
doNotReply,
|
||||
replyFeatureNotImplemented,
|
||||
replyServiceUnavailable,
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
import org.jivesoftware.smack.util.PacketUtil;
|
||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||
|
||||
|
@ -85,6 +86,7 @@ public class AbstractError {
|
|||
* @return the descriptive text or null.
|
||||
*/
|
||||
public String getDescriptiveText(String xmllang) {
|
||||
Objects.requireNonNull(xmllang, "xmllang must not be null");
|
||||
return descriptiveTexts.get(xmllang);
|
||||
}
|
||||
|
||||
|
@ -105,7 +107,8 @@ public class AbstractError {
|
|||
String xmllang = entry.getKey();
|
||||
String text = entry.getValue();
|
||||
xml.halfOpenElement("text").xmlnsAttribute(textNamespace)
|
||||
.xmllangAttribute(xmllang).rightAngleBracket();
|
||||
.optXmlLangAttribute(xmllang)
|
||||
.rightAngleBracket();
|
||||
xml.escape(text);
|
||||
xml.closeElement("text");
|
||||
}
|
||||
|
@ -120,6 +123,15 @@ public class AbstractError {
|
|||
protected List<ExtensionElement> extensions;
|
||||
|
||||
public B setDescriptiveTexts(Map<String, String> descriptiveTexts) {
|
||||
if (descriptiveTexts == null) {
|
||||
this.descriptiveTexts = null;
|
||||
return getThis();
|
||||
}
|
||||
for (String key : descriptiveTexts.keySet()) {
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("descriptiveTexts cannot contain null key");
|
||||
}
|
||||
}
|
||||
if (this.descriptiveTexts == null) {
|
||||
this.descriptiveTexts = descriptiveTexts;
|
||||
}
|
||||
|
|
|
@ -38,14 +38,14 @@ import org.jivesoftware.smack.util.XmlStringBuilder;
|
|||
* <tr><td>conflict</td><td>CANCEL</td><td>8.3.3.2</td></tr>
|
||||
* <tr><td>feature-not-implemented</td><td>CANCEL</td><td>8.3.3.3</td></tr>
|
||||
* <tr><td>forbidden</td><td>AUTH</td><td>8.3.3.4</td></tr>
|
||||
* <tr><td>gone</td><td>MODIFY</td><td>8.3.3.5</td></tr>
|
||||
* <tr><td>gone</td><td>CANCEL</td><td>8.3.3.5</td></tr>
|
||||
* <tr><td>internal-server-error</td><td>WAIT</td><td>8.3.3.6</td></tr>
|
||||
* <tr><td>item-not-found</td><td>CANCEL</td><td>8.3.3.7</td></tr>
|
||||
* <tr><td>jid-malformed</td><td>MODIFY</td><td>8.3.3.8</td></tr>
|
||||
* <tr><td>not-acceptable</td><td>MODIFY</td><td>8.3.3.9</td></tr>
|
||||
* <tr><td>not-allowed</td><td>CANCEL</td><td>8.3.3.10</td></tr>
|
||||
* <tr><td>not-authorized</td><td>AUTH</td><td>8.3.3.11</td></tr>
|
||||
* <tr><td>policy-violation</td><td>AUTH</td><td>8.3.3.12</td></tr>
|
||||
* <tr><td>policy-violation</td><td>MODIFY</td><td>8.3.3.12</td></tr>
|
||||
* <tr><td>recipient-unavailable</td><td>WAIT</td><td>8.3.3.13</td></tr>
|
||||
* <tr><td>redirect</td><td>MODIFY</td><td>8.3.3.14</td></tr>
|
||||
* <tr><td>registration-required</td><td>AUTH</td><td>8.3.3.15</td></tr>
|
||||
|
@ -54,7 +54,7 @@ import org.jivesoftware.smack.util.XmlStringBuilder;
|
|||
* <tr><td>resource-constraint</td><td>WAIT</td><td>8.3.3.18</td></tr>
|
||||
* <tr><td>service-unavailable</td><td>CANCEL</td><td>8.3.3.19</td></tr>
|
||||
* <tr><td>subscription-required</td><td>AUTH</td><td>8.3.3.20</td></tr>
|
||||
* <tr><td>undefined-condition</td><td>WAIT</td><td>8.3.3.21</td></tr>
|
||||
* <tr><td>undefined-condition</td><td>MODIFY</td><td>8.3.3.21</td></tr>
|
||||
* <tr><td>unexpected-request</td><td>WAIT</td><td>8.3.3.22</td></tr>
|
||||
* </table>
|
||||
*
|
||||
|
@ -69,7 +69,7 @@ public class XMPPError extends AbstractError {
|
|||
public static final String ERROR = "error";
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(XMPPError.class.getName());
|
||||
private static final Map<Condition, Type> CONDITION_TO_TYPE = new HashMap<Condition, Type>();
|
||||
static final Map<Condition, Type> CONDITION_TO_TYPE = new HashMap<Condition, Type>();
|
||||
|
||||
static {
|
||||
CONDITION_TO_TYPE.put(Condition.bad_request, Type.MODIFY);
|
||||
|
@ -90,9 +90,10 @@ public class XMPPError extends AbstractError {
|
|||
CONDITION_TO_TYPE.put(Condition.remote_server_not_found, Type.CANCEL);
|
||||
CONDITION_TO_TYPE.put(Condition.remote_server_timeout, Type.WAIT);
|
||||
CONDITION_TO_TYPE.put(Condition.resource_constraint, Type.WAIT);
|
||||
CONDITION_TO_TYPE.put(Condition.service_unavailable, Type.WAIT);
|
||||
CONDITION_TO_TYPE.put(Condition.subscription_required, Type.WAIT);
|
||||
CONDITION_TO_TYPE.put(Condition.unexpected_request, Type.MODIFY);
|
||||
CONDITION_TO_TYPE.put(Condition.service_unavailable, Type.CANCEL);
|
||||
CONDITION_TO_TYPE.put(Condition.subscription_required, Type.AUTH);
|
||||
CONDITION_TO_TYPE.put(Condition.undefined_condition, Type.MODIFY);
|
||||
CONDITION_TO_TYPE.put(Condition.unexpected_request, Type.WAIT);
|
||||
}
|
||||
|
||||
private final Condition condition;
|
||||
|
|
|
@ -749,6 +749,12 @@ public class PacketParserUtils {
|
|||
descriptiveTexts = new HashMap<String, String>();
|
||||
}
|
||||
String xmllang = getLanguageAttribute(parser);
|
||||
if (xmllang == null) {
|
||||
// XMPPError assumes the default locale, 'en', or the empty string.
|
||||
// Establish the invariant that there is never null as a key.
|
||||
xmllang = "";
|
||||
}
|
||||
|
||||
String text = parser.nextText();
|
||||
String previousValue = descriptiveTexts.put(xmllang, text);
|
||||
assert (previousValue == null);
|
||||
|
|
|
@ -361,7 +361,7 @@ public class XmlStringBuilder implements Appendable, CharSequence {
|
|||
}
|
||||
|
||||
public XmlStringBuilder optXmlLangAttribute(String lang) {
|
||||
if (lang != null) {
|
||||
if (!StringUtils.isNullOrEmpty(lang)) {
|
||||
xmllangAttribute(lang);
|
||||
}
|
||||
return this;
|
||||
|
|
|
@ -59,6 +59,20 @@ public abstract class DNSResolver {
|
|||
return new HostAddress(name, port, inetAddresses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the IP addresses of a given host name. Returns <code>null</code> if there was an error, in which the error
|
||||
* reason will be added in form of a <code>HostAddress</code> to <code>failedAddresses</code>. Returns a empty list
|
||||
* in case the DNS name exists but has no associated A or AAAA resource records. Otherwise, if the resolution was
|
||||
* successful <em>and</em> there is at least one A or AAAA resource record, then a non-empty list will be returned.
|
||||
* <p>
|
||||
* Concrete DNS resolver implementations are free to overwrite this, but have to stick to the interface contract.
|
||||
* </p>
|
||||
*
|
||||
* @param name the DNS name to lookup
|
||||
* @param failedAddresses a list with the failed addresses
|
||||
* @param dnssecMode the selected DNSSEC mode
|
||||
* @return A list, either empty or non-empty, or <code>null</code>
|
||||
*/
|
||||
protected List<InetAddress> lookupHostAddress0(String name, List<HostAddress> failedAddresses, DnssecMode dnssecMode) {
|
||||
// Default implementation of a DNS name lookup for A/AAAA records. It is assumed that this method does never
|
||||
// support DNSSEC. Subclasses are free to override this method.
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
*
|
||||
* Copyright © 2017 Ingo Bauersachs
|
||||
*
|
||||
* 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.smack.packet;
|
||||
|
||||
import static org.jivesoftware.smack.packet.XMPPError.Condition;
|
||||
import static org.jivesoftware.smack.packet.XMPPError.Type;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class XMPPErrorTest {
|
||||
@Test
|
||||
public void testConditionHasDefaultTypeMapping() throws NoSuchFieldException, IllegalAccessException {
|
||||
Map<Condition, Type> conditionToTypeMap = XMPPError.CONDITION_TO_TYPE;
|
||||
assertEquals("CONDITION_TO_TYPE map is likely out of sync with Condition enum",
|
||||
Condition.values().length,
|
||||
conditionToTypeMap.size());
|
||||
}
|
||||
}
|
|
@ -25,7 +25,9 @@ import static org.junit.Assert.assertTrue;
|
|||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.xml.parsers.FactoryConfigurationError;
|
||||
|
@ -35,6 +37,7 @@ import javax.xml.transform.TransformerException;
|
|||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.packet.Presence;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smack.packet.XMPPError;
|
||||
import org.jivesoftware.smack.sasl.SASLError;
|
||||
import org.jivesoftware.smack.sasl.packet.SaslStreamElements;
|
||||
import org.jivesoftware.smack.sasl.packet.SaslStreamElements.SASLFailure;
|
||||
|
@ -867,4 +870,44 @@ public class PacketParserUtilsTest {
|
|||
return otherLanguage;
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void descriptiveTextNullLangPassedMap() throws Exception {
|
||||
final String text = "Dummy descriptive text";
|
||||
Map<String, String> texts = new HashMap<>();
|
||||
texts.put(null, text);
|
||||
XMPPError
|
||||
.getBuilder(XMPPError.Condition.internal_server_error)
|
||||
.setDescriptiveTexts(texts)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ensureNoEmptyLangInDescriptiveText() throws Exception {
|
||||
final String text = "Dummy descriptive text";
|
||||
Map<String, String> texts = new HashMap<>();
|
||||
texts.put("", text);
|
||||
XMPPError error = XMPPError
|
||||
.getBuilder(XMPPError.Condition.internal_server_error)
|
||||
.setDescriptiveTexts(texts)
|
||||
.build();
|
||||
final String errorXml = XMLBuilder
|
||||
.create(XMPPError.ERROR).a("type", "cancel").up()
|
||||
.element("internal-server-error", XMPPError.NAMESPACE).up()
|
||||
.element("text", XMPPError.NAMESPACE).t(text).up()
|
||||
.asString();
|
||||
XmlUnitUtils.assertSimilar(errorXml, error.toXML());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ensureNoNullLangInParsedDescriptiveTexts() throws Exception {
|
||||
final String text = "Dummy descriptive text";
|
||||
final String errorXml = XMLBuilder
|
||||
.create(XMPPError.ERROR).a("type", "cancel").up()
|
||||
.element("internal-server-error", XMPPError.NAMESPACE).up()
|
||||
.element("text", XMPPError.NAMESPACE).t(text).up()
|
||||
.asString();
|
||||
XmlPullParser parser = TestUtils.getParser(errorXml);
|
||||
XMPPError error = PacketParserUtils.parseError(parser).build();
|
||||
assertEquals(text, error.getDescriptiveText());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,13 +87,32 @@ public final class PushNotificationsManager extends Manager {
|
|||
* @throws XMPPErrorException
|
||||
* @throws NotConnectedException
|
||||
* @throws InterruptedException
|
||||
* @deprecated Use {@link #isSupported()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
// TODO: Remove in Smack 4.3
|
||||
public boolean isSupportedByServer()
|
||||
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
return ServiceDiscoveryManager.getInstanceFor(connection())
|
||||
.serverSupportsFeature(PushNotificationsElements.NAMESPACE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if Push Notifications are supported by this account.
|
||||
*
|
||||
* @return true if Push Notifications are supported by this account.
|
||||
* @throws NoResponseException
|
||||
* @throws XMPPErrorException
|
||||
* @throws NotConnectedException
|
||||
* @throws InterruptedException
|
||||
* @since 4.2.2
|
||||
*/
|
||||
public boolean isSupported()
|
||||
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
return ServiceDiscoveryManager.getInstanceFor(connection()).accountSupportsFeatures(
|
||||
PushNotificationsElements.NAMESPACE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable push notifications.
|
||||
*
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.jivesoftware.smackx.disco.packet.DiscoverItems;
|
|||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||
|
||||
import org.jxmpp.jid.DomainBareJid;
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.jxmpp.jid.Jid;
|
||||
import org.jxmpp.util.cache.Cache;
|
||||
import org.jxmpp.util.cache.ExpirationCache;
|
||||
|
@ -680,6 +681,41 @@ public final class ServiceDiscoveryManager extends Manager {
|
|||
return supportsFeatures(connection().getXMPPServiceDomain(), features);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given features are supported by the connection account. This means that the discovery information
|
||||
* lookup will be performed on the bare JID of the connection managed by this ServiceDiscoveryManager.
|
||||
*
|
||||
* @param features the features to check
|
||||
* @return <code>true</code> if all features are supported by the connection account, <code>false</code> otherwise
|
||||
* @throws NoResponseException
|
||||
* @throws XMPPErrorException
|
||||
* @throws NotConnectedException
|
||||
* @throws InterruptedException
|
||||
* @since 4.2.2
|
||||
*/
|
||||
public boolean accountSupportsFeatures(CharSequence... features)
|
||||
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
return accountSupportsFeatures(Arrays.asList(features));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given collection of features are supported by the connection account. This means that the discovery
|
||||
* information lookup will be performed on the bare JID of the connection managed by this ServiceDiscoveryManager.
|
||||
*
|
||||
* @param features a collection of features
|
||||
* @return <code>true</code> if all features are supported by the connection account, <code>false</code> otherwise
|
||||
* @throws NoResponseException
|
||||
* @throws XMPPErrorException
|
||||
* @throws NotConnectedException
|
||||
* @throws InterruptedException
|
||||
* @since 4.2.2
|
||||
*/
|
||||
public boolean accountSupportsFeatures(Collection<? extends CharSequence> features)
|
||||
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
EntityBareJid accountJid = connection().getUser().asEntityBareJid();
|
||||
return supportsFeatures(accountJid, features);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the remote entity for it's features and returns true if the given feature is found.
|
||||
*
|
||||
|
|
|
@ -215,7 +215,7 @@ public final class Roster extends Manager {
|
|||
* Returns the default subscription processing mode to use when a new Roster is created. The
|
||||
* subscription processing mode dictates what action Smack will take when subscription
|
||||
* requests from other users are made. The default subscription mode
|
||||
* is {@link SubscriptionMode#accept_all}.
|
||||
* is {@link SubscriptionMode#reject_all}.
|
||||
*
|
||||
* @return the default subscription mode to use for new Rosters
|
||||
*/
|
||||
|
@ -227,7 +227,7 @@ public final class Roster extends Manager {
|
|||
* Sets the default subscription processing mode to use when a new Roster is created. The
|
||||
* subscription processing mode dictates what action Smack will take when subscription
|
||||
* requests from other users are made. The default subscription mode
|
||||
* is {@link SubscriptionMode#accept_all}.
|
||||
* is {@link SubscriptionMode#reject_all}.
|
||||
*
|
||||
* @param subscriptionMode the default subscription mode to use for new Rosters.
|
||||
*/
|
||||
|
@ -385,7 +385,7 @@ public final class Roster extends Manager {
|
|||
/**
|
||||
* Returns the subscription processing mode, which dictates what action
|
||||
* Smack will take when subscription requests from other users are made.
|
||||
* The default subscription mode is {@link SubscriptionMode#accept_all}.
|
||||
* The default subscription mode is {@link SubscriptionMode#reject_all}.
|
||||
* <p>
|
||||
* If using the manual mode, a PacketListener should be registered that
|
||||
* listens for Presence packets that have a type of
|
||||
|
@ -401,7 +401,7 @@ public final class Roster extends Manager {
|
|||
/**
|
||||
* Sets the subscription processing mode, which dictates what action
|
||||
* Smack will take when subscription requests from other users are made.
|
||||
* The default subscription mode is {@link SubscriptionMode#accept_all}.
|
||||
* The default subscription mode is {@link SubscriptionMode#reject_all}.
|
||||
* <p>
|
||||
* If using the manual mode, a PacketListener should be registered that
|
||||
* listens for Presence packets that have a type of
|
||||
|
@ -1409,14 +1409,14 @@ public final class Roster extends Manager {
|
|||
public enum SubscriptionMode {
|
||||
|
||||
/**
|
||||
* Automatically accept all subscription and unsubscription requests. This is
|
||||
* the default mode and is suitable for simple client. More complex client will
|
||||
* Automatically accept all subscription and unsubscription requests.
|
||||
* This is suitable for simple clients. More complex clients will
|
||||
* likely wish to handle subscription requests manually.
|
||||
*/
|
||||
accept_all,
|
||||
|
||||
/**
|
||||
* Automatically reject all subscription requests.
|
||||
* Automatically reject all subscription requests. This is the default mode.
|
||||
*/
|
||||
reject_all,
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import static junit.framework.TestCase.assertNotNull;
|
|||
import static junit.framework.TestCase.assertNotSame;
|
||||
import static junit.framework.TestCase.assertNull;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.jivesoftware.smackx.omemo.OmemoIntegrationTestHelper.cleanServerSideTraces;
|
||||
import static org.jivesoftware.smackx.omemo.OmemoIntegrationTestHelper.deletePath;
|
||||
import static org.jivesoftware.smackx.omemo.OmemoIntegrationTestHelper.setUpOmemoManager;
|
||||
|
||||
|
@ -154,6 +155,8 @@ public class OmemoStoreTest extends AbstractOmemoIntegrationTest {
|
|||
|
||||
@Override
|
||||
public void after() {
|
||||
cleanServerSideTraces(alice);
|
||||
cleanServerSideTraces(bob);
|
||||
alice.shutdown();
|
||||
bob.shutdown();
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.jivesoftware.smackx.omemo;
|
|||
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.BODY_OMEMO_HINT;
|
||||
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO;
|
||||
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO_NAMESPACE_V_AXOLOTL;
|
||||
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.PEP_NODE_DEVICE_LIST_NOTIFY;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -132,6 +133,9 @@ public final class OmemoManager extends Manager {
|
|||
}
|
||||
});
|
||||
|
||||
PEPManager.getInstanceFor(connection).addPEPListener(deviceListUpdateListener);
|
||||
ServiceDiscoveryManager.getInstanceFor(connection).addFeature(PEP_NODE_DEVICE_LIST_NOTIFY);
|
||||
|
||||
service = OmemoService.getInstance();
|
||||
}
|
||||
|
||||
|
@ -810,17 +814,24 @@ public final class OmemoManager extends Manager {
|
|||
Set<Integer> deviceListIds = omemoDeviceListElement.copyDeviceIds();
|
||||
//enroll at the deviceList
|
||||
deviceListIds.add(ourDeviceId);
|
||||
omemoDeviceListElement = new OmemoDeviceListVAxolotlElement(deviceListIds);
|
||||
final OmemoDeviceListVAxolotlElement newOmemoDeviceListElement = new OmemoDeviceListVAxolotlElement(deviceListIds);
|
||||
|
||||
// PEPListener is a synchronous listener. Avoid any deadlocks by using an async task to update the device list.
|
||||
Async.go(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
OmemoService.publishDeviceIds(OmemoManager.this, omemoDeviceListElement);
|
||||
} catch (SmackException | InterruptedException | XMPPException.XMPPErrorException e) {
|
||||
OmemoService.publishDeviceIds(OmemoManager.this, newOmemoDeviceListElement);
|
||||
}
|
||||
catch (SmackException | InterruptedException | XMPPException.XMPPErrorException e) {
|
||||
// TODO: It might be dangerous NOT to retry publishing our deviceId
|
||||
LOGGER.log(Level.SEVERE,
|
||||
"Could not publish our device list after an update without our id was received: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.jivesoftware.smackx.omemo;
|
|||
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO_NAMESPACE_V_AXOLOTL;
|
||||
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.PEP_NODE_BUNDLE_FROM_DEVICE_ID;
|
||||
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.PEP_NODE_DEVICE_LIST;
|
||||
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.PEP_NODE_DEVICE_LIST_NOTIFY;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
|
@ -55,7 +54,6 @@ import org.jivesoftware.smack.util.Async;
|
|||
import org.jivesoftware.smackx.carbons.CarbonCopyReceivedListener;
|
||||
import org.jivesoftware.smackx.carbons.CarbonManager;
|
||||
import org.jivesoftware.smackx.carbons.packet.CarbonExtension;
|
||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||
import org.jivesoftware.smackx.forward.packet.Forwarded;
|
||||
import org.jivesoftware.smackx.mam.MamManager;
|
||||
import org.jivesoftware.smackx.muc.MultiUserChat;
|
||||
|
@ -79,7 +77,6 @@ import org.jivesoftware.smackx.omemo.internal.OmemoMessageInformation;
|
|||
import org.jivesoftware.smackx.omemo.internal.OmemoSession;
|
||||
import org.jivesoftware.smackx.omemo.util.OmemoConstants;
|
||||
import org.jivesoftware.smackx.omemo.util.OmemoMessageBuilder;
|
||||
import org.jivesoftware.smackx.pep.PEPManager;
|
||||
import org.jivesoftware.smackx.pubsub.LeafNode;
|
||||
import org.jivesoftware.smackx.pubsub.PayloadItem;
|
||||
import org.jivesoftware.smackx.pubsub.PubSubException;
|
||||
|
@ -228,7 +225,6 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
|||
publishDeviceIdIfNeeded(omemoManager, false, mustPublishId);
|
||||
publishBundle(omemoManager);
|
||||
|
||||
subscribeToDeviceLists(omemoManager);
|
||||
registerOmemoMessageStanzaListeners(omemoManager); //Wait for new OMEMO messages
|
||||
getOmemoStoreBackend().initializeOmemoSessions(omemoManager); //Preload existing OMEMO sessions
|
||||
}
|
||||
|
@ -588,16 +584,6 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
|||
return new OmemoDeviceListVAxolotlElement(emptySet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to the device lists of our contacts using PEP.
|
||||
*
|
||||
* @param omemoManager omemoManager we want to subscribe with
|
||||
*/
|
||||
private static void subscribeToDeviceLists(OmemoManager omemoManager) {
|
||||
registerDeviceListListener(omemoManager);
|
||||
ServiceDiscoveryManager.getInstanceFor(omemoManager.getConnection()).addFeature(PEP_NODE_DEVICE_LIST_NOTIFY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build sessions for all devices of the contact that we do not have a session with yet.
|
||||
*
|
||||
|
@ -694,16 +680,6 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
|||
*/
|
||||
protected abstract void processBundle(OmemoManager omemoManager, T_Bundle bundle, OmemoDevice device) throws CorruptedOmemoKeyException;
|
||||
|
||||
/**
|
||||
* Register a PEPListener that listens for deviceList updates.
|
||||
*
|
||||
* @param omemoManager omemoManager we want to register with.
|
||||
*/
|
||||
private static void registerDeviceListListener(final OmemoManager omemoManager) {
|
||||
PEPManager.getInstanceFor(omemoManager.getConnection()).removePEPListener(omemoManager.deviceListUpdateListener);
|
||||
PEPManager.getInstanceFor(omemoManager.getConnection()).addPEPListener(omemoManager.deviceListUpdateListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a received message. Try to decrypt it in case we are a recipient device. If we are not a recipient
|
||||
* device, return null.
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.jivesoftware.smack.util.dns.dnsjava;
|
|||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.jivesoftware.smack.ConnectionConfiguration.DnssecMode;
|
||||
import org.jivesoftware.smack.initializer.SmackInitializer;
|
||||
|
@ -73,7 +74,13 @@ public class DNSJavaResolver extends DNSResolver implements SmackInitializer {
|
|||
int weight = srvRecord.getWeight();
|
||||
|
||||
List<InetAddress> hostAddresses = lookupHostAddress0(host, failedAddresses, dnssecMode);
|
||||
if (hostAddresses == null) {
|
||||
if (hostAddresses == null || hostAddresses.isEmpty()) {
|
||||
// If hostAddresses is not null but empty, then the DNS resolution was successful but the domain did not
|
||||
// have any A or AAAA resource records.
|
||||
if (hostAddresses.isEmpty()) {
|
||||
LOGGER.log(Level.INFO, "The DNS name " + name + ", points to a hostname (" + host
|
||||
+ ") which has neither A or AAAA resource records. This is an indication of a broken DNS setup.");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,13 @@ public class JavaxResolver extends DNSResolver implements SmackInitializer {
|
|||
String host = srvRecordEntries[srvRecordEntries.length - 1];
|
||||
|
||||
List<InetAddress> hostAddresses = lookupHostAddress0(host, failedAddresses, dnssecMode);
|
||||
if (hostAddresses == null) {
|
||||
if (hostAddresses == null || hostAddresses.isEmpty()) {
|
||||
// If hostAddresses is not null but empty, then the DNS resolution was successful but the domain did not
|
||||
// have any A or AAAA resource records.
|
||||
if (hostAddresses.isEmpty()) {
|
||||
LOGGER.log(Level.INFO, "The DNS name " + name + ", points to a hostname (" + host
|
||||
+ ") which has neither A or AAAA resource records. This is an indication of a broken DNS setup.");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.Collections;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.jivesoftware.smack.ConnectionConfiguration.DnssecMode;
|
||||
import org.jivesoftware.smack.initializer.SmackInitializer;
|
||||
|
@ -90,7 +91,13 @@ public class MiniDnsResolver extends DNSResolver implements SmackInitializer {
|
|||
for (SRV srv : result.getAnswers()) {
|
||||
String hostname = srv.name.ace;
|
||||
List<InetAddress> hostAddresses = lookupHostAddress0(hostname, failedAddresses, dnssecMode);
|
||||
if (hostAddresses == null) {
|
||||
if (hostAddresses == null || hostAddresses.isEmpty()) {
|
||||
// If hostAddresses is not null but empty, then the DNS resolution was successful but the domain did not
|
||||
// have any A or AAAA resource records.
|
||||
if (hostAddresses.isEmpty()) {
|
||||
LOGGER.log(Level.INFO, "The DNS name " + name + ", points to a hostname (" + hostname
|
||||
+ ") which has neither A or AAAA resource records. This is an indication of a broken DNS setup.");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue