
Fixes #791 Squash of commits: 534f25d7dae3ce6852243e28fdd0a69ac01e9463 808fdf5147f27a912a60bee39aa4bf1ddd4f43b4 1eaf8a8330710ad35ba7c368e04f909af623ae4c 31585242c2359efdcd0eeddb9745077f54dbc9eb 2e69bd0bd0286ed1e98a42f4c3421ba4d8cf524b e904fb5015bf3a1904ab941a1957edf3b1e7abd2 eebbadf3b3816bbf8fcccb763e419fed252d266f 7c5b87724ce494e5a6e8026557ed50a8fd9f23e8 b0eaaf446937794fe19cbdb4f8309c3ff83d4e42 8c652f9e8bb3512958d9ad8c6f1326505f2d98c8 ad0ea1ad948ff6f8fde7b0b10f5163dc8852032f f5d49897e0dba691ef53a0eddb9ed34d129ad442 a08fa64c505bd895b7c626cfad182380373be20b de67079113e08394a276048c31f6b21baa300829 9069f342173ba30c2b20c67529c7ff497a6a257d 0169fa79d161ee898c4b6762e207087682a952d8 8585a5bd75a5d56927fed8317729bd15fffe4dcc 0053528a078369e0b65dcf71bda251072a1299c7 e901a9c3554bd7cca193e92919b463991eadfea7 c5c78257434813c69ab9b7558bcc8f7cbe858433 e905af348d46d77bc46b5f7211527684acc02fab 13a0f9a10c7892b0f90f5fabd2f2615701b0fd66 2cfba1e24b0139839e4453b92be7e20634d150cf 58e074fb5bb44b05a8104250fccd7c024c808c1a 0d6cf98fc8eab212d798ac79b336f9b70a14f06d e23620f56b85bcab9f3b5d9ce1c01524cd9674dc d72cd2fcc8d54176c3ff53411a69b9bb4642eff3 195143dff8836623a37094a6b8fa6aa01ef31580 5f5f3caf3a1e480a99d27ee5c34ba516419c52e4 1dee3d5861c9f9c710da4cbda3688d94c622ca93 23949b8aa32c78b27bab49bb3c4f3ff588925ce1 9bf97f8ae522796e0dacb7f6fe7a7f90f86a93a1
423 lines
11 KiB
Java
423 lines
11 KiB
Java
package eu.siacs.conversations.entities;
|
|
|
|
import android.content.ContentValues;
|
|
import android.database.Cursor;
|
|
import android.os.SystemClock;
|
|
|
|
import net.java.otr4j.crypto.OtrCryptoEngineImpl;
|
|
import net.java.otr4j.crypto.OtrCryptoException;
|
|
|
|
import org.json.JSONException;
|
|
import org.json.JSONObject;
|
|
|
|
import java.security.interfaces.DSAPublicKey;
|
|
import java.util.Collection;
|
|
import java.util.List;
|
|
import java.util.concurrent.CopyOnWriteArrayList;
|
|
import java.util.concurrent.CopyOnWriteArraySet;
|
|
|
|
import eu.siacs.conversations.Config;
|
|
import eu.siacs.conversations.R;
|
|
import eu.siacs.conversations.crypto.OtrEngine;
|
|
import eu.siacs.conversations.services.XmppConnectionService;
|
|
import eu.siacs.conversations.xmpp.XmppConnection;
|
|
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
|
import eu.siacs.conversations.xmpp.jid.Jid;
|
|
|
|
public class Account extends AbstractEntity {
|
|
|
|
public static final String TABLENAME = "accounts";
|
|
|
|
public static final String USERNAME = "username";
|
|
public static final String SERVER = "server";
|
|
public static final String PASSWORD = "password";
|
|
public static final String OPTIONS = "options";
|
|
public static final String ROSTERVERSION = "rosterversion";
|
|
public static final String KEYS = "keys";
|
|
public static final String AVATAR = "avatar";
|
|
|
|
public static final String PINNED_MECHANISM_KEY = "pinned_mechanism";
|
|
|
|
public static final int OPTION_USETLS = 0;
|
|
public static final int OPTION_DISABLED = 1;
|
|
public static final int OPTION_REGISTER = 2;
|
|
public static final int OPTION_USECOMPRESSION = 3;
|
|
|
|
public static enum State {
|
|
DISABLED,
|
|
OFFLINE,
|
|
CONNECTING,
|
|
ONLINE,
|
|
NO_INTERNET,
|
|
UNAUTHORIZED(true),
|
|
SERVER_NOT_FOUND(true),
|
|
REGISTRATION_FAILED(true),
|
|
REGISTRATION_CONFLICT(true),
|
|
REGISTRATION_SUCCESSFUL,
|
|
REGISTRATION_NOT_SUPPORTED(true),
|
|
SECURITY_ERROR(true),
|
|
INCOMPATIBLE_SERVER(true);
|
|
|
|
private final boolean isError;
|
|
|
|
public boolean isError() {
|
|
return this.isError;
|
|
}
|
|
|
|
private State(final boolean isError) {
|
|
this.isError = isError;
|
|
}
|
|
|
|
private State() {
|
|
this(false);
|
|
}
|
|
|
|
public int getReadableId() {
|
|
switch (this) {
|
|
case DISABLED:
|
|
return R.string.account_status_disabled;
|
|
case ONLINE:
|
|
return R.string.account_status_online;
|
|
case CONNECTING:
|
|
return R.string.account_status_connecting;
|
|
case OFFLINE:
|
|
return R.string.account_status_offline;
|
|
case UNAUTHORIZED:
|
|
return R.string.account_status_unauthorized;
|
|
case SERVER_NOT_FOUND:
|
|
return R.string.account_status_not_found;
|
|
case NO_INTERNET:
|
|
return R.string.account_status_no_internet;
|
|
case REGISTRATION_FAILED:
|
|
return R.string.account_status_regis_fail;
|
|
case REGISTRATION_CONFLICT:
|
|
return R.string.account_status_regis_conflict;
|
|
case REGISTRATION_SUCCESSFUL:
|
|
return R.string.account_status_regis_success;
|
|
case REGISTRATION_NOT_SUPPORTED:
|
|
return R.string.account_status_regis_not_sup;
|
|
case SECURITY_ERROR:
|
|
return R.string.account_status_security_error;
|
|
case INCOMPATIBLE_SERVER:
|
|
return R.string.account_status_incompatible_server;
|
|
default:
|
|
return R.string.account_status_unknown;
|
|
}
|
|
}
|
|
}
|
|
|
|
public List<Conversation> pendingConferenceJoins = new CopyOnWriteArrayList<>();
|
|
public List<Conversation> pendingConferenceLeaves = new CopyOnWriteArrayList<>();
|
|
protected Jid jid;
|
|
protected String password;
|
|
protected int options = 0;
|
|
protected String rosterVersion;
|
|
protected State status = State.OFFLINE;
|
|
protected JSONObject keys = new JSONObject();
|
|
protected String avatar;
|
|
protected boolean online = false;
|
|
private OtrEngine otrEngine = null;
|
|
private XmppConnection xmppConnection = null;
|
|
private long mEndGracePeriod = 0L;
|
|
private String otrFingerprint;
|
|
private final Roster roster = new Roster(this);
|
|
private List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
|
|
private final Collection<Jid> blocklist = new CopyOnWriteArraySet<>();
|
|
|
|
public Account() {
|
|
this.uuid = "0";
|
|
}
|
|
|
|
public Account(final Jid jid, final String password) {
|
|
this(java.util.UUID.randomUUID().toString(), jid,
|
|
password, 0, null, "", null);
|
|
}
|
|
|
|
public Account(final String uuid, final Jid jid,
|
|
final String password, final int options, final String rosterVersion, final String keys,
|
|
final String avatar) {
|
|
this.uuid = uuid;
|
|
this.jid = jid;
|
|
if (jid.isBareJid()) {
|
|
this.setResource("mobile");
|
|
}
|
|
this.password = password;
|
|
this.options = options;
|
|
this.rosterVersion = rosterVersion;
|
|
try {
|
|
this.keys = new JSONObject(keys);
|
|
} catch (final JSONException ignored) {
|
|
|
|
}
|
|
this.avatar = avatar;
|
|
}
|
|
|
|
public static Account fromCursor(Cursor cursor) {
|
|
Jid jid = null;
|
|
try {
|
|
jid = Jid.fromParts(cursor.getString(cursor.getColumnIndex(USERNAME)),
|
|
cursor.getString(cursor.getColumnIndex(SERVER)), "mobile");
|
|
} catch (final InvalidJidException ignored) {
|
|
}
|
|
return new Account(cursor.getString(cursor.getColumnIndex(UUID)),
|
|
jid,
|
|
cursor.getString(cursor.getColumnIndex(PASSWORD)),
|
|
cursor.getInt(cursor.getColumnIndex(OPTIONS)),
|
|
cursor.getString(cursor.getColumnIndex(ROSTERVERSION)),
|
|
cursor.getString(cursor.getColumnIndex(KEYS)),
|
|
cursor.getString(cursor.getColumnIndex(AVATAR)));
|
|
}
|
|
|
|
public boolean isOptionSet(int option) {
|
|
return ((options & (1 << option)) != 0);
|
|
}
|
|
|
|
public void setOption(int option, boolean value) {
|
|
if (value) {
|
|
this.options |= 1 << option;
|
|
} else {
|
|
this.options &= ~(1 << option);
|
|
}
|
|
}
|
|
|
|
public String getUsername() {
|
|
return jid.getLocalpart();
|
|
}
|
|
|
|
public void setUsername(final String username) throws InvalidJidException {
|
|
jid = Jid.fromParts(username, jid.getDomainpart(), jid.getResourcepart());
|
|
}
|
|
|
|
public Jid getServer() {
|
|
return jid.toDomainJid();
|
|
}
|
|
|
|
public void setServer(final String server) throws InvalidJidException {
|
|
jid = Jid.fromParts(jid.getLocalpart(), server, jid.getResourcepart());
|
|
}
|
|
|
|
public String getPassword() {
|
|
return password;
|
|
}
|
|
|
|
public void setPassword(final String password) {
|
|
this.password = password;
|
|
}
|
|
|
|
public State getStatus() {
|
|
if (isOptionSet(OPTION_DISABLED)) {
|
|
return State.DISABLED;
|
|
} else {
|
|
return this.status;
|
|
}
|
|
}
|
|
|
|
public void setStatus(final State status) {
|
|
this.status = status;
|
|
}
|
|
|
|
public boolean errorStatus() {
|
|
return getStatus().isError();
|
|
}
|
|
|
|
public boolean hasErrorStatus() {
|
|
return getXmppConnection() != null && getStatus().isError() && getXmppConnection().getAttempt() >= 2;
|
|
}
|
|
|
|
public String getResource() {
|
|
return jid.getResourcepart();
|
|
}
|
|
|
|
public void setResource(final String resource) {
|
|
try {
|
|
jid = Jid.fromParts(jid.getLocalpart(), jid.getDomainpart(), resource);
|
|
} catch (final InvalidJidException ignored) {
|
|
}
|
|
}
|
|
|
|
public Jid getJid() {
|
|
return jid;
|
|
}
|
|
|
|
public JSONObject getKeys() {
|
|
return keys;
|
|
}
|
|
|
|
public String getSSLFingerprint() {
|
|
if (keys.has("ssl_cert")) {
|
|
try {
|
|
return keys.getString("ssl_cert");
|
|
} catch (JSONException e) {
|
|
return null;
|
|
}
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void setSSLCertFingerprint(String fingerprint) {
|
|
this.setKey("ssl_cert", fingerprint);
|
|
}
|
|
|
|
public boolean setKey(String keyName, String keyValue) {
|
|
try {
|
|
this.keys.put(keyName, keyValue);
|
|
return true;
|
|
} catch (JSONException e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public ContentValues getContentValues() {
|
|
ContentValues values = new ContentValues();
|
|
values.put(UUID, uuid);
|
|
values.put(USERNAME, jid.getLocalpart());
|
|
values.put(SERVER, jid.getDomainpart());
|
|
values.put(PASSWORD, password);
|
|
values.put(OPTIONS, options);
|
|
values.put(KEYS, this.keys.toString());
|
|
values.put(ROSTERVERSION, rosterVersion);
|
|
values.put(AVATAR, avatar);
|
|
return values;
|
|
}
|
|
|
|
public void initOtrEngine(final XmppConnectionService context) {
|
|
this.otrEngine = new OtrEngine(context, this);
|
|
}
|
|
|
|
public OtrEngine getOtrEngine() {
|
|
return this.otrEngine;
|
|
}
|
|
|
|
public XmppConnection getXmppConnection() {
|
|
return this.xmppConnection;
|
|
}
|
|
|
|
public void setXmppConnection(final XmppConnection connection) {
|
|
this.xmppConnection = connection;
|
|
}
|
|
|
|
public String getOtrFingerprint() {
|
|
if (this.otrFingerprint == null) {
|
|
try {
|
|
if (this.otrEngine == null) {
|
|
return null;
|
|
}
|
|
DSAPublicKey publicKey = (DSAPublicKey) this.otrEngine.getPublicKey();
|
|
if (publicKey == null) {
|
|
return null;
|
|
}
|
|
this.otrFingerprint = new OtrCryptoEngineImpl().getFingerprint(publicKey);
|
|
return this.otrFingerprint;
|
|
} catch (final OtrCryptoException ignored) {
|
|
return null;
|
|
}
|
|
} else {
|
|
return this.otrFingerprint;
|
|
}
|
|
}
|
|
|
|
public String getRosterVersion() {
|
|
if (this.rosterVersion == null) {
|
|
return "";
|
|
} else {
|
|
return this.rosterVersion;
|
|
}
|
|
}
|
|
|
|
public void setRosterVersion(final String version) {
|
|
this.rosterVersion = version;
|
|
}
|
|
|
|
public int countPresences() {
|
|
return this.getRoster().getContact(this.getJid().toBareJid()).getPresences().size();
|
|
}
|
|
|
|
public String getPgpSignature() {
|
|
if (keys.has("pgp_signature")) {
|
|
try {
|
|
return keys.getString("pgp_signature");
|
|
} catch (JSONException e) {
|
|
return null;
|
|
}
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public Roster getRoster() {
|
|
return this.roster;
|
|
}
|
|
|
|
public List<Bookmark> getBookmarks() {
|
|
return this.bookmarks;
|
|
}
|
|
|
|
public void setBookmarks(final List<Bookmark> bookmarks) {
|
|
this.bookmarks = bookmarks;
|
|
}
|
|
|
|
public boolean hasBookmarkFor(final Jid conferenceJid) {
|
|
for (Bookmark bookmark : this.bookmarks) {
|
|
final Jid jid = bookmark.getJid();
|
|
if (jid != null && jid.equals(conferenceJid.toBareJid())) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public boolean setAvatar(String filename) {
|
|
if (this.avatar != null && this.avatar.equals(filename)) {
|
|
return false;
|
|
} else {
|
|
this.avatar = filename;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public String getAvatar() {
|
|
return this.avatar;
|
|
}
|
|
|
|
public void activateGracePeriod() {
|
|
this.mEndGracePeriod = SystemClock.elapsedRealtime()
|
|
+ (Config.CARBON_GRACE_PERIOD * 1000);
|
|
}
|
|
|
|
public void deactivateGracePeriod() {
|
|
this.mEndGracePeriod = 0L;
|
|
}
|
|
|
|
public boolean inGracePeriod() {
|
|
return SystemClock.elapsedRealtime() < this.mEndGracePeriod;
|
|
}
|
|
|
|
public String getShareableUri() {
|
|
String fingerprint = this.getOtrFingerprint();
|
|
if (fingerprint != null) {
|
|
return "xmpp:" + this.getJid().toBareJid().toString() + "?otr-fingerprint="+fingerprint;
|
|
} else {
|
|
return "xmpp:" + this.getJid().toBareJid().toString();
|
|
}
|
|
}
|
|
|
|
public boolean isBlocked(final ListItem contact) {
|
|
final Jid jid = contact.getJid();
|
|
return jid != null && (blocklist.contains(jid.toBareJid()) || blocklist.contains(jid.toDomainJid()));
|
|
}
|
|
|
|
public boolean isBlocked(final Jid jid) {
|
|
return jid != null && blocklist.contains(jid.toBareJid());
|
|
}
|
|
|
|
public Collection<Jid> getBlocklist() {
|
|
return this.blocklist;
|
|
}
|
|
|
|
public void clearBlocklist() {
|
|
getBlocklist().clear();
|
|
}
|
|
}
|