diff options
Diffstat (limited to 'src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java')
-rw-r--r-- | src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java | 333 |
1 files changed, 158 insertions, 175 deletions
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index b907ea97..4bd3668a 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -18,12 +18,12 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; +import java.net.IDN; import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -38,7 +38,6 @@ import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.X509TrustManager; -import de.duenndns.ssl.MemorizingTrustManager; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.services.XmppConnectionService; @@ -50,6 +49,8 @@ import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Tag; import eu.siacs.conversations.xml.TagWriter; import eu.siacs.conversations.xml.XmlReader; +import eu.siacs.conversations.xmpp.jid.InvalidJidException; +import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.jingle.OnJinglePacketReceived; import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket; import eu.siacs.conversations.xmpp.stanzas.AbstractStanza; @@ -65,45 +66,35 @@ import eu.siacs.conversations.xmpp.stanzas.streammgmt.ResumePacket; public class XmppConnection implements Runnable { + private static final int PACKET_IQ = 0; + private static final int PACKET_MESSAGE = 1; + private static final int PACKET_PRESENCE = 2; + private final Context applicationContext; protected Account account; - private WakeLock wakeLock; - - private SecureRandom mRandom; - private Socket socket; private XmlReader tagReader; private TagWriter tagWriter; - private Features features = new Features(this); - private boolean shouldBind = true; private boolean shouldAuthenticate = true; private Element streamFeatures; - private HashMap<String, List<String>> disco = new HashMap<String, List<String>>(); + private HashMap<String, List<String>> disco = new HashMap<>(); private String streamId = null; private int smVersion = 3; - private SparseArray<String> messageReceipts = new SparseArray<String>(); + private SparseArray<String> messageReceipts = new SparseArray<>(); private boolean usingCompression = false; private boolean usingEncryption = false; - private int stanzasReceived = 0; private int stanzasSent = 0; - private long lastPaketReceived = 0; private long lastPingSent = 0; private long lastConnect = 0; private long lastSessionStarted = 0; - private int attempt = 0; - - private static final int PACKET_IQ = 0; - private static final int PACKET_MESSAGE = 1; - private static final int PACKET_PRESENCE = 2; - - private Hashtable<String, PacketReceived> packetCallbacks = new Hashtable<String, PacketReceived>(); + private Hashtable<String, PacketReceived> packetCallbacks = new Hashtable<>(); private OnPresencePacketReceived presenceListener = null; private OnJinglePacketReceived jingleListener = null; private OnIqPacketReceived unregisteredIqListener = null; @@ -111,16 +102,14 @@ public class XmppConnection implements Runnable { private OnStatusChanged statusListener = null; private OnBindListener bindListener = null; private OnMessageAcknowledged acknowledgedListener = null; - private MemorizingTrustManager mMemorizingTrustManager; - private final Context applicationContext; + private XmppConnectionService mXmppConnectionService = null; public XmppConnection(Account account, XmppConnectionService service) { - this.mRandom = service.getRNG(); - this.mMemorizingTrustManager = service.getMemorizingTrustManager(); this.account = account; this.wakeLock = service.getPowerManager().newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, account.getJid()); + PowerManager.PARTIAL_WAKE_LOCK, account.getJid().toBareJid().toString()); tagWriter = new TagWriter(); + mXmppConnectionService = service; applicationContext = service.getApplicationContext(); } @@ -143,7 +132,7 @@ public class XmppConnection implements Runnable { } protected void connect() { - Log.d(Config.LOGTAG, account.getJid() + ": connecting"); + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": connecting"); usingCompression = false; usingEncryption = false; lastConnect = SystemClock.elapsedRealtime(); @@ -159,7 +148,7 @@ public class XmppConnection implements Runnable { Bundle result = DNSHelper.getSRVRecord(account.getServer()); ArrayList<Parcelable> values = result.getParcelableArrayList("values"); if ("timeout".equals(result.getString("error"))) { - Log.d(Config.LOGTAG, account.getJid() + ": dns timeout"); + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": dns timeout"); this.changeStatus(Account.STATUS_OFFLINE); return; } else if (values != null) { @@ -168,18 +157,24 @@ public class XmppConnection implements Runnable { while (socketError && values.size() > i) { Bundle namePort = (Bundle) values.get(i); try { - String srvRecordServer = namePort.getString("name"); + String srvRecordServer; + try { + srvRecordServer=IDN.toASCII(namePort.getString("name")); + } catch (final IllegalArgumentException e) { + // TODO: Handle me?` + srvRecordServer = ""; + } int srvRecordPort = namePort.getInt("port"); String srvIpServer = namePort.getString("ipv4"); InetSocketAddress addr; if (srvIpServer != null) { addr = new InetSocketAddress(srvIpServer, srvRecordPort); - Log.d(Config.LOGTAG, account.getJid() + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": using values from dns " + srvRecordServer + "[" + srvIpServer + "]:" + srvRecordPort); } else { addr = new InetSocketAddress(srvRecordServer, srvRecordPort); - Log.d(Config.LOGTAG, account.getJid() + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": using values from dns " + srvRecordServer + ":" + srvRecordPort); } @@ -187,10 +182,10 @@ public class XmppConnection implements Runnable { socket.connect(addr, 20000); socketError = false; } catch (UnknownHostException e) { - Log.d(Config.LOGTAG, account.getJid() + ": " + e.getMessage()); + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage()); i++; } catch (IOException e) { - Log.d(Config.LOGTAG, account.getJid() + ": " + e.getMessage()); + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage()); i++; } } @@ -199,16 +194,16 @@ public class XmppConnection implements Runnable { if (wakeLock.isHeld()) { try { wakeLock.release(); - } catch (RuntimeException re) { + } catch (final RuntimeException ignored) { } } return; } } else if (result.containsKey("error") && "nosrv".equals(result.getString("error", null))) { - socket = new Socket(account.getServer(), 5222); + socket = new Socket(account.getServer().getDomainpart(), 5222); } else { - Log.d(Config.LOGTAG, account.getJid() + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": timeout in DNS resolution"); changeStatus(Account.STATUS_OFFLINE); return; @@ -238,51 +233,38 @@ public class XmppConnection implements Runnable { if (wakeLock.isHeld()) { try { wakeLock.release(); - } catch (RuntimeException re) { + } catch (final RuntimeException ignored) { } } - return; - } catch (IOException e) { - Log.d(Config.LOGTAG, account.getJid() + ": " + e.getMessage()); + } catch (final IOException | XmlPullParserException e) { + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage()); this.changeStatus(Account.STATUS_OFFLINE); if (wakeLock.isHeld()) { try { wakeLock.release(); - } catch (RuntimeException re) { + } catch (final RuntimeException ignored) { } } - return; - } catch (NoSuchAlgorithmException e) { - Log.d(Config.LOGTAG, account.getJid() + ": " + e.getMessage()); + } catch (NoSuchAlgorithmException e) { + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage()); this.changeStatus(Account.STATUS_OFFLINE); Log.d(Config.LOGTAG, "compression exception " + e.getMessage()); if (wakeLock.isHeld()) { try { wakeLock.release(); - } catch (RuntimeException re) { + } catch (final RuntimeException ignored) { } } - return; - } catch (XmlPullParserException e) { - Log.d(Config.LOGTAG, account.getJid() + ": " + e.getMessage()); - this.changeStatus(Account.STATUS_OFFLINE); - if (wakeLock.isHeld()) { - try { - wakeLock.release(); - } catch (RuntimeException re) { - } - } - return; - } + } - } + } @Override public void run() { connect(); } - private void processStream(Tag currentTag) throws XmlPullParserException, + private void processStream(final Tag currentTag) throws XmlPullParserException, IOException, NoSuchAlgorithmException { Tag nextTag = tagReader.readTag(); while ((nextTag != null) && (!nextTag.isEnd("stream"))) { @@ -295,7 +277,7 @@ public class XmppConnection implements Runnable { } else if (nextTag.isStart("compressed")) { switchOverToZLib(nextTag); } else if (nextTag.isStart("success")) { - Log.d(Config.LOGTAG, account.getJid() + ": logged in"); + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": logged in"); tagReader.readTag(); tagReader.reset(); sendStartStream(); @@ -310,17 +292,17 @@ public class XmppConnection implements Runnable { response.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl"); response.setContent(CryptoHelper.saslDigestMd5(account, - challange, mRandom)); + challange, mXmppConnectionService.getRNG())); tagWriter.writeElement(response); } else if (nextTag.isStart("enabled")) { Element enabled = tagReader.readElement(nextTag); if ("true".equals(enabled.getAttribute("resume"))) { this.streamId = enabled.getAttribute("id"); - Log.d(Config.LOGTAG, account.getJid() + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": stream managment(" + smVersion + ") enabled (resumable)"); } else { - Log.d(Config.LOGTAG, account.getJid() + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": stream managment(" + smVersion + ") enabled"); } this.lastSessionStarted = SystemClock.elapsedRealtime(); @@ -334,11 +316,11 @@ public class XmppConnection implements Runnable { try { int serverCount = Integer.parseInt(h); if (serverCount != stanzasSent) { - Log.d(Config.LOGTAG, account.getJid() + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": session resumed with lost packages"); stanzasSent = serverCount; } else { - Log.d(Config.LOGTAG, account.getJid() + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": session resumed"); } if (acknowledgedListener != null) { @@ -350,7 +332,7 @@ public class XmppConnection implements Runnable { } } messageReceipts.clear(); - } catch (NumberFormatException e) { + } catch (final NumberFormatException ignored) { } sendInitialPing(); @@ -373,7 +355,7 @@ public class XmppConnection implements Runnable { } } else if (nextTag.isStart("failed")) { tagReader.readElement(nextTag); - Log.d(Config.LOGTAG, account.getJid() + ": resumption failed"); + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": resumption failed"); streamId = null; if (account.getStatus() != Account.STATUS_ONLINE) { sendBindRequest(); @@ -388,7 +370,7 @@ public class XmppConnection implements Runnable { nextTag = tagReader.readTag(); } if (account.getStatus() == Account.STATUS_ONLINE) { - account.setStatus(Account.STATUS_OFFLINE); + account. setStatus(Account.STATUS_OFFLINE); if (statusListener != null) { statusListener.onStatusChanged(account); } @@ -396,15 +378,15 @@ public class XmppConnection implements Runnable { } private void sendInitialPing() { - Log.d(Config.LOGTAG, account.getJid() + ": sending intial ping"); + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": sending intial ping"); IqPacket iq = new IqPacket(IqPacket.TYPE_GET); - iq.setFrom(account.getFullJid()); + iq.setFrom(account.getJid()); iq.addChild("ping", "urn:xmpp:ping"); this.sendIqPacket(iq, new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { - Log.d(Config.LOGTAG, account.getJid() + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": online with resource " + account.getResource()); changeStatus(Account.STATUS_ONLINE); } @@ -523,7 +505,7 @@ public class XmppConnection implements Runnable { tagWriter.writeElement(compress); } - private void switchOverToZLib(Tag currentTag) + private void switchOverToZLib(final Tag currentTag) throws XmlPullParserException, IOException, NoSuchAlgorithmException { tagReader.readTag(); // read tag close @@ -533,7 +515,7 @@ public class XmppConnection implements Runnable { .setInputStream(new ZLibInputStream(tagReader.getInputStream())); sendStartStream(); - Log.d(Config.LOGTAG, account.getJid() + ": compression enabled"); + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": compression enabled"); usingCompression = true; processStream(tagReader.readTag()); } @@ -553,35 +535,37 @@ public class XmppConnection implements Runnable { return getPreferences().getBoolean("enable_legacy_ssl", false); } - private void switchOverToTls(Tag currentTag) throws XmlPullParserException, + private void switchOverToTls(final Tag currentTag) throws XmlPullParserException, IOException { tagReader.readTag(); try { SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, - new X509TrustManager[]{this.mMemorizingTrustManager}, - mRandom); + new X509TrustManager[]{this.mXmppConnectionService.getMemorizingTrustManager()}, + mXmppConnectionService.getRNG()); SSLSocketFactory factory = sc.getSocketFactory(); if (factory == null) { throw new IOException("SSLSocketFactory was null"); } - HostnameVerifier verifier = this.mMemorizingTrustManager - .wrapHostnameVerifier(new StrictHostnameVerifier()); - SSLSocket sslSocket = (SSLSocket) factory.createSocket(socket, + final HostnameVerifier verifier = this.mXmppConnectionService.getMemorizingTrustManager().wrapHostnameVerifier(new StrictHostnameVerifier()); + + if (socket == null) { + throw new IOException("socket was null"); + } + final SSLSocket sslSocket = (SSLSocket) factory.createSocket(socket, socket.getInetAddress().getHostAddress(), socket.getPort(), true); // Support all protocols except legacy SSL. // The min SDK version prevents us having to worry about SSLv2. In - // future, this may be - // true of SSLv3 as well. + // future, this may be true of SSLv3 as well. final String[] supportProtocols; if (enableLegacySSL()) { supportProtocols = sslSocket.getSupportedProtocols(); } else { - final List<String> supportedProtocols = new LinkedList<String>( + final List<String> supportedProtocols = new LinkedList<>( Arrays.asList(sslSocket.getSupportedProtocols())); supportedProtocols.remove("SSLv3"); supportProtocols = new String[supportedProtocols.size()]; @@ -590,7 +574,7 @@ public class XmppConnection implements Runnable { sslSocket.setEnabledProtocols(supportProtocols); if (verifier != null - && !verifier.verify(account.getServer(), + && !verifier.verify(account.getServer().getDomainpart(), sslSocket.getSession())) { sslSocket.close(); throw new IOException("host mismatch in TLS connection"); @@ -598,17 +582,15 @@ public class XmppConnection implements Runnable { tagReader.setInputStream(sslSocket.getInputStream()); tagWriter.setOutputStream(sslSocket.getOutputStream()); sendStartStream(); - Log.d(Config.LOGTAG, account.getJid() + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": TLS connection established"); usingEncryption = true; processStream(tagReader.readTag()); sslSocket.close(); - } catch (NoSuchAlgorithmException e1) { + } catch (final NoSuchAlgorithmException | KeyManagementException e1) { e1.printStackTrace(); - } catch (KeyManagementException e) { - e.printStackTrace(); } - } + } private void sendSaslAuthPlain() throws IOException { String saslString = CryptoHelper.saslPlain(account.getUsername(), @@ -660,7 +642,7 @@ public class XmppConnection implements Runnable { } else if (this.streamFeatures.hasChild("bind") && shouldBind) { sendBindRequest(); } else { - Log.d(Config.LOGTAG, account.getJid() + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": incompatible server. disconnecting"); disconnect(true); } @@ -689,7 +671,7 @@ public class XmppConnection implements Runnable { } private List<String> extractMechanisms(Element stream) { - ArrayList<String> mechanisms = new ArrayList<String>(stream + ArrayList<String> mechanisms = new ArrayList<>(stream .getChildren().size()); for (Element child : stream.getChildren()) { mechanisms.add(child.getContent()); @@ -738,7 +720,7 @@ public class XmppConnection implements Runnable { } else { changeStatus(Account.STATUS_REGISTRATION_FAILED); disconnect(true); - Log.d(Config.LOGTAG, account.getJid() + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not register. instructions are" + instructions.getContent()); } @@ -755,10 +737,14 @@ public class XmppConnection implements Runnable { public void onIqPacketReceived(Account account, IqPacket packet) { Element bind = packet.findChild("bind"); if (bind != null) { - Element jid = bind.findChild("jid"); + final Element jid = bind.findChild("jid"); if (jid != null && jid.getContent() != null) { - account.setResource(jid.getContent().split("/", 2)[1]); - if (streamFeatures.hasChild("sm", "urn:xmpp:sm:3")) { + try { + account.setResource(Jid.fromString(jid.getContent()).getResourcepart()); + } catch (final InvalidJidException e) { + // TODO: Handle the case where an external JID is technically invalid? + } + if (streamFeatures.hasChild("sm", "urn:xmpp:sm:3")) { smVersion = 3; EnablePacket enable = new EnablePacket(smVersion); tagWriter.writeStanzaAsync(enable); @@ -787,7 +773,7 @@ public class XmppConnection implements Runnable { } }); if (this.streamFeatures.hasChild("session")) { - Log.d(Config.LOGTAG, account.getJid() + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": sending deprecated session"); IqPacket startSession = new IqPacket(IqPacket.TYPE_SET); startSession.addChild("session", @@ -796,24 +782,24 @@ public class XmppConnection implements Runnable { } } - private void sendServiceDiscoveryInfo(final String server) { - IqPacket iq = new IqPacket(IqPacket.TYPE_GET); - iq.setTo(server); + private void sendServiceDiscoveryInfo(final Jid server) { + final IqPacket iq = new IqPacket(IqPacket.TYPE_GET); + iq.setTo(server.toDomainJid()); iq.query("http://jabber.org/protocol/disco#info"); this.sendIqPacket(iq, new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { - List<Element> elements = packet.query().getChildren(); - List<String> features = new ArrayList<String>(); - for (int i = 0; i < elements.size(); ++i) { - if (elements.get(i).getName().equals("feature")) { - features.add(elements.get(i).getAttribute("var")); - } - } - disco.put(server, features); - - if (account.getServer().equals(server)) { + final List<Element> elements = packet.query().getChildren(); + final List<String> features = new ArrayList<>(); + for (Element element : elements) { + if (element.getName().equals("feature")) { + features.add(element.getAttribute("var")); + } + } + disco.put(server.toDomainJid().toString(), features); + + if (account.getServer().equals(server.toDomainJid())) { enableAdvancedStreamFeatures(); } } @@ -826,21 +812,25 @@ public class XmppConnection implements Runnable { } } - private void sendServiceDiscoveryItems(final String server) { - IqPacket iq = new IqPacket(IqPacket.TYPE_GET); - iq.setTo(server); + private void sendServiceDiscoveryItems(final Jid server) { + final IqPacket iq = new IqPacket(IqPacket.TYPE_GET); + iq.setTo(server.toDomainJid()); iq.query("http://jabber.org/protocol/disco#items"); this.sendIqPacket(iq, new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { List<Element> elements = packet.query().getChildren(); - for (int i = 0; i < elements.size(); ++i) { - if (elements.get(i).getName().equals("item")) { - String jid = elements.get(i).getAttribute("jid"); - sendServiceDiscoveryInfo(jid); - } - } + for (Element element : elements) { + if (element.getName().equals("item")) { + final String jid = element.getAttribute("jid"); + try { + sendServiceDiscoveryInfo(Jid.fromString(jid).toDomainJid()); + } catch (final InvalidJidException ignored) { + // TODO: Handle the case where an external JID is technically invalid? + } + } + } } }); } @@ -853,10 +843,10 @@ public class XmppConnection implements Runnable { @Override public void onIqPacketReceived(Account account, IqPacket packet) { if (!packet.hasChild("error")) { - Log.d(Config.LOGTAG, account.getJid() + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": successfully enabled carbons"); } else { - Log.d(Config.LOGTAG, account.getJid() + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": error enableing carbons " + packet.toString()); } } @@ -867,18 +857,18 @@ public class XmppConnection implements Runnable { throws XmlPullParserException, IOException { Element streamError = tagReader.readElement(currentTag); if (streamError != null && streamError.hasChild("conflict")) { - String resource = account.getResource().split("\\.")[0]; - account.setResource(resource + "." + nextRandomId()); - Log.d(Config.LOGTAG, - account.getJid() + ": switching resource due to conflict (" + final String resource = account.getResource().split("\\.")[0]; + account.setResource(resource + "." + nextRandomId()); + Log.d(Config.LOGTAG, + account.getJid().toBareJid() + ": switching resource due to conflict (" + account.getResource() + ")"); } } private void sendStartStream() throws IOException { Tag stream = Tag.start("stream:stream"); - stream.setAttribute("from", account.getJid()); - stream.setAttribute("to", account.getServer()); + stream.setAttribute("from", account.getJid().toBareJid().toString()); + stream.setAttribute("to", account.getServer().toString()); stream.setAttribute("version", "1.0"); stream.setAttribute("xml:lang", "en"); stream.setAttribute("xmlns", "jabber:client"); @@ -887,7 +877,7 @@ public class XmppConnection implements Runnable { } private String nextRandomId() { - return new BigInteger(50, mRandom).toString(32); + return new BigInteger(50, mXmppConnectionService.getRNG()).toString(32); } public void sendIqPacket(IqPacket packet, OnIqPacketReceived callback) { @@ -895,7 +885,7 @@ public class XmppConnection implements Runnable { String id = nextRandomId(); packet.setAttribute("id", id); } - packet.setFrom(account.getFullJid()); + packet.setFrom(account.getJid()); this.sendPacket(packet, callback); } @@ -942,7 +932,7 @@ public class XmppConnection implements Runnable { tagWriter.writeStanzaAsync(new RequestPacket(smVersion)); } else { IqPacket iq = new IqPacket(IqPacket.TYPE_GET); - iq.setFrom(account.getFullJid()); + iq.setFrom(account.getJid()); iq.addChild("ping", "urn:xmpp:ping"); this.sendIqPacket(iq, null); } @@ -982,7 +972,7 @@ public class XmppConnection implements Runnable { } public void disconnect(boolean force) { - Log.d(Config.LOGTAG, account.getJid() + ": disconnecting"); + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting"); try { if (force) { socket.close(); @@ -1016,7 +1006,7 @@ public class XmppConnection implements Runnable { } public List<String> findDiscoItemsByFeature(String feature) { - List<String> items = new ArrayList<String>(); + final List<String> items = new ArrayList<>(); for (Entry<String, List<String>> cursor : disco.entrySet()) { if (cursor.getValue().contains(feature)) { items.add(cursor.getKey()); @@ -1055,6 +1045,36 @@ public class XmppConnection implements Runnable { return this.features; } + public long getLastSessionEstablished() { + long diff; + if (this.lastSessionStarted == 0) { + diff = SystemClock.elapsedRealtime() - this.lastConnect; + } else { + diff = SystemClock.elapsedRealtime() - this.lastSessionStarted; + } + return System.currentTimeMillis() - diff; + } + + public long getLastConnect() { + return this.lastConnect; + } + + public long getLastPingSent() { + return this.lastPingSent; + } + + public long getLastPacketReceived() { + return this.lastPaketReceived; + } + + public void sendActive() { + this.sendPacket(new ActivePacket(), null); + } + + public void sendInactive() { + this.sendPacket(new InactivePacket(), null); + } + public class Features { XmppConnection connection; @@ -1062,12 +1082,10 @@ public class XmppConnection implements Runnable { this.connection = connection; } - private boolean hasDiscoFeature(String server, String feature) { - if (!connection.disco.containsKey(server)) { - return false; - } - return connection.disco.get(server).contains(feature); - } + private boolean hasDiscoFeature(final Jid server, final String feature) { + return connection.disco.containsKey(server.toDomainJid().toString()) && + connection.disco.get(server.toDomainJid().toString()).contains(feature); + } public boolean carbons() { return hasDiscoFeature(account.getServer(), "urn:xmpp:carbons:2"); @@ -1078,12 +1096,7 @@ public class XmppConnection implements Runnable { } public boolean csi() { - if (connection.streamFeatures == null) { - return false; - } else { - return connection.streamFeatures.hasChild("csi", - "urn:xmpp:csi:0"); - } + return connection.streamFeatures != null && connection.streamFeatures.hasChild("csi", "urn:xmpp:csi:0"); } public boolean pubsub() { @@ -1091,12 +1104,12 @@ public class XmppConnection implements Runnable { "http://jabber.org/protocol/pubsub#publish"); } + public boolean mam() { + return hasDiscoFeature(account.getServer(), "urn:xmpp:mam:0"); + } + public boolean rosterVersioning() { - if (connection.streamFeatures == null) { - return false; - } else { - return connection.streamFeatures.hasChild("ver"); - } + return connection.streamFeatures != null && connection.streamFeatures.hasChild("ver"); } public boolean streamhost() { @@ -1108,34 +1121,4 @@ public class XmppConnection implements Runnable { return connection.usingCompression; } } - - public long getLastSessionEstablished() { - long diff; - if (this.lastSessionStarted == 0) { - diff = SystemClock.elapsedRealtime() - this.lastConnect; - } else { - diff = SystemClock.elapsedRealtime() - this.lastSessionStarted; - } - return System.currentTimeMillis() - diff; - } - - public long getLastConnect() { - return this.lastConnect; - } - - public long getLastPingSent() { - return this.lastPingSent; - } - - public long getLastPacketReceived() { - return this.lastPaketReceived; - } - - public void sendActive() { - this.sendPacket(new ActivePacket(), null); - } - - public void sendInactive() { - this.sendPacket(new InactivePacket(), null); - } } |