aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/de')
-rw-r--r--src/main/java/de/pixart/messenger/entities/Account.java15
-rw-r--r--src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java6
-rw-r--r--src/main/java/de/pixart/messenger/services/XmppConnectionService.java11
-rw-r--r--src/main/java/de/pixart/messenger/ui/SettingsActivity.java84
-rw-r--r--src/main/java/de/pixart/messenger/xmpp/XmppConnection.java325
5 files changed, 197 insertions, 244 deletions
diff --git a/src/main/java/de/pixart/messenger/entities/Account.java b/src/main/java/de/pixart/messenger/entities/Account.java
index c641902a3..8b2eef3eb 100644
--- a/src/main/java/de/pixart/messenger/entities/Account.java
+++ b/src/main/java/de/pixart/messenger/entities/Account.java
@@ -49,6 +49,7 @@ public class Account extends AbstractEntity {
public static final String PORT = "port";
public static final String STATUS = "status";
public static final String STATUS_MESSAGE = "status_message";
+ public static final String RESOURCE = "resource";
public static final String PINNED_MECHANISM_KEY = "pinned_mechanism";
@@ -238,6 +239,7 @@ public class Account extends AbstractEntity {
protected String rosterVersion;
protected State status = State.OFFLINE;
protected final JSONObject keys;
+ protected String resource;
protected String avatar;
protected String displayName = null;
protected String hostname = null;
@@ -266,9 +268,6 @@ public class Account extends AbstractEntity {
final Presence.Status status, String statusMessage) {
this.uuid = uuid;
this.jid = jid;
- if (jid.isBareJid()) {
- this.setResource("mobile");
- }
this.password = password;
this.options = options;
this.rosterVersion = rosterVersion;
@@ -290,8 +289,10 @@ public class Account extends AbstractEntity {
public static Account fromCursor(final Cursor cursor) {
Jid jid = null;
try {
- jid = Jid.fromParts(cursor.getString(cursor.getColumnIndex(USERNAME)),
- cursor.getString(cursor.getColumnIndex(SERVER)), "mobile");
+ jid = Jid.fromParts(
+ cursor.getString(cursor.getColumnIndex(USERNAME)),
+ cursor.getString(cursor.getColumnIndex(SERVER)),
+ cursor.getString(cursor.getColumnIndex(RESOURCE)));
} catch (final InvalidJidException ignored) {
}
return new Account(cursor.getString(cursor.getColumnIndex(UUID)),
@@ -327,6 +328,7 @@ public class Account extends AbstractEntity {
}
public boolean setJid(final Jid next) {
+ final Jid previousFull = this.jid;
final Jid prev = this.jid != null ? this.jid.toBareJid() : null;
final boolean changed = prev == null || (next != null && !prev.equals(next.toBareJid()));
if (changed) {
@@ -338,7 +340,7 @@ public class Account extends AbstractEntity {
}
}
this.jid = next;
- return changed;
+ return next != null && next.equals(previousFull);
}
public Jid getServer() {
@@ -493,6 +495,7 @@ public class Account extends AbstractEntity {
values.put(PORT, port);
values.put(STATUS, presenceStatus.toShowString());
values.put(STATUS_MESSAGE, presenceStatusMessage);
+ values.put(RESOURCE, jid.getResourcepart());
return values;
}
diff --git a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
index cc334addb..c0c74d78b 100644
--- a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
+++ b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
@@ -59,7 +59,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
private static DatabaseBackend instance = null;
public static final String DATABASE_NAME = "history";
- public static final int DATABASE_VERSION = 40; // = Conversations DATABASE_VERSION + 1
+ public static final int DATABASE_VERSION = 41; // = Conversations DATABASE_VERSION + 1
private static String CREATE_CONTATCS_STATEMENT = "create table "
+ Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, "
@@ -179,6 +179,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ Account.AVATAR + " TEXT, "
+ Account.KEYS + " TEXT, "
+ Account.HOSTNAME + " TEXT, "
+ + Account.RESOURCE + " TEXT,"
+ Account.PORT + " NUMBER DEFAULT 5222)");
db.execSQL("create table " + Conversation.TABLENAME + " ("
+ Conversation.UUID + " TEXT PRIMARY KEY, " + Conversation.NAME
@@ -301,6 +302,9 @@ public class DatabaseBackend extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.STATUS + " TEXT");
db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.STATUS_MESSAGE + " TEXT");
}
+ if (oldVersion < 41 && newVersion >= 41) {
+ db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.RESOURCE + " TEXT");
+ }
/* Any migrations that alter the Account table need to happen BEFORE this migration, as it
* depends on account de-serialization.
*/
diff --git a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
index 19266764a..74c6a84f6 100644
--- a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
+++ b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
@@ -1262,17 +1262,6 @@ public class XmppConnectionService extends Service {
}
public XmppConnection createConnection(final Account account) {
- final SharedPreferences sharedPref = getPreferences();
- String resource;
- try {
- resource = sharedPref.getString("resource", getString(R.string.default_resource)).toLowerCase(Locale.ENGLISH);
- if (resource.trim().isEmpty()) {
- throw new Exception();
- }
- } catch (Exception e) {
- resource = "Pix-Art Messenger";
- }
- account.setResource(resource);
final XmppConnection connection = new XmppConnection(account, this);
connection.setOnMessagePacketReceivedListener(this.mMessageParser);
connection.setOnStatusChangedListener(this.statusListener);
diff --git a/src/main/java/de/pixart/messenger/ui/SettingsActivity.java b/src/main/java/de/pixart/messenger/ui/SettingsActivity.java
index b6b1ba565..c832809d6 100644
--- a/src/main/java/de/pixart/messenger/ui/SettingsActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/SettingsActivity.java
@@ -11,11 +11,11 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
-import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
+import android.support.annotation.NonNull;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.LayoutInflater;
@@ -29,7 +29,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.Locale;
import de.pixart.messenger.Config;
import de.pixart.messenger.R;
@@ -37,7 +36,6 @@ import de.pixart.messenger.entities.Account;
import de.pixart.messenger.services.ExportLogsService;
import de.pixart.messenger.services.MemorizingTrustManager;
import de.pixart.messenger.ui.util.Color;
-import de.pixart.messenger.xmpp.XmppConnection;
import de.pixart.messenger.xmpp.jid.InvalidJidException;
import de.pixart.messenger.xmpp.jid.Jid;
@@ -96,16 +94,6 @@ public class SettingsActivity extends XmppActivity implements
isMultiAccountChecked = ((CheckBoxPreference) multiAccountPreference).isChecked();
}
- ListPreference resources = (ListPreference) mSettingsFragment.findPreference("resource");
- if (resources != null) {
- ArrayList<CharSequence> entries = new ArrayList<>(Arrays.asList(resources.getEntries()));
- if (!entries.contains(Build.MODEL)) {
- entries.add(0, Build.MODEL);
- resources.setEntries(entries.toArray(new CharSequence[entries.size()]));
- resources.setEntryValues(entries.toArray(new CharSequence[entries.size()]));
- }
- }
-
if (Config.FORCE_ORBOT) {
PreferenceCategory connectionOptions = (PreferenceCategory) mSettingsFragment.findPreference("connection_options");
PreferenceScreen expert = (PreferenceScreen) mSettingsFragment.findPreference("expert");
@@ -303,36 +291,29 @@ public class SettingsActivity extends XmppActivity implements
}
}
final boolean[] checkedItems = new boolean[accounts.size()];
- builder.setMultiChoiceItems(accounts.toArray(new CharSequence[accounts.size()]), checkedItems, new DialogInterface.OnMultiChoiceClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which, boolean isChecked) {
- checkedItems[which] = isChecked;
- final AlertDialog alertDialog = (AlertDialog) dialog;
- for (boolean item : checkedItems) {
- if (item) {
- alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true);
- return;
- }
+ builder.setMultiChoiceItems(accounts.toArray(new CharSequence[accounts.size()]), checkedItems, (dialog, which, isChecked) -> {
+ checkedItems[which] = isChecked;
+ final AlertDialog alertDialog = (AlertDialog) dialog;
+ for (boolean item : checkedItems) {
+ if (item) {
+ alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true);
+ return;
}
- alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
}
+ alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
});
builder.setNegativeButton(R.string.cancel, null);
- builder.setPositiveButton(R.string.delete_selected_keys, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- for (int i = 0; i < checkedItems.length; ++i) {
- if (checkedItems[i]) {
- try {
- Jid jid = Jid.fromString(accounts.get(i).toString());
- Account account = xmppConnectionService.findAccountByJid(jid);
- if (account != null) {
- account.getAxolotlService().regenerateKeys(true);
- }
- } catch (InvalidJidException e) {
- //
+ builder.setPositiveButton(R.string.delete_selected_keys, (dialog, which) -> {
+ for (int i = 0; i < checkedItems.length; ++i) {
+ if (checkedItems[i]) {
+ try {
+ Jid jid = Jid.fromString(accounts.get(i).toString());
+ Account account = xmppConnectionService.findAccountByJid(jid);
+ if (account != null) {
+ account.getAxolotlService().regenerateKeys(true);
}
-
+ } catch (InvalidJidException e) {
+ //
}
}
}
@@ -429,23 +410,7 @@ public class SettingsActivity extends XmppActivity implements
TREAT_VIBRATE_AS_SILENT,
MANUALLY_CHANGE_PRESENCE,
BROADCAST_LAST_ACTIVITY);
- if (name.equals("resource")) {
- String resource = preferences.getString("resource", "mobile")
- .toLowerCase(Locale.US);
- if (xmppConnectionServiceBound) {
- for (Account account : xmppConnectionService.getAccounts()) {
- if (account.setResource(resource)) {
- if (account.isEnabled()) {
- XmppConnection connection = account.getXmppConnection();
- if (connection != null) {
- connection.resetStreamId();
- }
- xmppConnectionService.reconnectAccountInBackground(account);
- }
- }
- }
- }
- } else if (name.equals(SHOW_FOREGROUND_SERVICE)) {
+ if (name.equals(SHOW_FOREGROUND_SERVICE)) {
xmppConnectionService.toggleForegroundService();
} else if (resendPresence.contains(name)) {
if (xmppConnectionServiceBound) {
@@ -474,7 +439,7 @@ public class SettingsActivity extends XmppActivity implements
}
@Override
- public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (grantResults.length > 0)
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (requestCode == REQUEST_WRITE_LOGS) {
@@ -490,12 +455,7 @@ public class SettingsActivity extends XmppActivity implements
}
private void displayToast(final String msg) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(SettingsActivity.this, msg, Toast.LENGTH_LONG).show();
- }
- });
+ runOnUiThread(() -> Toast.makeText(SettingsActivity.this, msg, Toast.LENGTH_LONG).show());
}
private void reconnectAccounts() {
diff --git a/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java b/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java
index 1025c5f1d..154627afe 100644
--- a/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java
+++ b/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java
@@ -50,9 +50,9 @@ import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
-import de.pixart.messenger.crypto.DomainHostnameVerifier;
-import de.pixart.messenger.services.MemorizingTrustManager;
import de.pixart.messenger.Config;
+import de.pixart.messenger.R;
+import de.pixart.messenger.crypto.DomainHostnameVerifier;
import de.pixart.messenger.crypto.XmppDomainVerifier;
import de.pixart.messenger.crypto.axolotl.AxolotlService;
import de.pixart.messenger.crypto.sasl.Anonymous;
@@ -67,6 +67,7 @@ import de.pixart.messenger.entities.Message;
import de.pixart.messenger.entities.ServiceDiscoveryResult;
import de.pixart.messenger.generator.IqGenerator;
import de.pixart.messenger.persistance.FileBackend;
+import de.pixart.messenger.services.MemorizingTrustManager;
import de.pixart.messenger.services.NotificationService;
import de.pixart.messenger.services.XmppConnectionService;
import de.pixart.messenger.ui.EditAccountActivity;
@@ -104,21 +105,55 @@ 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;
+ public final OnIqPacketReceived registrationResponseListener = new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ if (packet.getType() == IqPacket.TYPE.RESULT) {
+ account.setOption(Account.OPTION_REGISTER, false);
+ throw new StateChangingError(Account.State.REGISTRATION_SUCCESSFUL);
+ } else {
+ final List<String> PASSWORD_TOO_WEAK_MSGS = Arrays.asList(
+ "The password is too weak",
+ "Please use a longer password.");
+ final Element error = packet.findChild("error");
+ Account.State state = Account.State.REGISTRATION_FAILED;
+ mXmppConnectionService.deleteAccount(account);
+ if (error != null) {
+ if (error.hasChild("text")) {
+ errorMessage = error.findChildContent("text");
+ Log.d(Config.LOGTAG, "Error creating account : " + error.findChildContent("text"));
+ }
+ if (error.hasChild("conflict")) {
+ state = Account.State.REGISTRATION_CONFLICT;
+ } else if (error.hasChild("resource-constraint")
+ && "wait".equals(error.getAttribute("type"))) {
+ state = Account.State.REGISTRATION_PLEASE_WAIT;
+ } else if (error.hasChild("not-acceptable")
+ && PASSWORD_TOO_WEAK_MSGS.contains(error.findChildContent("text"))) {
+ state = Account.State.REGISTRATION_PASSWORD_TOO_WEAK;
+ }
+ }
+ Log.d(Config.LOGTAG, "Delete account because of error " + error);
+ throw new StateChangingError(state);
+ }
+ }
+ };
protected final Account account;
+ private final Features features = new Features(this);
+ private final HashMap<Jid, ServiceDiscoveryResult> disco = new HashMap<>();
+ private final SparseArray<AbstractAcknowledgeableStanza> mStanzaQueue = new SparseArray<>();
+ private final Hashtable<String, Pair<IqPacket, OnIqPacketReceived>> packetCallbacks = new Hashtable<>();
+ private final ArrayList<OnAdvancedStreamFeaturesLoaded> advancedStreamFeaturesLoadedListeners = new ArrayList<>();
+ private final XmppConnectionService mXmppConnectionService;
private Socket socket;
private XmlReader tagReader;
private TagWriter tagWriter = new TagWriter();
- private final Features features = new Features(this);
private boolean isBound = false;
private boolean shouldAuthenticate = true;
private boolean inSmacksSession = false;
private Element streamFeatures;
- private final HashMap<Jid, ServiceDiscoveryResult> disco = new HashMap<>();
-
private String streamId = null;
private int smVersion = 3;
- private final SparseArray<AbstractAcknowledgeableStanza> mStanzaQueue = new SparseArray<>();
-
private int stanzasReceived = 0;
private int stanzasSent = 0;
private long lastPacketReceived = 0;
@@ -133,101 +168,20 @@ public class XmppConnection implements Runnable {
private boolean mInteractive = false;
private int attempt = 0;
public static String errorMessage = null;
- private final Hashtable<String, Pair<IqPacket, OnIqPacketReceived>> packetCallbacks = new Hashtable<>();
private OnPresencePacketReceived presenceListener = null;
private OnJinglePacketReceived jingleListener = null;
private OnIqPacketReceived unregisteredIqListener = null;
private OnMessagePacketReceived messageListener = null;
private OnStatusChanged statusListener = null;
private OnBindListener bindListener = null;
- private final ArrayList<OnAdvancedStreamFeaturesLoaded> advancedStreamFeaturesLoadedListeners = new ArrayList<>();
private OnMessageAcknowledged acknowledgedListener = null;
- private final XmppConnectionService mXmppConnectionService;
private EditAccountActivity mEditAccountActivity = null;
-
private SaslMechanism saslMechanism;
private URL redirectionUrl = null;
private String verifiedHostname = null;
private Thread mThread;
private CountDownLatch mStreamCountDownLatch;
- private class MyKeyManager implements X509KeyManager {
- @Override
- public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) {
- return account.getPrivateKeyAlias();
- }
-
- @Override
- public String chooseServerAlias(String s, Principal[] principals, Socket socket) {
- return null;
- }
-
- @Override
- public X509Certificate[] getCertificateChain(String alias) {
- Log.d(Config.LOGTAG, "getting certificate chain");
- try {
- return KeyChain.getCertificateChain(mXmppConnectionService, alias);
- } catch (Exception e) {
- Log.d(Config.LOGTAG, e.getMessage());
- return new X509Certificate[0];
- }
- }
-
- @Override
- public String[] getClientAliases(String s, Principal[] principals) {
- final String alias = account.getPrivateKeyAlias();
- return alias != null ? new String[]{alias} : new String[0];
- }
-
- @Override
- public String[] getServerAliases(String s, Principal[] principals) {
- return new String[0];
- }
-
- @Override
- public PrivateKey getPrivateKey(String alias) {
- try {
- return KeyChain.getPrivateKey(mXmppConnectionService, alias);
- } catch (Exception e) {
- return null;
- }
- }
- }
-
- public final OnIqPacketReceived registrationResponseListener = new OnIqPacketReceived() {
- @Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- if (packet.getType() == IqPacket.TYPE.RESULT) {
- account.setOption(Account.OPTION_REGISTER, false);
- throw new StateChangingError(Account.State.REGISTRATION_SUCCESSFUL);
- } else {
- final List<String> PASSWORD_TOO_WEAK_MSGS = Arrays.asList(
- "The password is too weak",
- "Please use a longer password.");
- final Element error = packet.findChild("error");
- Account.State state = Account.State.REGISTRATION_FAILED;
- mXmppConnectionService.deleteAccount(account);
- if (error != null) {
- if (error.hasChild("text")) {
- errorMessage = error.findChildContent("text");
- Log.d(Config.LOGTAG, "Error creating account : " + error.findChildContent("text"));
- }
- if (error.hasChild("conflict")) {
- state = Account.State.REGISTRATION_CONFLICT;
- } else if (error.hasChild("resource-constraint")
- && "wait".equals(error.getAttribute("type"))) {
- state = Account.State.REGISTRATION_PLEASE_WAIT;
- } else if (error.hasChild("not-acceptable")
- && PASSWORD_TOO_WEAK_MSGS.contains(error.findChildContent("text"))) {
- state = Account.State.REGISTRATION_PASSWORD_TOO_WEAK;
- }
- }
- Log.d(Config.LOGTAG, "Delete account because of error " + error);
- throw new StateChangingError(state);
- }
- }
- };
-
public XmppConnection(final Account account, final XmppConnectionService service) {
this.account = account;
final String tag = account.getJid().toBareJid().toPreppedString();
@@ -509,19 +463,6 @@ public class XmppConnection implements Runnable {
return tag != null && tag.isStart("stream");
}
- private static class TlsFactoryVerifier {
- private final SSLSocketFactory factory;
- private final DomainHostnameVerifier verifier;
-
- public TlsFactoryVerifier(final SSLSocketFactory factory, final DomainHostnameVerifier verifier) throws IOException {
- this.factory = factory;
- this.verifier = verifier;
- if (factory == null || verifier == null) {
- throw new IOException("could not setup ssl");
- }
- }
- }
-
private TlsFactoryVerifier getTlsFactoryVerifier() throws NoSuchAlgorithmException, KeyManagementException, IOException {
final SSLContext sc = SSLSocketHelper.getSSLContext();
MemorizingTrustManager trustManager = this.mXmppConnectionService.getMemorizingTrustManager();
@@ -865,7 +806,6 @@ public class XmppConnection implements Runnable {
tagWriter.writeTag(startTLS);
}
-
private void switchOverToTls(final Tag currentTag) throws XmlPullParserException, IOException {
tagReader.readTag();
try {
@@ -1099,55 +1039,52 @@ public class XmppConnection implements Runnable {
return;
}
clearIqCallbacks();
+ if (account.getJid().isBareJid()) {
+ account.setResource(this.createNewResource());
+ }
final IqPacket iq = new IqPacket(IqPacket.TYPE.SET);
final String resource = Config.USE_RANDOM_RESOURCE_ON_EVERY_BIND ? nextRandomId() : account.getResource();
iq.addChild("bind", Namespace.BIND).addChild("resource").setContent(resource);
- this.sendUnmodifiedIqPacket(iq, new OnIqPacketReceived() {
- @Override
- public void onIqPacketReceived(final Account account, final IqPacket packet) {
- if (packet.getType() == IqPacket.TYPE.TIMEOUT) {
- return;
- }
- final Element bind = packet.findChild("bind");
- if (bind != null && packet.getType() == IqPacket.TYPE.RESULT) {
- isBound = true;
- final Element jid = bind.findChild("jid");
- if (jid != null && jid.getContent() != null) {
- try {
- Jid assignedJid = Jid.fromString(jid.getContent());
- if (!account.getJid().getDomainpart().equals(assignedJid.getDomainpart())) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": server tried to re-assign domain to " + assignedJid.getDomainpart());
- throw new StateChangingError(Account.State.BIND_FAILURE);
- }
- if (account.setJid(assignedJid)) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": bare jid changed during bind. updating database");
- mXmppConnectionService.databaseBackend.updateAccount(account);
- }
- if (streamFeatures.hasChild("session")
- && !streamFeatures.findChild("session").hasChild("optional")) {
- sendStartSession();
- } else {
- sendPostBindInitialization();
- }
- return;
- } catch (final InvalidJidException e) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": server reported invalid jid (" + jid.getContent() + ") on bind");
+ this.sendUnmodifiedIqPacket(iq, (account, packet) -> {
+ if (packet.getType() == IqPacket.TYPE.TIMEOUT) {
+ return;
+ }
+ final Element bind = packet.findChild("bind");
+ if (bind != null && packet.getType() == IqPacket.TYPE.RESULT) {
+ isBound = true;
+ final Element jid = bind.findChild("jid");
+ if (jid != null && jid.getContent() != null) {
+ try {
+ Jid assignedJid = Jid.fromString(jid.getContent());
+ if (!account.getJid().getDomainpart().equals(assignedJid.getDomainpart())) {
+ Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": server tried to re-assign domain to " + assignedJid.getDomainpart());
+ throw new StateChangingError(Account.State.BIND_FAILURE);
}
- } else {
- Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure. (no jid)");
+ if (account.setJid(assignedJid)) {
+ Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": jid changed during bind. updating database");
+ mXmppConnectionService.databaseBackend.updateAccount(account);
+ }
+ if (streamFeatures.hasChild("session")
+ && !streamFeatures.findChild("session").hasChild("optional")) {
+ sendStartSession();
+ } else {
+ sendPostBindInitialization();
+ }
+ return;
+ } catch (final InvalidJidException e) {
+ Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": server reported invalid jid (" + jid.getContent() + ") on bind");
}
} else {
- Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure (" + packet.toString());
+ Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure. (no jid)");
}
- final Element error = packet.findChild("error");
- final String resource = account.getResource().split("\\.")[0];
- if (packet.getType() == IqPacket.TYPE.ERROR && error != null && error.hasChild("conflict")) {
- account.setResource(resource + "." + nextRandomId());
- } else {
- account.setResource(resource);
- }
- throw new StateChangingError(Account.State.BIND_FAILURE);
+ } else {
+ Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure (" + packet.toString());
}
+ final Element error = packet.findChild("error");
+ if (packet.getType() == IqPacket.TYPE.ERROR && error != null && error.hasChild("conflict")) {
+ account.setResource(createNewResource());
+ }
+ throw new StateChangingError(Account.State.BIND_FAILURE);
}, true);
}
@@ -1367,18 +1304,14 @@ public class XmppConnection implements Runnable {
});
}
- private void processStreamError(final Tag currentTag)
- throws XmlPullParserException, IOException {
+ private void processStreamError(final Tag currentTag) throws XmlPullParserException, IOException {
final Element streamError = tagReader.readElement(currentTag);
if (streamError == null) {
return;
}
if (streamError.hasChild("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() + ")");
+ account.setResource(createNewResource());
+ Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": switching resource due to conflict (" + account.getResource() + ")");
throw new IOException();
} else if (streamError.hasChild("host-unknown")) {
throw new StateChangingException(Account.State.HOST_UNKNOWN);
@@ -1400,8 +1333,16 @@ public class XmppConnection implements Runnable {
tagWriter.writeTag(stream);
}
+ private String createNewResource() {
+ return mXmppConnectionService.getString(R.string.app_name) + '.' + nextRandomId(true);
+ }
+
private String nextRandomId() {
- return CryptoHelper.random(10, mXmppConnectionService.getRNG());
+ return nextRandomId(false);
+ }
+
+ private String nextRandomId(boolean s) {
+ return CryptoHelper.random(s ? 3 : 9, mXmppConnectionService.getRNG());
}
public String sendIqPacket(final IqPacket packet, final OnIqPacketReceived callback) {
@@ -1690,6 +1631,75 @@ public class XmppConnection implements Runnable {
return Identity.UNKNOWN;
}
+ private IqGenerator getIqGenerator() {
+ return mXmppConnectionService.getIqGenerator();
+ }
+
+ public enum Identity {
+ FACEBOOK,
+ SLACK,
+ EJABBERD,
+ PROSODY,
+ NIMBUZZ,
+ UNKNOWN
+ }
+
+ private static class TlsFactoryVerifier {
+ private final SSLSocketFactory factory;
+ private final DomainHostnameVerifier verifier;
+
+ public TlsFactoryVerifier(final SSLSocketFactory factory, final DomainHostnameVerifier verifier) throws IOException {
+ this.factory = factory;
+ this.verifier = verifier;
+ if (factory == null || verifier == null) {
+ throw new IOException("could not setup ssl");
+ }
+ }
+ }
+
+ private class MyKeyManager implements X509KeyManager {
+ @Override
+ public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) {
+ return account.getPrivateKeyAlias();
+ }
+
+ @Override
+ public String chooseServerAlias(String s, Principal[] principals, Socket socket) {
+ return null;
+ }
+
+ @Override
+ public X509Certificate[] getCertificateChain(String alias) {
+ Log.d(Config.LOGTAG, "getting certificate chain");
+ try {
+ return KeyChain.getCertificateChain(mXmppConnectionService, alias);
+ } catch (Exception e) {
+ Log.d(Config.LOGTAG, e.getMessage());
+ return new X509Certificate[0];
+ }
+ }
+
+ @Override
+ public String[] getClientAliases(String s, Principal[] principals) {
+ final String alias = account.getPrivateKeyAlias();
+ return alias != null ? new String[]{alias} : new String[0];
+ }
+
+ @Override
+ public String[] getServerAliases(String s, Principal[] principals) {
+ return new String[0];
+ }
+
+ @Override
+ public PrivateKey getPrivateKey(String alias) {
+ try {
+ return KeyChain.getPrivateKey(mXmppConnectionService, alias);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ }
+
private class StateChangingError extends Error {
private final Account.State state;
@@ -1706,15 +1716,6 @@ public class XmppConnection implements Runnable {
}
}
- public enum Identity {
- FACEBOOK,
- SLACK,
- EJABBERD,
- PROSODY,
- NIMBUZZ,
- UNKNOWN
- }
-
public class Features {
XmppConnection connection;
private boolean carbonsEnabled = false;
@@ -1846,8 +1847,4 @@ public class XmppConnection implements Runnable {
return hasDiscoFeature(account.getJid().toBareJid(), Namespace.STANZA_IDS);
}
}
-
- private IqGenerator getIqGenerator() {
- return mXmppConnectionService.getIqGenerator();
- }
}