rudimentary bind 2 implementation
This commit is contained in:
parent
e204457c31
commit
052c58f377
|
@ -313,7 +313,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
|||
private boolean handleErrorMessage(final Account account, final MessagePacket packet) {
|
||||
if (packet.getType() == MessagePacket.TYPE_ERROR) {
|
||||
if (packet.fromServer(account)) {
|
||||
final Pair<MessagePacket, Long> forwarded = packet.getForwardedMessagePacket("received", "urn:xmpp:carbons:2");
|
||||
final Pair<MessagePacket, Long> forwarded = packet.getForwardedMessagePacket("received", Namespace.CARBONS);
|
||||
if (forwarded != null) {
|
||||
return handleErrorMessage(account, forwarded.first);
|
||||
}
|
||||
|
@ -389,8 +389,8 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
|||
return;
|
||||
} else if (original.fromServer(account)) {
|
||||
Pair<MessagePacket, Long> f;
|
||||
f = original.getForwardedMessagePacket("received", "urn:xmpp:carbons:2");
|
||||
f = f == null ? original.getForwardedMessagePacket("sent", "urn:xmpp:carbons:2") : f;
|
||||
f = original.getForwardedMessagePacket("received", Namespace.CARBONS);
|
||||
f = f == null ? original.getForwardedMessagePacket("sent", Namespace.CARBONS) : f;
|
||||
packet = f != null ? f.first : original;
|
||||
if (handleErrorMessage(account, packet)) {
|
||||
return;
|
||||
|
|
|
@ -25,9 +25,10 @@ public final class Namespace {
|
|||
public static final String NICK = "http://jabber.org/protocol/nick";
|
||||
public static final String FLEXIBLE_OFFLINE_MESSAGE_RETRIEVAL = "http://jabber.org/protocol/offline";
|
||||
public static final String BIND = "urn:ietf:params:xml:ns:xmpp-bind";
|
||||
public static final String BIND2 = "urn:xmpp:bind2:0";
|
||||
public static final String BIND2 = "urn:xmpp:bind2:1";
|
||||
public static final String STREAM_MANAGEMENT = "urn:xmpp:sm:3";
|
||||
public static final String CSI = "urn:xmpp:csi:0";
|
||||
public static final String CARBONS = "urn:xmpp:carbons:2";
|
||||
public static final String BOOKMARKS_CONVERSION = "urn:xmpp:bookmarks-conversion:0";
|
||||
public static final String BOOKMARKS = "storage:bookmarks";
|
||||
public static final String SYNCHRONIZATION = "im.quicksy.synchronization:0";
|
||||
|
|
|
@ -13,6 +13,7 @@ import android.util.SparseArray;
|
|||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Collections2;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
|
@ -32,6 +33,7 @@ import java.security.PrivateKey;
|
|||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -274,7 +276,7 @@ public class XmppConnection implements Runnable {
|
|||
this.attempt++;
|
||||
this.verifiedHostname =
|
||||
null; // will be set if user entered hostname is being used or hostname was verified
|
||||
// with dnssec
|
||||
// with dnssec
|
||||
try {
|
||||
Socket localSocket;
|
||||
shouldAuthenticate = !account.isOptionSet(Account.OPTION_REGISTER);
|
||||
|
@ -409,7 +411,7 @@ public class XmppConnection implements Runnable {
|
|||
if (startXmpp(localSocket)) {
|
||||
localSocket.setSoTimeout(
|
||||
0); // reset to 0; once the connection is established we don’t
|
||||
// want this
|
||||
// want this
|
||||
if (!hardcoded && !result.equals(storedBackupResult)) {
|
||||
mXmppConnectionService.databaseBackend.saveResolverResult(
|
||||
domain, result);
|
||||
|
@ -615,24 +617,9 @@ public class XmppConnection implements Runnable {
|
|||
throw new StateChangingException(Account.State.UNAUTHORIZED);
|
||||
}
|
||||
tagWriter.writeElement(response);
|
||||
} else if (nextTag.isStart("enabled")) {
|
||||
} else if (nextTag.isStart("enabled", Namespace.STREAM_MANAGEMENT)) {
|
||||
final Element enabled = tagReader.readElement(nextTag);
|
||||
if (enabled.getAttributeAsBoolean("resume")) {
|
||||
this.streamId = enabled.getAttribute("id");
|
||||
Log.d(
|
||||
Config.LOGTAG,
|
||||
account.getJid().asBareJid().toString()
|
||||
+ ": stream management enabled (resumable)");
|
||||
} else {
|
||||
Log.d(
|
||||
Config.LOGTAG,
|
||||
account.getJid().asBareJid().toString()
|
||||
+ ": stream management enabled");
|
||||
}
|
||||
this.stanzasReceived = 0;
|
||||
this.inSmacksSession = true;
|
||||
final RequestPacket r = new RequestPacket();
|
||||
tagWriter.writeStanzaAsync(r);
|
||||
processEnabled(enabled);
|
||||
} else if (nextTag.isStart("resumed")) {
|
||||
final Element resumed = tagReader.readElement(nextTag);
|
||||
processResumed(resumed);
|
||||
|
@ -771,13 +758,31 @@ public class XmppConnection implements Runnable {
|
|||
+ ": jid changed during SASL 2.0. updating database");
|
||||
mXmppConnectionService.databaseBackend.updateAccount(account);
|
||||
}
|
||||
final Element bound = success.findChild("bound", Namespace.BIND2);
|
||||
final Element resumed = success.findChild("resumed", "urn:xmpp:sm:3");
|
||||
final Element failed = success.findChild("failed", "urn:xmpp:sm:3");
|
||||
// TODO check if resumed and bound exist and throw bind failure
|
||||
if (resumed != null && streamId != null) {
|
||||
processResumed(resumed);
|
||||
} else if (failed != null) {
|
||||
processFailed(failed, false); // wait for new stream features
|
||||
}
|
||||
if (bound != null) {
|
||||
this.isBound = true;
|
||||
final Element streamManagementEnabled =
|
||||
bound.findChild("enabled", Namespace.STREAM_MANAGEMENT);
|
||||
final Element carbonsEnabled = bound.findChild("enabled", Namespace.CARBONS);
|
||||
if (streamManagementEnabled != null) {
|
||||
processEnabled(streamManagementEnabled);
|
||||
}
|
||||
if (carbonsEnabled != null) {
|
||||
Log.d(
|
||||
Config.LOGTAG,
|
||||
account.getJid().asBareJid() + ": successfully enabled carbons");
|
||||
features.carbonsEnabled = true;
|
||||
}
|
||||
sendPostBindInitialization(streamManagementEnabled != null, carbonsEnabled != null);
|
||||
}
|
||||
}
|
||||
if (version == SaslMechanism.Version.SASL) {
|
||||
tagReader.reset();
|
||||
|
@ -794,6 +799,27 @@ public class XmppConnection implements Runnable {
|
|||
}
|
||||
}
|
||||
|
||||
private void processEnabled(final Element enabled) {
|
||||
final String streamId;
|
||||
if (enabled.getAttributeAsBoolean("resume")) {
|
||||
streamId = enabled.getAttribute("id");
|
||||
Log.d(
|
||||
Config.LOGTAG,
|
||||
account.getJid().asBareJid().toString()
|
||||
+ ": stream management enabled (resumable)");
|
||||
} else {
|
||||
Log.d(
|
||||
Config.LOGTAG,
|
||||
account.getJid().asBareJid().toString() + ": stream management enabled");
|
||||
streamId = null;
|
||||
}
|
||||
this.streamId = streamId;
|
||||
this.stanzasReceived = 0;
|
||||
this.inSmacksSession = true;
|
||||
final RequestPacket r = new RequestPacket();
|
||||
// tagWriter.writeStanzaAsync(r);
|
||||
}
|
||||
|
||||
private void processResumed(final Element resumed) throws StateChangingException {
|
||||
this.inSmacksSession = true;
|
||||
this.isBound = true;
|
||||
|
@ -1241,6 +1267,16 @@ public class XmppConnection implements Runnable {
|
|||
final boolean inlineStreamManagement =
|
||||
inline != null && inline.hasChild("sm", "urn:xmpp:sm:3");
|
||||
final boolean inlineBind2 = inline != null && inline.hasChild("bind", Namespace.BIND2);
|
||||
final Element inlineBindFeatures =
|
||||
this.streamFeatures.findChild("inline", Namespace.BIND2);
|
||||
if (inlineBind2 && inlineBindFeatures != null) {
|
||||
final Element bind =
|
||||
generateBindRequest(
|
||||
Collections2.transform(
|
||||
inlineBindFeatures.getChildren(),
|
||||
c -> c == null ? null : c.getAttribute("var")));
|
||||
authenticate.addChild(bind);
|
||||
}
|
||||
if (inlineStreamManagement && streamId != null) {
|
||||
final ResumePacket resume = new ResumePacket(this.streamId, stanzasReceived);
|
||||
this.mSmCatchupMessageCounter.set(0);
|
||||
|
@ -1259,9 +1295,26 @@ public class XmppConnection implements Runnable {
|
|||
+ "/"
|
||||
+ saslMechanism.getMechanism());
|
||||
authenticate.setAttribute("mechanism", saslMechanism.getMechanism());
|
||||
Log.d(Config.LOGTAG, "authenticate " + authenticate);
|
||||
tagWriter.writeElement(authenticate);
|
||||
}
|
||||
|
||||
private Element generateBindRequest(final Collection<String> bindFeatures) {
|
||||
Log.d(Config.LOGTAG, "inline bind features: " + bindFeatures);
|
||||
final Element bind = new Element("bind", Namespace.BIND2);
|
||||
final Element clientId = bind.addChild("client-id");
|
||||
clientId.setAttribute("tag", mXmppConnectionService.getString(R.string.app_name));
|
||||
clientId.setContent(account.getUuid());
|
||||
final Element features = bind.addChild("features");
|
||||
if (bindFeatures.contains(Namespace.CARBONS)) {
|
||||
features.addChild("enable", Namespace.CARBONS);
|
||||
}
|
||||
if (bindFeatures.contains(Namespace.STREAM_MANAGEMENT)) {
|
||||
features.addChild("enable", Namespace.STREAM_MANAGEMENT);
|
||||
}
|
||||
return bind;
|
||||
}
|
||||
|
||||
private static List<String> extractMechanisms(final Element stream) {
|
||||
final ArrayList<String> mechanisms = new ArrayList<>(stream.getChildren().size());
|
||||
for (final Element child : stream.getChildren()) {
|
||||
|
@ -1469,7 +1522,8 @@ public class XmppConnection implements Runnable {
|
|||
.hasChild("optional")) {
|
||||
sendStartSession();
|
||||
} else {
|
||||
sendPostBindInitialization();
|
||||
final boolean waitForDisco = enableStreamManagement();
|
||||
sendPostBindInitialization(waitForDisco, false);
|
||||
}
|
||||
return;
|
||||
} catch (final IllegalArgumentException e) {
|
||||
|
@ -1565,7 +1619,8 @@ public class XmppConnection implements Runnable {
|
|||
startSession,
|
||||
(account, packet) -> {
|
||||
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
||||
sendPostBindInitialization();
|
||||
final boolean waitForDisco = enableStreamManagement();
|
||||
sendPostBindInitialization(waitForDisco, false);
|
||||
} else if (packet.getType() != IqPacket.TYPE.TIMEOUT) {
|
||||
throw new StateChangingError(Account.State.SESSION_FAILURE);
|
||||
}
|
||||
|
@ -1573,7 +1628,7 @@ public class XmppConnection implements Runnable {
|
|||
true);
|
||||
}
|
||||
|
||||
private void sendPostBindInitialization() {
|
||||
private boolean enableStreamManagement() {
|
||||
final boolean streamManagement =
|
||||
this.streamFeatures.hasChild("sm", Namespace.STREAM_MANAGEMENT);
|
||||
if (streamManagement) {
|
||||
|
@ -1583,15 +1638,22 @@ public class XmppConnection implements Runnable {
|
|||
stanzasSent = 0;
|
||||
mStanzaQueue.clear();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
features.carbonsEnabled = false;
|
||||
}
|
||||
|
||||
private void sendPostBindInitialization(
|
||||
final boolean waitForDisco, final boolean carbonsEnabled) {
|
||||
features.carbonsEnabled = carbonsEnabled;
|
||||
features.blockListRequested = false;
|
||||
synchronized (this.disco) {
|
||||
this.disco.clear();
|
||||
}
|
||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": starting service discovery");
|
||||
mPendingServiceDiscoveries.set(0);
|
||||
if (!streamManagement
|
||||
if (!waitForDisco
|
||||
|| Patches.DISCO_EXCEPTIONS.contains(
|
||||
account.getJid().getDomain().toEscapedString())) {
|
||||
Log.d(
|
||||
|
@ -1819,11 +1881,11 @@ public class XmppConnection implements Runnable {
|
|||
|
||||
private void sendEnableCarbons() {
|
||||
final IqPacket iq = new IqPacket(IqPacket.TYPE.SET);
|
||||
iq.addChild("enable", "urn:xmpp:carbons:2");
|
||||
iq.addChild("enable", Namespace.CARBONS);
|
||||
this.sendIqPacket(
|
||||
iq,
|
||||
(account, packet) -> {
|
||||
if (!packet.hasChild("error")) {
|
||||
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
||||
Log.d(
|
||||
Config.LOGTAG,
|
||||
account.getJid().asBareJid() + ": successfully enabled carbons");
|
||||
|
@ -2309,7 +2371,7 @@ public class XmppConnection implements Runnable {
|
|||
}
|
||||
|
||||
public boolean carbons() {
|
||||
return hasDiscoFeature(account.getDomain(), "urn:xmpp:carbons:2");
|
||||
return hasDiscoFeature(account.getDomain(), Namespace.CARBONS);
|
||||
}
|
||||
|
||||
public boolean commands() {
|
||||
|
|
Loading…
Reference in a new issue