diff --git a/documentation/messaging.md b/documentation/messaging.md index 3ee5a4b0c..3aa595dae 100644 --- a/documentation/messaging.md +++ b/documentation/messaging.md @@ -17,7 +17,7 @@ and then send them a text message: ``` // Assume we've created an XMPPConnection name "connection"._ -ChatManager chatmanager = connection.getChatManager(); +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); @@ -72,8 +72,9 @@ 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 = connection.getChatManager().addChatListener( +// 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) diff --git a/resources/releasedocs/changelog.html b/resources/releasedocs/changelog.html index 7a805d5f5..184c15f70 100644 --- a/resources/releasedocs/changelog.html +++ b/resources/releasedocs/changelog.html @@ -141,6 +141,19 @@ hr {
+

4.1.3 -- 2015-07-15

+ +

Bug +

+ +

4.1.2 -- 2015-06-27

Bug diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java index 3363a725f..b7bd7f699 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java @@ -477,7 +477,7 @@ public class PacketParserUtils { } break; case XmlPullParser.TEXT: - xml.append(parser.getText()); + xml.escape(parser.getText()); break; } event = parser.next(); @@ -493,7 +493,12 @@ public class PacketParserUtils { // Only append the text if the parser is not on on an empty element' start tag. Empty elements are reported // twice, so in order to prevent duplication we only add their text when we are on their end tag. if (!(event == XmlPullParser.START_TAG && parser.isEmptyElementTag())) { - sb.append(parser.getText()); + CharSequence text = parser.getText(); + if (event == XmlPullParser.TEXT) { + // TODO the toString() can be removed in Smack 4.2. + text = StringUtils.escapeForXML(text.toString()); + } + sb.append(text); } if (event == XmlPullParser.END_TAG && parser.getDepth() <= depth) { break outerloop; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java index 57c69bc1a..d05e1577e 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java @@ -20,13 +20,13 @@ import java.io.IOException; import java.net.Socket; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; +import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeoutException; @@ -113,7 +113,7 @@ public final class Socks5BytestreamManager extends Manager implements Bytestream private final static Random randomGenerator = new Random(); /* stores one Socks5BytestreamManager for each XMPP connection */ - private final static Map managers = new HashMap(); + private final static Map managers = new WeakHashMap<>(); /* * assigns a user to a listener that is informed if a bytestream request for this user is diff --git a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java index 8bcfff223..a26d34024 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java @@ -159,9 +159,16 @@ public final class Roster extends Manager { */ private final Object rosterListenersAndEntriesLock = new Object(); - // The roster is marked as initialized when at least a single roster packet - // has been received and processed. - private boolean loaded = false; + private enum RosterState { + uninitialized, + loading, + loaded, + } + + /** + * The current state of the roster. + */ + private RosterState rosterState = RosterState.uninitialized; private final PresencePacketListener presencePacketListener = new PresencePacketListener(); @@ -338,9 +345,11 @@ public final class Roster extends Manager { if (rosterStore != null && isRosterVersioningSupported()) { packet.setVersion(rosterStore.getRosterVersion()); } + rosterState = RosterState.loading; connection.sendIqWithResponseCallback(packet, new RosterResultListener(), new ExceptionCallback() { @Override public void processException(Exception exception) { + rosterState = RosterState.uninitialized; Level logLevel; if (exception instanceof NotConnectedException) { logLevel = Level.FINE; @@ -384,16 +393,15 @@ public final class Roster extends Manager { return true; } - boolean waitUntilLoaded() throws InterruptedException { - final XMPPConnection connection = connection(); - while (!loaded) { - long waitTime = connection.getPacketReplyTimeout(); - long start = System.currentTimeMillis(); + protected boolean waitUntilLoaded() throws InterruptedException { + long waitTime = connection().getPacketReplyTimeout(); + long start = System.currentTimeMillis(); + while (!isLoaded()) { if (waitTime <= 0) { break; } synchronized (this) { - if (!loaded) { + if (!isLoaded()) { wait(waitTime); } } @@ -411,7 +419,7 @@ public final class Roster extends Manager { * @since 4.1 */ public boolean isLoaded() { - return loaded; + return rosterState == RosterState.loaded; } /** @@ -1059,7 +1067,7 @@ public final class Roster extends Manager { } } } - loaded = false; + rosterState = RosterState.uninitialized; } /** @@ -1270,6 +1278,21 @@ public final class Roster extends Manager { @Override public void processPacket(Stanza packet) throws NotConnectedException, InterruptedException { + // Try to ensure that the roster is loaded when processing presence stanzas. While the + // presence listener is synchronous, the roster result listener is not, which means that + // the presence listener may be invoked with a not yet loaded roster. + if (rosterState == RosterState.loading) { + try { + waitUntilLoaded(); + } + catch (InterruptedException e) { + LOGGER.log(Level.INFO, "Presence listener was interrupted", e); + + } + } + if (!isLoaded()) { + LOGGER.warning("Roster not loaded while processing presence stanza"); + } Presence presence = (Presence) packet; Jid from = presence.getFrom(); Resourcepart fromResource = Resourcepart.EMPTY; @@ -1409,7 +1432,7 @@ public final class Roster extends Manager { } } - loaded = true; + rosterState = RosterState.loaded; synchronized (Roster.this) { Roster.this.notifyAll(); }