Smack 4.2.0-rc2

-----BEGIN PGP SIGNATURE-----
 
 iQF8BAABCgBmBQJYe7kjXxSAAAAAAC4AKGlzc3Vlci1mcHJAbm90YXRpb25zLm9w
 ZW5wZ3AuZmlmdGhob3JzZW1hbi5uZXQ5Nzc1MDU5RjNBMjFEQ0UxNkJFNEZCQUUy
 MjM5QTdFOEY1ODUyMDUyAAoJECI5p+j1hSBSuGkH/1mU66MNR0/ywbdZ2RKcb9MK
 WTHBBOuD/KaqkQOQQ5Fud+ktyahmDd9Nk4TbchIJ56PlEPqJbhnwP8txh1gU+8Zz
 jpRHYYQiTEuLSblToVL3afrfd/IQnOrh7VbwkG7S1wkWmOFKCv94wlv/OgZFaICc
 RHHJyJbJ0TTuavEkJ141ruNYmq/qYjUjdLmFrqhT3hv3iuiHCT1PK1787wEB0EWS
 ciwkw2j/j/2i27XNQRwu7QaLsmUGk8rLnr2/AsYpmsBsjAMqMbNEQEPbIgO9MVef
 7dt/GWoqHjH1opVcOw+rRz/cynMii2sSTXiqRVTEZsWlx3uYYz5eKsuiuckZcBs=
 =yqh1
 -----END PGP SIGNATURE-----

Merge tag '4.2.0-rc2'

Smack 4.2.0-rc2
This commit is contained in:
Florian Schmaus 2017-01-15 19:03:32 +01:00
commit 382ed9d871
53 changed files with 797 additions and 182 deletions

View File

@ -69,6 +69,7 @@ Smack Extensions and currently supported XEPs of smack-extensions
| XMPP Over BOSH | [XEP-0206](http://xmpp.org/extensions/xep-0206.html) | Use Bidirectional-streams Over Synchronous HTTP (BOSH) to transport XMPP stanzas. |
| Attention | [XEP-0224](http://xmpp.org/extensions/xep-0224.html) | Getting attention of another user. |
| Bits of Binary | [XEP-0231](http://xmpp.org/extensions/xep-0231.html) | Including or referring to small bits of binary data in an XML stanza. |
| Best Practices for Resource Locking | [XEP-0296](https://xmpp.org/extensions/xep-0296.html) | Specifies best practices to be followed by Jabber/XMPP clients about when to lock into, and unlock away from, resources. |
| Last Message Correction | [XEP-0308](http://xmpp.org/extensions/xep-0308.html) | Provides a method for indicating that a message is a correction of the last sent message. |
| [Group Chat Invitations](invitation.md) | n/a | Send invitations to other users to join a group chat room. |
| [Jive Properties](properties.md) | n/a | TODO |

View File

@ -97,8 +97,8 @@ done. The last step is to send the message as you do with any other message.
An XHTML message is like any regular message, therefore to send the message
you can follow the usual steps you do in order to send a message. For example,
to send a message as part of a chat just use the message **#send(Message)** of
_**Chat**_ or you can use the message **#send(Stanza)** of
to send a message as part of a chat just use the message **#sendMessage(Message)** of
_**Chat**_ or you can use the message **#sendStanza(Stanza)** of
_**XMPPConnection**_.
**Example**
@ -142,19 +142,20 @@ XHTML bodies of any received message.
```
// Create a listener for the chat and display any XHTML content
PacketListener packetListener = new PacketListener() {
public void processStanza(Stanza stanza) {
Message message = (Message) stanza;
IncomingChatMessageListener listener = new IncomingChatMessageListener() {
public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
// Obtain the XHTML bodies of the message
List<CharSequence> bodies = XHTMLManager.getBodies(message);
if (bodies != null) {
// Display the bodies on the console
for (CharSequence body : bodies) {
System.out.println(body);
}
if (bodies == null) {
return;
// Display the bodies on the console
for (CharSequence body : bodies) {
System.out.println(body);
}
}
};
chat.addMessageListener(packetListener);
chatManager.addListener(listener);
```
Discover support for XHTML Messages

View File

@ -70,7 +70,7 @@ created, such as the ability to disable or require encryption. See
Once you've created a connection, you should login with the
`XMPPConnection.login()` method. Once you've logged in, you can being
chatting with other users by creating new `Chat` or `GroupChat`
chatting with other users by creating new `Chat` or `MultiUserChat`
objects.
Working with the Roster
@ -98,18 +98,18 @@ your presence to let people know you're unavailable and "out fishing":
// Create a new presence. Pass in false to indicate we're unavailable._
Presence presence = new Presence(Presence.Type.unavailable);
presence.setStatus("Gone fishing");
// Send the packet (assume we have an XMPPConnection instance called "con").
// Send the stanza (assume we have an XMPPConnection instance called "con").
con.sendStanza(presence);
```
Smack provides two ways to read incoming packets: `PacketListener`, and
`PacketCollector`. Both use `StanzaFilter` instances to determine which
packets should be processed. A packet listener is used for event style
programming, while a packet collector has a result queue of packets that you
can do polling and blocking operations on. So, a packet listener is useful
when you want to take some action whenever a packet happens to come in, while
a packet collector is useful when you want to wait for a specific packet to
arrive. Packet collectors and listeners can be created using an Connection
Smack provides two ways to read incoming packets: `StanzaListener`, and
`StanzaCollector`. Both use `StanzaFilter` instances to determine which
stanzas should be processed. A stanza listener is used for event style
programming, while a stanza collector has a result queue of packets that you
can do polling and blocking operations on. So, a stanza listener is useful
when you want to take some action whenever a stanza happens to come in, while
a stanza collector is useful when you want to wait for a specific packet to
arrive. Stanza collectors and listeners can be created using an Connection
instance.
Copyright (C) Jive Software 2002-2008

View File

@ -6,7 +6,7 @@ Messaging using Chats
Sending messages back and forth is at the core of instant messaging. Although
individual messages can be sent and received as packets, it's generally easier
to treat the string of messages as a chat using the
`org.jivesoftware.smack.Chat` class.
`org.jivesoftware.smack.chat2.Chat` class.
Chat
----
@ -17,80 +17,44 @@ and then send them a text message:
```
// Assume we've created an XMPPConnection name "connection"._
ChatManager chatmanager = ChatManager.getInstanceFor(connection);
Chat newChat = chatmanager.createChat("jsmith@jivesoftware.com", new MessageListener() {
public void processMessage(Chat chat, Message message) {
System.out.println("Received message: " + message);
}
ChatManager chatManager = ChatManager.getInstanceFor(connection);
chatManager.addListener(new IncomingChatMessageListener() {
@Override
void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
System.out.println("New message from " + from ": " + message.getBody());
}
});
try {
newChat.sendMessage("Howdy!");
}
catch (XMPPException e) {
System.out.println("Error Delivering block");
EntityBareJid jid = JidCreate.entityBareFrom("jsmith@jivesoftware.com");
Chat chat = chatManager.chatWith(jid);
chat.sendMessage("Howdy!");
}
```
The `Chat.sendMessage(String)` method is a convenience method that creates a
Message object, sets the body using the String parameter, then sends the
message. In the case that you wish to set additional values on a Message
before sending it, use the `Chat.createMessage()` and
`Chat.sendMessage(Message)` methods, as in the following code snippet:
before sending it, use
`Chat.sendMessage(Message)` method, as in the following code snippet:
```
Message newMessage = new Message();
newMessage.setBody("Howdy!");
// Additional modifications to the message Stanza.
JivePropertiesManager.addProperty(newMessage, "favoriteColor", "red");
newChat.sendMessage(newMessage);
chat.sendMessage(newMessage);
```
You'll also notice in the example above that we specified a MessageListener
when creating a chat. The listener is notified any time a new message arrives
from the other user in the chat. The following code snippet uses the listener
You'll also notice in the example above that we specified an IncomingChatMessageListener.
The listener is notified any time a new chat message arrives.
The following code snippet uses the listener
as a parrot-bot -- it echoes back everything the other user types.
```
// Assume a MessageListener we've setup with a chat._
public void processMessage(Chat chat, Message message) {
// Send back the same text the other user sent us._
chat.sendMessage(message.getBody());
// Assume a IncomingChatMessageListener we've setup with a ChatManager
public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
// Send back the same text the other user sent us.
chat.sendMessage(message.getBody());
}
```
Incoming Chat
-------------
When chats are prompted by another user, the setup is slightly different since
you are receiving a chat message first. Instead of explicitly creating a chat
to send messages, you need to register to handle newly created Chat instances
when the ChatManager creates them. The ChatManager will already find a
matching chat (by thread id) and if none exists, then it will create a new one
that does match. To get this new chat, you have to register to be notified
when it happens. You can register a message listener to receive all future
messages as part of this handler.
```
// Assume we've created an XMPPConnection name "connection"._
ChatManager chatManager = ChatManager.getInstanceFor(connection);
chatManager.addChatListener(
new ChatManagerListener() {
@Override
public void chatCreated(Chat chat, boolean createdLocally)
{
if (!createdLocally)
chat.addMessageListener(new MyNewMessageListener());;
}
});
```
In addition to thread based chat messages, there are some clients that do not
send a thread id as part of the chat. To handle this scenario, Smack will
attempt match the incoming messages to the best fit existing chat, based on
the JID. It will attempt to find a chat with the same full JID, failing that,
it will try the base JID. If no existing chat to the user can found, then a
new one is created.
Copyright (C) Jive Software 2002-2008

View File

@ -182,7 +182,7 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
// Wait for the response from the server
synchronized (this) {
if (!connected) {
final long deadline = System.currentTimeMillis() + getPacketReplyTimeout();
final long deadline = System.currentTimeMillis() + getReplyTimeout();
while (!notified) {
final long now = System.currentTimeMillis();
if (now >= deadline) break;
@ -198,6 +198,9 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
+ getHost() + ":" + getPort() + ".";
throw new SmackException(errorMessage);
}
tlsHandled.reportSuccess();
saslFeatureReceived.reportSuccess();
}
public boolean isSecureConnection() {

View File

@ -169,9 +169,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
protected String streamId;
/**
*
* The timeout to wait for a reply in milliseconds.
*/
private long packetReplyTimeout = SmackConfiguration.getDefaultPacketReplyTimeout();
private long replyTimeout = SmackConfiguration.getDefaultReplyTimeout();
/**
* The SmackDebugger allows to log and debug XML traffic.
@ -188,6 +188,8 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
*/
protected Writer writer;
protected final SynchronizationPoint<SmackException> tlsHandled = new SynchronizationPoint<>(this, "establishing TLS");
/**
* Set to success if the last features stanza from the server has been parsed. A XMPP connection
* handshake can invoke multiple features stanzas, e.g. when TLS is activated a second feature
@ -198,9 +200,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
AbstractXMPPConnection.this, "last stream features received from server");
/**
* Set to success if the sasl feature has been received.
* Set to success if the SASL feature has been received.
*/
protected final SynchronizationPoint<SmackException> saslFeatureReceived = new SynchronizationPoint<SmackException>(
protected final SynchronizationPoint<XMPPException> saslFeatureReceived = new SynchronizationPoint<>(
AbstractXMPPConnection.this, "SASL mechanisms stream feature from server");
/**
@ -368,11 +370,15 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
saslAuthentication.init();
saslFeatureReceived.init();
lastFeaturesReceived.init();
tlsHandled.init();
streamId = null;
// Perform the actual connection to the XMPP service
connectInternal();
// TLS handled will be successful either if TLS was established, or if it was not mandatory.
tlsHandled.checkIfSuccessOrWaitOrThrow();
// Wait with SASL auth until the SASL mechanisms have been received
saslFeatureReceived.checkIfSuccessOrWaitOrThrow();
@ -596,7 +602,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
protected List<HostAddress> hostAddresses;
/**
* Populates {@link #hostAddresses} with at least one host address.
* Populates {@link #hostAddresses} with the resolved addresses or with the configured host address. If no host
* address was configured and all lookups failed, for example with NX_DOMAIN, then {@link #hostAddresses} will be
* populated with the empty list.
*
* @return a list of host addresses where DNS (SRV) RR resolution failed.
*/
@ -610,14 +618,15 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
else if (config.host != null) {
hostAddresses = new ArrayList<HostAddress>(1);
HostAddress hostAddress = DNSUtil.getDNSResolver().lookupHostAddress(config.host, config.port, failedAddresses, config.getDnssecMode());
hostAddresses.add(hostAddress);
if (hostAddress != null) {
hostAddresses.add(hostAddress);
}
} else {
// N.B.: Important to use config.serviceName and not AbstractXMPPConnection.serviceName
hostAddresses = DNSUtil.resolveXMPPServiceDomain(config.getXMPPServiceDomain().toString(), failedAddresses, config.getDnssecMode());
}
// If we reach this, then hostAddresses *must not* be empty, i.e. there is at least one host added, either the
// config.host one or the host representing the service name by DNSUtil
assert(!hostAddresses.isEmpty());
// Either the populated host addresses are not empty *or* there must be at least one failed address.
assert(!hostAddresses.isEmpty() || !failedAddresses.isEmpty());
return failedAddresses;
}
@ -960,14 +969,26 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
}
}
@SuppressWarnings("deprecation")
@Override
public long getPacketReplyTimeout() {
return packetReplyTimeout;
return getReplyTimeout();
}
@SuppressWarnings("deprecation")
@Override
public void setPacketReplyTimeout(long timeout) {
setReplyTimeout(timeout);
}
@Override
public void setPacketReplyTimeout(long timeout) {
packetReplyTimeout = timeout;
public long getReplyTimeout() {
return replyTimeout;
}
@Override
public void setReplyTimeout(long timeout) {
replyTimeout = timeout;
}
private static boolean replyToUnknownIqDefault = true;
@ -1407,6 +1428,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
// Only proceed with SASL auth if TLS is disabled or if the server doesn't announce it
if (!hasFeature(StartTls.ELEMENT, StartTls.NAMESPACE)
|| config.getSecurityMode() == SecurityMode.disabled) {
tlsHandled.reportSuccess();
saslFeatureReceived.reportSuccess();
}
}
@ -1456,7 +1478,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
StanzaListener callback, ExceptionCallback exceptionCallback)
throws NotConnectedException, InterruptedException {
sendStanzaWithResponseCallback(stanza, replyFilter, callback, exceptionCallback,
getPacketReplyTimeout());
getReplyTimeout());
}
@Override
@ -1517,7 +1539,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
@Override
public void sendIqWithResponseCallback(IQ iqRequest, StanzaListener callback,
ExceptionCallback exceptionCallback) throws NotConnectedException, InterruptedException {
sendIqWithResponseCallback(iqRequest, callback, exceptionCallback, getPacketReplyTimeout());
sendIqWithResponseCallback(iqRequest, callback, exceptionCallback, getReplyTimeout());
}
@Override
@ -1546,7 +1568,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
public void run() {
removeSyncStanzaListener(packetListener);
}
}, getPacketReplyTimeout(), TimeUnit.MILLISECONDS);
}, getReplyTimeout(), TimeUnit.MILLISECONDS);
}
@Override

View File

@ -200,7 +200,7 @@ public final class SASLAuthentication {
else {
currentMechanism.authenticate(username, host, xmppServiceDomain, password, authzid, sslSession);
}
final long deadline = System.currentTimeMillis() + connection.getPacketReplyTimeout();
final long deadline = System.currentTimeMillis() + connection.getReplyTimeout();
while (!authenticationSuccessful && saslException == null) {
final long now = System.currentTimeMillis();
if (now >= deadline) break;

View File

@ -101,8 +101,32 @@ public final class SmackConfiguration {
* the server. The default value is 5000 ms.
*
* @return the milliseconds to wait for a response from the server
* @deprecated use {@link #getDefaultReplyTimeout()} instead.
*/
@Deprecated
public static int getDefaultPacketReplyTimeout() {
return getDefaultReplyTimeout();
}
/**
* Sets the number of milliseconds to wait for a response from
* the server.
*
* @param timeout the milliseconds to wait for a response from the server
* @deprecated use {@link #setDefaultReplyTimeout(int)} instead.
*/
@Deprecated
public static void setDefaultPacketReplyTimeout(int timeout) {
setDefaultReplyTimeout(timeout);
}
/**
* Returns the number of milliseconds to wait for a response from
* the server. The default value is 5000 ms.
*
* @return the milliseconds to wait for a response from the server
*/
public static int getDefaultReplyTimeout() {
// The timeout value must be greater than 0 otherwise we will answer the default value
if (defaultPacketReplyTimeout <= 0) {
defaultPacketReplyTimeout = 5000;
@ -116,7 +140,7 @@ public final class SmackConfiguration {
*
* @param timeout the milliseconds to wait for a response from the server
*/
public static void setDefaultPacketReplyTimeout(int timeout) {
public static void setDefaultReplyTimeout(int timeout) {
if (timeout <= 0) {
throw new IllegalArgumentException();
}

View File

@ -58,7 +58,7 @@ public class SmackException extends Exception {
/**
* Exception thrown always when there was no response to an request within the stanza(/packet) reply timeout of the used
* connection instance. You can modify (e.g. increase) the stanza(/packet) reply timeout with
* {@link XMPPConnection#setPacketReplyTimeout(long)}.
* {@link XMPPConnection#setReplyTimeout(long)}.
*/
public static final class NoResponseException extends SmackException {
/**
@ -111,7 +111,7 @@ public class SmackException extends Exception {
}
private static StringBuilder getWaitingFor(XMPPConnection connection) {
final long replyTimeout = connection.getPacketReplyTimeout();
final long replyTimeout = connection.getReplyTimeout();
final StringBuilder sb = new StringBuilder(256);
sb.append("No response received within reply timeout. Timeout was "
+ replyTimeout + "ms (~"

View File

@ -161,7 +161,7 @@ public class StanzaCollector {
* @throws InterruptedException
*/
public <P extends Stanza> P nextResult() throws InterruptedException {
return nextResult(connection.getPacketReplyTimeout());
return nextResult(connection.getReplyTimeout());
}
private volatile long waitStart;
@ -205,7 +205,7 @@ public class StanzaCollector {
*/
public <P extends Stanza> P nextResultOrThrow() throws NoResponseException, XMPPErrorException,
InterruptedException, NotConnectedException {
return nextResultOrThrow(connection.getPacketReplyTimeout());
return nextResultOrThrow(connection.getReplyTimeout());
}
/**

View File

@ -234,7 +234,7 @@ public class SynchronizationPoint<E extends Exception> {
* @throws InterruptedException
*/
private void waitForConditionOrTimeout() throws InterruptedException {
long remainingWait = TimeUnit.MILLISECONDS.toNanos(connection.getPacketReplyTimeout());
long remainingWait = TimeUnit.MILLISECONDS.toNanos(connection.getReplyTimeout());
while (state == State.RequestSent || state == State.Initial) {
if (remainingWait <= 0) {
state = State.NoResponse;

View File

@ -410,7 +410,9 @@ public interface XMPPConnection {
* XMPPConnection instance.
*
* @return the stanza(/packet) reply timeout in milliseconds
* @deprecated use {@link #getReplyTimeout()} instead.
*/
@Deprecated
public long getPacketReplyTimeout();
/**
@ -418,9 +420,27 @@ public interface XMPPConnection {
* {@link NoResponseException} if no reply to a request was received within the timeout period.
*
* @param timeout the stanza(/packet) reply timeout in milliseconds
* @deprecated use {@link #setReplyTimeout(long)} instead.
*/
@Deprecated
public void setPacketReplyTimeout(long timeout);
/**
* Returns the current value of the reply timeout in milliseconds for request for this
* XMPPConnection instance.
*
* @return the reply timeout in milliseconds
*/
public long getReplyTimeout();
/**
* Set the stanza(/packet) reply timeout in milliseconds. In most cases, Smack will throw a
* {@link NoResponseException} if no reply to a request was received within the timeout period.
*
* @param timeout for a reply in milliseconds
*/
public void setReplyTimeout(long timeout);
/**
* Get the connection counter of this XMPPConnection instance. Those can be used as ID to
* identify the connection, but beware that the ID may not be unique if you create more then

View File

@ -0,0 +1,62 @@
/**
*
* 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.Stanza;
import org.jxmpp.jid.Jid;
public abstract class AbstractJidTypeFilter implements StanzaFilter {
protected enum JidType {
entityFull,
entityBare,
domainFull,
domainBare,
;
}
private final JidType jidType;
protected AbstractJidTypeFilter(JidType jidType) {
this.jidType = jidType;
}
protected abstract Jid getJidToInspect(Stanza stanza);
@Override
public final boolean accept(Stanza stanza) {
final Jid jid = stanza.getFrom();
if (jid == null) {
return false;
}
switch (jidType) {
case entityFull:
return jid.isEntityFullJid();
case entityBare:
return jid.isEntityBareJid();
case domainFull:
return jid.isDomainFullJid();
case domainBare:
return jid.isDomainBareJid();
default:
throw new AssertionError();
}
}
}

View File

@ -0,0 +1,38 @@
/**
*
* 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.Stanza;
import org.jxmpp.jid.Jid;
public final class FromTypeFilter extends AbstractJidTypeFilter {
public static final FromTypeFilter ENTITY_FULL_JID = new FromTypeFilter(JidType.entityFull);
public static final FromTypeFilter ENTITY_BARE_JID = new FromTypeFilter(JidType.entityBare);
public static final FromTypeFilter DOMAIN_FULL_JID = new FromTypeFilter(JidType.domainFull);
public static final FromTypeFilter DOMAIN_BARE_JID = new FromTypeFilter(JidType.domainBare);
private FromTypeFilter(JidType jidType) {
super(jidType);
}
@Override
protected Jid getJidToInspect(Stanza stanza) {
return stanza.getFrom();
}
}

View File

@ -0,0 +1,40 @@
/**
*
* 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.Stanza;
import org.jxmpp.jid.Jid;
public final class ToTypeFilter extends AbstractJidTypeFilter {
public static final ToTypeFilter ENTITY_FULL_JID = new ToTypeFilter(JidType.entityFull);
public static final ToTypeFilter ENTITY_BARE_JID = new ToTypeFilter(JidType.entityBare);
public static final ToTypeFilter DOMAIN_FULL_JID = new ToTypeFilter(JidType.domainFull);
public static final ToTypeFilter DOMAIN_BARE_JID = new ToTypeFilter(JidType.domainBare);
public static final StanzaFilter ENTITY_FULL_OR_BARE_JID = new OrFilter(ENTITY_FULL_JID, ENTITY_BARE_JID);
private ToTypeFilter(JidType jidType) {
super(jidType);
}
@Override
protected Jid getJidToInspect(Stanza stanza) {
return stanza.getTo();
}
}

View File

@ -250,14 +250,16 @@ public class DNSUtil {
List<SRVRecord> bucket = buckets.get(priority);
int bucketSize;
while ((bucketSize = bucket.size()) > 0) {
int[] totals = new int[bucket.size()];
int[] totals = new int[bucketSize];
int running_total = 0;
int count = 0;
int zeroWeight = 1;
for (SRVRecord r : bucket) {
if (r.getWeight() > 0)
if (r.getWeight() > 0) {
zeroWeight = 0;
break;
}
}
for (SRVRecord r : bucket) {

View File

@ -1,6 +1,6 @@
/**
*
* Copyright 2013-2016 Florian Schmaus
* Copyright 2013-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.
@ -50,7 +50,7 @@ public abstract class DNSResolver {
public final HostAddress lookupHostAddress(String name, int port, List<HostAddress> failedAddresses, DnssecMode dnssecMode) {
checkIfDnssecRequestedAndSupported(dnssecMode);
List<InetAddress> inetAddresses = lookupHostAddress0(name, failedAddresses, dnssecMode);
if (inetAddresses == null) {
if (inetAddresses == null || inetAddresses.isEmpty()) {
return null;
}
return new HostAddress(name, port, inetAddresses);

View File

@ -1,6 +1,6 @@
/**
*
* Copyright © 2013-2016 Florian Schmaus
* Copyright © 2013-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.
@ -25,7 +25,7 @@ import java.util.Map;
import java.util.Map.Entry;
import org.jivesoftware.smack.SmackException.ConnectionException;
import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.StringUtils;
public class HostAddress {
private final String fqdn;
@ -34,18 +34,17 @@ public class HostAddress {
private final List<InetAddress> inetAddresses;
/**
* Creates a new HostAddress with the given FQDN. The port will be set to the default XMPP client port: 5222
* Creates a new HostAddress with the given FQDN.
*
* @param fqdn Fully qualified domain name.
* @param fqdn the optional fully qualified domain name (FQDN).
* @param port The port to connect on.
* @throws IllegalArgumentException If the fqdn is null or port is out of valid range (0 - 65535).
* @throws IllegalArgumentException If the port is out of valid range (0 - 65535).
*/
public HostAddress(String fqdn, int port, List<InetAddress> inetAddresses) {
Objects.requireNonNull(fqdn, "FQDN is null");
if (port < 0 || port > 65535)
throw new IllegalArgumentException(
"Port must be a 16-bit unsiged integer (i.e. between 0-65535. Port was: " + port);
if (fqdn.charAt(fqdn.length() - 1) == '.') {
if (StringUtils.isNotEmpty(fqdn) && fqdn.charAt(fqdn.length() - 1) == '.') {
this.fqdn = fqdn.substring(0, fqdn.length() - 1);
}
else {
@ -59,7 +58,7 @@ public class HostAddress {
}
public HostAddress(int port, InetAddress hostAddress) {
this("", port, Collections.singletonList(hostAddress));
this(null, port, Collections.singletonList(hostAddress));
}
/**

View File

@ -1,6 +1,6 @@
/**
*
* Copyright 2013-2016 Florian Schmaus
* Copyright 2013-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,6 +19,8 @@ package org.jivesoftware.smack.util.dns;
import java.net.InetAddress;
import java.util.List;
import org.jivesoftware.smack.util.StringUtils;
/**
* A DNS SRV RR.
*
@ -43,6 +45,7 @@ public class SRVRecord extends HostAddress implements Comparable<SRVRecord> {
*/
public SRVRecord(String fqdn, int port, int priority, int weight, List<InetAddress> inetAddresses) {
super(fqdn, port, inetAddresses);
StringUtils.requireNotNullOrEmpty(fqdn, "The FQDN must not be null");
if (weight < 0 || weight > 65535)
throw new IllegalArgumentException(
"DNS SRV records weight must be a 16-bit unsiged integer (i.e. between 0-65535. Weight was: "

View File

@ -91,6 +91,7 @@ public class DummyConnection extends AbstractXMPPConnection {
protected void connectInternal() {
connected = true;
saslFeatureReceived.reportSuccess();
tlsHandled.reportSuccess();
streamId = "dummy-" + new Random(new Date().getTime()).nextInt();
if (reconnect) {

View File

@ -28,7 +28,7 @@ public class SmackConfigurationTest {
@Test
public void testSmackConfiguration() {
try {
SmackConfiguration.getDefaultPacketReplyTimeout();
SmackConfiguration.getDefaultReplyTimeout();
} catch (Throwable t) {
fail("SmackConfiguration threw Throwable");
}
@ -40,7 +40,7 @@ public class SmackConfigurationTest {
@Ignore
@Test
public void smackConfigurationShouldNotCauseInitializationTest() {
SmackConfiguration.getDefaultPacketReplyTimeout();
SmackConfiguration.getDefaultReplyTimeout();
// Only a call to SmackConfiguration.getVersion() should cause Smack to become initialized.
assertFalse(SmackConfiguration.isSmackInitialized());

View File

@ -18,6 +18,6 @@ package org.jivesoftware.smackx.iot.data.element;
public class Constants {
public static final String IOT_SENSORDATA_NAMESPACE = "urn:xmpp:iot:data";
public static final String IOT_SENSORDATA_NAMESPACE = "urn:xmpp:iot:sensordata";
}

View File

@ -28,8 +28,6 @@ import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.chat.Chat;
import org.jivesoftware.smack.chat.ChatManager;
import org.jivesoftware.smack.chat.ChatMessageListener;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.FromMatchesFilter;
@ -146,8 +144,10 @@ public class MultiUserChatLight {
* for the newly created chat.
* @return new Chat for sending private messages to a given room occupant.
*/
public Chat createPrivateChat(EntityJid occupant, ChatMessageListener listener) {
return ChatManager.getInstanceFor(connection).createChat(occupant, listener);
@Deprecated
// Do not re-use Chat API, which was designed for XMPP-IM 1:1 chats and not MUClight private chats.
public org.jivesoftware.smack.chat.Chat createPrivateChat(EntityJid occupant, ChatMessageListener listener) {
return org.jivesoftware.smack.chat.ChatManager.getInstanceFor(connection).createChat(occupant, listener);
}
/**

View File

@ -0,0 +1,73 @@
/**
*
* 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.chat2;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.EntityFullJid;
import org.jxmpp.jid.Jid;
public final class Chat extends Manager {
private final EntityBareJid jid;
volatile EntityFullJid lockedResource;
Presence lastPresenceOfLockedResource;
Chat(final XMPPConnection connection, EntityBareJid jid) {
super(connection);
this.jid = jid;
}
public void send(CharSequence message) throws NotConnectedException, InterruptedException {
Message stanza = new Message();
stanza.setBody(message);
send(stanza);
}
public void send(Message message) throws NotConnectedException, InterruptedException {
switch (message.getType()) {
case normal:
case chat:
break;
default:
throw new IllegalArgumentException("Message must be of type 'normal' or 'chat'");
}
Jid to = lockedResource;
if (to == null) {
to = jid;
}
message.setTo(to);
connection().sendStanza(message);
}
public EntityBareJid getXmppAddressOfChatPartner() {
return jid;
}
void unlockResource() {
lockedResource = null;
lastPresenceOfLockedResource = null;
}
}

View File

@ -0,0 +1,237 @@
/**
*
* 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.chat2;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.FromTypeFilter;
import org.jivesoftware.smack.filter.MessageTypeFilter;
import org.jivesoftware.smack.filter.MessageWithBodiesFilter;
import org.jivesoftware.smack.filter.OrFilter;
import org.jivesoftware.smack.filter.StanzaExtensionFilter;
import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.filter.ToTypeFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.roster.AbstractRosterListener;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smackx.xhtmlim.packet.XHTMLExtension;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.EntityFullJid;
import org.jxmpp.jid.Jid;
/**
* A chat manager for 1:1 XMPP instant messaging chats.
* <p>
* This manager and the according {@link Chat} API implement "Resource Locking" (XEP-0296). Support for Carbon Copies
* (XEP-0280) will be added once the XEP has progressed from experimental.
* </p>
*
* @see <a href="https://xmpp.org/extensions/xep-0296.html">XEP-0296: Best Practices for Resource Locking</a>
*/
public final class ChatManager extends Manager {
private static final Map<XMPPConnection, ChatManager> INSTANCES = new WeakHashMap<>();
public static synchronized ChatManager getInstanceFor(XMPPConnection connection) {
ChatManager chatManager = INSTANCES.get(connection);
if (chatManager == null) {
chatManager = new ChatManager(connection);
INSTANCES.put(connection, chatManager);
}
return chatManager;
}
// @FORMATTER:OFF
private static final StanzaFilter MESSAGE_FILTER = new AndFilter(
MessageTypeFilter.NORMAL_OR_CHAT,
new OrFilter(MessageWithBodiesFilter.INSTANCE), new StanzaExtensionFilter(XHTMLExtension.ELEMENT, XHTMLExtension.NAMESPACE)
);
private static final StanzaFilter OUTGOING_MESSAGE_FILTER = new AndFilter(
MESSAGE_FILTER,
ToTypeFilter.ENTITY_FULL_OR_BARE_JID
);
private static final StanzaFilter INCOMING_MESSAGE_FILTER = new AndFilter(
MESSAGE_FILTER,
FromTypeFilter.ENTITY_FULL_JID
);
// @FORMATTER:ON
private final Map<EntityBareJid, Chat> chats = new ConcurrentHashMap<>();
private final Set<IncomingChatMessageListener> incomingListeners = new CopyOnWriteArraySet<>();
private final Set<OutgoingChatMessageListener> outgoingListeners = new CopyOnWriteArraySet<>();
private boolean xhtmlIm;
private ChatManager(final XMPPConnection connection) {
super(connection);
connection.addSyncStanzaListener(new StanzaListener() {
@Override
public void processStanza(Stanza stanza) {
Message message = (Message) stanza;
if (!shouldAcceptMessage(message)) {
return;
}
final Jid from = message.getFrom();
final EntityFullJid fullFrom = from.asEntityFullJidOrThrow();
final EntityBareJid bareFrom = fullFrom.asEntityBareJid();
final Chat chat = chatWith(bareFrom);
chat.lockedResource = fullFrom;
for (IncomingChatMessageListener listener : incomingListeners) {
listener.newIncomingMessage(bareFrom, message, chat);
}
}
}, INCOMING_MESSAGE_FILTER);
connection.addPacketInterceptor(new StanzaListener() {
@Override
public void processStanza(Stanza stanza) throws NotConnectedException, InterruptedException {
Message message = (Message) stanza;
if (!shouldAcceptMessage(message)) {
return;
}
final EntityBareJid to = message.getTo().asEntityBareJidOrThrow();
final Chat chat = chatWith(to);
for (OutgoingChatMessageListener listener : outgoingListeners) {
listener.newOutgoingMessage(to, message, chat);
}
}
}, OUTGOING_MESSAGE_FILTER);
Roster roster = Roster.getInstanceFor(connection);
roster.addRosterListener(new AbstractRosterListener() {
@Override
public void presenceChanged(Presence presence) {
final Jid from = presence.getFrom();
final EntityBareJid bareFrom = from.asEntityBareJidIfPossible();
if (bareFrom == null) {
return;
}
final Chat chat = chats.get(bareFrom);
if (chat == null) {
return;
}
if (chat.lockedResource == null) {
// According to XEP-0296, no action is required for resource locking upon receiving a presence if no
// resource is currently locked.
return;
}
final EntityFullJid fullFrom = from.asEntityFullJidIfPossible();
if (!chat.lockedResource.equals(fullFrom)) {
return;
}
if (chat.lastPresenceOfLockedResource == null) {
// We have no last known presence from the locked resource.
chat.lastPresenceOfLockedResource = presence;
return;
}
if (chat.lastPresenceOfLockedResource.getMode() != presence.getMode()
|| chat.lastPresenceOfLockedResource.getType() != presence.getType()) {
chat.unlockResource();
}
}
});
}
private boolean shouldAcceptMessage(Message message) {
if (!message.getBodies().isEmpty()) {
return true;
}
// Message has no XMPP-IM bodies, abort here if xhtmlIm is not enabled.
if (!xhtmlIm) {
return false;
}
XHTMLExtension xhtmlExtension = XHTMLExtension.from(message);
if (xhtmlExtension == null) {
// Message has no XHTML-IM extension, abort.
return false;
}
return true;
}
public boolean addListener(IncomingChatMessageListener listener) {
return incomingListeners.add(listener);
}
public boolean removeListener(IncomingChatMessageListener listener) {
return incomingListeners.remove(listener);
}
public boolean addListener(OutgoingChatMessageListener listener) {
return outgoingListeners.add(listener);
}
public boolean removeOutoingLIstener(OutgoingChatMessageListener listener) {
return outgoingListeners.remove(listener);
}
/**
* Start a new or retrieve the existing chat with <code>jid</code>.
*
* @param jid the XMPP address of the other entity to chat with.
* @return the Chat API for the given XMPP address.
*/
public Chat chatWith(EntityBareJid jid) {
Chat chat = chats.get(jid);
if (chat == null) {
synchronized (chats) {
// Double-checked locking.
chat = chats.get(jid);
if (chat != null) {
return chat;
}
chat = new Chat(connection(), jid);
chats.put(jid, chat);
}
}
return chat;
}
/**
* Also notify about messages containing XHTML-IM.
*
* @param xhtmlIm
*/
public void setXhmtlImEnabled(boolean xhtmlIm) {
this.xhtmlIm = xhtmlIm;
}
}

View File

@ -0,0 +1,26 @@
/**
*
* 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.chat2;
import org.jivesoftware.smack.packet.Message;
import org.jxmpp.jid.EntityBareJid;
public interface IncomingChatMessageListener {
void newIncomingMessage(EntityBareJid from, Message message, Chat chat);
}

View File

@ -0,0 +1,26 @@
/**
*
* 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.chat2;
import org.jivesoftware.smack.packet.Message;
import org.jxmpp.jid.EntityBareJid;
public interface OutgoingChatMessageListener {
void newOutgoingMessage(EntityBareJid to, Message message, Chat chat);
}

View File

@ -0,0 +1,21 @@
/**
*
* 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 new improved API for 1:1 chats.
*/
package org.jivesoftware.smack.chat2;

View File

@ -17,7 +17,6 @@
package org.jivesoftware.smackx.chatstates;
import org.jivesoftware.smack.chat.Chat;
import org.jivesoftware.smack.chat.ChatMessageListener;
import org.jivesoftware.smack.packet.Message;
@ -35,5 +34,7 @@ public interface ChatStateListener extends ChatMessageListener {
* @param state the new state of the participant.
* @param message the message carrying the chat state.
*/
void stateChanged(Chat chat, ChatState state, Message message);
// TODO Migrate to new chat2 API on Smack 4.3.
@SuppressWarnings("deprecation")
void stateChanged(org.jivesoftware.smack.chat.Chat chat, ChatState state, Message message);
}

View File

@ -24,8 +24,6 @@ import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.chat.Chat;
import org.jivesoftware.smack.chat.ChatManager;
import org.jivesoftware.smack.chat.ChatManagerListener;
import org.jivesoftware.smack.chat.ChatMessageListener;
import org.jivesoftware.smack.filter.NotFilter;
@ -49,6 +47,8 @@ import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
* @see org.jivesoftware.smackx.chatstates.ChatState
* @see org.jivesoftware.smackx.chatstates.packet.ChatStateExtension
*/
// TODO Migrate to new chat2 API on Smack 4.3.
@SuppressWarnings("deprecation")
public final class ChatStateManager extends Manager {
public static final String NAMESPACE = "http://jabber.org/protocol/chatstates";
@ -79,13 +79,13 @@ public final class ChatStateManager extends Manager {
/**
* Maps chat to last chat state.
*/
private final Map<Chat, ChatState> chatStates = new WeakHashMap<Chat, ChatState>();
private final Map<org.jivesoftware.smack.chat.Chat, ChatState> chatStates = new WeakHashMap<>();
private final ChatManager chatManager;
private final org.jivesoftware.smack.chat.ChatManager chatManager;
private ChatStateManager(XMPPConnection connection) {
super(connection);
chatManager = ChatManager.getInstanceFor(connection);
chatManager = org.jivesoftware.smack.chat.ChatManager.getInstanceFor(connection);
chatManager.addOutgoingMessageInterceptor(outgoingInterceptor, filter);
chatManager.addChatListener(incomingInterceptor);
@ -104,7 +104,7 @@ public final class ChatStateManager extends Manager {
* @throws NotConnectedException
* @throws InterruptedException
*/
public void setCurrentState(ChatState newState, Chat chat) throws NotConnectedException, InterruptedException {
public void setCurrentState(ChatState newState, org.jivesoftware.smack.chat.Chat chat) throws NotConnectedException, InterruptedException {
if(chat == null || newState == null) {
throw new IllegalArgumentException("Arguments cannot be null.");
}
@ -133,7 +133,7 @@ public final class ChatStateManager extends Manager {
return connection().hashCode();
}
private synchronized boolean updateChatState(Chat chat, ChatState newState) {
private synchronized boolean updateChatState(org.jivesoftware.smack.chat.Chat chat, ChatState newState) {
ChatState lastChatState = chatStates.get(chat);
if (lastChatState != newState) {
chatStates.put(chat, newState);
@ -142,7 +142,7 @@ public final class ChatStateManager extends Manager {
return false;
}
private static void fireNewChatState(Chat chat, ChatState state, Message message) {
private static void fireNewChatState(org.jivesoftware.smack.chat.Chat chat, ChatState state, Message message) {
for (ChatMessageListener listener : chat.getListeners()) {
if (listener instanceof ChatStateListener) {
((ChatStateListener) listener).stateChanged(chat, state, message);
@ -154,7 +154,7 @@ public final class ChatStateManager extends Manager {
@Override
public void processMessage(Message message) {
Chat chat = chatManager.getThreadChat(message.getThread());
org.jivesoftware.smack.chat.Chat chat = chatManager.getThreadChat(message.getThread());
if (chat == null) {
return;
}
@ -166,11 +166,11 @@ public final class ChatStateManager extends Manager {
private class IncomingMessageInterceptor implements ChatManagerListener, ChatMessageListener {
public void chatCreated(final Chat chat, boolean createdLocally) {
public void chatCreated(final org.jivesoftware.smack.chat.Chat chat, boolean createdLocally) {
chat.addMessageListener(this);
}
public void processMessage(Chat chat, Message message) {
public void processMessage(org.jivesoftware.smack.chat.Chat chat, Message message) {
ExtensionElement extension = message.getExtension(NAMESPACE);
if (extension == null) {
return;

View File

@ -96,7 +96,7 @@ public abstract class StreamNegotiator {
final String eventKey = initiation.getFrom().toString() + '\t' + initiation.getSessionID();
IQ streamMethodInitiation;
try {
streamMethodInitiation = initationSetEvents.performActionAndWaitForEvent(eventKey, connection.getPacketReplyTimeout(), new Callback<NotConnectedException>() {
streamMethodInitiation = initationSetEvents.performActionAndWaitForEvent(eventKey, connection.getReplyTimeout(), new Callback<NotConnectedException>() {
@Override
public void action() throws NotConnectedException {
try {

View File

@ -335,12 +335,19 @@ public final class AccountManager extends Manager {
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
XMPPConnection connection = connection();
ExtensionElement extensionElement = connection.getFeature(Registration.ELEMENT, Registration.NAMESPACE);
ExtensionElement extensionElement = connection.getFeature(Registration.Feature.ELEMENT,
Registration.Feature.NAMESPACE);
if (extensionElement != null) {
return true;
}
return ServiceDiscoveryManager.getInstanceFor(connection).serverSupportsFeature(Registration.NAMESPACE);
// Fallback to disco#info only if this connection is authenticated, as otherwise we won't have an full JID and
// won't be able to do IQs.
if (connection.isAuthenticated()) {
return ServiceDiscoveryManager.getInstanceFor(connection).serverSupportsFeature(Registration.NAMESPACE);
}
return false;
}
/**

View File

@ -37,8 +37,6 @@ import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.chat.Chat;
import org.jivesoftware.smack.chat.ChatManager;
import org.jivesoftware.smack.chat.ChatMessageListener;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.FromMatchesFilter;
@ -357,7 +355,7 @@ public class MultiUserChat {
* @since 4.2
*/
public MucEnterConfiguration.Builder getEnterConfigurationBuilder(Resourcepart nickname) {
return new MucEnterConfiguration.Builder(nickname, connection.getPacketReplyTimeout());
return new MucEnterConfiguration.Builder(nickname, connection.getReplyTimeout());
}
/**
@ -1847,8 +1845,11 @@ public class MultiUserChat {
* created chat.
* @return new Chat for sending private messages to a given room occupant.
*/
public Chat createPrivateChat(EntityFullJid occupant, ChatMessageListener listener) {
return ChatManager.getInstanceFor(connection).createChat(occupant, listener);
// TODO This should be made new not using chat.Chat. Private MUC chats are different from XMPP-IM 1:1 chats in to many ways.
// API sketch: PrivateMucChat createPrivateChat(Resourcepart nick)
@SuppressWarnings("deprecation")
public org.jivesoftware.smack.chat.Chat createPrivateChat(EntityFullJid occupant, ChatMessageListener listener) {
return org.jivesoftware.smack.chat.ChatManager.getInstanceFor(connection).createChat(occupant, listener);
}
/**

View File

@ -158,12 +158,14 @@ public class OfflineMessageManager {
return nodes.contains(info.getNode());
}
});
int pendingNodes = nodes.size();
StanzaCollector messageCollector = connection.createStanzaCollector(messageFilter);
try {
connection.createStanzaCollectorAndSend(request).nextResultOrThrow();
// Collect the received offline messages
Message message = messageCollector.nextResult();
while (message != null) {
while (message != null && pendingNodes > 0) {
pendingNodes--;
messages.add(message);
message = messageCollector.nextResult();
}

View File

@ -186,7 +186,7 @@ public final class PingManager extends Manager {
* @throws InterruptedException
*/
public boolean ping(Jid jid) throws NotConnectedException, NoResponseException, InterruptedException {
return ping(jid, connection().getPacketReplyTimeout());
return ping(jid, connection().getReplyTimeout());
}
/**
@ -231,7 +231,7 @@ public final class PingManager extends Manager {
* @throws InterruptedException
*/
public boolean pingMyServer(boolean notifyListeners) throws NotConnectedException, InterruptedException {
return pingMyServer(notifyListeners, connection().getPacketReplyTimeout());
return pingMyServer(notifyListeners, connection().getReplyTimeout());
}
/**

View File

@ -248,7 +248,7 @@ public class PingTest extends InitExtensions {
*/
private static DummyConnection getAuthenticatedDummyConnectionWithoutIqReplies() throws SmackException, IOException, XMPPException, InterruptedException {
DummyConnection con = new DummyConnection();
con.setPacketReplyTimeout(500);
con.setReplyTimeout(500);
con.connect();
con.login();
return con;

View File

@ -88,7 +88,7 @@ public class ConfigureFormTest
Node node = mgr.getNode("princely_musings");
SmackConfiguration.setDefaultPacketReplyTimeout(100);
SmackConfiguration.setDefaultReplyTimeout(100);
con.setTimeout();
node.getNodeConfiguration();

View File

@ -36,7 +36,9 @@ import java.util.concurrent.CopyOnWriteArraySet;
* sender.
*
* @author Matt Tucker
* @deprecated use <code>org.jivesoftware.smack.chat2.Chat</code> from <code>smack-extensions</code> instead.
*/
@Deprecated
public class Chat {
private ChatManager chatManager;

View File

@ -52,7 +52,9 @@ import org.jxmpp.jid.EntityJid;
* made aware of new chats, register a listener by calling {@link #addChatListener(ChatManagerListener)}.
*
* @author Alexander Wenckus
* @deprecated use <code>org.jivesoftware.smack.chat2.ChatManager</code> from <code>smack-extensions</code> instead.
*/
@Deprecated
public final class ChatManager extends Manager{
private static final Logger LOGGER = Logger.getLogger(ChatManager.class.getName());

View File

@ -30,5 +30,6 @@ public interface ChatManagerListener {
* @param chat the chat that was created.
* @param createdLocally true if the chat was created by the local user and false if it wasn't.
*/
@SuppressWarnings("deprecation")
void chatCreated(Chat chat, boolean createdLocally);
}

View File

@ -20,5 +20,6 @@ package org.jivesoftware.smack.chat;
import org.jivesoftware.smack.packet.Message;
public interface ChatMessageListener {
@SuppressWarnings("deprecation")
void processMessage(Chat chat, Message message);
}

View File

@ -473,7 +473,7 @@ public final class Roster extends Manager {
}
protected boolean waitUntilLoaded() throws InterruptedException {
long waitTime = connection().getPacketReplyTimeout();
long waitTime = connection().getReplyTimeout();
long start = System.currentTimeMillis();
while (!isLoaded()) {
if (waitTime <= 0) {

View File

@ -24,7 +24,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.jivesoftware.smack.DummyConnection;
import org.jivesoftware.smack.chat.ChatManager.MatchMode;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Message.Type;
import org.jivesoftware.smack.packet.Stanza;
@ -35,6 +34,7 @@ import org.junit.Test;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.JidTestUtil;
@SuppressWarnings("deprecation")
public class ChatConnectionTest {
private DummyConnection dc;
@ -46,7 +46,7 @@ public class ChatConnectionTest {
public void setUp() throws Exception {
// Defaults
ChatManager.setDefaultIsNormalIncluded(true);
ChatManager.setDefaultMatchMode(MatchMode.BARE_JID);
ChatManager.setDefaultMatchMode(ChatManager.MatchMode.BARE_JID);
dc = DummyConnection.newConnectedDummyConnection();
cm = ChatManager.getInstanceFor(dc);
@ -77,14 +77,14 @@ public class ChatConnectionTest {
@Test
public void validateDefaultSetMatchModeNone() {
ChatManager.setDefaultMatchMode(MatchMode.NONE);
assertEquals(MatchMode.NONE, ChatManager.getInstanceFor(new DummyConnection()).getMatchMode());
ChatManager.setDefaultMatchMode(ChatManager.MatchMode.NONE);
assertEquals(ChatManager.MatchMode.NONE, ChatManager.getInstanceFor(new DummyConnection()).getMatchMode());
}
@Test
public void validateDefaultSetMatchModeEntityBareJid() {
ChatManager.setDefaultMatchMode(MatchMode.BARE_JID);
assertEquals(MatchMode.BARE_JID, ChatManager.getInstanceFor(new DummyConnection()).getMatchMode());
ChatManager.setDefaultMatchMode(ChatManager.MatchMode.BARE_JID);
assertEquals(ChatManager.MatchMode.BARE_JID, ChatManager.getInstanceFor(new DummyConnection()).getMatchMode());
}
@Test
@ -138,7 +138,7 @@ public class ChatConnectionTest {
// No thread behaviour
@Test
public void chatMatchedOnJIDWhenNoThreadBareMode() {
// MatchMode.BARE_JID is the default, so setting required.
// ChatManager.MatchMode.BARE_JID is the default, so setting required.
TestMessageListener msgListener = new TestMessageListener();
TestChatManagerListener listener = new TestChatManagerListener(msgListener);
cm.addChatListener(listener);
@ -162,7 +162,7 @@ public class ChatConnectionTest {
public void chatMatchedOnJIDWhenNoThreadJidMode() {
TestMessageListener msgListener = new TestMessageListener();
TestChatManagerListener listener = new TestChatManagerListener(msgListener);
cm.setMatchMode(MatchMode.SUPPLIED_JID);
cm.setMatchMode(ChatManager.MatchMode.SUPPLIED_JID);
cm.addChatListener(listener);
Stanza incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat);
@ -188,7 +188,7 @@ public class ChatConnectionTest {
public void chatMatchedOnJIDWhenNoThreadNoneMode() {
TestMessageListener msgListener = new TestMessageListener();
TestChatManagerListener listener = new TestChatManagerListener(msgListener);
cm.setMatchMode(MatchMode.NONE);
cm.setMatchMode(ChatManager.MatchMode.NONE);
cm.addChatListener(listener);
Stanza incomingChat = createChatPacket(null, true);
processServerMessage(incomingChat);

View File

@ -75,7 +75,7 @@ public class RosterTest extends InitSmackIm {
rosterListener = new TestRosterListener();
roster = Roster.getInstanceFor(connection);
roster.addRosterListener(rosterListener);
connection.setPacketReplyTimeout(1000 * 60 * 5);
connection.setReplyTimeout(1000 * 60 * 5);
}
@After

View File

@ -61,7 +61,7 @@ public class SubscriptionPreApprovalTest extends InitSmackIm {
rosterListener = new TestRosterListener();
roster = Roster.getInstanceFor(connection);
roster.addRosterListener(rosterListener);
connection.setPacketReplyTimeout(1000 * 60 * 5);
connection.setReplyTimeout(1000 * 60 * 5);
}
@After

View File

@ -133,7 +133,7 @@ public class SmackIntegrationTestFramework {
SmackConfiguration.DEBUG = true;
}
if (config.replyTimeout > 0) {
SmackConfiguration.setDefaultPacketReplyTimeout(config.replyTimeout);
SmackConfiguration.setDefaultReplyTimeout(config.replyTimeout);
}
if (config.securityMode != SecurityMode.required) {
AccountManager.sensitiveOperationOverInsecureConnectionDefault(true);

View File

@ -31,8 +31,6 @@ 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.chat.Chat;
import org.jivesoftware.smack.chat.ChatManager;
import org.jivesoftware.smack.chat.ChatManagerListener;
import org.jivesoftware.smack.filter.ThreadFilter;
import org.jivesoftware.smack.packet.Message;
@ -46,12 +44,14 @@ import org.jxmpp.stringprep.XmppStringprepException;
*/
public class ChatTest extends AbstractSmackIntegrationTest {
private final ChatManager chatManagerOne;
@SuppressWarnings("deprecation")
private final org.jivesoftware.smack.chat.ChatManager chatManagerOne;
private boolean invoked;
@SuppressWarnings("deprecation")
public ChatTest(SmackIntegrationTestEnvironment environment) {
super(environment);
chatManagerOne = ChatManager.getInstanceFor(conOne);
chatManagerOne = org.jivesoftware.smack.chat.ChatManager.getInstanceFor(conOne);
}
@BeforeClass
@ -64,9 +64,10 @@ public class ChatTest extends AbstractSmackIntegrationTest {
JivePropertiesManager.setJavaObjectEnabled(false);
}
@SuppressWarnings("deprecation")
@SmackIntegrationTest
public void testProperties() throws XmppStringprepException, NotConnectedException, Exception {
Chat newChat = chatManagerOne.createChat(conTwo.getUser());
org.jivesoftware.smack.chat.Chat newChat = chatManagerOne.createChat(conTwo.getUser());
StanzaCollector collector = conTwo.createStanzaCollector(new ThreadFilter(newChat.getThreadID()));
Message msg = new Message();
@ -112,12 +113,13 @@ public class ChatTest extends AbstractSmackIntegrationTest {
getProperty(msg2, "birthdate"));
}
@SuppressWarnings("deprecation")
@SmackIntegrationTest
public void chatManagerTest() {
ChatManagerListener listener = new ChatManagerListener() {
@Override
public void chatCreated(Chat chat, boolean createdLocally) {
public void chatCreated(org.jivesoftware.smack.chat.Chat chat, boolean createdLocally) {
invoked = true;
}

View File

@ -104,7 +104,7 @@ public class RosterIntegrationTest extends AbstractSmackIntegrationTest {
try {
rosterOne.createEntry(conTwo.getUser().asBareJid(), conTwosRosterName, null);
assertTrue(addedAndSubscribed.waitForResult(2 * connection.getPacketReplyTimeout()));
assertTrue(addedAndSubscribed.waitForResult(2 * connection.getReplyTimeout()));
}
finally {
rosterTwo.removeSubscribeListener(subscribeListener);

View File

@ -26,8 +26,6 @@ import org.igniterealtime.smack.inttest.SmackIntegrationTest;
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.StanzaCollector;
import org.jivesoftware.smack.chat.Chat;
import org.jivesoftware.smack.chat.ChatManager;
import org.jivesoftware.smack.filter.ThreadFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.xdata.packet.DataForm;
@ -51,7 +49,8 @@ public class FormTest extends AbstractSmackIntegrationTest {
* @throws InterruptedException
* @throws NotConnectedException
*/
@SmackIntegrationTest
@SuppressWarnings("deprecation")
@SmackIntegrationTest
public void testFilloutForm() throws NotConnectedException, InterruptedException {
Form formToSend = new Form(DataForm.Type.form);
formToSend.setInstructions(
@ -88,7 +87,7 @@ public class FormTest extends AbstractSmackIntegrationTest {
formToSend.addField(field);
// Create the chats between the two participants
Chat chat = ChatManager.getInstanceFor(conOne).createChat(conTwo.getUser(), null);
org.jivesoftware.smack.chat.Chat chat = org.jivesoftware.smack.chat.ChatManager.getInstanceFor(conOne).createChat(conTwo.getUser(), null);
StanzaCollector collector = conOne.createStanzaCollector(
new ThreadFilter(chat.getThreadID()));
StanzaCollector collector2 = conTwo.createStanzaCollector(

View File

@ -75,8 +75,8 @@ public class IoT {
final XMPPTCPConnection dataThingConnection = new XMPPTCPConnection(dataThingConnectionConfiguration);
final XMPPTCPConnection readingThingConnection = new XMPPTCPConnection(readingThingConnectionConfiguration);
dataThingConnection.setPacketReplyTimeout(TIMEOUT);
readingThingConnection.setPacketReplyTimeout(TIMEOUT);
dataThingConnection.setReplyTimeout(TIMEOUT);
readingThingConnection.setReplyTimeout(TIMEOUT);
dataThingConnection.setUseStreamManagement(false);
readingThingConnection.setUseStreamManagement(false);

View File

@ -89,7 +89,7 @@ public class TlsTest {
XMPPTCPConnection connection = new XMPPTCPConnection(builder.build());
connection.setPacketReplyTimeout(20000);
connection.setReplyTimeout(20000);
try {
connection.connect().login();

View File

@ -20,8 +20,10 @@ import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.jivesoftware.smack.ConnectionConfiguration.DnssecMode;
import org.jivesoftware.smack.initializer.SmackInitializer;
@ -126,10 +128,28 @@ public class MiniDnsResolver extends DNSResolver implements SmackInitializer {
return null;
}
List<InetAddress> inetAddresses = new ArrayList<>(aResult.getAnswers().size()
+ aaaaResult.getAnswers().size());
// TODO: Use ResolverResult.getAnswersOrEmptySet() once we updated MiniDNS.
Set<A> aResults;
if (aResult.wasSuccessful()) {
aResults = aResult.getAnswers();
}
else {
aResults = Collections.emptySet();
}
for (A a : aResult.getAnswers()) {
// TODO: Use ResolverResult.getAnswersOrEmptySet() once we updated MiniDNS.
Set<AAAA> aaaaResults;
if (aaaaResult.wasSuccessful()) {
aaaaResults = aaaaResult.getAnswers();
}
else {
aaaaResults = Collections.emptySet();
}
List<InetAddress> inetAddresses = new ArrayList<>(aResults.size()
+ aaaaResults.size());
for (A a : aResults) {
InetAddress inetAddress;
try {
inetAddress = InetAddress.getByAddress(a.getIp());
@ -139,7 +159,7 @@ public class MiniDnsResolver extends DNSResolver implements SmackInitializer {
}
inetAddresses.add(inetAddress);
}
for (AAAA aaaa : aaaaResult.getAnswers()) {
for (AAAA aaaa : aaaaResults) {
InetAddress inetAddress;
try {
inetAddress = InetAddress.getByAddress(name, aaaa.getIp());

View File

@ -46,6 +46,7 @@ import org.jivesoftware.smack.packet.StreamOpen;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.StartTls;
import org.jivesoftware.smack.packet.StreamError;
import org.jivesoftware.smack.sasl.packet.SaslStreamElements;
import org.jivesoftware.smack.sasl.packet.SaslStreamElements.Challenge;
import org.jivesoftware.smack.sasl.packet.SaslStreamElements.SASLFailure;
@ -593,6 +594,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
}
failedAddresses.add(hostAddress);
} else {
socket = socketFactory.createSocket();
StringUtils.requireNotNullOrEmpty(host, "Host of HostAddress " + hostAddress + " must not be null when using a Proxy");
final String hostAndPort = host + " at port " + port;
LOGGER.finer("Trying to establish TCP connection via Proxy to " + hostAndPort);
try {
@ -922,13 +925,19 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
StartTls startTlsFeature = getFeature(StartTls.ELEMENT, StartTls.NAMESPACE);
if (startTlsFeature != null) {
if (startTlsFeature.required() && config.getSecurityMode() == SecurityMode.disabled) {
notifyConnectionError(new SecurityRequiredByServerException());
SmackException smackException = new SecurityRequiredByServerException();
tlsHandled.reportFailure(smackException);
notifyConnectionError(smackException);
return;
}
if (config.getSecurityMode() != ConnectionConfiguration.SecurityMode.disabled) {
sendNonza(new StartTls());
} else {
tlsHandled.reportSuccess();
}
} else {
tlsHandled.reportSuccess();
}
if (getSASLAuthentication().authenticationSuccessful()) {
@ -1027,7 +1036,13 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
}
break;
case "error":
throw new StreamErrorException(PacketParserUtils.parseStreamError(parser));
StreamError streamError = PacketParserUtils.parseStreamError(parser);
saslFeatureReceived.reportFailure(new StreamErrorException(streamError));
// Mark the tlsHandled sync point as success, we will use the saslFeatureReceived sync
// point to report the error, which is checked immediately after tlsHandled in
// connectInternal().
tlsHandled.reportSuccess();
throw new StreamErrorException(streamError);
case "features":
parseFeatures(parser);
break;
@ -1039,9 +1054,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
openStream();
}
catch (Exception e) {
// We report any failure regarding TLS in the second stage of XMPP
// connection establishment, namely the SASL authentication
saslFeatureReceived.reportFailure(new SmackException(e));
SmackException smackException = new SmackException(e);
tlsHandled.reportFailure(smackException);
throw e;
}
break;