Skip to content

Commit

Permalink
Merge tag '4.2.0-rc2'
Browse files Browse the repository at this point in the history
Smack 4.2.0-rc2
  • Loading branch information
Flowdalic committed Jan 15, 2017
2 parents 4cd0143 + ce19481 commit 382ed9d
Show file tree
Hide file tree
Showing 53 changed files with 796 additions and 181 deletions.
1 change: 1 addition & 0 deletions documentation/extensions/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
23 changes: 12 additions & 11 deletions documentation/extensions/xhtml.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**
Expand Down Expand Up @@ -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
Expand Down
20 changes: 10 additions & 10 deletions documentation/gettingstarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
76 changes: 20 additions & 56 deletions documentation/messaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
----
Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ protected void connectInternal() throws SmackException, InterruptedException {
// 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;
Expand All @@ -198,6 +198,9 @@ protected void connectInternal() throws SmackException, InterruptedException {
+ getHost() + ":" + getPort() + ".";
throw new SmackException(errorMessage);
}

tlsHandled.reportSuccess();
saslFeatureReceived.reportSuccess();
}

public boolean isSecureConnection() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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");

/**
Expand Down Expand Up @@ -368,11 +370,15 @@ public synchronized AbstractXMPPConnection connect() throws SmackException, IOEx
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();

Expand Down Expand Up @@ -596,7 +602,9 @@ public final String getUsedSaslMechansism() {
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.
*/
Expand All @@ -610,14 +618,15 @@ protected List<HostAddress> populateHostAddresses() {
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;
}

Expand Down Expand Up @@ -960,14 +969,26 @@ protected void initDebugger() {
}
}

@SuppressWarnings("deprecation")
@Override
public long getPacketReplyTimeout() {
return packetReplyTimeout;
return getReplyTimeout();
}

@SuppressWarnings("deprecation")
@Override
public void setPacketReplyTimeout(long timeout) {
packetReplyTimeout = timeout;
setReplyTimeout(timeout);
}

@Override
public long getReplyTimeout() {
return replyTimeout;
}

@Override
public void setReplyTimeout(long timeout) {
replyTimeout = timeout;
}

private static boolean replyToUnknownIqDefault = true;
Expand Down Expand Up @@ -1407,6 +1428,7 @@ else if (eventType == XmlPullParser.END_TAG && parser.getDepth() == initialDepth
// 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();
}
}
Expand Down Expand Up @@ -1456,7 +1478,7 @@ public void sendStanzaWithResponseCallback(Stanza stanza, StanzaFilter replyFilt
StanzaListener callback, ExceptionCallback exceptionCallback)
throws NotConnectedException, InterruptedException {
sendStanzaWithResponseCallback(stanza, replyFilter, callback, exceptionCallback,
getPacketReplyTimeout());
getReplyTimeout());
}

@Override
Expand Down Expand Up @@ -1517,7 +1539,7 @@ public void sendIqWithResponseCallback(IQ iqRequest, StanzaListener callback)
@Override
public void sendIqWithResponseCallback(IQ iqRequest, StanzaListener callback,
ExceptionCallback exceptionCallback) throws NotConnectedException, InterruptedException {
sendIqWithResponseCallback(iqRequest, callback, exceptionCallback, getPacketReplyTimeout());
sendIqWithResponseCallback(iqRequest, callback, exceptionCallback, getReplyTimeout());
}

@Override
Expand Down Expand Up @@ -1546,7 +1568,7 @@ public void processStanza(Stanza packet) throws NotConnectedException, Interrupt
public void run() {
removeSyncStanzaListener(packetListener);
}
}, getPacketReplyTimeout(), TimeUnit.MILLISECONDS);
}, getReplyTimeout(), TimeUnit.MILLISECONDS);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ public void authenticate(String username, String password, EntityBareJid authzid
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;
Expand Down
Loading

0 comments on commit 382ed9d

Please sign in to comment.