modify XmppConnection to change status to online for unbound cons

This commit is contained in:
Daniel Gultsch 2023-02-14 18:04:04 +01:00
parent a204bf9ec1
commit 35360fde91
No known key found for this signature in database
GPG key ID: F43D18AD2A0982C2
9 changed files with 158 additions and 114 deletions

View file

@ -2,11 +2,11 @@
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "219a451e9a1889222b7549c8b3c0a5b3",
"identityHash": "1952101c2c0d439fcd6c9d417f126a54",
"entities": [
{
"tableName": "account",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `address` TEXT NOT NULL, `resource` TEXT, `randomSeed` BLOB, `enabled` INTEGER NOT NULL, `quickStartAvailable` INTEGER NOT NULL, `pendingRegistration` INTEGER NOT NULL, `loggedInSuccessfully` INTEGER NOT NULL, `showErrorNotification` INTEGER NOT NULL, `rosterVersion` TEXT, `hostname` TEXT, `port` INTEGER, `directTls` INTEGER, `proxytype` TEXT, `proxyhostname` TEXT, `proxyport` INTEGER)",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `address` TEXT NOT NULL, `resource` TEXT, `randomSeed` BLOB, `enabled` INTEGER NOT NULL, `quickStartAvailable` INTEGER NOT NULL, `loginAndBind` INTEGER NOT NULL, `showErrorNotification` INTEGER NOT NULL, `rosterVersion` TEXT, `hostname` TEXT, `port` INTEGER, `directTls` INTEGER, `proxytype` TEXT, `proxyhostname` TEXT, `proxyport` INTEGER)",
"fields": [
{
"fieldPath": "id",
@ -45,14 +45,8 @@
"notNull": true
},
{
"fieldPath": "pendingRegistration",
"columnName": "pendingRegistration",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "loggedInSuccessfully",
"columnName": "loggedInSuccessfully",
"fieldPath": "loginAndBind",
"columnName": "loginAndBind",
"affinity": "INTEGER",
"notNull": true
},
@ -2266,7 +2260,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '219a451e9a1889222b7549c8b3c0a5b3')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1952101c2c0d439fcd6c9d417f126a54')"
]
}
}

View file

@ -16,6 +16,7 @@ public final class Namespace {
public static final String BOOKMARKS2_COMPAT = BOOKMARKS2 + "#compat";
public static final String BOOKMARKS_CONVERSION = "urn:xmpp:bookmarks-conversion:0";
public static final String BYTE_STREAMS = "http://jabber.org/protocol/bytestreams";
public static final String CAPTCHA = "urn:xmpp:captcha";
public static final String CARBONS = "urn:xmpp:carbons:2";
public static final String CHANNEL_BINDING = "urn:xmpp:sasl-cb:0";
public static final String CHAT_MARKERS = "urn:xmpp:chat-markers:0";

View file

@ -2,6 +2,7 @@ package im.conversations.android.database.dao;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import com.google.common.util.concurrent.ListenableFuture;
import eu.siacs.conversations.xmpp.Jid;
@ -13,7 +14,7 @@ import java.util.List;
@Dao
public interface AccountDao {
@Insert
@Insert(onConflict = OnConflictStrategy.REPLACE)
long insert(final AccountEntity account);
@Query("SELECT id,address,randomSeed FROM account WHERE enabled = 1")
@ -37,11 +38,8 @@ public interface AccountDao {
@Query("SELECT quickStartAvailable FROM account where id=:id")
boolean quickStartAvailable(long id);
@Query("SELECT pendingRegistration FROM account where id=:id")
boolean pendingRegistration(long id);
@Query("SELECT loggedInSuccessfully == 0 FROM account where id=:id")
boolean isInitialLogin(long id);
@Query("SELECT loginAndBind FROM account where id=:id")
boolean loginAndBind(long id);
@Query(
"UPDATE account set quickStartAvailable=:available WHERE id=:id AND"
@ -49,14 +47,9 @@ public interface AccountDao {
void setQuickStartAvailable(long id, boolean available);
@Query(
"UPDATE account set pendingRegistration=:pendingRegistration WHERE id=:id AND"
+ " pendingRegistration != :pendingRegistration")
void setPendingRegistration(long id, boolean pendingRegistration);
@Query(
"UPDATE account set loggedInSuccessfully=:loggedInSuccessfully WHERE id=:id AND"
+ " loggedInSuccessfully != :loggedInSuccessfully")
int setLoggedInSuccessfully(long id, boolean loggedInSuccessfully);
"UPDATE account set loginAndBind=:loginAndBind WHERE id=:id AND"
+ " loginAndBind != :loginAndBind")
void setLoginAndBind(long id, boolean loginAndBind);
@Query(
"UPDATE account set showErrorNotification=:showErrorNotification WHERE id=:id AND"

View file

@ -28,11 +28,7 @@ public class AccountEntity {
public boolean enabled;
public boolean quickStartAvailable = false;
public boolean pendingRegistration = false;
// TODO this is only used during setup; depending on how the setup procedure will look in the
// future we might get rid of this property
public boolean loggedInSuccessfully = false;
public boolean loginAndBind = true;
public boolean showErrorNotification = true;

View file

@ -5,12 +5,15 @@ import androidx.annotation.NonNull;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.IDs;
import im.conversations.android.database.CredentialStore;
import im.conversations.android.database.entity.AccountEntity;
import im.conversations.android.database.model.Account;
import im.conversations.android.xmpp.ConnectionPool;
import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.manager.RegistrationManager;
public class AccountRepository extends AbstractRepository {
@ -18,7 +21,8 @@ public class AccountRepository extends AbstractRepository {
super(context);
}
private Account createAccount(@NonNull final Jid address, final String password) {
private Account createAccount(
@NonNull final Jid address, final String password, final boolean loginAndBind) {
Preconditions.checkArgument(
address.isBareJid(), "Account should be specified without resource");
Preconditions.checkArgument(password != null, "Missing password");
@ -26,6 +30,7 @@ public class AccountRepository extends AbstractRepository {
final var entity = new AccountEntity();
entity.address = address;
entity.enabled = true;
entity.loginAndBind = loginAndBind;
entity.randomSeed = randomSeed;
final long id = database.accountDao().insert(entity);
final var account = new Account(id, address, entity.randomSeed);
@ -38,8 +43,23 @@ public class AccountRepository extends AbstractRepository {
return account;
}
public ListenableFuture<Account> createAccountAsync(
final @NonNull Jid address, final String password, final boolean loginAndBind) {
return Futures.submit(() -> createAccount(address, password, loginAndBind), IO_EXECUTOR);
}
public ListenableFuture<Account> createAccountAsync(
final @NonNull Jid address, final String password) {
return Futures.submit(() -> createAccount(address, password), IO_EXECUTOR);
return createAccountAsync(address, password, true);
}
public ListenableFuture<RegistrationManager.Registration> getRegistration(
final Account account) {
final ListenableFuture<XmppConnection> connectedFuture =
ConnectionPool.getInstance(context).reconfigure(account).asConnectedFuture();
return Futures.transformAsync(
connectedFuture,
xc -> xc.getManager(RegistrationManager.class).getRegistration(),
MoreExecutors.directExecutor());
}
}

View file

@ -118,10 +118,14 @@ import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.HttpUrl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmlpull.v1.XmlPullParserException;
public class XmppConnection implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(XmppConnection.class);
protected final Account account;
private final SparseArray<Stanza> mStanzaQueue = new SparseArray<>();
private final Hashtable<String, Pair<Iq, Consumer<Iq>>> packetCallbacks = new Hashtable<>();
@ -289,9 +293,9 @@ public class XmppConnection implements Runnable {
try {
Socket localSocket;
shouldAuthenticate =
!ConversationsDatabase.getInstance(context)
ConversationsDatabase.getInstance(context)
.accountDao()
.pendingRegistration(account.id);
.loginAndBind(account.id);
this.changeStatus(ConnectionState.CONNECTING);
// TODO introduce proxy check
final boolean useTor = /*fcontext.useTorToConnect() ||*/ account.isOnion();
@ -1177,7 +1181,7 @@ public class XmppConnection implements Runnable {
final SSLSocket sslSocket = upgradeSocketToTls(socket);
tagReader.setInputStream(sslSocket.getInputStream());
tagWriter.setOutputStream(sslSocket.getOutputStream());
Log.d(Config.LOGTAG, account.address + ": TLS connection established");
LOGGER.info("TLS connection established");
final boolean quickStart;
try {
quickStart = establishStream(SSLSockets.version(sslSocket));
@ -1234,13 +1238,10 @@ public class XmppConnection implements Runnable {
}
private void processStreamFeatures(final Tag currentTag) throws IOException {
final boolean pendingRegistration =
ConversationsDatabase.getInstance(context)
.accountDao()
.pendingRegistration(account.id);
final boolean loginAndBind =
ConversationsDatabase.getInstance(context).accountDao().loginAndBind(account.id);
this.streamFeatures = tagReader.readElement(currentTag, Features.class);
final boolean isSecure = isSecure();
final boolean needsBinding = !isBound && !pendingRegistration;
final boolean needsBinding = !isBound && loginAndBind;
if (this.quickStartInProgress) {
if (this.streamFeatures.hasChild("authentication", Namespace.SASL_2)) {
Log.d(
@ -1271,29 +1272,23 @@ public class XmppConnection implements Runnable {
throw new StateChangingException(ConnectionState.INCOMPATIBLE_SERVER);
}
if (this.streamFeatures.hasChild("starttls", Namespace.TLS) && !this.encryptionEnabled) {
LOGGER.info("Negotiating TLS (STARTTLS)");
sendStartTLS();
} else if (this.streamFeatures.hasChild("register", Namespace.REGISTER_STREAM_FEATURE)
&& pendingRegistration) {
if (isSecure) {
register();
} else {
Log.d(
Config.LOGTAG,
account.address
+ ": unable to find STARTTLS for registration process "
+ XmlHelper.printElementNames(this.streamFeatures));
throw new StateChangingException(ConnectionState.INCOMPATIBLE_SERVER);
}
} else if (!this.streamFeatures.hasChild("register", Namespace.REGISTER_STREAM_FEATURE)
&& pendingRegistration) {
throw new StateChangingException(ConnectionState.REGISTRATION_NOT_SUPPORTED);
return;
} else if (!isSecure()) {
LOGGER.error("Server does not support STARTTLS");
throw new StateChangingException(ConnectionState.INCOMPATIBLE_SERVER);
}
if (Boolean.FALSE.equals(loginAndBind)) {
LOGGER.info("No login and bind required. Connection is considered online");
this.lastPacketReceived = SystemClock.elapsedRealtime();
this.changeStatus(ConnectionState.ONLINE);
} else if (this.streamFeatures.hasChild("authentication", Namespace.SASL_2)
&& shouldAuthenticate
&& isSecure) {
&& shouldAuthenticate) {
authenticate(SaslMechanism.Version.SASL_2);
} else if (this.streamFeatures.hasChild("mechanisms", Namespace.SASL)
&& shouldAuthenticate
&& isSecure) {
&& shouldAuthenticate) {
authenticate(SaslMechanism.Version.SASL);
} else if (this.streamFeatures.streamManagement() && streamId != null && !inSmacksSession) {
if (Config.EXTENDED_SM_LOGGING) {
@ -1306,7 +1301,7 @@ public class XmppConnection implements Runnable {
this.mWaitingForSmCatchup.set(true);
this.tagWriter.writeStanzaAsync(resume);
} else if (needsBinding) {
if (this.streamFeatures.hasChild("bind", Namespace.BIND) && isSecure) {
if (this.streamFeatures.hasChild("bind", Namespace.BIND)) {
sendBindRequest();
} else {
Log.d(
@ -1516,7 +1511,7 @@ public class XmppConnection implements Runnable {
}
final Iq preAuthRequest = new Iq(Iq.Type.SET);
preAuthRequest.addChild("preauth", Namespace.PARS).setAttribute("token", preAuth);
sendUnmodifiedIqPacket(
sendIqPacketUnbound(
preAuthRequest,
(response) -> {
if (response.getType() == Iq.Type.RESULT) {
@ -1526,15 +1521,14 @@ public class XmppConnection implements Runnable {
Log.d(Config.LOGTAG, account.address + ": failed to pre auth. " + error);
throw new StateChangingError(ConnectionState.REGISTRATION_INVALID_TOKEN);
}
},
true);
});
}
private void sendRegistryRequest() {
final Iq retrieveRegistration = new Iq(Iq.Type.GET);
retrieveRegistration.addExtension(new Register());
retrieveRegistration.setTo(account.address.getDomain());
sendUnmodifiedIqPacket(
sendIqPacketUnbound(
retrieveRegistration,
(packet) -> {
if (packet.getType() == Iq.Type.TIMEOUT) {
@ -1562,8 +1556,7 @@ public class XmppConnection implements Runnable {
register.addChild(username);
register.addChild(password);
registrationRequest.setFrom(account.address);
sendUnmodifiedIqPacket(
registrationRequest, this::handleRegistrationResponse, true);
sendIqPacketUnbound(registrationRequest, this::handleRegistrationResponse);
} else if (query.hasChild("x", Namespace.DATA)) {
final Data data = Data.parse(query.findChild("x", Namespace.DATA));
final Element blob = query.findChild("data", "urn:xmpp:bob");
@ -1621,15 +1614,14 @@ public class XmppConnection implements Runnable {
}
throw new StateChangingError(ConnectionState.REGISTRATION_FAILED);
}
},
true);
});
}
private void handleRegistrationResponse(final Iq packet) {
if (packet.getType() == Iq.Type.RESULT) {
ConversationsDatabase.getInstance(context)
.accountDao()
.setPendingRegistration(account.id, false);
.setLoginAndBind(account.id, true);
Log.d(
Config.LOGTAG,
account.address + ": successfully registered new account on server");
@ -1693,7 +1685,7 @@ public class XmppConnection implements Runnable {
}
final Iq iq = new Iq(Iq.Type.SET);
iq.addChild("bind", Namespace.BIND).addChild("resource").setContent(resource);
this.sendUnmodifiedIqPacket(
this.sendIqPacketUnbound(
iq,
(packet) -> {
if (packet.getType() == Iq.Type.TIMEOUT) {
@ -1759,8 +1751,7 @@ public class XmppConnection implements Runnable {
+ ")");
}
throw new StateChangingError(ConnectionState.BIND_FAILURE);
},
true);
});
}
private void setConnectionAddress(final Jid jid) {
@ -1813,7 +1804,7 @@ public class XmppConnection implements Runnable {
Log.d(Config.LOGTAG, account.address + ": sending legacy session to outdated server");
final Iq startSession = new Iq(Iq.Type.SET);
startSession.addChild("session", "urn:ietf:params:xml:ns:xmpp-session");
this.sendUnmodifiedIqPacket(
this.sendIqPacketUnbound(
startSession,
(packet) -> {
if (packet.getType() == Iq.Type.RESULT) {
@ -1822,8 +1813,7 @@ public class XmppConnection implements Runnable {
} else if (packet.getType() != Iq.Type.TIMEOUT) {
throw new StateChangingError(ConnectionState.SESSION_FAILURE);
}
},
true);
});
}
// TODO the return value is not used any more
@ -2009,6 +1999,14 @@ public class XmppConnection implements Runnable {
}
public ListenableFuture<Iq> sendIqPacket(final Iq packet) {
return sendIqPacket(packet, false);
}
public ListenableFuture<Iq> sendIqPacketUnbound(final Iq packet) {
return sendIqPacket(packet, true);
}
private ListenableFuture<Iq> sendIqPacket(final Iq packet, final boolean sendToUnboundStream) {
final SettableFuture<Iq> future = SettableFuture.create();
sendIqPacket(
packet,
@ -2021,17 +2019,21 @@ public class XmppConnection implements Runnable {
} else {
future.setException(new IqErrorException(result));
}
});
},
sendToUnboundStream);
return future;
}
public String sendIqPacket(final Iq packet, final Consumer<Iq> callback) {
packet.setFrom(account.address);
return this.sendUnmodifiedIqPacket(packet, callback, false);
public void sendIqPacket(final Iq packet, final Consumer<Iq> callback) {
this.sendIqPacket(packet, callback, false);
}
public synchronized String sendUnmodifiedIqPacket(
final Iq packet, final Consumer<Iq> callback, boolean force) {
public void sendIqPacketUnbound(final Iq packet, final Consumer<Iq> callback) {
this.sendIqPacket(packet, callback, true);
}
private synchronized void sendIqPacket(
final Iq packet, final Consumer<Iq> callback, final boolean sendToUnboundStream) {
if (Strings.isNullOrEmpty(packet.getId())) {
packet.setId(IDs.medium());
}
@ -2040,8 +2042,7 @@ public class XmppConnection implements Runnable {
packetCallbacks.put(packet.getId(), new Pair<>(packet, callback));
}
}
this.sendPacket(packet, force);
return packet.getId();
this.sendPacket(packet, sendToUnboundStream);
}
public void sendResultFor(final Iq request, final Extension... extensions) {
@ -2079,14 +2080,15 @@ public class XmppConnection implements Runnable {
sendPacket(packet, false);
}
private synchronized void sendPacket(final StreamElement packet, final boolean force) {
private synchronized void sendPacket(
final StreamElement packet, final boolean sendToUnboundStream) {
if (stanzasSent == Integer.MAX_VALUE) {
resetStreamId();
disconnect(true);
return;
}
synchronized (this.mStanzaQueue) {
if (force || isBound) {
if (sendToUnboundStream || isBound) {
tagWriter.writeStanzaAsync(packet);
} else {
Log.d(
@ -2131,11 +2133,17 @@ public class XmppConnection implements Runnable {
}
public void sendPing() {
if (!r()) {
if (this.inSmacksSession) {
this.tagWriter.writeStanzaAsync(new Request());
} else {
final Iq iq = new Iq(Iq.Type.GET);
iq.setFrom(account.address);
iq.addExtension(new Ping());
this.sendIqPacket(iq, null);
this.sendIqPacket(
iq,
response -> {
LOGGER.info("Server responded to ping");
});
}
this.lastPingSent = SystemClock.elapsedRealtime();
}
@ -2213,15 +2221,6 @@ public class XmppConnection implements Runnable {
this.streamId = null;
}
public boolean r() {
if (this.inSmacksSession) {
this.tagWriter.writeStanzaAsync(new Request());
return true;
} else {
return false;
}
}
public int getTimeToNextAttempt() {
final int additionalTime =
recentErrorConnectionState == ConnectionState.POLICY_VIOLATION ? 3 : 0;

View file

@ -10,16 +10,23 @@ import eu.siacs.conversations.xml.Namespace;
import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.model.data.Data;
import im.conversations.android.xmpp.model.oob.OutOfBandData;
import im.conversations.android.xmpp.model.pars.PreAuth;
import im.conversations.android.xmpp.model.register.Instructions;
import im.conversations.android.xmpp.model.register.Password;
import im.conversations.android.xmpp.model.register.Register;
import im.conversations.android.xmpp.model.register.Remove;
import im.conversations.android.xmpp.model.register.Username;
import im.conversations.android.xmpp.model.stanza.Iq;
import java.util.Arrays;
import java.util.regex.Matcher;
import okhttp3.HttpUrl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RegistrationManager extends AbstractManager {
private static final Logger LOGGER = LoggerFactory.getLogger(RegistrationManager.class);
public RegistrationManager(Context context, XmppConnection connection) {
super(context, connection);
}
@ -27,6 +34,7 @@ public class RegistrationManager extends AbstractManager {
public ListenableFuture<Void> setPassword(final String password) {
final var account = getAccount();
final var iq = new Iq(Iq.Type.SET);
iq.setTo(account.address.getDomain());
final var register = iq.addExtension(new Register());
register.addUsername(account.address.getEscapedLocal());
register.addPassword(password);
@ -36,6 +44,7 @@ public class RegistrationManager extends AbstractManager {
public ListenableFuture<Void> unregister() {
final var iq = new Iq(Iq.Type.SET);
iq.setTo(getAccount().address.getDomain());
final var register = iq.addExtension(new Register());
register.addExtension(new Remove());
return Futures.transform(
@ -43,10 +52,11 @@ public class RegistrationManager extends AbstractManager {
}
public ListenableFuture<Registration> getRegistration() {
final var iq = new Iq(Iq.Type.SET);
final var iq = new Iq(Iq.Type.GET);
iq.setTo(getAccount().address.getDomain());
iq.addExtension(new Register());
return Futures.transform(
connection.sendIqPacket(iq),
connection.sendIqPacketUnbound(iq),
result -> {
final var register = result.getExtension(Register.class);
if (register == null) {
@ -58,7 +68,11 @@ public class RegistrationManager extends AbstractManager {
return new SimpleRegistration();
}
final var data = register.getExtension(Data.class);
if (data != null && Namespace.REGISTER.equals(data.getFormType())) {
// note that the captcha namespace is incorrect here. That namespace is only
// used in message challenges. ejabberd uses the incorrect namespace though
if (data != null
&& Arrays.asList(Namespace.REGISTER, Namespace.CAPTCHA)
.contains(data.getFormType())) {
return new ExtendedRegistration(data);
}
final var oob = register.getExtension(OutOfBandData.class);
@ -67,14 +81,14 @@ public class RegistrationManager extends AbstractManager {
instructions == null ? null : instructions.getContent();
final String redirectUrl = oob == null ? null : oob.getURL();
if (redirectUrl != null) {
return new RedirectRegistration(redirectUrl);
return RedirectRegistration.ifValid(redirectUrl);
}
if (instructionsText != null) {
final Matcher matcher = Patterns.WEB_URL.matcher(instructionsText);
if (matcher.find()) {
final String instructionsUrl =
instructionsText.substring(matcher.start(), matcher.end());
return new RedirectRegistration(instructionsUrl);
return RedirectRegistration.ifValid(instructionsUrl);
}
}
throw new IllegalStateException("No supported registration method found");
@ -82,7 +96,16 @@ public class RegistrationManager extends AbstractManager {
MoreExecutors.directExecutor());
}
private abstract static class Registration {}
public ListenableFuture<Void> sendPreAuthentication(final String token) {
final var iq = new Iq(Iq.Type.GET);
iq.setTo(getAccount().address.getDomain());
final var preAuthentication = iq.addExtension(new PreAuth());
preAuthentication.setToken(token);
return Futures.transform(
connection.sendIqPacketUnbound(iq), result -> null, MoreExecutors.directExecutor());
}
public abstract static class Registration {}
// only requires Username + Password
public static class SimpleRegistration extends Registration {}
@ -102,14 +125,23 @@ public class RegistrationManager extends AbstractManager {
// Redirection as show here: https://xmpp.org/extensions/xep-0077.html#redirect
public static class RedirectRegistration extends Registration {
private final String url;
private final HttpUrl url;
public RedirectRegistration(@NonNull final String url) {
private RedirectRegistration(@NonNull HttpUrl url) {
this.url = url;
}
public @NonNull String getURL() {
public @NonNull HttpUrl getURL() {
return this.url;
}
public static RedirectRegistration ifValid(final String url) {
final HttpUrl httpUrl = HttpUrl.parse(url);
if (httpUrl != null && httpUrl.isHttps()) {
return new RedirectRegistration(httpUrl);
}
throw new IllegalStateException(
"A URL found the registration instructions is not valid");
}
}
}

View file

@ -0,0 +1,17 @@
package im.conversations.android.xmpp.model.pars;
import eu.siacs.conversations.xml.Namespace;
import im.conversations.android.annotation.XmlElement;
import im.conversations.android.xmpp.model.Extension;
@XmlElement(namespace = Namespace.PARS)
public class PreAuth extends Extension {
public PreAuth() {
super(PreAuth.class);
}
public void setToken(final String token) {
this.setAttribute("token", token);
}
}

View file

@ -24,14 +24,6 @@ public class BindProcessor extends XmppConnection.Delegate implements Consumer<J
final var account = getAccount();
final var database = getDatabase();
final boolean firstLogin =
database.accountDao().setLoggedInSuccessfully(account.id, true) > 0;
if (firstLogin) {
// TODO publish display name if this is the first attempt
// IIRC this is used when the display name is set from a certificate or something
}
database.presenceDao().deletePresences(account.id);
getManager(RosterManager.class).fetch();