get rid of customizable resources
This commit is contained in:
parent
fcbbb552f4
commit
b393f54a03
|
@ -42,6 +42,7 @@ public class Account extends AbstractEntity {
|
||||||
public static final String PORT = "port";
|
public static final String PORT = "port";
|
||||||
public static final String STATUS = "status";
|
public static final String STATUS = "status";
|
||||||
public static final String STATUS_MESSAGE = "status_message";
|
public static final String STATUS_MESSAGE = "status_message";
|
||||||
|
public static final String RESOURCE = "resource";
|
||||||
|
|
||||||
public static final String PINNED_MECHANISM_KEY = "pinned_mechanism";
|
public static final String PINNED_MECHANISM_KEY = "pinned_mechanism";
|
||||||
|
|
||||||
|
@ -229,6 +230,7 @@ public class Account extends AbstractEntity {
|
||||||
protected String rosterVersion;
|
protected String rosterVersion;
|
||||||
protected State status = State.OFFLINE;
|
protected State status = State.OFFLINE;
|
||||||
protected final JSONObject keys;
|
protected final JSONObject keys;
|
||||||
|
protected String resource;
|
||||||
protected String avatar;
|
protected String avatar;
|
||||||
protected String displayName = null;
|
protected String displayName = null;
|
||||||
protected String hostname = null;
|
protected String hostname = null;
|
||||||
|
@ -238,7 +240,6 @@ public class Account extends AbstractEntity {
|
||||||
private PgpDecryptionService pgpDecryptionService = null;
|
private PgpDecryptionService pgpDecryptionService = null;
|
||||||
private XmppConnection xmppConnection = null;
|
private XmppConnection xmppConnection = null;
|
||||||
private long mEndGracePeriod = 0L;
|
private long mEndGracePeriod = 0L;
|
||||||
private String otrFingerprint;
|
|
||||||
private final Roster roster = new Roster(this);
|
private final Roster roster = new Roster(this);
|
||||||
private List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
|
private List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
|
||||||
private final Collection<Jid> blocklist = new CopyOnWriteArraySet<>();
|
private final Collection<Jid> blocklist = new CopyOnWriteArraySet<>();
|
||||||
|
@ -256,9 +257,6 @@ public class Account extends AbstractEntity {
|
||||||
final Presence.Status status, String statusMessage) {
|
final Presence.Status status, String statusMessage) {
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
this.jid = jid;
|
this.jid = jid;
|
||||||
if (jid.isBareJid()) {
|
|
||||||
this.setResource("mobile");
|
|
||||||
}
|
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.rosterVersion = rosterVersion;
|
this.rosterVersion = rosterVersion;
|
||||||
|
@ -280,8 +278,10 @@ public class Account extends AbstractEntity {
|
||||||
public static Account fromCursor(final Cursor cursor) {
|
public static Account fromCursor(final Cursor cursor) {
|
||||||
Jid jid = null;
|
Jid jid = null;
|
||||||
try {
|
try {
|
||||||
jid = Jid.fromParts(cursor.getString(cursor.getColumnIndex(USERNAME)),
|
jid = Jid.fromParts(
|
||||||
cursor.getString(cursor.getColumnIndex(SERVER)), "mobile");
|
cursor.getString(cursor.getColumnIndex(USERNAME)),
|
||||||
|
cursor.getString(cursor.getColumnIndex(SERVER)),
|
||||||
|
cursor.getString(cursor.getColumnIndex(RESOURCE)));
|
||||||
} catch (final InvalidJidException ignored) {
|
} catch (final InvalidJidException ignored) {
|
||||||
}
|
}
|
||||||
return new Account(cursor.getString(cursor.getColumnIndex(UUID)),
|
return new Account(cursor.getString(cursor.getColumnIndex(UUID)),
|
||||||
|
@ -317,6 +317,7 @@ public class Account extends AbstractEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setJid(final Jid next) {
|
public boolean setJid(final Jid next) {
|
||||||
|
final Jid previousFull = this.jid;
|
||||||
final Jid prev = this.jid != null ? this.jid.toBareJid() : null;
|
final Jid prev = this.jid != null ? this.jid.toBareJid() : null;
|
||||||
final boolean changed = prev == null || (next != null && !prev.equals(next.toBareJid()));
|
final boolean changed = prev == null || (next != null && !prev.equals(next.toBareJid()));
|
||||||
if (changed) {
|
if (changed) {
|
||||||
|
@ -328,7 +329,7 @@ public class Account extends AbstractEntity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.jid = next;
|
this.jid = next;
|
||||||
return changed;
|
return next != null && next.equals(previousFull);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Jid getServer() {
|
public Jid getServer() {
|
||||||
|
@ -483,6 +484,7 @@ public class Account extends AbstractEntity {
|
||||||
values.put(PORT, port);
|
values.put(PORT, port);
|
||||||
values.put(STATUS, presenceStatus.toShowString());
|
values.put(STATUS, presenceStatus.toShowString());
|
||||||
values.put(STATUS_MESSAGE, presenceStatusMessage);
|
values.put(STATUS_MESSAGE, presenceStatusMessage);
|
||||||
|
values.put(RESOURCE,jid.getResourcepart());
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
private static DatabaseBackend instance = null;
|
private static DatabaseBackend instance = null;
|
||||||
|
|
||||||
private static final String DATABASE_NAME = "history";
|
private static final String DATABASE_NAME = "history";
|
||||||
private static final int DATABASE_VERSION = 39;
|
private static final int DATABASE_VERSION = 40;
|
||||||
|
|
||||||
private static String CREATE_CONTATCS_STATEMENT = "create table "
|
private static String CREATE_CONTATCS_STATEMENT = "create table "
|
||||||
+ Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, "
|
+ Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, "
|
||||||
|
@ -184,6 +184,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
+ Account.AVATAR + " TEXT, "
|
+ Account.AVATAR + " TEXT, "
|
||||||
+ Account.KEYS + " TEXT, "
|
+ Account.KEYS + " TEXT, "
|
||||||
+ Account.HOSTNAME + " TEXT, "
|
+ Account.HOSTNAME + " TEXT, "
|
||||||
|
+ Account.RESOURCE + " TEXT,"
|
||||||
+ Account.PORT + " NUMBER DEFAULT 5222)");
|
+ Account.PORT + " NUMBER DEFAULT 5222)");
|
||||||
db.execSQL("create table " + Conversation.TABLENAME + " ("
|
db.execSQL("create table " + Conversation.TABLENAME + " ("
|
||||||
+ Conversation.UUID + " TEXT PRIMARY KEY, " + Conversation.NAME
|
+ Conversation.UUID + " TEXT PRIMARY KEY, " + Conversation.NAME
|
||||||
|
@ -305,6 +306,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 + " TEXT");
|
||||||
db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.STATUS_MESSAGE + " TEXT");
|
db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.STATUS_MESSAGE + " TEXT");
|
||||||
}
|
}
|
||||||
|
if (oldVersion < 40 && newVersion >= 40) {
|
||||||
|
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
|
/* Any migrations that alter the Account table need to happen BEFORE this migration, as it
|
||||||
* depends on account de-serialization.
|
* depends on account de-serialization.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1125,17 +1125,6 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
public XmppConnection createConnection(final Account account) {
|
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 = "conversations";
|
|
||||||
}
|
|
||||||
account.setResource(resource);
|
|
||||||
final XmppConnection connection = new XmppConnection(account, this);
|
final XmppConnection connection = new XmppConnection(account, this);
|
||||||
connection.setOnMessagePacketReceivedListener(this.mMessageParser);
|
connection.setOnMessagePacketReceivedListener(this.mMessageParser);
|
||||||
connection.setOnStatusChangedListener(this.statusListener);
|
connection.setOnStatusChangedListener(this.statusListener);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package eu.siacs.conversations.ui;
|
package eu.siacs.conversations.ui;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.app.FragmentManager;
|
import android.app.FragmentManager;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
@ -68,7 +69,7 @@ public class SettingsActivity extends XmppActivity implements
|
||||||
|
|
||||||
this.mTheme = findTheme();
|
this.mTheme = findTheme();
|
||||||
setTheme(this.mTheme);
|
setTheme(this.mTheme);
|
||||||
getWindow().getDecorView().setBackgroundColor(Color.get(this,R.attr.color_background_primary));
|
getWindow().getDecorView().setBackgroundColor(Color.get(this, R.attr.color_background_primary));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,15 +82,6 @@ public class SettingsActivity extends XmppActivity implements
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
|
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
|
||||||
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) {
|
if (Config.FORCE_ORBOT) {
|
||||||
PreferenceCategory connectionOptions = (PreferenceCategory) mSettingsFragment.findPreference("connection_options");
|
PreferenceCategory connectionOptions = (PreferenceCategory) mSettingsFragment.findPreference("connection_options");
|
||||||
|
@ -281,37 +273,31 @@ public class SettingsActivity extends XmppActivity implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final boolean[] checkedItems = new boolean[accounts.size()];
|
final boolean[] checkedItems = new boolean[accounts.size()];
|
||||||
builder.setMultiChoiceItems(accounts.toArray(new CharSequence[accounts.size()]), checkedItems, new DialogInterface.OnMultiChoiceClickListener() {
|
builder.setMultiChoiceItems(accounts.toArray(new CharSequence[accounts.size()]), checkedItems, (dialog, which, isChecked) -> {
|
||||||
@Override
|
checkedItems[which] = isChecked;
|
||||||
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
|
final AlertDialog alertDialog = (AlertDialog) dialog;
|
||||||
checkedItems[which] = isChecked;
|
for (boolean item : checkedItems) {
|
||||||
final AlertDialog alertDialog = (AlertDialog) dialog;
|
if (item) {
|
||||||
for (boolean item : checkedItems) {
|
alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true);
|
||||||
if (item) {
|
return;
|
||||||
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.setNegativeButton(R.string.cancel, null);
|
||||||
builder.setPositiveButton(R.string.delete_selected_keys, new DialogInterface.OnClickListener() {
|
builder.setPositiveButton(R.string.delete_selected_keys, (dialog, which) -> {
|
||||||
@Override
|
for (int i = 0; i < checkedItems.length; ++i) {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
if (checkedItems[i]) {
|
||||||
for (int i = 0; i < checkedItems.length; ++i) {
|
try {
|
||||||
if (checkedItems[i]) {
|
Jid jid = Jid.fromString(accounts.get(i).toString());
|
||||||
try {
|
Account account = xmppConnectionService.findAccountByJid(jid);
|
||||||
Jid jid = Jid.fromString(accounts.get(i).toString());
|
if (account != null) {
|
||||||
Account account = xmppConnectionService.findAccountByJid(jid);
|
account.getAxolotlService().regenerateKeys(true);
|
||||||
if (account != null) {
|
|
||||||
account.getAxolotlService().regenerateKeys(true);
|
|
||||||
}
|
|
||||||
} catch (InvalidJidException e) {
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
|
} catch (InvalidJidException e) {
|
||||||
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -338,23 +324,7 @@ public class SettingsActivity extends XmppActivity implements
|
||||||
TREAT_VIBRATE_AS_SILENT,
|
TREAT_VIBRATE_AS_SILENT,
|
||||||
MANUALLY_CHANGE_PRESENCE,
|
MANUALLY_CHANGE_PRESENCE,
|
||||||
BROADCAST_LAST_ACTIVITY);
|
BROADCAST_LAST_ACTIVITY);
|
||||||
if (name.equals("resource")) {
|
if (name.equals(KEEP_FOREGROUND_SERVICE)) {
|
||||||
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(KEEP_FOREGROUND_SERVICE)) {
|
|
||||||
xmppConnectionService.toggleForegroundService();
|
xmppConnectionService.toggleForegroundService();
|
||||||
} else if (resendPresence.contains(name)) {
|
} else if (resendPresence.contains(name)) {
|
||||||
if (xmppConnectionServiceBound) {
|
if (xmppConnectionServiceBound) {
|
||||||
|
@ -383,7 +353,7 @@ public class SettingsActivity extends XmppActivity implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.length > 0)
|
||||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
if (requestCode == REQUEST_WRITE_LOGS) {
|
if (requestCode == REQUEST_WRITE_LOGS) {
|
||||||
|
@ -399,12 +369,7 @@ public class SettingsActivity extends XmppActivity implements
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayToast(final String msg) {
|
private void displayToast(final String msg) {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(() -> Toast.makeText(SettingsActivity.this, msg, Toast.LENGTH_LONG).show());
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Toast.makeText(SettingsActivity.this, msg, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reconnectAccounts() {
|
private void reconnectAccounts() {
|
||||||
|
|
|
@ -50,6 +50,7 @@ import javax.net.ssl.X509KeyManager;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.crypto.DomainHostnameVerifier;
|
import eu.siacs.conversations.crypto.DomainHostnameVerifier;
|
||||||
import eu.siacs.conversations.crypto.XmppDomainVerifier;
|
import eu.siacs.conversations.crypto.XmppDomainVerifier;
|
||||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||||
|
@ -102,94 +103,6 @@ public class XmppConnection implements Runnable {
|
||||||
private static final int PACKET_IQ = 0;
|
private static final int PACKET_IQ = 0;
|
||||||
private static final int PACKET_MESSAGE = 1;
|
private static final int PACKET_MESSAGE = 1;
|
||||||
private static final int PACKET_PRESENCE = 2;
|
private static final int PACKET_PRESENCE = 2;
|
||||||
protected final Account account;
|
|
||||||
private Socket socket;
|
|
||||||
private XmlReader tagReader;
|
|
||||||
private TagWriter tagWriter = new TagWriter();
|
|
||||||
private final Features features = new Features(this);
|
|
||||||
private boolean shouldAuthenticate = true;
|
|
||||||
private boolean inSmacksSession = false;
|
|
||||||
private boolean isBound = 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;
|
|
||||||
private long lastPingSent = 0;
|
|
||||||
private long lastConnect = 0;
|
|
||||||
private long lastSessionStarted = 0;
|
|
||||||
private long lastDiscoStarted = 0;
|
|
||||||
private AtomicInteger mPendingServiceDiscoveries = new AtomicInteger(0);
|
|
||||||
private AtomicBoolean mWaitForDisco = new AtomicBoolean(true);
|
|
||||||
private AtomicBoolean mWaitingForSmCatchup = new AtomicBoolean(false);
|
|
||||||
private AtomicInteger mSmCatchupMessageCounter = new AtomicInteger(0);
|
|
||||||
private boolean mInteractive = false;
|
|
||||||
private int attempt = 0;
|
|
||||||
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 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() {
|
public final OnIqPacketReceived registrationResponseListener = new OnIqPacketReceived() {
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
|
@ -217,6 +130,47 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
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 boolean shouldAuthenticate = true;
|
||||||
|
private boolean inSmacksSession = false;
|
||||||
|
private boolean isBound = false;
|
||||||
|
private Element streamFeatures;
|
||||||
|
private String streamId = null;
|
||||||
|
private int smVersion = 3;
|
||||||
|
private int stanzasReceived = 0;
|
||||||
|
private int stanzasSent = 0;
|
||||||
|
private long lastPacketReceived = 0;
|
||||||
|
private long lastPingSent = 0;
|
||||||
|
private long lastConnect = 0;
|
||||||
|
private long lastSessionStarted = 0;
|
||||||
|
private long lastDiscoStarted = 0;
|
||||||
|
private AtomicInteger mPendingServiceDiscoveries = new AtomicInteger(0);
|
||||||
|
private AtomicBoolean mWaitForDisco = new AtomicBoolean(true);
|
||||||
|
private AtomicBoolean mWaitingForSmCatchup = new AtomicBoolean(false);
|
||||||
|
private AtomicInteger mSmCatchupMessageCounter = new AtomicInteger(0);
|
||||||
|
private boolean mInteractive = false;
|
||||||
|
private int attempt = 0;
|
||||||
|
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 OnMessageAcknowledged acknowledgedListener = null;
|
||||||
|
private SaslMechanism saslMechanism;
|
||||||
|
private URL redirectionUrl = null;
|
||||||
|
private String verifiedHostname = null;
|
||||||
|
private Thread mThread;
|
||||||
|
private CountDownLatch mStreamCountDownLatch;
|
||||||
|
|
||||||
public XmppConnection(final Account account, final XmppConnectionService service) {
|
public XmppConnection(final Account account, final XmppConnectionService service) {
|
||||||
this.account = account;
|
this.account = account;
|
||||||
|
@ -479,19 +433,6 @@ public class XmppConnection implements Runnable {
|
||||||
return tag != null && tag.isStart("stream");
|
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 {
|
private TlsFactoryVerifier getTlsFactoryVerifier() throws NoSuchAlgorithmException, KeyManagementException, IOException {
|
||||||
final SSLContext sc = SSLSocketHelper.getSSLContext();
|
final SSLContext sc = SSLSocketHelper.getSSLContext();
|
||||||
MemorizingTrustManager trustManager = this.mXmppConnectionService.getMemorizingTrustManager();
|
MemorizingTrustManager trustManager = this.mXmppConnectionService.getMemorizingTrustManager();
|
||||||
|
@ -836,7 +777,6 @@ public class XmppConnection implements Runnable {
|
||||||
tagWriter.writeTag(startTLS);
|
tagWriter.writeTag(startTLS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void switchOverToTls(final Tag currentTag) throws XmlPullParserException, IOException {
|
private void switchOverToTls(final Tag currentTag) throws XmlPullParserException, IOException {
|
||||||
tagReader.readTag();
|
tagReader.readTag();
|
||||||
try {
|
try {
|
||||||
|
@ -1069,55 +1009,52 @@ public class XmppConnection implements Runnable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clearIqCallbacks();
|
clearIqCallbacks();
|
||||||
|
if (account.getJid().isBareJid()) {
|
||||||
|
account.setResource(this.createNewResource());
|
||||||
|
}
|
||||||
final IqPacket iq = new IqPacket(IqPacket.TYPE.SET);
|
final IqPacket iq = new IqPacket(IqPacket.TYPE.SET);
|
||||||
final String resource = Config.USE_RANDOM_RESOURCE_ON_EVERY_BIND ? nextRandomId() : account.getResource();
|
final String resource = Config.USE_RANDOM_RESOURCE_ON_EVERY_BIND ? nextRandomId() : account.getResource();
|
||||||
iq.addChild("bind", Namespace.BIND).addChild("resource").setContent(resource);
|
iq.addChild("bind", Namespace.BIND).addChild("resource").setContent(resource);
|
||||||
this.sendUnmodifiedIqPacket(iq, new OnIqPacketReceived() {
|
this.sendUnmodifiedIqPacket(iq, (account, packet) -> {
|
||||||
@Override
|
if (packet.getType() == IqPacket.TYPE.TIMEOUT) {
|
||||||
public void onIqPacketReceived(final Account account, final IqPacket packet) {
|
return;
|
||||||
if (packet.getType() == IqPacket.TYPE.TIMEOUT) {
|
}
|
||||||
return;
|
final Element bind = packet.findChild("bind");
|
||||||
}
|
if (bind != null && packet.getType() == IqPacket.TYPE.RESULT) {
|
||||||
final Element bind = packet.findChild("bind");
|
isBound = true;
|
||||||
if (bind != null && packet.getType() == IqPacket.TYPE.RESULT) {
|
final Element jid = bind.findChild("jid");
|
||||||
isBound = true;
|
if (jid != null && jid.getContent() != null) {
|
||||||
final Element jid = bind.findChild("jid");
|
try {
|
||||||
if (jid != null && jid.getContent() != null) {
|
Jid assignedJid = Jid.fromString(jid.getContent());
|
||||||
try {
|
if (!account.getJid().getDomainpart().equals(assignedJid.getDomainpart())) {
|
||||||
Jid assignedJid = Jid.fromString(jid.getContent());
|
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": server tried to re-assign domain to "+assignedJid.getDomainpart());
|
||||||
if (!account.getJid().getDomainpart().equals(assignedJid.getDomainpart())) {
|
throw new StateChangingError(Account.State.BIND_FAILURE);
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
} else {
|
if (account.setJid(assignedJid)) {
|
||||||
Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure. (no jid)");
|
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 {
|
} 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");
|
} else {
|
||||||
final String resource = account.getResource().split("\\.")[0];
|
Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure (" + packet.toString());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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);
|
},true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1337,18 +1274,14 @@ public class XmppConnection implements Runnable {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processStreamError(final Tag currentTag)
|
private void processStreamError(final Tag currentTag) throws XmlPullParserException, IOException {
|
||||||
throws XmlPullParserException, IOException {
|
|
||||||
final Element streamError = tagReader.readElement(currentTag);
|
final Element streamError = tagReader.readElement(currentTag);
|
||||||
if (streamError == null) {
|
if (streamError == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (streamError.hasChild("conflict")) {
|
if (streamError.hasChild("conflict")) {
|
||||||
final String resource = account.getResource().split("\\.")[0];
|
account.setResource(createNewResource());
|
||||||
account.setResource(resource + "." + nextRandomId());
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": switching resource due to conflict (" + account.getResource() + ")");
|
||||||
Log.d(Config.LOGTAG,
|
|
||||||
account.getJid().toBareJid() + ": switching resource due to conflict ("
|
|
||||||
+ account.getResource() + ")");
|
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
} else if (streamError.hasChild("host-unknown")) {
|
} else if (streamError.hasChild("host-unknown")) {
|
||||||
throw new StateChangingException(Account.State.HOST_UNKNOWN);
|
throw new StateChangingException(Account.State.HOST_UNKNOWN);
|
||||||
|
@ -1370,8 +1303,16 @@ public class XmppConnection implements Runnable {
|
||||||
tagWriter.writeTag(stream);
|
tagWriter.writeTag(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String createNewResource() {
|
||||||
|
return mXmppConnectionService.getString(R.string.app_name)+'.'+nextRandomId(true);
|
||||||
|
}
|
||||||
|
|
||||||
private String nextRandomId() {
|
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) {
|
public String sendIqPacket(final IqPacket packet, final OnIqPacketReceived callback) {
|
||||||
|
@ -1662,6 +1603,75 @@ public class XmppConnection implements Runnable {
|
||||||
return Identity.UNKNOWN;
|
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 class StateChangingError extends Error {
|
||||||
private final Account.State state;
|
private final Account.State state;
|
||||||
|
|
||||||
|
@ -1678,15 +1688,6 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Identity {
|
|
||||||
FACEBOOK,
|
|
||||||
SLACK,
|
|
||||||
EJABBERD,
|
|
||||||
PROSODY,
|
|
||||||
NIMBUZZ,
|
|
||||||
UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Features {
|
public class Features {
|
||||||
XmppConnection connection;
|
XmppConnection connection;
|
||||||
private boolean carbonsEnabled = false;
|
private boolean carbonsEnabled = false;
|
||||||
|
@ -1818,8 +1819,4 @@ public class XmppConnection implements Runnable {
|
||||||
return hasDiscoFeature(account.getJid().toBareJid(), Namespace.STANZA_IDS);
|
return hasDiscoFeature(account.getJid().toBareJid(), Namespace.STANZA_IDS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IqGenerator getIqGenerator() {
|
|
||||||
return mXmppConnectionService.getIqGenerator();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<string-array name="resources">
|
|
||||||
<item>Mobile</item>
|
|
||||||
<item>Phone</item>
|
|
||||||
<item>Tablet</item>
|
|
||||||
<item>@string/app_name</item>
|
|
||||||
<item>Android</item>
|
|
||||||
</string-array>
|
|
||||||
<string-array name="themes">
|
<string-array name="themes">
|
||||||
<item>@string/pref_theme_light</item>
|
<item>@string/pref_theme_light</item>
|
||||||
<item>@string/pref_theme_dark</item>
|
<item>@string/pref_theme_dark</item>
|
||||||
|
|
|
@ -100,8 +100,6 @@
|
||||||
<string name="no_pgp_keys">No OpenPGP Keys found</string>
|
<string name="no_pgp_keys">No OpenPGP Keys found</string>
|
||||||
<string name="contacts_have_no_pgp_keys">Conversations is unable to encrypt your messages because your contacts are not announcing their public key.\n\n<small>Please ask your contacts to setup OpenPGP.</small></string>
|
<string name="contacts_have_no_pgp_keys">Conversations is unable to encrypt your messages because your contacts are not announcing their public key.\n\n<small>Please ask your contacts to setup OpenPGP.</small></string>
|
||||||
<string name="pref_general">General</string>
|
<string name="pref_general">General</string>
|
||||||
<string name="pref_xmpp_resource">XMPP resource</string>
|
|
||||||
<string name="pref_xmpp_resource_summary">The name this client identifies itself with</string>
|
|
||||||
<string name="pref_accept_files">Accept files</string>
|
<string name="pref_accept_files">Accept files</string>
|
||||||
<string name="pref_accept_files_summary">Automatically accept files smaller than…</string>
|
<string name="pref_accept_files_summary">Automatically accept files smaller than…</string>
|
||||||
<string name="pref_attachments">Attachments</string>
|
<string name="pref_attachments">Attachments</string>
|
||||||
|
|
|
@ -9,14 +9,6 @@
|
||||||
android:key="grant_new_contacts"
|
android:key="grant_new_contacts"
|
||||||
android:summary="@string/pref_grant_presence_updates_summary"
|
android:summary="@string/pref_grant_presence_updates_summary"
|
||||||
android:title="@string/pref_grant_presence_updates"/>
|
android:title="@string/pref_grant_presence_updates"/>
|
||||||
|
|
||||||
<ListPreference
|
|
||||||
android:defaultValue="@string/default_resource"
|
|
||||||
android:entries="@array/resources"
|
|
||||||
android:entryValues="@array/resources"
|
|
||||||
android:key="resource"
|
|
||||||
android:summary="@string/pref_xmpp_resource_summary"
|
|
||||||
android:title="@string/pref_xmpp_resource"/>
|
|
||||||
<PreferenceScreen
|
<PreferenceScreen
|
||||||
android:key="huawei"
|
android:key="huawei"
|
||||||
android:title="@string/huawei_protected_apps"
|
android:title="@string/huawei_protected_apps"
|
||||||
|
|
Loading…
Reference in a new issue