mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-21 22:02:06 +01:00
Merge branch '4.2'
This commit is contained in:
commit
7a5f9e6a03
187 changed files with 2284 additions and 588 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,6 +1,8 @@
|
|||
# IntelliJ
|
||||
.idea
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
# Mac OS X
|
||||
.DS_Store
|
||||
|
|
|
@ -10,7 +10,7 @@ cache:
|
|||
- $HOME/.m2
|
||||
|
||||
before_install:
|
||||
- export GRADLE_VERSION=2.12
|
||||
- export GRADLE_VERSION=3.5
|
||||
- wget https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-all.zip
|
||||
- unzip -q gradle-${GRADLE_VERSION}-all.zip
|
||||
- export PATH="$(pwd)/gradle-${GRADLE_VERSION}/bin:$PATH"
|
||||
|
@ -20,5 +20,5 @@ script: gradle check --stacktrace
|
|||
|
||||
after_success:
|
||||
- JAVAC_VERSION=$((javac -version) 2>&1)
|
||||
# Only run jacocoRootReport in the Java7 build
|
||||
- if [[ "$JAVAC_VERSION" = javac\ 1.7.* ]]; then gradle jacocoRootReport coveralls; fi
|
||||
# Only run jacocoRootReport in the Java 8 build
|
||||
- if [[ "$JAVAC_VERSION" = javac\ 1.8.* ]]; then gradle jacocoRootReport coveralls; fi
|
||||
|
|
|
@ -8,9 +8,9 @@ buildscript {
|
|||
}
|
||||
dependencies {
|
||||
classpath 'org.kordamp:markdown-gradle-plugin:1.0.0'
|
||||
classpath 'org.kordamp.gradle:clirr-gradle-plugin:0.2.0'
|
||||
classpath 'org.kordamp.gradle:clirr-gradle-plugin:0.2.2'
|
||||
classpath "org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.3.1"
|
||||
classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.9'
|
||||
classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.10'
|
||||
}
|
||||
}
|
||||
apply plugin: 'org.kordamp.gradle.markdown'
|
||||
|
@ -20,6 +20,7 @@ apply from: 'version.gradle'
|
|||
allprojects {
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'jacoco'
|
||||
apply plugin: 'net.ltgt.errorprone'
|
||||
|
||||
|
@ -266,6 +267,7 @@ subprojects {
|
|||
|
||||
checkstyle {
|
||||
configFile = new File(rootConfigDir, 'checkstyle.xml')
|
||||
toolVersion = '7.7'
|
||||
}
|
||||
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||
classifier = 'sources'
|
||||
|
|
|
@ -117,5 +117,75 @@
|
|||
, INDEX_OP
|
||||
"/>
|
||||
</module>
|
||||
<module name="WhitespaceAfter">
|
||||
<property name="tokens" value="TYPECAST
|
||||
, LITERAL_IF
|
||||
, LITERAL_ELSE
|
||||
, LITERAL_WHILE
|
||||
, LITERAL_DO
|
||||
, LITERAL_FOR
|
||||
, DO_WHILE
|
||||
"/>
|
||||
</module>
|
||||
<module name="WhitespaceAround">
|
||||
<property
|
||||
name="ignoreEnhancedForColon"
|
||||
value="false"
|
||||
/>
|
||||
<!-- Currently disabled tokens: LCURLY, RCURLY, WILDCARD_TYPE, GENERIC_START, GENERIC_END -->
|
||||
<property
|
||||
name="tokens"
|
||||
value="ASSIGN
|
||||
, ARRAY_INIT
|
||||
, BAND
|
||||
, BAND_ASSIGN
|
||||
, BOR
|
||||
, BOR_ASSIGN
|
||||
, BSR
|
||||
, BSR_ASSIGN
|
||||
, BXOR
|
||||
, BXOR_ASSIGN
|
||||
, COLON
|
||||
, DIV
|
||||
, DIV_ASSIGN
|
||||
, DO_WHILE
|
||||
, EQUAL
|
||||
, GE
|
||||
, GT
|
||||
, LAMBDA
|
||||
, LAND
|
||||
, LE
|
||||
, LITERAL_CATCH
|
||||
, LITERAL_DO
|
||||
, LITERAL_ELSE
|
||||
, LITERAL_FINALLY
|
||||
, LITERAL_FOR
|
||||
, LITERAL_IF
|
||||
, LITERAL_RETURN
|
||||
, LITERAL_SWITCH
|
||||
, LITERAL_SYNCHRONIZED
|
||||
, LITERAL_TRY
|
||||
, LITERAL_WHILE
|
||||
, LOR
|
||||
, LT
|
||||
, MINUS
|
||||
, MINUS_ASSIGN
|
||||
, MOD
|
||||
, MOD_ASSIGN
|
||||
, NOT_EQUAL
|
||||
, PLUS
|
||||
, PLUS_ASSIGN
|
||||
, QUESTION
|
||||
, SL
|
||||
, SLIST
|
||||
, SL_ASSIGN
|
||||
, SR
|
||||
, SR_ASSIGN
|
||||
, STAR
|
||||
, STAR_ASSIGN
|
||||
, LITERAL_ASSERT
|
||||
, TYPE_EXTENSION_AND
|
||||
"/>
|
||||
</module>
|
||||
</module>
|
||||
</module>
|
||||
|
|
|
@ -87,6 +87,7 @@ Experimental Smack Extensions and currently supported XEPs of smack-experimental
|
|||
| [Internet of Things - Control](iot.md) | [XEP-0325](http://xmpp.org/extensions/xep-0325.html) | Describes how to control devices or actuators in an XMPP-based sensor netowrk. |
|
||||
| [HTTP over XMPP transport](hoxt.md) | [XEP-0332](http://xmpp.org/extensions/xep-0332.html) | Allows to transport HTTP communication over XMPP peer-to-peer networks. |
|
||||
| Chat Markers | [XEP-0333](http://xmpp.org/extensions/xep-0333.html) | A solution of marking the last received, displayed and acknowledged message in a chat. |
|
||||
| Message Processing Hints | [XEP-0334](http://xmpp.org/extensions/xep-0334.html) | Hints to entities routing or receiving a message. |
|
||||
| JSON Containers | [XEP-0335](http://xmpp.org/extensions/xep-0335.html) | Encapsulation of JSON data within XMPP Stanzas. |
|
||||
| [Internet of Things - Discovery](iot.md) | [XEP-0347](http://xmpp.org/extensions/xep-0347.html) | Describes how Things can be installed and discovered by their owners. |
|
||||
| Client State Indication | [XEP-0352](http://xmpp.org/extensions/xep-0352.html) | A way for the client to indicate its active/inactive state. |
|
||||
|
|
|
@ -41,6 +41,7 @@ import java.util.logging.Level;
|
|||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
|
||||
import org.jivesoftware.smack.SmackConfiguration.UnknownIqRequestReplyMode;
|
||||
import org.jivesoftware.smack.SmackException.AlreadyConnectedException;
|
||||
import org.jivesoftware.smack.SmackException.AlreadyLoggedInException;
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
|
@ -894,7 +895,8 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
}});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -991,20 +993,31 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
replyTimeout = timeout;
|
||||
}
|
||||
|
||||
private static boolean replyToUnknownIqDefault = true;
|
||||
|
||||
/**
|
||||
* Set the default value used to determine if new connection will reply to unknown IQ requests. The pre-configured
|
||||
* default is 'true'.
|
||||
*
|
||||
* @param replyToUnkownIqDefault
|
||||
* @see #setReplyToUnknownIq(boolean)
|
||||
* @deprecated Use {@link SmackConfiguration#setUnknownIqRequestReplyMode(org.jivesoftware.smack.SmackConfiguration.UnknownIqRequestReplyMode)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
// TODO Remove in Smack 4.3
|
||||
public static void setReplyToUnknownIqDefault(boolean replyToUnkownIqDefault) {
|
||||
AbstractXMPPConnection.replyToUnknownIqDefault = replyToUnkownIqDefault;
|
||||
SmackConfiguration.UnknownIqRequestReplyMode mode;
|
||||
if (replyToUnkownIqDefault) {
|
||||
mode = SmackConfiguration.UnknownIqRequestReplyMode.replyServiceUnavailable;
|
||||
} else {
|
||||
mode = SmackConfiguration.UnknownIqRequestReplyMode.doNotReply;
|
||||
}
|
||||
SmackConfiguration.setUnknownIqRequestReplyMode(mode);
|
||||
}
|
||||
|
||||
private boolean replyToUnkownIq = replyToUnknownIqDefault;
|
||||
private SmackConfiguration.UnknownIqRequestReplyMode unknownIqRequestReplyMode = SmackConfiguration.getUnknownIqRequestReplyMode();
|
||||
|
||||
public void setUnknownIqRequestReplyMode(UnknownIqRequestReplyMode unknownIqRequestReplyMode) {
|
||||
this.unknownIqRequestReplyMode = Objects.requireNonNull(unknownIqRequestReplyMode, "Mode must not be null");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if Smack will automatically send
|
||||
|
@ -1012,9 +1025,18 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
* registered {@link IQRequestHandler} is received.
|
||||
*
|
||||
* @param replyToUnknownIq
|
||||
* @deprecated use {@link #setUnknownIqRequestReplyMode(UnknownIqRequestReplyMode)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
// TODO Remove in Smack 4.3
|
||||
public void setReplyToUnknownIq(boolean replyToUnknownIq) {
|
||||
this.replyToUnkownIq = replyToUnknownIq;
|
||||
SmackConfiguration.UnknownIqRequestReplyMode mode;
|
||||
if (replyToUnknownIq) {
|
||||
mode = SmackConfiguration.UnknownIqRequestReplyMode.replyServiceUnavailable;
|
||||
} else {
|
||||
mode = SmackConfiguration.UnknownIqRequestReplyMode.doNotReply;
|
||||
}
|
||||
unknownIqRequestReplyMode = mode;
|
||||
}
|
||||
|
||||
protected void parseAndProcessStanza(XmlPullParser parser) throws Exception {
|
||||
|
@ -1089,13 +1111,24 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
throw new IllegalStateException("Should only encounter IQ type 'get' or 'set'");
|
||||
}
|
||||
if (iqRequestHandler == null) {
|
||||
if (!replyToUnkownIq) {
|
||||
XMPPError.Condition replyCondition;
|
||||
switch (unknownIqRequestReplyMode) {
|
||||
case doNotReply:
|
||||
return;
|
||||
case replyFeatureNotImplemented:
|
||||
replyCondition = XMPPError.Condition.feature_not_implemented;
|
||||
break;
|
||||
case replyServiceUnavailable:
|
||||
replyCondition = XMPPError.Condition.service_unavailable;
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
// If the IQ stanza is of type "get" or "set" with no registered IQ request handler, then answer an
|
||||
// IQ of type 'error' with condition 'service-unavailable'.
|
||||
ErrorIQ errorIQ = IQ.createErrorResponse(iq, XMPPError.getBuilder((
|
||||
XMPPError.Condition.service_unavailable)));
|
||||
replyCondition)));
|
||||
try {
|
||||
sendStanza(errorIQ);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.jivesoftware.smack.debugger.SmackDebugger;
|
|||
import org.jivesoftware.smack.debugger.SmackDebuggerFactory;
|
||||
import org.jivesoftware.smack.parsing.ExceptionThrowingCallback;
|
||||
import org.jivesoftware.smack.parsing.ParsingExceptionCallback;
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents the configuration of Smack. The configuration is used for:
|
||||
|
@ -370,4 +371,20 @@ public final class SmackConfiguration {
|
|||
return defaultHostnameVerififer;
|
||||
}
|
||||
|
||||
enum UnknownIqRequestReplyMode {
|
||||
doNotReply,
|
||||
replyFeatureNotImplemented,
|
||||
replyServiceUnavailable,
|
||||
}
|
||||
|
||||
// TODO Change to replyFeatureNotImplemented in Smack 4.3
|
||||
private static UnknownIqRequestReplyMode unknownIqRequestReplyMode = UnknownIqRequestReplyMode.replyServiceUnavailable;
|
||||
|
||||
public static UnknownIqRequestReplyMode getUnknownIqRequestReplyMode() {
|
||||
return unknownIqRequestReplyMode;
|
||||
}
|
||||
|
||||
public static void setUnknownIqRequestReplyMode(UnknownIqRequestReplyMode unknownIqRequestReplyMode) {
|
||||
SmackConfiguration.unknownIqRequestReplyMode = Objects.requireNonNull(unknownIqRequestReplyMode, "Must set mode");
|
||||
}
|
||||
}
|
||||
|
|
170
smack-core/src/main/java/org/jivesoftware/smack/SmackFuture.java
Normal file
170
smack-core/src/main/java/org/jivesoftware/smack/SmackFuture.java
Normal file
|
@ -0,0 +1,170 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
|
||||
public abstract class SmackFuture<V> implements Future<V> {
|
||||
|
||||
private boolean cancelled;
|
||||
|
||||
private V result;
|
||||
|
||||
protected Exception exception;
|
||||
|
||||
private SuccessCallback<V> successCallback;
|
||||
|
||||
private ExceptionCallback exceptionCallback;
|
||||
|
||||
@Override
|
||||
public synchronized final boolean cancel(boolean mayInterruptIfRunning) {
|
||||
if (isDone()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cancelled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized final boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized final boolean isDone() {
|
||||
return result != null;
|
||||
}
|
||||
|
||||
public void onSuccessOrError(SuccessCallback<V> successCallback, ExceptionCallback exceptionCallback) {
|
||||
this.successCallback = successCallback;
|
||||
this.exceptionCallback = exceptionCallback;
|
||||
|
||||
maybeInvokeCallbacks();
|
||||
}
|
||||
|
||||
public void onSuccess(SuccessCallback<V> successCallback) {
|
||||
onSuccessOrError(successCallback, null);
|
||||
}
|
||||
|
||||
public void onError(ExceptionCallback exceptionCallback) {
|
||||
onSuccessOrError(null, exceptionCallback);
|
||||
}
|
||||
|
||||
private final V getResultOrThrow() throws ExecutionException {
|
||||
assert (result != null || exception != null);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
throw new ExecutionException(exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized final V get() throws InterruptedException, ExecutionException {
|
||||
while (result == null && exception == null) {
|
||||
wait();
|
||||
}
|
||||
|
||||
return getResultOrThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized final V get(long timeout, TimeUnit unit)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
final long deadline = System.currentTimeMillis() + unit.toMillis(timeout);
|
||||
while (result != null && exception != null) {
|
||||
final long waitTimeRemaining = deadline - System.currentTimeMillis();
|
||||
if (waitTimeRemaining > 0) {
|
||||
wait(waitTimeRemaining);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null || exception == null) {
|
||||
throw new TimeoutException();
|
||||
}
|
||||
|
||||
return getResultOrThrow();
|
||||
}
|
||||
|
||||
protected final synchronized void maybeInvokeCallbacks() {
|
||||
if (result != null && successCallback != null) {
|
||||
successCallback.onSuccess(result);
|
||||
} else if (exception != null && exceptionCallback != null) {
|
||||
exceptionCallback.processException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks if the given exception is <b>not</b> fatal. If this method returns <code>false</code>, then
|
||||
* the future will automatically set the given exception as failure reason and notify potential waiting threads.
|
||||
*
|
||||
* @param exception the exception to check.
|
||||
* @return <code>true</code> if the exception is not fatal, <code>false</code> otherwise.
|
||||
*/
|
||||
protected abstract boolean isNonFatalException(Exception exception);
|
||||
|
||||
protected abstract void handleStanza(Stanza stanza) throws NotConnectedException, InterruptedException;
|
||||
|
||||
protected final void setResult(V result) {
|
||||
assert (Thread.holdsLock(this));
|
||||
|
||||
this.result = result;
|
||||
this.notifyAll();
|
||||
|
||||
maybeInvokeCallbacks();
|
||||
}
|
||||
|
||||
public static abstract class InternalSmackFuture<V> extends SmackFuture<V> implements StanzaListener, ExceptionCallback {
|
||||
|
||||
@Override
|
||||
public synchronized final void processException(Exception exception) {
|
||||
if (!isNonFatalException(exception)) {
|
||||
this.exception = exception;
|
||||
this.notifyAll();
|
||||
|
||||
maybeInvokeCallbacks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper method for {@link #handleStanza(Stanza)}. Note that this method is <code>synchronized</code>.
|
||||
*/
|
||||
@Override
|
||||
public synchronized final void processStanza(Stanza stanza) throws NotConnectedException, InterruptedException {
|
||||
handleStanza(stanza);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple version of InternalSmackFuture which implements {@link #isNonFatalException(Exception)} as always returning <code>false</code> method.
|
||||
*
|
||||
* @param <V>
|
||||
*/
|
||||
public static abstract class SimpleInternalSmackFuture<V> extends InternalSmackFuture<V> {
|
||||
@Override
|
||||
protected boolean isNonFatalException(Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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;
|
||||
|
||||
public interface SuccessCallback<T> {
|
||||
|
||||
public void onSuccess(T result);
|
||||
|
||||
}
|
|
@ -413,6 +413,7 @@ public interface XMPPConnection {
|
|||
* @deprecated use {@link #getReplyTimeout()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
// TODO Remove in Smack 4.3
|
||||
public long getPacketReplyTimeout();
|
||||
|
||||
/**
|
||||
|
@ -423,6 +424,7 @@ public interface XMPPConnection {
|
|||
* @deprecated use {@link #setReplyTimeout(long)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
// TODO Remove in Smack 4.3
|
||||
public void setPacketReplyTimeout(long timeout);
|
||||
|
||||
/**
|
||||
|
|
|
@ -39,7 +39,7 @@ public abstract class AbstractJidTypeFilter implements StanzaFilter {
|
|||
|
||||
@Override
|
||||
public final boolean accept(Stanza stanza) {
|
||||
final Jid jid = stanza.getFrom();
|
||||
final Jid jid = getJidToInspect(stanza);
|
||||
|
||||
if (jid == null) {
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.filter;
|
||||
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Filters message stanzas which have at least one body.
|
||||
*/
|
||||
public final class MessageWithThreadFilter extends FlexibleStanzaTypeFilter<Message> {
|
||||
|
||||
public static final StanzaFilter INSTANCE = new MessageWithThreadFilter();
|
||||
|
||||
private MessageWithThreadFilter() {
|
||||
super(Message.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean acceptSpecific(Message message) {
|
||||
return StringUtils.isNotEmpty(message.getThread());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
}
|
|
@ -66,9 +66,12 @@ public class AbstractError {
|
|||
public String getDescriptiveText() {
|
||||
String defaultLocale = Locale.getDefault().getLanguage();
|
||||
String descriptiveText = getDescriptiveText(defaultLocale);
|
||||
if (descriptiveText == null) {
|
||||
descriptiveText = getDescriptiveText("en");
|
||||
if (descriptiveText == null) {
|
||||
descriptiveText = getDescriptiveText("");
|
||||
}
|
||||
}
|
||||
return descriptiveText;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2014 Florian Schmaus
|
||||
* Copyright 2014-2017 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -19,9 +19,13 @@ package org.jivesoftware.smack.util;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class LazyStringBuilder implements Appendable, CharSequence {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(LazyStringBuilder.class.getName());
|
||||
|
||||
private final List<CharSequence> list;
|
||||
|
||||
private String cache;
|
||||
|
@ -69,9 +73,16 @@ public class LazyStringBuilder implements Appendable, CharSequence {
|
|||
return cache.length();
|
||||
}
|
||||
int length = 0;
|
||||
try {
|
||||
for (CharSequence csq : list) {
|
||||
length += csq.length();
|
||||
}
|
||||
}
|
||||
catch (NullPointerException npe) {
|
||||
StringBuilder sb = safeToStringBuilder();
|
||||
LOGGER.log(Level.SEVERE, "The following LazyStringBuilder threw a NullPointerException: " + sb, npe);
|
||||
throw npe;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
|
@ -107,6 +118,14 @@ public class LazyStringBuilder implements Appendable, CharSequence {
|
|||
return cache;
|
||||
}
|
||||
|
||||
public StringBuilder safeToStringBuilder() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (CharSequence csq : list) {
|
||||
sb.append(csq);
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the List of CharSequences representation of this instance. The list is unmodifiable. If
|
||||
* the resulting String was already cached, a list with a single String entry will be returned.
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.SmackFuture.InternalSmackFuture;
|
||||
import org.jivesoftware.smack.SmackFuture.SimpleInternalSmackFuture;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SmackFutureTest {
|
||||
|
||||
@Test
|
||||
public void simpleSmackFutureSuccessTest() throws NotConnectedException, InterruptedException, ExecutionException {
|
||||
InternalSmackFuture<Boolean> future = new SimpleInternalSmackFuture<Boolean>() {
|
||||
@Override
|
||||
protected void handleStanza(Stanza stanza) throws NotConnectedException, InterruptedException {
|
||||
setResult(true);
|
||||
}
|
||||
};
|
||||
|
||||
future.processStanza(null);
|
||||
|
||||
assertTrue(future.get());
|
||||
}
|
||||
|
||||
@Test(expected = TimeoutException.class)
|
||||
public void simpleSmackFutureTimeoutTest() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
InternalSmackFuture<Boolean> future = new SimpleInternalSmackFuture<Boolean>() {
|
||||
@Override
|
||||
protected void handleStanza(Stanza stanza) throws NotConnectedException, InterruptedException {
|
||||
}
|
||||
};
|
||||
|
||||
future.get(5, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
|
@ -57,9 +57,10 @@ public class ThreadedDummyConnection extends DummyConnection {
|
|||
replyQ.add(replyPacket);
|
||||
}
|
||||
replyPacket.setStanzaId(packet.getStanzaId());
|
||||
replyPacket.setFrom(packet.getTo());
|
||||
replyPacket.setTo(packet.getFrom());
|
||||
if (replyPacket.getType() == null) {
|
||||
replyPacket.setType(Type.result);
|
||||
}
|
||||
|
||||
new ProcessQueue(replyQ).start();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright © 2014 Florian Schmaus
|
||||
* Copyright © 2014-2017 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -32,7 +32,7 @@ import org.jxmpp.jid.EntityBareJid;
|
|||
|
||||
public class DigestMd5SaslTest extends AbstractSaslTest {
|
||||
|
||||
protected static final String challenge = "realm=\"xmpp.org\",nonce=\"aTUr3GXqUtyy2B7HVDW6C+gQs+j+0EhWWjoBKkkg\",qop=\"auth\",charset=utf-8,algorithm=md5-sess";
|
||||
protected static final String challenge = "realm=\"xmpp.org\",nonce=\"jgGgnz+cQcmyVaAs2n88kQ==\",qop=\"auth\",charset=utf-8,algorithm=md5-sess";
|
||||
protected static final byte[] challengeBytes = StringUtils.toBytes(challenge);
|
||||
|
||||
public DigestMd5SaslTest(SASLMechanism saslMechanism) {
|
||||
|
@ -50,8 +50,7 @@ public class DigestMd5SaslTest extends AbstractSaslTest {
|
|||
String[] responseParts = responseString.split(",");
|
||||
Map<String, String> responsePairs = new HashMap<String, String>();
|
||||
for (String part : responseParts) {
|
||||
String[] keyValue = part.split("=");
|
||||
assertTrue(keyValue.length == 2);
|
||||
String[] keyValue = part.split("=", 2);
|
||||
String key = keyValue[0];
|
||||
String value = keyValue[1].replace("\"", "");
|
||||
responsePairs.put(key, value);
|
||||
|
@ -59,7 +58,7 @@ public class DigestMd5SaslTest extends AbstractSaslTest {
|
|||
if (useAuthzid) {
|
||||
assertMapValue("authzid", "shazbat@xmpp.org", responsePairs);
|
||||
} else {
|
||||
assert(!responsePairs.containsKey("authzid"));
|
||||
assertTrue (!responsePairs.containsKey("authzid"));
|
||||
}
|
||||
assertMapValue("username", "florian", responsePairs);
|
||||
assertMapValue("realm", "xmpp.org", responsePairs);
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.eme;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.XMPPConnectionRegistry;
|
||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||
import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement;
|
||||
|
||||
public final class ExplicitMessageEncryptionManager {
|
||||
|
||||
private static final Map<XMPPConnection, ExplicitMessageEncryptionManager> INSTANCES = new WeakHashMap<>();
|
||||
|
||||
static {
|
||||
XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
|
||||
@Override
|
||||
public void connectionCreated(XMPPConnection connection) {
|
||||
getInstanceFor(connection);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static final String NAMESPACE_V0 = ExplicitMessageEncryptionElement.NAMESPACE;
|
||||
|
||||
public static synchronized ExplicitMessageEncryptionManager getInstanceFor(XMPPConnection connection) {
|
||||
ExplicitMessageEncryptionManager manager = INSTANCES.get(connection);
|
||||
if (manager == null) {
|
||||
manager = new ExplicitMessageEncryptionManager(connection);
|
||||
INSTANCES.put(connection, manager);
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
private ExplicitMessageEncryptionManager(XMPPConnection connection) {
|
||||
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
|
||||
sdm.addFeature(NAMESPACE_V0);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.eme.element;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||
|
||||
public class ExplicitMessageEncryptionElement implements ExtensionElement {
|
||||
|
||||
private static final Map<String, ExplicitMessageEncryptionProtocol> PROTOCOL_LUT = new HashMap<>();
|
||||
|
||||
public static final String ELEMENT = "encryption";
|
||||
|
||||
public static final String NAMESPACE = "urn:xmpp:eme:0";
|
||||
|
||||
public enum ExplicitMessageEncryptionProtocol {
|
||||
|
||||
/**
|
||||
* The encryption method specified in <a href="https://xmpp.org/extensions/xep-0373.html">XEP-0373: OpenPGP for
|
||||
* XMPP</a>.
|
||||
*/
|
||||
openpgpV0("urn:xmpp:openpgp:0", "OpenPGP for XMPP (XEP-0373)"),
|
||||
|
||||
otrV0("urn:xmpp:otr:0", "Off-the-Record Messaging (XEP-0364)"),
|
||||
|
||||
legacyOpenPGP("jabber:x:encrypted", "Legacy OpenPGP for XMPP [DANGEROUS, DO NOT USE!]"),
|
||||
;
|
||||
|
||||
private final String namespace;
|
||||
private final String name;
|
||||
|
||||
private ExplicitMessageEncryptionProtocol(String namespace, String name) {
|
||||
this.namespace = namespace;
|
||||
this.name = name;
|
||||
PROTOCOL_LUT.put(namespace, this);
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static ExplicitMessageEncryptionProtocol from(String namespace) {
|
||||
return PROTOCOL_LUT.get(namespace);
|
||||
}
|
||||
}
|
||||
|
||||
private final String encryptionNamespace;
|
||||
|
||||
private final String name;
|
||||
|
||||
private boolean isUnknownProtocol;
|
||||
|
||||
private ExplicitMessageEncryptionProtocol protocolCache;
|
||||
|
||||
public ExplicitMessageEncryptionElement(ExplicitMessageEncryptionProtocol protocol) {
|
||||
this(protocol.getNamespace(), protocol.getName());
|
||||
}
|
||||
|
||||
public ExplicitMessageEncryptionElement(String encryptionNamespace) {
|
||||
this(encryptionNamespace, null);
|
||||
}
|
||||
|
||||
public ExplicitMessageEncryptionElement(String encryptionNamespace, String name) {
|
||||
this.encryptionNamespace = StringUtils.requireNotNullOrEmpty(encryptionNamespace,
|
||||
"encryptionNamespace must not be null");
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public ExplicitMessageEncryptionProtocol getProtocol() {
|
||||
if (protocolCache != null) {
|
||||
return protocolCache;
|
||||
}
|
||||
|
||||
if (isUnknownProtocol) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ExplicitMessageEncryptionProtocol protocol = PROTOCOL_LUT.get(encryptionNamespace);
|
||||
if (protocol == null) {
|
||||
isUnknownProtocol = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
protocolCache = protocol;
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public String getEncryptionNamespace() {
|
||||
return encryptionNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional name of the encryption method.
|
||||
*
|
||||
* @return the name of the encryption method or <code>null</code>.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getElementName() {
|
||||
return ELEMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
return NAMESPACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlStringBuilder toXML() {
|
||||
XmlStringBuilder xml = new XmlStringBuilder(this);
|
||||
xml.attribute("namespace", getEncryptionNamespace());
|
||||
xml.optAttribute("name", getName());
|
||||
xml.closeEmptyElement();
|
||||
return xml;
|
||||
}
|
||||
|
||||
public static ExplicitMessageEncryptionElement from(Message message) {
|
||||
return message.getExtension(ELEMENT, NAMESPACE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/**
|
||||
* XMPP extension elements for XEP-0380: Explicit Message Encryption.
|
||||
*/
|
||||
package org.jivesoftware.smackx.eme.element;
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 Florian Schmaus
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -14,8 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* TODO describe me
|
||||
* Smack's API for XEP-0380: Explicit Message Encryption.
|
||||
*/
|
||||
package org.jivesoftware.smackx.iqprivate;
|
||||
package org.jivesoftware.smackx.eme;
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.eme.provider;
|
||||
|
||||
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
||||
import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
public class ExplicitMessageEncryptionProvider extends ExtensionElementProvider<ExplicitMessageEncryptionElement> {
|
||||
|
||||
@Override
|
||||
public ExplicitMessageEncryptionElement parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||
String namespace = parser.getAttributeValue(null, "namespace");
|
||||
String name = parser.getAttributeValue(null, "name");
|
||||
return new ExplicitMessageEncryptionElement(namespace, name);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/**
|
||||
* Smack Provider for XEP-0380: Explicit Message Encryption.
|
||||
*/
|
||||
package org.jivesoftware.smackx.eme.provider;
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.hints;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smackx.hints.element.MessageProcessingHintType;
|
||||
import org.jivesoftware.smackx.hints.element.NoCopyHint;
|
||||
import org.jivesoftware.smackx.hints.element.NoPermanentStoreHint;
|
||||
import org.jivesoftware.smackx.hints.element.NoStoreHint;
|
||||
import org.jivesoftware.smackx.hints.element.StoreHint;
|
||||
|
||||
public class MessageProcessingHintsManager {
|
||||
|
||||
public static Set<MessageProcessingHintType> getHintsFrom(Message message) {
|
||||
Set<MessageProcessingHintType> hints = null;
|
||||
|
||||
boolean noCopyHint = NoCopyHint.hasHint(message);
|
||||
if (noCopyHint) {
|
||||
hints = new HashSet<>(MessageProcessingHintType.values().length);
|
||||
hints.add(MessageProcessingHintType.no_copy);
|
||||
}
|
||||
|
||||
boolean noPermanentStoreHint = NoPermanentStoreHint.hasHint(message);
|
||||
if (noPermanentStoreHint) {
|
||||
if (hints == null) {
|
||||
hints = new HashSet<>(MessageProcessingHintType.values().length);
|
||||
}
|
||||
hints.add(MessageProcessingHintType.no_permanent_store);
|
||||
}
|
||||
|
||||
boolean noStoreHint = NoStoreHint.hasHint(message);
|
||||
if (noStoreHint) {
|
||||
if (hints == null) {
|
||||
hints = new HashSet<>(MessageProcessingHintType.values().length);
|
||||
}
|
||||
hints.add(MessageProcessingHintType.no_store);
|
||||
}
|
||||
|
||||
boolean storeHint = StoreHint.hasHint(message);
|
||||
if (storeHint) {
|
||||
if (hints == null) {
|
||||
hints = new HashSet<>(MessageProcessingHintType.values().length);
|
||||
}
|
||||
hints.add(MessageProcessingHintType.store);
|
||||
}
|
||||
|
||||
if (hints == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
return hints;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.hints.element;
|
||||
|
||||
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||
|
||||
public abstract class MessageProcessingHint implements ExtensionElement {
|
||||
|
||||
public static final String NAMESPACE = "urn:xmpp:hints";
|
||||
|
||||
@Override
|
||||
public final String getNamespace() {
|
||||
return NAMESPACE;
|
||||
}
|
||||
|
||||
public abstract MessageProcessingHintType getHintType();
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.hints.element;
|
||||
|
||||
public enum MessageProcessingHintType {
|
||||
|
||||
no_permanent_store,
|
||||
no_store,
|
||||
no_copy,
|
||||
store,
|
||||
;
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.hints.element;
|
||||
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
|
||||
/**
|
||||
* A "no copy" hint. Messages with this hint should not be copied to addresses other than the one to which it is addressed.
|
||||
*
|
||||
* @see <a href="https://xmpp.org/extensions/xep-0334.html#no-copy">XEP-0344 § 4.3 No copies</a>
|
||||
*/
|
||||
public final class NoCopyHint extends MessageProcessingHint {
|
||||
|
||||
public static final NoCopyHint INSTANCE = new NoCopyHint();
|
||||
|
||||
public static final String ELEMENT = "no-copy";
|
||||
|
||||
private NoCopyHint() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getElementName() {
|
||||
return ELEMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toXML() {
|
||||
return '<' + ELEMENT + " xmlns='" + NAMESPACE + "'/>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageProcessingHintType getHintType() {
|
||||
return MessageProcessingHintType.no_copy;
|
||||
}
|
||||
|
||||
public static NoCopyHint from(Message message) {
|
||||
return message.getExtension(ELEMENT, NAMESPACE);
|
||||
}
|
||||
|
||||
public static boolean hasHint(Message message) {
|
||||
return from(message) != null;
|
||||
}
|
||||
|
||||
public static void set(Message message) {
|
||||
message.addExtension(INSTANCE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.hints.element;
|
||||
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
|
||||
/**
|
||||
* A "no permanent store" hint. Messages with this hint should not be stored in permanent stores or archives.
|
||||
*
|
||||
* @see <a href="https://xmpp.org/extensions/xep-0334.html#no-permanent-store">XEP-0334 § 4.1 No permanent store</a>
|
||||
*/
|
||||
public final class NoPermanentStoreHint extends MessageProcessingHint {
|
||||
|
||||
public static final NoPermanentStoreHint INSTANCE = new NoPermanentStoreHint();
|
||||
|
||||
public static final String ELEMENT = "no-permanent-store";
|
||||
|
||||
private NoPermanentStoreHint() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getElementName() {
|
||||
return ELEMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toXML() {
|
||||
return '<' + ELEMENT + " xmlns='" + NAMESPACE + "'/>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageProcessingHintType getHintType() {
|
||||
return MessageProcessingHintType.no_permanent_store;
|
||||
}
|
||||
|
||||
public static NoPermanentStoreHint from(Message message) {
|
||||
return message.getExtension(ELEMENT, NAMESPACE);
|
||||
}
|
||||
|
||||
public static boolean hasHint(Message message) {
|
||||
return from(message) != null;
|
||||
}
|
||||
|
||||
public static void set(Message message) {
|
||||
if (StoreHint.hasHint(message)) {
|
||||
// No need to set the no-permanent-store hint when a no-store hint is already set.
|
||||
return;
|
||||
}
|
||||
setExplicitly(message);
|
||||
}
|
||||
|
||||
public static void setExplicitly(Message message) {
|
||||
message.addExtension(INSTANCE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.hints.element;
|
||||
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
|
||||
/**
|
||||
* A "no store" hint. Messages with this hint should not be stored in stores or archives.
|
||||
*
|
||||
* <a href="https://xmpp.org/extensions/xep-0334.html#no-store">XEP-0334 § 4.2 No store</a>
|
||||
*/
|
||||
public final class NoStoreHint extends MessageProcessingHint {
|
||||
|
||||
public static final NoStoreHint INSTANCE = new NoStoreHint();
|
||||
|
||||
public static final String ELEMENT = "no-store";
|
||||
|
||||
private NoStoreHint() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getElementName() {
|
||||
return ELEMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toXML() {
|
||||
return '<' + ELEMENT + " xmlns='" + NAMESPACE + "'/>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageProcessingHintType getHintType() {
|
||||
return MessageProcessingHintType.no_store;
|
||||
}
|
||||
|
||||
public static NoStoreHint from(Message message) {
|
||||
return message.getExtension(ELEMENT, NAMESPACE);
|
||||
}
|
||||
|
||||
public static boolean hasHint(Message message) {
|
||||
return from(message) != null;
|
||||
}
|
||||
|
||||
public static void set(Message message) {
|
||||
message.addExtension(INSTANCE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.hints.element;
|
||||
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
|
||||
/**
|
||||
* A "store" hint. Messages with this hint should be stored in permanent stores or archives.
|
||||
*
|
||||
* @see <a href="https://xmpp.org/extensions/xep-0334.html#sect-idm140684698220992">XEP-0334 § 4.4 Store</a>
|
||||
*/
|
||||
public final class StoreHint extends MessageProcessingHint {
|
||||
|
||||
public static final StoreHint INSTANCE = new StoreHint();
|
||||
|
||||
public static final String ELEMENT = "store";
|
||||
|
||||
private StoreHint() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getElementName() {
|
||||
return ELEMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toXML() {
|
||||
return '<' + ELEMENT + " xmlns='" + NAMESPACE + "'/>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageProcessingHintType getHintType() {
|
||||
return MessageProcessingHintType.store;
|
||||
}
|
||||
|
||||
public static StoreHint from(Message message) {
|
||||
return message.getExtension(ELEMENT, NAMESPACE);
|
||||
}
|
||||
|
||||
public static boolean hasHint(Message message) {
|
||||
return from(message) != null;
|
||||
}
|
||||
|
||||
public static void set(Message message) {
|
||||
message.addExtension(INSTANCE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/**
|
||||
* XMPP extension elements for XEP-0334: Message Processing Hints.
|
||||
*/
|
||||
package org.jivesoftware.smackx.hints.element;
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/**
|
||||
* Smack's API for XEP-0334: Message Processing Hints.
|
||||
*/
|
||||
package org.jivesoftware.smackx.hints;
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.hints.provider;
|
||||
|
||||
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
||||
import org.jivesoftware.smackx.hints.element.MessageProcessingHint;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
public abstract class MessageProcessingHintProvider<H extends MessageProcessingHint> extends ExtensionElementProvider<H> {
|
||||
|
||||
@Override
|
||||
public H parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||
return getHint();
|
||||
}
|
||||
|
||||
protected abstract H getHint();
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.hints.provider;
|
||||
|
||||
import org.jivesoftware.smackx.hints.element.NoCopyHint;
|
||||
|
||||
public class NoCopyHintProvider extends MessageProcessingHintProvider<NoCopyHint> {
|
||||
|
||||
@Override
|
||||
protected NoCopyHint getHint() {
|
||||
return NoCopyHint.INSTANCE;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.hints.provider;
|
||||
|
||||
import org.jivesoftware.smackx.hints.element.NoPermanentStoreHint;
|
||||
|
||||
public class NoPermanentStoreHintProvider extends MessageProcessingHintProvider<NoPermanentStoreHint> {
|
||||
|
||||
@Override
|
||||
protected NoPermanentStoreHint getHint() {
|
||||
return NoPermanentStoreHint.INSTANCE;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.hints.provider;
|
||||
|
||||
import org.jivesoftware.smackx.hints.element.NoStoreHint;
|
||||
|
||||
public class NoStoreHintProvider extends MessageProcessingHintProvider<NoStoreHint> {
|
||||
|
||||
@Override
|
||||
protected NoStoreHint getHint() {
|
||||
return NoStoreHint.INSTANCE;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.hints.provider;
|
||||
|
||||
import org.jivesoftware.smackx.hints.element.StoreHint;
|
||||
|
||||
public class StoreHintProvider extends MessageProcessingHintProvider<StoreHint> {
|
||||
|
||||
@Override
|
||||
protected StoreHint getHint() {
|
||||
return StoreHint.INSTANCE;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/**
|
||||
* Smack Provider for XEP-0334: Message Processing Hints.
|
||||
*/
|
||||
package org.jivesoftware.smackx.hints.provider;
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright © 2016 Florian Schmaus
|
||||
* Copyright © 2016-2017 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -21,7 +21,7 @@ import org.jxmpp.jid.BareJid;
|
|||
|
||||
public class IoTIsFriendResponse extends IQ {
|
||||
|
||||
public static final String ELEMENT = "isFriend";
|
||||
public static final String ELEMENT = "isFriendResponse";
|
||||
public static final String NAMESPACE = Constants.IOT_PROVISIONING_NAMESPACE;
|
||||
|
||||
private final BareJid jid;
|
||||
|
@ -46,6 +46,7 @@ public class IoTIsFriendResponse extends IQ {
|
|||
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||
xml.attribute("jid", jid);
|
||||
xml.attribute("result", result);
|
||||
xml.setEmptyElement();
|
||||
return xml;
|
||||
}
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ public class EnablePushNotificationsIQ extends IQ {
|
|||
xml.rightAngleBracket();
|
||||
|
||||
if (publishOptions != null) {
|
||||
DataForm dataForm = new DataForm(DataForm.Type.form);
|
||||
DataForm dataForm = new DataForm(DataForm.Type.submit);
|
||||
|
||||
FormField formTypeField = new FormField("FORM_TYPE");
|
||||
formTypeField.addValue(PubSub.NAMESPACE + "#publish-options");
|
||||
|
|
|
@ -233,6 +233,28 @@
|
|||
<className>org.jivesoftware.smackx.chat_markers.provider.AcknowledgedProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-0334: Message Processing Hints -->
|
||||
<extensionProvider>
|
||||
<elementName>no-copy</elementName>
|
||||
<namespace>urn:xmpp:hints</namespace>
|
||||
<className>org.jivesoftware.smackx.hints.provider.NoCopyHintProvider</className>
|
||||
</extensionProvider>
|
||||
<extensionProvider>
|
||||
<elementName>no-permanent-store</elementName>
|
||||
<namespace>urn:xmpp:hints</namespace>
|
||||
<className>org.jivesoftware.smackx.hints.provider.NoPermanentStoreHintProvider</className>
|
||||
</extensionProvider>
|
||||
<extensionProvider>
|
||||
<elementName>no-store</elementName>
|
||||
<namespace>urn:xmpp:hints</namespace>
|
||||
<className>org.jivesoftware.smackx.hints.provider.NoStoreHintProvider</className>
|
||||
</extensionProvider>
|
||||
<extensionProvider>
|
||||
<elementName>store</elementName>
|
||||
<namespace>urn:xmpp:hints</namespace>
|
||||
<className>org.jivesoftware.smackx.hints.provider.StoreHintProvider</className>
|
||||
</extensionProvider>
|
||||
g
|
||||
<!-- XEP-0363: HTTP File Upload -->
|
||||
<iqProvider>
|
||||
<elementName>slot</elementName>
|
||||
|
@ -255,4 +277,11 @@
|
|||
<className>org.jivesoftware.smackx.httpfileupload.provider.FileTooLargeErrorProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-0380: Explicit Message Encryption -->
|
||||
<extensionProvider>
|
||||
<elementName>encryption</elementName>
|
||||
<namespace>urn:xmpp:eme:0</namespace>
|
||||
<className>org.jivesoftware.smackx.eme.provider.ExplicitMessageEncryptionProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
</smackProviders>
|
||||
|
|
|
@ -5,5 +5,6 @@
|
|||
<className>org.jivesoftware.smackx.iot.discovery.IoTDiscoveryManager</className>
|
||||
<className>org.jivesoftware.smackx.iot.provisioning.IoTProvisioningManager</className>
|
||||
<className>org.jivesoftware.smackx.httpfileupload.HttpFileUploadManager</className>
|
||||
<className>org.jivesoftware.smackx.eme.ExplicitMessageEncryptionManager</className>
|
||||
</startupClasses>
|
||||
</smack>
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.eme.provider;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.jivesoftware.smack.test.util.TestUtils;
|
||||
import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement;
|
||||
import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ExplicitMessageEncryptionProviderTest {
|
||||
|
||||
private static final String OX_EME_ELEMENT = "<encryption xmlns='urn:xmpp:eme:0' namespace='urn:xmpp:openpgp:0'/>";
|
||||
|
||||
private static final String UNKNOWN_NAMESPACE = "urn:xmpp:foobar:0";
|
||||
private static final String UNKNOWN_NAME = "Foo Bar";
|
||||
private static final String UNKNOWN_EME_ELEMENT = "<encryption xmlns='urn:xmpp:eme:0' namespace='" + UNKNOWN_NAMESPACE
|
||||
+ "' name='" + UNKNOWN_NAME + "'/>";
|
||||
|
||||
@Test
|
||||
public void testParseOxEmeElement() throws Exception {
|
||||
ExplicitMessageEncryptionElement eme = TestUtils.parseExtensionElement(OX_EME_ELEMENT);
|
||||
assertEquals(ExplicitMessageEncryptionProtocol.openpgpV0, eme.getProtocol());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseUnknownEmeElement() throws Exception {
|
||||
ExplicitMessageEncryptionElement eme = TestUtils.parseExtensionElement(UNKNOWN_EME_ELEMENT);
|
||||
assertEquals(UNKNOWN_NAMESPACE, eme.getEncryptionNamespace());
|
||||
assertEquals(UNKNOWN_NAME, eme.getName());
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ public class EnablePushNotificationsIQTest {
|
|||
|
||||
String exampleEnableIQWithPublishOptions = "<iq id='x42' type='set'>"
|
||||
+ "<enable xmlns='urn:xmpp:push:0' jid='push-5.client.example' node='yxs32uqsflafdk3iuqo'>"
|
||||
+ "<x xmlns='jabber:x:data' type='form'>"
|
||||
+ "<x xmlns='jabber:x:data' type='submit'>"
|
||||
+ "<field var='FORM_TYPE'><value>http://jabber.org/protocol/pubsub#publish-options</value></field>"
|
||||
+ "<field var='secret'><value>eruio234vzxc2kla-91</value></field>" + "</x>" + "</enable>" + "</iq>";
|
||||
|
||||
|
|
|
@ -41,7 +41,9 @@ import org.jivesoftware.smack.chat.ChatMessageListener;
|
|||
import org.jivesoftware.smack.filter.AndFilter;
|
||||
import org.jivesoftware.smack.filter.FromMatchesFilter;
|
||||
import org.jivesoftware.smack.filter.MessageTypeFilter;
|
||||
import org.jivesoftware.smack.filter.MessageWithBodiesFilter;
|
||||
import org.jivesoftware.smack.filter.MessageWithSubjectFilter;
|
||||
import org.jivesoftware.smack.filter.MessageWithThreadFilter;
|
||||
import org.jivesoftware.smack.filter.NotFilter;
|
||||
import org.jivesoftware.smack.filter.OrFilter;
|
||||
import org.jivesoftware.smack.filter.PresenceTypeFilter;
|
||||
|
@ -170,10 +172,6 @@ public class MultiUserChat {
|
|||
public void processStanza(Stanza packet) {
|
||||
Message msg = (Message) packet;
|
||||
EntityFullJid from = msg.getFrom().asEntityFullJidIfPossible();
|
||||
if (from == null) {
|
||||
LOGGER.warning("Message subject not changed by a full JID: " + msg.getFrom());
|
||||
return;
|
||||
}
|
||||
// Update the room subject
|
||||
subject = msg.getSubject();
|
||||
// Fire event for subject updated listeners
|
||||
|
@ -322,8 +320,17 @@ public class MultiUserChat {
|
|||
connection.addSyncStanzaListener(messageListener, fromRoomGroupchatFilter);
|
||||
connection.addSyncStanzaListener(presenceListener, new AndFilter(fromRoomFilter,
|
||||
StanzaTypeFilter.PRESENCE));
|
||||
connection.addSyncStanzaListener(subjectListener, new AndFilter(fromRoomFilter,
|
||||
MessageWithSubjectFilter.INSTANCE, new NotFilter(MessageTypeFilter.ERROR)));
|
||||
// @formatter:off
|
||||
connection.addSyncStanzaListener(subjectListener,
|
||||
new AndFilter(fromRoomFilter,
|
||||
MessageWithSubjectFilter.INSTANCE,
|
||||
new NotFilter(MessageTypeFilter.ERROR),
|
||||
// According to XEP-0045 § 8.1 "A message with a <subject/> and a <body/> or a <subject/> and a <thread/> is a
|
||||
// legitimate message, but it SHALL NOT be interpreted as a subject change."
|
||||
new NotFilter(MessageWithBodiesFilter.INSTANCE),
|
||||
new NotFilter(MessageWithThreadFilter.INSTANCE))
|
||||
);
|
||||
// @formatter:on
|
||||
connection.addSyncStanzaListener(declinesListener, DECLINE_FILTER);
|
||||
connection.addPacketInterceptor(presenceInterceptor, new AndFilter(ToMatchesFilter.create(room),
|
||||
StanzaTypeFilter.PRESENCE));
|
||||
|
|
|
@ -124,7 +124,7 @@ public class Occupant {
|
|||
int result;
|
||||
result = affiliation.hashCode();
|
||||
result = 17 * result + role.hashCode();
|
||||
result = 17 * result + jid.hashCode();
|
||||
result = 17 * result + (jid != null ? jid.hashCode() : 0);
|
||||
result = 17 * result + (nick != null ? nick.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public interface SubjectUpdatedListener {
|
|||
* Called when a MUC room has changed its subject.
|
||||
*
|
||||
* @param subject the new room's subject.
|
||||
* @param from the user that changed the room's subject (e.g. room@conference.jabber.org/nick).
|
||||
* @param from the user that changed the room's subject or <code>null</code> if the room itself changed the subject.
|
||||
*/
|
||||
public abstract void subjectUpdated(String subject, EntityFullJid from);
|
||||
|
||||
|
|
|
@ -31,16 +31,20 @@ import org.jivesoftware.smack.AbstractConnectionClosedListener;
|
|||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.SmackException.NotLoggedInException;
|
||||
import org.jivesoftware.smack.SmackFuture;
|
||||
import org.jivesoftware.smack.SmackFuture.InternalSmackFuture;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||
import org.jivesoftware.smack.Manager;
|
||||
import org.jivesoftware.smack.XMPPConnectionRegistry;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
|
||||
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.IQ.Type;
|
||||
import org.jivesoftware.smack.packet.XMPPError;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smack.util.SmackExecutorThreadFactory;
|
||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||
import org.jivesoftware.smackx.ping.packet.Ping;
|
||||
|
@ -142,6 +146,71 @@ public final class PingManager extends Manager {
|
|||
maybeSchedulePingServerTask();
|
||||
}
|
||||
|
||||
private boolean isValidErrorPong(Jid destinationJid, XMPPErrorException xmppErrorException) {
|
||||
// If it is an error error response and the destination was our own service, then this must mean that the
|
||||
// service responded, i.e. is up and pingable.
|
||||
if (destinationJid.equals(connection().getServiceName())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final XMPPError xmppError = xmppErrorException.getXMPPError();
|
||||
|
||||
// We may received an error response from an intermediate service returning an error like
|
||||
// 'remote-server-not-found' or 'remote-server-timeout' to us (which would fake the 'from' address,
|
||||
// see RFC 6120 § 8.3.1 2.). Or the recipient could became unavailable.
|
||||
|
||||
// Sticking with the current rules of RFC 6120/6121, it is undecidable at this point whether we received an
|
||||
// error response from the pinged entity or not. This is because a service-unavailable error condition is
|
||||
// *required* (as per the RFCs) to be send back in both relevant cases:
|
||||
// 1. When the receiving entity is unaware of the IQ request type. RFC 6120 § 8.4.:
|
||||
// "If an intended recipient receives an IQ stanza of type "get" or
|
||||
// "set" containing a child element qualified by a namespace it does
|
||||
// not understand, then the entity MUST return an IQ stanza of type
|
||||
// "error" with an error condition of <service-unavailable/>.
|
||||
// 2. When the receiving resource is not available. RFC 6121 § 8.5.3.2.3.
|
||||
|
||||
// Some clients don't obey the first rule and instead send back a feature-not-implement condition with type 'cancel',
|
||||
// which allows us to consider this response as valid "error response" pong.
|
||||
XMPPError.Type type = xmppError.getType();
|
||||
XMPPError.Condition condition = xmppError.getCondition();
|
||||
return type == XMPPError.Type.CANCEL && condition == XMPPError.Condition.feature_not_implemented;
|
||||
}
|
||||
|
||||
public SmackFuture<Boolean> pingAsync(Jid jid) {
|
||||
return pingAsync(jid, connection().getReplyTimeout());
|
||||
}
|
||||
|
||||
public SmackFuture<Boolean> pingAsync(final Jid jid, long pongTimeout) {
|
||||
final InternalSmackFuture<Boolean> future = new InternalSmackFuture<Boolean>() {
|
||||
@Override
|
||||
public void handleStanza(Stanza packet) throws NotConnectedException, InterruptedException {
|
||||
setResult(true);
|
||||
}
|
||||
@Override
|
||||
public boolean isNonFatalException(Exception exception) {
|
||||
if (exception instanceof XMPPErrorException) {
|
||||
XMPPErrorException xmppErrorException = (XMPPErrorException) exception;
|
||||
if (isValidErrorPong(jid, xmppErrorException)) {
|
||||
setResult(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
Ping ping = new Ping(jid);
|
||||
try {
|
||||
XMPPConnection connection = getAuthenticatedConnectionOrThrow();
|
||||
connection.sendIqWithResponseCallback(ping, future, future, pongTimeout);
|
||||
}
|
||||
catch (NotLoggedInException | NotConnectedException | InterruptedException e) {
|
||||
future.processException(e);
|
||||
}
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pings the given jid. This method will return false if an error occurs. The exception
|
||||
* to this, is a server ping, which will always return true if the server is reachable,
|
||||
|
@ -168,8 +237,8 @@ public final class PingManager extends Manager {
|
|||
try {
|
||||
connection.createStanzaCollectorAndSend(ping).nextResultOrThrow(pingTimeout);
|
||||
}
|
||||
catch (XMPPException exc) {
|
||||
return jid.equals(connection.getXMPPServiceDomain());
|
||||
catch (XMPPErrorException e) {
|
||||
return isValidErrorPong(jid, e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -608,9 +608,7 @@ abstract public class Node
|
|||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void processStanza(Stanza packet)
|
||||
{
|
||||
// CHECKSTYLE:OFF
|
||||
EventElement event = (EventElement) packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
|
||||
// CHECKSTYLE:ON
|
||||
ItemsExtension itemsElem = (ItemsExtension) event.getEvent();
|
||||
ItemPublishEvent eventItems = new ItemPublishEvent(itemsElem.getNode(), itemsElem.getItems(), getSubscriptionIds(packet), DelayInformationManager.getDelayTimestamp(packet));
|
||||
listener.handlePublishedItems(eventItems);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Florian Schmaus
|
||||
*
|
||||
* 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.smackx.pubsub;
|
||||
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
|
||||
public abstract class PubSubException extends SmackException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static class NotALeafNodeException extends PubSubException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String nodeId;
|
||||
private final BareJid pubSubService;
|
||||
|
||||
NotALeafNodeException(String nodeId, BareJid pubSubService) {
|
||||
this.nodeId = nodeId;
|
||||
this.pubSubService = pubSubService;
|
||||
}
|
||||
|
||||
public String getNodeId() {
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
public BareJid getPubSubService() {
|
||||
return pubSubService;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -16,8 +16,6 @@
|
|||
*/
|
||||
package org.jivesoftware.smackx.pubsub;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -42,6 +40,7 @@ import org.jivesoftware.smack.packet.ExtensionElement;
|
|||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverItems;
|
||||
import org.jivesoftware.smackx.pubsub.PubSubException.NotALeafNodeException;
|
||||
import org.jivesoftware.smackx.pubsub.packet.PubSub;
|
||||
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
|
||||
import org.jivesoftware.smackx.pubsub.util.NodeUtils;
|
||||
|
@ -64,6 +63,8 @@ import org.jxmpp.stringprep.XmppStringprepException;
|
|||
*/
|
||||
public final class PubSubManager extends Manager {
|
||||
|
||||
public static final String AUTO_CREATE_FEATURE = "http://jabber.org/protocol/pubsub#auto-create";
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(PubSubManager.class.getName());
|
||||
private static final Map<XMPPConnection, Map<BareJid, PubSubManager>> INSTANCES = new WeakHashMap<>();
|
||||
|
||||
|
@ -267,10 +268,11 @@ public final class PubSubManager extends Manager {
|
|||
* @throws NotConnectedException
|
||||
* @throws InterruptedException
|
||||
* @throws XMPPErrorException
|
||||
* @throws NotALeafNodeException in case the node already exists as collection node.
|
||||
* @since 4.2.1
|
||||
*/
|
||||
public LeafNode getOrCreateLeafNode(final String id)
|
||||
throws NoResponseException, NotConnectedException, InterruptedException, XMPPErrorException {
|
||||
throws NoResponseException, NotConnectedException, InterruptedException, XMPPErrorException, NotALeafNodeException {
|
||||
try {
|
||||
return getNode(id);
|
||||
}
|
||||
|
@ -287,9 +289,7 @@ public final class PubSubManager extends Manager {
|
|||
throw e2;
|
||||
}
|
||||
}
|
||||
throw e1;
|
||||
}
|
||||
catch (PubSubAssertionError.DiscoInfoNodeAssertionError e) {
|
||||
if (e1.getXMPPError().getCondition() == Condition.service_unavailable) {
|
||||
// This could be caused by Prosody bug #805 (see https://prosody.im/issues/issue/805). Prosody does not
|
||||
// answer to disco#info requests on the node ID, which makes it undecidable if a node is a leaf or
|
||||
// collection node.
|
||||
|
@ -297,32 +297,107 @@ public final class PubSubManager extends Manager {
|
|||
+ " threw an DiscoInfoNodeAssertionError, trying workaround for Prosody bug #805 (https://prosody.im/issues/issue/805)");
|
||||
return getOrCreateLeafNodeProsodyWorkaround(id);
|
||||
}
|
||||
throw e1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get a leaf node with the given node ID.
|
||||
*
|
||||
* @param id the node ID.
|
||||
* @return the requested leaf node.
|
||||
* @throws NotALeafNodeException in case the node exists but is a collection node.
|
||||
* @throws NoResponseException
|
||||
* @throws NotConnectedException
|
||||
* @throws InterruptedException
|
||||
* @throws XMPPErrorException
|
||||
* @since 4.2.1
|
||||
*/
|
||||
public LeafNode getLeafNode(String id) throws NotALeafNodeException, NoResponseException, NotConnectedException,
|
||||
InterruptedException, XMPPErrorException {
|
||||
Node node;
|
||||
try {
|
||||
node = getNode(id);
|
||||
}
|
||||
catch (XMPPErrorException e) {
|
||||
if (e.getXMPPError().getCondition() == Condition.service_unavailable) {
|
||||
// This could be caused by Prosody bug #805 (see https://prosody.im/issues/issue/805). Prosody does not
|
||||
// answer to disco#info requests on the node ID, which makes it undecidable if a node is a leaf or
|
||||
// collection node.
|
||||
return getLeafNodeProsodyWorkaround(id);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (node instanceof LeafNode) {
|
||||
return (LeafNode) node;
|
||||
}
|
||||
|
||||
throw new PubSubException.NotALeafNodeException(id, pubSubService);
|
||||
}
|
||||
|
||||
private LeafNode getLeafNodeProsodyWorkaround(final String id) throws NoResponseException, NotConnectedException,
|
||||
InterruptedException, NotALeafNodeException, XMPPErrorException {
|
||||
LeafNode leafNode = new LeafNode(this, id);
|
||||
try {
|
||||
// Try to ensure that this is not a collection node by asking for one item form the node.
|
||||
leafNode.getItems(1);
|
||||
} catch (XMPPErrorException e) {
|
||||
Condition condition = e.getXMPPError().getCondition();
|
||||
if (condition == Condition.feature_not_implemented) {
|
||||
// XEP-0060 § 6.5.9.5: Item retrieval not supported, e.g. because node is a collection node
|
||||
throw new PubSubException.NotALeafNodeException(id, pubSubService);
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
nodeMap.put(id, leafNode);
|
||||
|
||||
return leafNode;
|
||||
}
|
||||
|
||||
private LeafNode getOrCreateLeafNodeProsodyWorkaround(final String id)
|
||||
throws XMPPErrorException, NoResponseException, NotConnectedException, InterruptedException {
|
||||
throws XMPPErrorException, NoResponseException, NotConnectedException, InterruptedException, NotALeafNodeException {
|
||||
try {
|
||||
return createNode(id);
|
||||
}
|
||||
catch (XMPPErrorException e1) {
|
||||
if (e1.getXMPPError().getCondition() == Condition.conflict) {
|
||||
Constructor<?> constructor = LeafNode.class.getDeclaredConstructors()[0];
|
||||
constructor.setAccessible(true);
|
||||
LeafNode res;
|
||||
try {
|
||||
res = (LeafNode) constructor.newInstance(this, id);
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
||||
| InvocationTargetException e2) {
|
||||
throw new AssertionError(e2);
|
||||
}
|
||||
// TODO: How to verify that this is actually a leafe node and not a conflict with a collection node?
|
||||
return res;
|
||||
return getLeafNodeProsodyWorkaround(id);
|
||||
}
|
||||
throw e1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to publish an item and, if the node with the given ID does not exists, auto-create the node.
|
||||
* <p>
|
||||
* Not every PubSub service supports automatic node creation. You can discover if this service supports it by using
|
||||
* {@link #supportsAutomaticNodeCreation()}.
|
||||
* </p>
|
||||
*
|
||||
* @param id The unique id of the node.
|
||||
* @param item The item to publish.
|
||||
* @return the LeafNode on which the item was published.
|
||||
* @throws NoResponseException
|
||||
* @throws XMPPErrorException
|
||||
* @throws NotConnectedException
|
||||
* @throws InterruptedException
|
||||
* @since 4.2.1
|
||||
*/
|
||||
public <I extends Item> LeafNode tryToPublishAndPossibleAutoCreate(String id, I item)
|
||||
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
LeafNode leafNode = new LeafNode(this, id);
|
||||
leafNode.publish(item);
|
||||
|
||||
// If LeafNode.publish() did not throw then we have successfully published an item and possible auto-created
|
||||
// (XEP-0163 § 3., XEP-0060 § 7.1.4) the node. So we can put the node into the nodeMap.
|
||||
nodeMap.put(id, leafNode);
|
||||
|
||||
return leafNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the nodes that currently exist as a child of the specified
|
||||
* collection node. If the service does not support collection nodes
|
||||
|
@ -440,6 +515,23 @@ public final class PubSubManager extends Manager {
|
|||
return mgr.discoverInfo(pubSubService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the PubSub service supports automatic node creation.
|
||||
*
|
||||
* @return true if the PubSub service supports automatic node creation.
|
||||
* @throws NoResponseException
|
||||
* @throws XMPPErrorException
|
||||
* @throws NotConnectedException
|
||||
* @throws InterruptedException
|
||||
* @since 4.2.1
|
||||
* @see <a href="https://xmpp.org/extensions/xep-0060.html#publisher-publish-autocreate">XEP-0060 § 7.1.4 Automatic Node Creation</a>
|
||||
*/
|
||||
public boolean supportsAutomaticNodeCreation()
|
||||
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection());
|
||||
return sdm.supportsFeature(pubSubService, AUTO_CREATE_FEATURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if it is possible to create PubSub nodes on this service. It could be possible that the
|
||||
* PubSub service allows only certain XMPP entities (clients) to create nodes and publish items
|
||||
|
|
|
@ -26,7 +26,9 @@ import org.jivesoftware.smack.ThreadedDummyConnection;
|
|||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.packet.XMPPError;
|
||||
import org.jivesoftware.smack.packet.IQ.Type;
|
||||
import org.jivesoftware.smack.packet.XMPPError.Condition;
|
||||
import org.jivesoftware.smackx.InitExtensions;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo.Identity;
|
||||
import org.jivesoftware.smackx.pubsub.packet.PubSub;
|
||||
|
@ -39,7 +41,7 @@ import org.junit.Test;
|
|||
* @author Robin Collier
|
||||
*
|
||||
*/
|
||||
public class ConfigureFormTest
|
||||
public class ConfigureFormTest extends InitExtensions
|
||||
{
|
||||
@Test
|
||||
public void checkChildrenAssocPolicy()
|
||||
|
@ -55,6 +57,8 @@ public class ConfigureFormTest
|
|||
ThreadedDummyConnection con = ThreadedDummyConnection.newInstance();
|
||||
PubSubManager mgr = new PubSubManager(con, PubSubManagerTest.DUMMY_PUBSUB_SERVICE);
|
||||
DiscoverInfo info = new DiscoverInfo();
|
||||
info.setType(Type.result);
|
||||
info.setFrom(PubSubManagerTest.DUMMY_PUBSUB_SERVICE);
|
||||
Identity ident = new Identity("pubsub", null, "leaf");
|
||||
info.addIdentity(ident);
|
||||
con.addIQReply(info);
|
||||
|
@ -62,6 +66,8 @@ public class ConfigureFormTest
|
|||
Node node = mgr.getNode("princely_musings");
|
||||
|
||||
PubSub errorIq = new PubSub();
|
||||
errorIq.setType(Type.error);
|
||||
errorIq.setFrom(PubSubManagerTest.DUMMY_PUBSUB_SERVICE);
|
||||
XMPPError.Builder error = XMPPError.getBuilder(Condition.forbidden);
|
||||
errorIq.setError(error);
|
||||
con.addIQReply(errorIq);
|
||||
|
|
|
@ -283,14 +283,46 @@ public final class RosterEntry extends Manager {
|
|||
return other.item.equals(this.item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the RosterEntry to a Roster stanza <item/> element.
|
||||
*
|
||||
* @param entry the roster entry.
|
||||
* @return the roster item.
|
||||
*/
|
||||
static RosterPacket.Item toRosterItem(RosterEntry entry) {
|
||||
return toRosterItem(entry, entry.getName());
|
||||
return toRosterItem(entry, entry.getName(), false);
|
||||
}
|
||||
|
||||
private static RosterPacket.Item toRosterItem(RosterEntry entry, String name) {
|
||||
/**
|
||||
* Convert the RosterEntry to a Roster stanza <item/> element.
|
||||
*
|
||||
* @param entry the roster entry
|
||||
* @param name the name of the roster item.
|
||||
* @return the roster item.
|
||||
*/
|
||||
static RosterPacket.Item toRosterItem(RosterEntry entry, String name) {
|
||||
return toRosterItem(entry, name, false);
|
||||
}
|
||||
|
||||
static RosterPacket.Item toRosterItem(RosterEntry entry, boolean includeAskAttribute) {
|
||||
return toRosterItem(entry, entry.getName(), includeAskAttribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a roster entry with the given name to a roster item. As per RFC 6121 § 2.1.2.2., clients MUST NOT include
|
||||
* the 'ask' attribute, thus set {@code includeAskAttribute} to {@code false}.
|
||||
*
|
||||
* @param entry the roster entry.
|
||||
* @param name the name of the roster item.
|
||||
* @param includeAskAttribute whether or not to include the 'ask' attribute.
|
||||
* @return the roster item.
|
||||
*/
|
||||
private static RosterPacket.Item toRosterItem(RosterEntry entry, String name, boolean includeAskAttribute) {
|
||||
RosterPacket.Item item = new RosterPacket.Item(entry.getJid(), name);
|
||||
item.setItemType(entry.getType());
|
||||
if (includeAskAttribute) {
|
||||
item.setSubscriptionPending(entry.isSubscriptionPending());
|
||||
}
|
||||
item.setApproved(entry.isApproved());
|
||||
// Set the correct group names for the item.
|
||||
for (RosterGroup group : entry.getGroups()) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 Florian Schmaus
|
||||
* Copyright 2015-2017 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,10 +18,23 @@ package org.jivesoftware.smackx.ping;
|
|||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jxmpp.jid.Jid;
|
||||
|
||||
public class PingIntegrationTest extends AbstractSmackIntegrationTest {
|
||||
|
||||
|
@ -35,4 +48,52 @@ public class PingIntegrationTest extends AbstractSmackIntegrationTest {
|
|||
assertTrue(pingManager.pingMyServer());
|
||||
}
|
||||
|
||||
private static final class Pinger implements Runnable {
|
||||
private final List<Jid> toPing;
|
||||
private final Collection<Future<Boolean>> pongFutures;
|
||||
|
||||
private final PingManager pingManager;
|
||||
|
||||
private Pinger(XMPPConnection connection, Collection<Future<Boolean>> pongFutures, Jid... toPing) {
|
||||
this(connection, pongFutures, Arrays.asList(toPing));
|
||||
}
|
||||
|
||||
private Pinger(XMPPConnection connection, Collection<Future<Boolean>> pongFutures, List<Jid> toPing) {
|
||||
this.toPing = toPing;
|
||||
this.pongFutures = pongFutures;
|
||||
|
||||
this.pingManager = PingManager.getInstanceFor(connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
List<Future<Boolean>> futures = new ArrayList<>();
|
||||
for (Jid jid : toPing) {
|
||||
Future<Boolean> future = pingManager.pingAsync(jid);
|
||||
futures.add(future);
|
||||
}
|
||||
pongFutures.addAll(futures);
|
||||
}
|
||||
}
|
||||
|
||||
@SmackIntegrationTest
|
||||
public void pingAsync() throws InterruptedException, ExecutionException {
|
||||
List<Future<Boolean>> pongFutures = Collections.synchronizedList(new ArrayList<Future<Boolean>>());
|
||||
Runnable[] pinger = new Runnable[3];
|
||||
pinger[0] = new Pinger(conOne, pongFutures, conTwo.getUser(), conThree.getUser());
|
||||
pinger[1] = new Pinger(conTwo, pongFutures, conOne.getUser(), conThree.getUser());
|
||||
pinger[2] = new Pinger(conThree, pongFutures, conOne.getUser(), conTwo.getUser());
|
||||
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(pinger.length);
|
||||
for (Runnable runnable : pinger) {
|
||||
executorService.execute(runnable);
|
||||
}
|
||||
|
||||
executorService.shutdown();
|
||||
executorService.awaitTermination(1, TimeUnit.MINUTES);
|
||||
|
||||
for (Future<Boolean> pongFuture : pongFutures) {
|
||||
assertTrue(pongFuture.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2014 Florian Schmaus
|
||||
* Copyright 2014-2017 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -115,8 +115,7 @@ public class SASLDigestMD5Mechanism extends SASLMechanism {
|
|||
switch (state) {
|
||||
case INITIAL:
|
||||
for (String part : challengeParts) {
|
||||
String[] keyValue = part.split("=");
|
||||
assert (keyValue.length == 2);
|
||||
String[] keyValue = part.split("=", 2);
|
||||
String key = keyValue[0];
|
||||
// RFC 2831 § 7.1 about the formating of the digest-challenge:
|
||||
// "The full form is "<n>#<m>element" indicating at least <n> and
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright © 2014 Florian Schmaus
|
||||
* Copyright © 2014-2017 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
Loading…
Reference in a new issue