aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian S <christian@pix-art.de>2015-10-17 19:35:02 +0200
committerChristian S <christian@pix-art.de>2015-10-17 19:35:02 +0200
commit5f77d4d1242e7ef64a3895492a9fe8f9bc38c78f (patch)
treef3cdf3e3ed60dd9aaae8bd2337019fa69cf027f1
parent5dc0b7df6a81a6dee2baf468ed3442527fe730de (diff)
parent3c6c424d31be3e21d1bebd6288646f1cbc6881d9 (diff)
copy commits
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java131
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Account.java3
-rw-r--r--src/main/java/eu/siacs/conversations/generator/IqGenerator.java10
-rw-r--r--src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java13
-rw-r--r--src/main/java/eu/siacs/conversations/parser/IqParser.java29
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java385
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java3
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationFragment.java3
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java2
-rw-r--r--src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java104
-rw-r--r--src/main/java/eu/siacs/conversations/utils/CryptoHelper.java28
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/OnKeyStatusUpdated.java4
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java77
-rw-r--r--src/main/res/values/strings.xml2
14 files changed, 484 insertions, 310 deletions
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
index 58e5a0957..ab3aefac0 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
@@ -1,10 +1,10 @@
package eu.siacs.conversations.crypto.axolotl;
import android.security.KeyChain;
-import android.security.KeyChainException;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
+import android.util.Pair;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.whispersystems.libaxolotl.AxolotlAddress;
@@ -20,11 +20,9 @@ import org.whispersystems.libaxolotl.state.PreKeyRecord;
import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
import org.whispersystems.libaxolotl.util.KeyHelper;
-import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.Signature;
-import java.security.SignatureException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashMap;
@@ -43,12 +41,13 @@ import eu.siacs.conversations.parser.IqParser;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
import eu.siacs.conversations.xml.Element;
+import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
-public class AxolotlService {
+public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
public static final String PEP_PREFIX = "eu.siacs.conversations.axolotl";
public static final String PEP_DEVICE_LIST = PEP_PREFIX + ".devicelist";
@@ -71,6 +70,15 @@ public class AxolotlService {
private int numPublishTriesOnEmptyPep = 0;
private boolean pepBroken = false;
+ @Override
+ public void onAdvancedStreamFeaturesAvailable(Account account) {
+ if (account.getXmppConnection().getFeatures().pep()) {
+ publishBundlesIfNeeded(true, false);
+ } else {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": skipping OMEMO initialization");
+ }
+ }
+
private static class AxolotlAddressMap<T> {
protected Map<String, Map<Integer, T>> map;
protected final Object MAP_LOCK = new Object();
@@ -167,9 +175,11 @@ public class AxolotlService {
}
}
- private enum FetchStatus {
+ public enum FetchStatus {
PENDING,
SUCCESS,
+ SUCCESS_VERIFIED,
+ TIMEOUT,
ERROR
}
@@ -313,7 +323,8 @@ public class AxolotlService {
setTrustOnSessions(jid, newDevices, XmppAxolotlSession.Trust.INACTIVE_UNTRUSTED,
XmppAxolotlSession.Trust.UNTRUSTED);
this.deviceIds.put(jid, deviceIds);
- mXmppConnectionService.keyStatusUpdated();
+ findDevicesWithoutSession(jid);
+ mXmppConnectionService.keyStatusUpdated(null);
}
public void wipeOtherPepDevices() {
@@ -402,7 +413,6 @@ public class AxolotlService {
byte[] signature = verifier.sign();
IqPacket packet = mXmppConnectionService.getIqGenerator().publishVerification(signature, chain, getOwnDeviceId());
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + ": publish verification for device "+getOwnDeviceId());
- Log.d(Config.LOGTAG,"verification : "+packet.toString());
mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
@@ -565,6 +575,61 @@ public class AxolotlService {
axolotlStore.setFingerprintTrust(fingerprint, trust);
}
+ private void verifySessionWithPEP(final XmppAxolotlSession session, final IdentityKey identityKey) {
+ final AxolotlAddress address = session.getRemoteAddress();
+ try {
+ IqPacket packet = mXmppConnectionService.getIqGenerator().retrieveVerificationForDevice(Jid.fromString(address.getName()), address.getDeviceId());
+ mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ Pair<X509Certificate[],byte[]> verification = mXmppConnectionService.getIqParser().verification(packet);
+ if (verification != null) {
+ try {
+ Signature verifier = Signature.getInstance("sha256WithRSA");
+ verifier.initVerify(verification.first[0]);
+ verifier.update(identityKey.serialize());
+ if (verifier.verify(verification.second)) {
+ try {
+ mXmppConnectionService.getMemorizingTrustManager().getNonInteractive().checkClientTrusted(verification.first, "RSA");
+ Log.d(Config.LOGTAG, "verified session with x.509 signature. fingerprint was: "+session.getFingerprint());
+ setFingerprintTrust(session.getFingerprint(), XmppAxolotlSession.Trust.TRUSTED);
+ fetchStatusMap.put(address, FetchStatus.SUCCESS_VERIFIED);
+ finishBuildingSessionsFromPEP(address);
+ return;
+ } catch (Exception e) {
+ Log.d(Config.LOGTAG,"could not verify certificate");
+ }
+ }
+ } catch (Exception e) {
+ Log.d(Config.LOGTAG, "error during verification " + e.getMessage());
+ }
+ }
+ fetchStatusMap.put(address, FetchStatus.SUCCESS);
+ finishBuildingSessionsFromPEP(address);
+ }
+ });
+ } catch (InvalidJidException e) {
+ fetchStatusMap.put(address, FetchStatus.SUCCESS);
+ finishBuildingSessionsFromPEP(address);
+ }
+ }
+
+ private void finishBuildingSessionsFromPEP(final AxolotlAddress address) {
+ AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(), 0);
+ if (!fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)
+ && !fetchStatusMap.getAll(address).containsValue(FetchStatus.PENDING)) {
+ FetchStatus report = null;
+ if (fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.SUCCESS_VERIFIED)
+ | fetchStatusMap.getAll(address).containsValue(FetchStatus.SUCCESS_VERIFIED)) {
+ report = FetchStatus.SUCCESS_VERIFIED;
+ } else if (fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.ERROR)
+ || fetchStatusMap.getAll(address).containsValue(FetchStatus.ERROR)) {
+ report = FetchStatus.ERROR;
+ }
+ mXmppConnectionService.keyStatusUpdated(report);
+ }
+ }
+
private void buildSessionFromPEP(final AxolotlAddress address) {
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Building new sesstion for " + address.toString());
if (address.getDeviceId() == getOwnDeviceId()) {
@@ -576,17 +641,12 @@ public class AxolotlService {
Jid.fromString(address.getName()), address.getDeviceId());
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Retrieving bundle: " + bundlesPacket);
mXmppConnectionService.sendIqPacket(account, bundlesPacket, new OnIqPacketReceived() {
- private void finish() {
- AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(), 0);
- if (!fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)
- && !fetchStatusMap.getAll(address).containsValue(FetchStatus.PENDING)) {
- mXmppConnectionService.keyStatusUpdated();
- }
- }
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
- if (packet.getType() == IqPacket.TYPE.RESULT) {
+ if (packet.getType() == IqPacket.TYPE.TIMEOUT) {
+ fetchStatusMap.put(address, FetchStatus.TIMEOUT);
+ } else if (packet.getType() == IqPacket.TYPE.RESULT) {
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received preKey IQ packet, processing...");
final IqParser parser = mXmppConnectionService.getIqParser();
final List<PreKeyBundle> preKeyBundleList = parser.preKeys(packet);
@@ -594,7 +654,7 @@ public class AxolotlService {
if (preKeyBundleList.isEmpty() || bundle == null) {
Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "preKey IQ packet invalid: " + packet);
fetchStatusMap.put(address, FetchStatus.ERROR);
- finish();
+ finishBuildingSessionsFromPEP(address);
return;
}
Random random = new Random();
@@ -602,7 +662,7 @@ public class AxolotlService {
if (preKey == null) {
//should never happen
fetchStatusMap.put(address, FetchStatus.ERROR);
- finish();
+ finishBuildingSessionsFromPEP(address);
return;
}
@@ -616,18 +676,22 @@ public class AxolotlService {
builder.process(preKeyBundle);
XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, bundle.getIdentityKey().getFingerprint().replaceAll("\\s", ""));
sessions.put(address, session);
- fetchStatusMap.put(address, FetchStatus.SUCCESS);
+ if (Config.X509_VERIFICATION) {
+ verifySessionWithPEP(session, bundle.getIdentityKey());
+ } else {
+ fetchStatusMap.put(address, FetchStatus.SUCCESS);
+ finishBuildingSessionsFromPEP(address);
+ }
} catch (UntrustedIdentityException | InvalidKeyException e) {
Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Error building session for " + address + ": "
+ e.getClass().getName() + ", " + e.getMessage());
fetchStatusMap.put(address, FetchStatus.ERROR);
+ finishBuildingSessionsFromPEP(address);
}
-
- finish();
} else {
fetchStatusMap.put(address, FetchStatus.ERROR);
Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while building session:" + packet.findChild("error"));
- finish();
+ finishBuildingSessionsFromPEP(address);
}
}
});
@@ -637,8 +701,11 @@ public class AxolotlService {
}
public Set<AxolotlAddress> findDevicesWithoutSession(final Conversation conversation) {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Finding devices without session for " + conversation.getContact().getJid().toBareJid());
- Jid contactJid = conversation.getContact().getJid().toBareJid();
+ return findDevicesWithoutSession(conversation.getContact().getJid().toBareJid());
+ }
+
+ public Set<AxolotlAddress> findDevicesWithoutSession(final Jid contactJid) {
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Finding devices without session for " + contactJid);
Set<AxolotlAddress> addresses = new HashSet<>();
if (deviceIds.get(contactJid) != null) {
for (Integer foreignId : this.deviceIds.get(contactJid)) {
@@ -651,7 +718,11 @@ public class AxolotlService {
sessions.put(address, session);
} else {
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Found device " + account.getJid().toBareJid() + ":" + foreignId);
- addresses.add(new AxolotlAddress(contactJid.toString(), foreignId));
+ if (fetchStatusMap.get(address) != FetchStatus.ERROR) {
+ addresses.add(address);
+ } else {
+ Log.d(Config.LOGTAG,getLogprefix(account)+"skipping over "+address+" because it's broken");
+ }
}
}
}
@@ -669,7 +740,11 @@ public class AxolotlService {
sessions.put(address, session);
} else {
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Found device " + account.getJid().toBareJid() + ":" + ownId);
- addresses.add(new AxolotlAddress(account.getJid().toBareJid().toString(), ownId));
+ if (fetchStatusMap.get(address) != FetchStatus.ERROR) {
+ addresses.add(address);
+ } else {
+ Log.d(Config.LOGTAG,getLogprefix(account)+"skipping over "+address+" because it's broken");
+ }
}
}
}
@@ -685,7 +760,7 @@ public class AxolotlService {
for (AxolotlAddress address : addresses) {
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Processing device: " + address.toString());
FetchStatus status = fetchStatusMap.get(address);
- if (status == null || status == FetchStatus.ERROR) {
+ if (status == null || status == FetchStatus.TIMEOUT) {
fetchStatusMap.put(address, FetchStatus.PENDING);
this.buildSessionFromPEP(address);
newSessions = true;
@@ -699,9 +774,9 @@ public class AxolotlService {
return newSessions;
}
- public boolean hasPendingKeyFetches(Conversation conversation) {
+ public boolean hasPendingKeyFetches(Account account, Contact contact) {
AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(), 0);
- AxolotlAddress foreignAddress = new AxolotlAddress(conversation.getJid().toBareJid().toString(), 0);
+ AxolotlAddress foreignAddress = new AxolotlAddress(contact.getJid().toBareJid().toString(), 0);
return fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)
|| fetchStatusMap.getAll(foreignAddress).containsValue(FetchStatus.PENDING);
diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java
index 0eb38c9fd..ebfd98055 100644
--- a/src/main/java/eu/siacs/conversations/entities/Account.java
+++ b/src/main/java/eu/siacs/conversations/entities/Account.java
@@ -297,6 +297,9 @@ public class Account extends AbstractEntity {
public void initAccountServices(final XmppConnectionService context) {
this.mOtrService = new OtrService(context, this);
this.axolotlService = new AxolotlService(this, context);
+ if (xmppConnection != null) {
+ xmppConnection.addOnAdvancedStreamFeaturesAvailableListener(axolotlService);
+ }
}
public OtrService getOtrService() {
diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
index fb69860db..7457cad8b 100644
--- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
@@ -137,9 +137,13 @@ public class IqGenerator extends AbstractGenerator {
public IqPacket retrieveBundlesForDevice(final Jid to, final int deviceid) {
final IqPacket packet = retrieve(AxolotlService.PEP_BUNDLES+":"+deviceid, null);
- if(to != null) {
- packet.setTo(to);
- }
+ packet.setTo(to);
+ return packet;
+ }
+
+ public IqPacket retrieveVerificationForDevice(final Jid to, final int deviceid) {
+ final IqPacket packet = retrieve(AxolotlService.PEP_VERIFICATION+":"+deviceid, null);
+ packet.setTo(to);
return packet;
}
diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
index 5fa7bf816..792a71e8b 100644
--- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
+++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
@@ -22,6 +22,7 @@ import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Transferable;
+import eu.siacs.conversations.entities.TransferablePlaceholder;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.AbstractConnectionManager;
import eu.siacs.conversations.services.XmppConnectionService;
@@ -66,7 +67,11 @@ public class HttpDownloadConnection implements Transferable {
this.message = message;
this.message.setTransferable(this);
try {
- mUrl = new URL(message.getBody());
+ if (message.hasFileOnRemoteHost()) {
+ mUrl = message.getFileParams().url;
+ } else {
+ mUrl = new URL(message.getBody());
+ }
String[] parts = mUrl.getPath().toLowerCase().split("\\.");
String lastPart = parts.length >= 1 ? parts[parts.length - 1] : null;
String secondToLast = parts.length >= 2 ? parts[parts.length -2] : null;
@@ -106,7 +111,11 @@ public class HttpDownloadConnection implements Transferable {
public void cancel() {
mHttpConnectionManager.finishConnection(this);
- message.setTransferable(null);
+ if (message.isFileOrImage()) {
+ message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
+ } else {
+ message.setTransferable(null);
+ }
mXmppConnectionService.updateConversationUi();
}
diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java
index f6446cfd1..e26a493f5 100644
--- a/src/main/java/eu/siacs/conversations/parser/IqParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java
@@ -3,6 +3,7 @@ package eu.siacs.conversations.parser;
import android.support.annotation.NonNull;
import android.util.Base64;
import android.util.Log;
+import android.util.Pair;
import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.libaxolotl.InvalidKeyException;
@@ -10,6 +11,10 @@ import org.whispersystems.libaxolotl.ecc.Curve;
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.libaxolotl.state.PreKeyBundle;
+import java.io.ByteArrayInputStream;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -204,6 +209,30 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
return preKeyRecords;
}
+ public Pair<X509Certificate[],byte[]> verification(final IqPacket packet) {
+ Element item = getItem(packet);
+ Element verification = item != null ? item.findChild("verification",AxolotlService.PEP_PREFIX) : null;
+ Element chain = verification != null ? verification.findChild("chain") : null;
+ Element signature = verification != null ? verification.findChild("signature") : null;
+ if (chain != null && signature != null) {
+ List<Element> certElements = chain.getChildren();
+ X509Certificate[] certificates = new X509Certificate[certElements.size()];
+ try {
+ CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
+ int i = 0;
+ for(Element cert : certElements) {
+ certificates[i] = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(Base64.decode(cert.getContent(),Base64.DEFAULT)));
+ ++i;
+ }
+ return new Pair<>(certificates,Base64.decode(signature.getContent(),Base64.DEFAULT));
+ } catch (CertificateException e) {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
public PreKeyBundle bundle(final IqPacket bundle) {
Element bundleItem = getItem(bundle);
if(bundleItem == null) {
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index f9f9b71e2..d9ae6a921 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -26,10 +26,9 @@ import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
import android.security.KeyChain;
-import android.security.KeyChainException;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.util.LruCache;
-import android.util.DisplayMetrics;
import android.util.Pair;
import net.java.otr4j.OtrException;
@@ -38,16 +37,11 @@ import net.java.otr4j.session.SessionID;
import net.java.otr4j.session.SessionImpl;
import net.java.otr4j.session.SessionStatus;
-import org.bouncycastle.asn1.x500.X500Name;
-import org.bouncycastle.asn1.x500.style.BCStyle;
-import org.bouncycastle.asn1.x500.style.IETFUtils;
-import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpServiceConnection;
import java.math.BigInteger;
import java.security.SecureRandom;
-import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
@@ -66,6 +60,7 @@ import de.duenndns.ssl.MemorizingTrustManager;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
+import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Blockable;
@@ -124,9 +119,16 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public static final String ACTION_CLEAR_NOTIFICATION = "clear_notification";
public static final String ACTION_DISABLE_FOREGROUND = "disable_foreground";
- private static final String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
public static final String ACTION_TRY_AGAIN = "try_again";
public static final String ACTION_DISABLE_ACCOUNT = "disable_account";
+ private static final String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
+ private final SerialSingleThreadExecutor mFileAddingExecutor = new SerialSingleThreadExecutor();
+ private final SerialSingleThreadExecutor mDatabaseExecutor = new SerialSingleThreadExecutor();
+ private final IBinder mBinder = new XmppConnectionBinder();
+ private final List<Conversation> conversations = new CopyOnWriteArrayList<>();
+ private final IqGenerator mIqGenerator = new IqGenerator(this);
+ private final List<String> mInProgressAvatarFetches = new ArrayList<>();
+ public DatabaseBackend databaseBackend;
private ContentObserver contactObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
@@ -137,63 +139,30 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
startService(intent);
}
};
-
- private final SerialSingleThreadExecutor mFileAddingExecutor = new SerialSingleThreadExecutor();
- private final SerialSingleThreadExecutor mDatabaseExecutor = new SerialSingleThreadExecutor();
-
- private final IBinder mBinder = new XmppConnectionBinder();
- private final List<Conversation> conversations = new CopyOnWriteArrayList<>();
- private final FileObserver fileObserver = new FileObserver(
- FileBackend.getConversationsImageDirectory()) {
-
- @Override
- public void onEvent(int event, String path) {
- if (event == FileObserver.DELETE) {
- markFileDeleted(path.split("\\.")[0]);
- }
- }
- };
- private final OnJinglePacketReceived jingleListener = new OnJinglePacketReceived() {
-
- @Override
- public void onJinglePacketReceived(Account account, JinglePacket packet) {
- mJingleConnectionManager.deliverPacket(account, packet);
- }
- };
- private final OnBindListener mOnBindListener = new OnBindListener() {
-
- @Override
- public void onBind(final Account account) {
- account.getRoster().clearPresences();
- fetchRosterFromServer(account);
- fetchBookmarks(account);
- sendPresence(account);
- connectMultiModeConversations(account);
- mMessageArchiveService.executePendingQueries(account);
- mJingleConnectionManager.cancelInTransmission();
- syncDirtyContacts(account);
- account.getAxolotlService().publishBundlesIfNeeded(true, false);
- }
- };
- private final OnMessageAcknowledged mOnMessageAcknowledgedListener = new OnMessageAcknowledged() {
-
+ private FileBackend fileBackend = new FileBackend(this);
+ private MemorizingTrustManager mMemorizingTrustManager;
+ private NotificationService mNotificationService = new NotificationService(
+ this);
+ private OnMessagePacketReceived mMessageParser = new MessageParser(this);
+ private OnPresencePacketReceived mPresenceParser = new PresenceParser(this);
+ private IqParser mIqParser = new IqParser(this);
+ private OnIqPacketReceived mDefaultIqHandler = new OnIqPacketReceived() {
@Override
- public void onMessageAcknowledged(Account account, String uuid) {
- for (final Conversation conversation : getConversations()) {
- if (conversation.getAccount() == account) {
- Message message = conversation.findUnsentMessageWithUuid(uuid);
- if (message != null) {
- markMessage(message, Message.STATUS_SEND);
- if (conversation.setLastMessageTransmitted(System.currentTimeMillis())) {
- databaseBackend.updateConversation(conversation);
- }
- }
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ if (packet.getType() != IqPacket.TYPE.RESULT) {
+ Element error = packet.findChild("error");
+ String text = error != null ? error.findChildContent("text") : null;
+ if (text != null) {
+ Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": received iq error - " + text);
}
}
}
};
- private final IqGenerator mIqGenerator = new IqGenerator(this);
- public DatabaseBackend databaseBackend;
+ private MessageGenerator mMessageGenerator = new MessageGenerator(this);
+ private PresenceGenerator mPresenceGenerator = new PresenceGenerator(this);
+ private List<Account> accounts;
+ private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(
+ this);
public OnContactStatusChanged onContactStatusChanged = new OnContactStatusChanged() {
@Override
@@ -220,42 +189,76 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
};
- private FileBackend fileBackend = new FileBackend(this);
- private MemorizingTrustManager mMemorizingTrustManager;
- private NotificationService mNotificationService = new NotificationService(
+ private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager(
this);
- private OnMessagePacketReceived mMessageParser = new MessageParser(this);
- private OnPresencePacketReceived mPresenceParser = new PresenceParser(this);
- private IqParser mIqParser = new IqParser(this);
- private OnIqPacketReceived mDefaultIqHandler = new OnIqPacketReceived() {
+ private AvatarService mAvatarService = new AvatarService(this);
+ private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this);
+ private OnConversationUpdate mOnConversationUpdate = null;
+ private final FileObserver fileObserver = new FileObserver(
+ FileBackend.getConversationsImageDirectory()) {
+
@Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- if (packet.getType() != IqPacket.TYPE.RESULT) {
- Element error = packet.findChild("error");
- String text = error != null ? error.findChildContent("text") : null;
- if (text != null) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": received iq error - "+text);
+ public void onEvent(int event, String path) {
+ if (event == FileObserver.DELETE) {
+ markFileDeleted(path.split("\\.")[0]);
+ }
+ }
+ };
+ private final OnJinglePacketReceived jingleListener = new OnJinglePacketReceived() {
+
+ @Override
+ public void onJinglePacketReceived(Account account, JinglePacket packet) {
+ mJingleConnectionManager.deliverPacket(account, packet);
+ }
+ };
+ private final OnMessageAcknowledged mOnMessageAcknowledgedListener = new OnMessageAcknowledged() {
+
+ @Override
+ public void onMessageAcknowledged(Account account, String uuid) {
+ for (final Conversation conversation : getConversations()) {
+ if (conversation.getAccount() == account) {
+ Message message = conversation.findUnsentMessageWithUuid(uuid);
+ if (message != null) {
+ markMessage(message, Message.STATUS_SEND);
+ if (conversation.setLastMessageTransmitted(System.currentTimeMillis())) {
+ databaseBackend.updateConversation(conversation);
+ }
+ }
}
}
}
};
- private MessageGenerator mMessageGenerator = new MessageGenerator(this);
- private PresenceGenerator mPresenceGenerator = new PresenceGenerator(this);
- private List<Account> accounts;
- private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(
- this);
- private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager(
- this);
- private AvatarService mAvatarService = new AvatarService(this);
- private final List<String> mInProgressAvatarFetches = new ArrayList<>();
- private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this);
- private OnConversationUpdate mOnConversationUpdate = null;
private int convChangedListenerCount = 0;
private OnShowErrorToast mOnShowErrorToast = null;
private int showErrorToastListenerCount = 0;
private int unreadCount = -1;
private OnAccountUpdate mOnAccountUpdate = null;
private OnCaptchaRequested mOnCaptchaRequested = null;
+ private int accountChangedListenerCount = 0;
+ private int captchaRequestedListenerCount = 0;
+ private OnRosterUpdate mOnRosterUpdate = null;
+ private OnUpdateBlocklist mOnUpdateBlocklist = null;
+ private int updateBlocklistListenerCount = 0;
+ private int rosterChangedListenerCount = 0;
+ private OnMucRosterUpdate mOnMucRosterUpdate = null;
+ private int mucRosterChangedListenerCount = 0;
+ private OnKeyStatusUpdated mOnKeyStatusUpdated = null;
+ private int keyStatusUpdatedListenerCount = 0;
+ private SecureRandom mRandom;
+ private final OnBindListener mOnBindListener = new OnBindListener() {
+
+ @Override
+ public void onBind(final Account account) {
+ account.getRoster().clearPresences();
+ fetchRosterFromServer(account);
+ fetchBookmarks(account);
+ sendPresence(account);
+ connectMultiModeConversations(account);
+ mMessageArchiveService.executePendingQueries(account);
+ mJingleConnectionManager.cancelInTransmission();
+ syncDirtyContacts(account);
+ }
+ };
private OnStatusChanged statusListener = new OnStatusChanged() {
@Override
@@ -267,10 +270,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (account.getStatus() == Account.State.ONLINE) {
if (connection != null && connection.getFeatures().csi()) {
if (checkListeners()) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid()+ " sending csi//inactive");
+ Log.d(Config.LOGTAG, account.getJid().toBareJid() + " sending csi//inactive");
connection.sendInactive();
} else {
- Log.d(Config.LOGTAG, account.getJid().toBareJid()+ " sending csi//active");
+ Log.d(Config.LOGTAG, account.getJid().toBareJid() + " sending csi//active");
connection.sendActive();
}
}
@@ -294,7 +297,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
resetSendingToWaiting(account);
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
int timeToReconnect = mRandom.nextInt(20) + 10;
- scheduleWakeUpCall(timeToReconnect,account.getUuid().hashCode());
+ scheduleWakeUpCall(timeToReconnect, account.getUuid().hashCode());
}
} else if (account.getStatus() == Account.State.REGISTRATION_SUCCESSFUL) {
databaseBackend.updateAccount(account);
@@ -307,23 +310,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
+ ": error connecting account. try again in "
+ next + "s for the "
+ (connection.getAttempt() + 1) + " time");
- scheduleWakeUpCall(next,account.getUuid().hashCode());
+ scheduleWakeUpCall(next, account.getUuid().hashCode());
}
- }
+ }
getNotificationService().updateErrorNotification();
}
};
- private int accountChangedListenerCount = 0;
- private int captchaRequestedListenerCount = 0;
- private OnRosterUpdate mOnRosterUpdate = null;
- private OnUpdateBlocklist mOnUpdateBlocklist = null;
- private int updateBlocklistListenerCount = 0;
- private int rosterChangedListenerCount = 0;
- private OnMucRosterUpdate mOnMucRosterUpdate = null;
- private int mucRosterChangedListenerCount = 0;
- private OnKeyStatusUpdated mOnKeyStatusUpdated = null;
- private int keyStatusUpdatedListenerCount = 0;
- private SecureRandom mRandom;
private OpenPgpServiceConnection pgpServiceConnection;
private PgpEngine mPgpEngine = null;
private WakeLock wakeLock;
@@ -333,6 +325,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
private EventReceiver mEventReceiver = new EventReceiver();
private boolean mRestoredFromDatabase = false;
+
+ private static String generateFetchKey(Account account, final Avatar avatar) {
+ return account.getJid().toBareJid() + "_" + avatar.owner + "_" + avatar.sha1sum;
+ }
+
public boolean areMessagesInitialized() {
return this.mRestoredFromDatabase;
}
@@ -341,8 +338,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (pgpServiceConnection.isBound()) {
if (this.mPgpEngine == null) {
this.mPgpEngine = new PgpEngine(new OpenPgpApi(
- getApplicationContext(),
- pgpServiceConnection.getService()), this);
+ getApplicationContext(),
+ pgpServiceConnection.getService()), this);
}
return mPgpEngine;
} else {
@@ -366,7 +363,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (encryption == Message.ENCRYPTION_PGP) {
encryption = Message.ENCRYPTION_DECRYPTED;
}
- Message message = new Message(conversation,uri.toString(),encryption);
+ Message message = new Message(conversation, uri.toString(), encryption);
if (conversation.getNextCounterpart() != null) {
message.setCounterpart(conversation.getNextCounterpart());
}
@@ -378,8 +375,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
public void attachFileToConversation(final Conversation conversation,
- final Uri uri,
- final UiCallback<Message> callback) {
+ final Uri uri,
+ final UiCallback<Message> callback) {
final Message message;
if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) {
message = new Message(conversation, "", Message.ENCRYPTION_DECRYPTED);
@@ -389,7 +386,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
message.setCounterpart(conversation.getNextCounterpart());
message.setType(Message.TYPE_FILE);
String path = getFileBackend().getOriginalPath(uri);
- if (path!=null) {
+ if (path != null) {
message.setRelativeFilePath(path);
getFileBackend().updateFileParams(message);
if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
@@ -419,7 +416,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void attachImageToConversation(final Conversation conversation, final Uri uri, final UiCallback<Message> callback) {
if (getFileBackend().useImageAsIs(uri)) {
- Log.d(Config.LOGTAG,"using image as is");
+ Log.d(Config.LOGTAG, "using image as is");
attachFileToConversation(conversation, uri, callback);
return;
}
@@ -427,7 +424,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) {
message = new Message(conversation, "", Message.ENCRYPTION_DECRYPTED);
} else {
- message = new Message(conversation, "",conversation.getNextEncryption());
+ message = new Message(conversation, "", conversation.getNextEncryption());
}
message.setCounterpart(conversation.getNextCounterpart());
message.setType(Message.TYPE_IMAGE);
@@ -462,7 +459,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
final String action = intent == null ? null : intent.getAction();
boolean interactive = false;
if (action != null) {
- Log.d(Config.LOGTAG,"action: "+action);
switch (action) {
case ConnectivityManager.CONNECTIVITY_ACTION:
if (hasInternetConnection() && Config.RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE) {
@@ -483,7 +479,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
mNotificationService.clear();
break;
case ACTION_DISABLE_FOREGROUND:
- getPreferences().edit().putBoolean("keep_foreground_service",false).commit();
+ getPreferences().edit().putBoolean("keep_foreground_service", false).commit();
toggleForegroundService();
break;
case ACTION_TRY_AGAIN:
@@ -495,7 +491,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
String jid = intent.getStringExtra("account");
Account account = jid == null ? null : findAccountByJid(Jid.fromString(jid));
if (account != null) {
- account.setOption(Account.OPTION_DISABLED,true);
+ account.setOption(Account.OPTION_DISABLED, true);
updateAccount(account);
}
} catch (final InvalidJidException ignored) {
@@ -535,7 +531,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
long lastReceived = account.getXmppConnection().getLastPacketReceived();
long lastSent = account.getXmppConnection().getLastPingSent();
long pingInterval = "ui".equals(action) ? Config.PING_MIN_INTERVAL * 1000 : Config.PING_MAX_INTERVAL * 1000;
- long msToNextPing = (Math.max(lastReceived,lastSent) + pingInterval) - SystemClock.elapsedRealtime();
+ long msToNextPing = (Math.max(lastReceived, lastSent) + pingInterval) - SystemClock.elapsedRealtime();
long pingTimeoutIn = (lastSent + Config.PING_TIMEOUT * 1000) - SystemClock.elapsedRealtime();
if (lastSent > lastReceived) {
if (pingTimeoutIn < 0) {
@@ -543,24 +539,24 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
this.reconnectAccount(account, true, interactive);
} else {
int secs = (int) (pingTimeoutIn / 1000);
- this.scheduleWakeUpCall(secs,account.getUuid().hashCode());
+ this.scheduleWakeUpCall(secs, account.getUuid().hashCode());
}
} else if (msToNextPing <= 0) {
account.getXmppConnection().sendPing();
- Log.d(Config.LOGTAG, account.getJid().toBareJid()+" send ping");
- this.scheduleWakeUpCall(Config.PING_TIMEOUT,account.getUuid().hashCode());
+ Log.d(Config.LOGTAG, account.getJid().toBareJid() + " send ping");
+ this.scheduleWakeUpCall(Config.PING_TIMEOUT, account.getUuid().hashCode());
} else {
this.scheduleWakeUpCall((int) (msToNextPing / 1000), account.getUuid().hashCode());
}
} else if (account.getStatus() == Account.State.OFFLINE) {
- reconnectAccount(account,true, interactive);
+ reconnectAccount(account, true, interactive);
} else if (account.getStatus() == Account.State.CONNECTING) {
long timeout = Config.CONNECT_TIMEOUT - ((SystemClock.elapsedRealtime() - account.getXmppConnection().getLastConnect()) / 1000);
if (timeout < 0) {
Log.d(Config.LOGTAG, account.getJid() + ": time out during connect reconnecting");
reconnectAccount(account, true, interactive);
} else {
- scheduleWakeUpCall((int) timeout,account.getUuid().hashCode());
+ scheduleWakeUpCall((int) timeout, account.getUuid().hashCode());
}
} else {
if (account.getXmppConnection().getTimeToNextAttempt() <= 0) {
@@ -621,8 +617,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
private void resetAllAttemptCounts(boolean reallyAll) {
- Log.d(Config.LOGTAG,"resetting all attepmt counts");
- for(Account account : accounts) {
+ Log.d(Config.LOGTAG, "resetting all attepmt counts");
+ for (Account account : accounts) {
if (account.hasErrorStatus() || reallyAll) {
final XmppConnection connection = account.getXmppConnection();
if (connection != null) {
@@ -634,7 +630,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public boolean hasInternetConnection() {
ConnectivityManager cm = (ConnectivityManager) getApplicationContext()
- .getSystemService(Context.CONNECTIVITY_SERVICE);
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnected();
}
@@ -667,7 +663,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
this.pgpServiceConnection.bindToService();
this.pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- this.wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"XmppConnectionService");
+ this.wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "XmppConnectionService");
toggleForegroundService();
updateUnreadCountBadge();
toggleScreenEventReceiver();
@@ -677,7 +673,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (level >= TRIM_MEMORY_COMPLETE) {
- Log.d(Config.LOGTAG,"clear cache due to low memory");
+ Log.d(Config.LOGTAG, "clear cache due to low memory");
getBitmapCache().evictAll();
}
}
@@ -717,7 +713,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
@Override
public void onTaskRemoved(final Intent rootIntent) {
super.onTaskRemoved(rootIntent);
- if (!getPreferences().getBoolean("keep_foreground_service",false)) {
+ if (!getPreferences().getBoolean("keep_foreground_service", false)) {
this.logoutAndSave();
}
}
@@ -763,6 +759,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
connection.setOnBindListener(this.mOnBindListener);
connection.setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener);
connection.addOnAdvancedStreamFeaturesAvailableListener(this.mMessageArchiveService);
+ AxolotlService axolotlService = account.getAxolotlService();
+ if (axolotlService != null) {
+ connection.addOnAdvancedStreamFeaturesAvailableListener(axolotlService);
+ }
return connection;
}
@@ -800,11 +800,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
message.getConversation().endOtrIfNeeded();
message.getConversation().findUnsentMessagesWithEncryption(Message.ENCRYPTION_OTR,
new Conversation.OnMessageFound() {
- @Override
- public void onMessageFound(Message message) {
- markMessage(message,Message.STATUS_SEND_FAILED);
- }
- });
+ @Override
+ public void onMessageFound(Message message) {
+ markMessage(message, Message.STATUS_SEND_FAILED);
+ }
+ });
}
if (account.isOnlineAndConnected()) {
@@ -812,7 +812,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
case Message.ENCRYPTION_NONE:
if (message.needsUploading()) {
if (account.httpUploadAvailable() || message.fixCounterpart()) {
- this.sendFileMessage(message,delay);
+ this.sendFileMessage(message, delay);
} else {
break;
}
@@ -824,7 +824,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
case Message.ENCRYPTION_DECRYPTED:
if (message.needsUploading()) {
if (account.httpUploadAvailable() || message.fixCounterpart()) {
- this.sendFileMessage(message,delay);
+ this.sendFileMessage(message, delay);
} else {
break;
}
@@ -857,7 +857,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
message.setAxolotlFingerprint(account.getAxolotlService().getOwnFingerprint());
if (message.needsUploading()) {
if (account.httpUploadAvailable() || message.fixCounterpart()) {
- this.sendFileMessage(message,delay);
+ this.sendFileMessage(message, delay);
} else {
break;
}
@@ -880,7 +880,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
} else {
- switch(message.getEncryption()) {
+ switch (message.getEncryption()) {
case Message.ENCRYPTION_DECRYPTED:
if (!message.needsUploading()) {
String pgpBody = message.getEncryptedBody();
@@ -907,9 +907,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (resend) {
if (packet != null) {
if (account.getXmppConnection().getFeatures().sm() || conversation.getMode() == Conversation.MODE_MULTI) {
- markMessage(message,Message.STATUS_UNSEND);
+ markMessage(message, Message.STATUS_UNSEND);
} else {
- markMessage(message,Message.STATUS_SEND);
+ markMessage(message, Message.STATUS_SEND);
}
}
} else {
@@ -921,7 +921,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
if (packet != null) {
if (delay) {
- mMessageGenerator.addDelay(packet,message.getTimeSent());
+ mMessageGenerator.addDelay(packet, message.getTimeSent());
}
if (conversation.setOutgoingChatState(Config.DEFAULT_CHATSTATE)) {
if (this.sendChatStates()) {
@@ -989,7 +989,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
account.setBookmarks(bookmarks);
} else {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not fetch bookmarks");
+ Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not fetch bookmarks");
}
}
};
@@ -1013,12 +1013,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
mPhoneContactMergerThread = new Thread(new Runnable() {
@Override
public void run() {
- Log.d(Config.LOGTAG,"start merging phone contacts with roster");
+ Log.d(Config.LOGTAG, "start merging phone contacts with roster");
for (Account account : accounts) {
List<Contact> withSystemAccounts = account.getRoster().getWithSystemAccounts();
for (Bundle phoneContact : phoneContacts) {
if (Thread.interrupted()) {
- Log.d(Config.LOGTAG,"interrupted merging phone contacts");
+ Log.d(Config.LOGTAG, "interrupted merging phone contacts");
return;
}
Jid jid;
@@ -1029,8 +1029,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
final Contact contact = account.getRoster().getContact(jid);
String systemAccount = phoneContact.getInt("phoneid")
- + "#"
- + phoneContact.getString("lookup");
+ + "#"
+ + phoneContact.getString("lookup");
contact.setSystemAccount(systemAccount);
if (contact.setPhotoUri(phoneContact.getString("photouri"))) {
getAvatarService().clear(contact);
@@ -1038,7 +1038,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
contact.setSystemName(phoneContact.getString("displayname"));
withSystemAccounts.remove(contact);
}
- for(Contact contact : withSystemAccounts) {
+ for (Contact contact : withSystemAccounts) {
contact.setSystemAccount(null);
contact.setSystemName(null);
if (contact.setPhotoUri(null)) {
@@ -1046,7 +1046,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
}
- Log.d(Config.LOGTAG,"finished merging phone contacts");
+ Log.d(Config.LOGTAG, "finished merging phone contacts");
updateAccountUi();
}
});
@@ -1064,20 +1064,20 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
Account account = accountLookupTable.get(conversation.getAccountUuid());
conversation.setAccount(account);
}
- Runnable runnable =new Runnable() {
+ Runnable runnable = new Runnable() {
@Override
public void run() {
- Log.d(Config.LOGTAG,"restoring roster");
- for(Account account : accounts) {
- databaseBackend.readRoster(account.getRoster());
+ Log.d(Config.LOGTAG, "restoring roster");
+ for (Account account : accounts) {
account.initAccountServices(XmppConnectionService.this);
+ databaseBackend.readRoster(account.getRoster());
}
getBitmapCache().evictAll();
Looper.prepare();
PhoneHelper.loadPhoneContacts(getApplicationContext(),
new CopyOnWriteArrayList<Bundle>(),
XmppConnectionService.this);
- Log.d(Config.LOGTAG,"restoring messages");
+ Log.d(Config.LOGTAG, "restoring messages");
for (Conversation conversation : conversations) {
conversation.addAll(0, databaseBackend.getMessages(conversation, Config.PAGE_SIZE));
checkDeletedFiles(conversation);
@@ -1090,7 +1090,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
mNotificationService.finishBacklog();
mRestoredFromDatabase = true;
- Log.d(Config.LOGTAG,"restored all messages");
+ Log.d(Config.LOGTAG, "restored all messages");
updateConversationUi();
}
};
@@ -1110,8 +1110,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (!getFileBackend().isFileAvailable(message)) {
message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
final int s = message.getStatus();
- if(s == Message.STATUS_WAITING || s == Message.STATUS_OFFERED || s == Message.STATUS_UNSEND) {
- markMessage(message,Message.STATUS_SEND_FAILED);
+ if (s == Message.STATUS_WAITING || s == Message.STATUS_OFFERED || s == Message.STATUS_UNSEND) {
+ markMessage(message, Message.STATUS_SEND_FAILED);
}
}
}
@@ -1125,8 +1125,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (!getFileBackend().isFileAvailable(message)) {
message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
final int s = message.getStatus();
- if(s == Message.STATUS_WAITING || s == Message.STATUS_OFFERED || s == Message.STATUS_UNSEND) {
- markMessage(message,Message.STATUS_SEND_FAILED);
+ if (s == Message.STATUS_WAITING || s == Message.STATUS_OFFERED || s == Message.STATUS_UNSEND) {
+ markMessage(message, Message.STATUS_SEND_FAILED);
} else {
updateConversationUi();
}
@@ -1169,7 +1169,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
public void loadMoreMessages(final Conversation conversation, final long timestamp, final OnMoreMessagesLoaded callback) {
- if (XmppConnectionService.this.getMessageArchiveService().queryInProgress(conversation,callback)) {
+ if (XmppConnectionService.this.getMessageArchiveService().queryInProgress(conversation, callback)) {
return;
}
Log.d(Config.LOGTAG, "load more messages for " + conversation.getName() + " prior to " + MessageGenerator.getTimestamp(timestamp));
@@ -1177,7 +1177,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
@Override
public void run() {
final Account account = conversation.getAccount();
- List<Message> messages = databaseBackend.getMessages(conversation, 50,timestamp);
+ List<Message> messages = databaseBackend.getMessages(conversation, 50, timestamp);
if (messages.size() > 0) {
conversation.addAll(0, messages);
checkDeletedFiles(conversation);
@@ -1186,7 +1186,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
&& account.isOnlineAndConnected()) {
if ((conversation.getMode() == Conversation.MODE_SINGLE && account.getXmppConnection().getFeatures().mam())
|| (conversation.getMode() == Conversation.MODE_MULTI && conversation.getMucOptions().mamSupport())) {
- MessageArchiveService.Query query = getMessageArchiveService().query(conversation,0,timestamp - 1);
+ MessageArchiveService.Query query = getMessageArchiveService().query(conversation, 0, timestamp - 1);
if (query != null) {
query.setCallback(callback);
}
@@ -1320,7 +1320,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void run() {
try {
X509Certificate[] chain = KeyChain.getCertificateChain(XmppConnectionService.this, alias);
- Pair<Jid,String> info = CryptoHelper.extractJidAndName(chain[0]);
+ Pair<Jid, String> info = CryptoHelper.extractJidAndName(chain[0]);
if (findAccountByJid(info.first) == null) {
Account account = new Account(info.first, "");
account.setPrivateKeyAlias(alias);
@@ -1338,6 +1338,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
callback.informUser(R.string.account_already_exists);
}
} catch (Exception e) {
+ e.printStackTrace();
callback.informUser(R.string.unable_to_parse_certificate);
}
}
@@ -1364,13 +1365,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
} else {
showErrorToastInUi(R.string.jid_does_not_match_certificate);
}
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (KeyChainException e) {
- e.printStackTrace();
- } catch (InvalidJidException e) {
- e.printStackTrace();
- } catch (CertificateEncodingException e) {
+ } catch (Exception e) {
e.printStackTrace();
}
}
@@ -1378,7 +1373,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void updateAccount(final Account account) {
this.statusListener.onStatusChanged(account);
databaseBackend.updateAccount(account);
- reconnectAccount(account, false, true);
+ reconnectAccountInBackground(account);
updateAccountUi();
getNotificationService().updateErrorNotification();
}
@@ -1655,7 +1650,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
}
- for(Conversation conversation : getConversations()) {
+ for (Conversation conversation : getConversations()) {
conversation.setIncomingChatState(ChatState.ACTIVE);
}
this.mNotificationService.setIsInForeground(false);
@@ -1666,7 +1661,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
List<Conversation> conversations = getConversations();
for (Conversation conversation : conversations) {
if (conversation.getMode() == Conversation.MODE_MULTI && conversation.getAccount() == account) {
- joinMuc(conversation,true);
+ joinMuc(conversation, true);
}
}
}
@@ -1791,10 +1786,14 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
public void leaveMuc(Conversation conversation) {
+ leaveMuc(conversation, false);
+ }
+
+ private void leaveMuc(Conversation conversation, boolean now) {
Account account = conversation.getAccount();
account.pendingConferenceJoins.remove(conversation);
account.pendingConferenceLeaves.remove(conversation);
- if (account.getStatus() == Account.State.ONLINE) {
+ if (account.getStatus() == Account.State.ONLINE || now) {
PresencePacket packet = new PresencePacket();
packet.setTo(conversation.getJid());
packet.setFrom(conversation.getAccount().getJid());
@@ -2006,7 +2005,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
});
}
- public void disconnect(Account account, boolean force) {
+ private void disconnect(Account account, boolean force) {
if ((account.getStatus() == Account.State.ONLINE)
|| (account.getStatus() == Account.State.DISABLED)) {
if (!force) {
@@ -2014,7 +2013,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
for (Conversation conversation : conversations) {
if (conversation.getAccount() == account) {
if (conversation.getMode() == Conversation.MODE_MULTI) {
- leaveMuc(conversation);
+ leaveMuc(conversation, true);
} else {
if (conversation.endOtrIfNeeded()) {
Log.d(Config.LOGTAG, account.getJid().toBareJid()
@@ -2204,13 +2203,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
fetchAvatar(account, avatar, null);
}
- private static String generateFetchKey(Account account, final Avatar avatar) {
- return account.getJid().toBareJid()+"_"+avatar.owner+"_"+avatar.sha1sum;
- }
-
public void fetchAvatar(Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
final String KEY = generateFetchKey(account, avatar);
- synchronized(this.mInProgressAvatarFetches) {
+ synchronized (this.mInProgressAvatarFetches) {
if (this.mInProgressAvatarFetches.contains(KEY)) {
return;
} else {
@@ -2375,9 +2370,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
synchronized (this.mInProgressAvatarFetches) {
- for(Iterator<String> iterator = this.mInProgressAvatarFetches.iterator(); iterator.hasNext();) {
+ for (Iterator<String> iterator = this.mInProgressAvatarFetches.iterator(); iterator.hasNext(); ) {
final String KEY = iterator.next();
- if (KEY.startsWith(account.getJid().toBareJid()+"_")) {
+ if (KEY.startsWith(account.getJid().toBareJid() + "_")) {
iterator.remove();
}
}
@@ -2385,6 +2380,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (account.getXmppConnection() == null) {
account.setXmppConnection(createConnection(account));
+ } else if (!force) {
+ try {
+ Log.d(Config.LOGTAG, "wait for disconnect");
+ Thread.sleep(500); //sleep wait for disconnect
+ } catch (InterruptedException e) {
+ //ignored
+ }
}
Thread thread = new Thread(account.getXmppConnection());
account.getXmppConnection().setInteractive(interactive);
@@ -2401,20 +2403,20 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
new Thread(new Runnable() {
@Override
public void run() {
- reconnectAccount(account,false,true);
+ reconnectAccount(account, false, true);
}
}).start();
}
public void invite(Conversation conversation, Jid contact) {
- Log.d(Config.LOGTAG,conversation.getAccount().getJid().toBareJid()+": inviting "+contact+" to "+conversation.getJid().toBareJid());
+ Log.d(Config.LOGTAG, conversation.getAccount().getJid().toBareJid() + ": inviting " + contact + " to " + conversation.getJid().toBareJid());
MessagePacket packet = mMessageGenerator.invite(conversation, contact);
sendMessagePacket(conversation.getAccount(), packet);
}
public void directInvite(Conversation conversation, Jid jid) {
MessagePacket packet = mMessageGenerator.directInvite(conversation, jid);
- sendMessagePacket(conversation.getAccount(),packet);
+ sendMessagePacket(conversation.getAccount(), packet);
}
public void resetSendingToWaiting(Account account) {
@@ -2499,7 +2501,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public int unreadCount() {
int count = 0;
- for(Conversation conversation : getConversations()) {
+ for (Conversation conversation : getConversations()) {
count += conversation.unreadCount();
}
return count;
@@ -2534,8 +2536,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
boolean rc = false;
if (mOnCaptchaRequested != null) {
DisplayMetrics metrics = getApplicationContext().getResources().getDisplayMetrics();
- Bitmap scaled = Bitmap.createScaledBitmap(captcha, (int)(captcha.getWidth() * metrics.scaledDensity),
- (int)(captcha.getHeight() * metrics.scaledDensity), false);
+ Bitmap scaled = Bitmap.createScaledBitmap(captcha, (int) (captcha.getWidth() * metrics.scaledDensity),
+ (int) (captcha.getHeight() * metrics.scaledDensity), false);
mOnCaptchaRequested.onCaptchaRequested(account, id, data, scaled);
rc = true;
@@ -2556,9 +2558,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
- public void keyStatusUpdated() {
- if(mOnKeyStatusUpdated != null) {
- mOnKeyStatusUpdated.onKeyStatusUpdated();
+ public void keyStatusUpdated(AxolotlService.FetchStatus report) {
+ if (mOnKeyStatusUpdated != null) {
+ mOnKeyStatusUpdated.onKeyStatusUpdated(report);
}
}
@@ -2582,7 +2584,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void markRead(final Conversation conversation) {
mNotificationService.clear(conversation);
- for(Message message : conversation.markRead()) {
+ for (Message message : conversation.markRead()) {
databaseBackend.updateMessage(message);
}
updateUnreadCountBadge();
@@ -2630,7 +2632,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
final MemorizingTrustManager tm;
final boolean dontTrustSystemCAs = getPreferences().getBoolean("dont_trust_system_cas", false);
if (dontTrustSystemCAs) {
- tm = new MemorizingTrustManager(getApplicationContext(), null);
+ tm = new MemorizingTrustManager(getApplicationContext(), null);
} else {
tm = new MemorizingTrustManager(getApplicationContext());
}
@@ -2791,7 +2793,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
for (final Message msg : messages) {
msg.setTime(System.currentTimeMillis());
markMessage(msg, Message.STATUS_WAITING);
- this.resendMessage(msg,false);
+ this.resendMessage(msg, false);
}
}
@@ -2840,6 +2842,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public interface OnAccountCreated {
void onAccountCreated(Account account);
+
void informUser(int r);
}
@@ -2877,9 +2880,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public interface OnCaptchaRequested {
void onCaptchaRequested(Account account,
- String id,
- Data data,
- Bitmap captcha);
+ String id,
+ Data data,
+ Bitmap captcha);
}
public interface OnRosterUpdate {
diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
index c610d2c89..aff50502c 100644
--- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -35,6 +35,7 @@ import java.util.List;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
+import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.ListItem;
@@ -479,7 +480,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
}
@Override
- public void onKeyStatusUpdated() {
+ public void onKeyStatusUpdated(AxolotlService.FetchStatus report) {
refreshUi();
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index 3a52cf36c..16ccceb28 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -489,7 +489,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|| m.treatAsDownloadable() == Message.Decision.MUST) {
copyUrl.setVisible(true);
}
- if (m.getType() == Message.TYPE_TEXT && m.getTransferable() == null && m.treatAsDownloadable() != Message.Decision.NEVER) {
+ if ((m.getType() == Message.TYPE_TEXT && m.getTransferable() == null && m.treatAsDownloadable() != Message.Decision.NEVER)
+ || (m.isFileOrImage() && m.getTransferable() instanceof TransferablePlaceholder && m.hasFileOnRemoteHost())){
downloadFile.setVisible(true);
downloadFile.setTitle(activity.getString(R.string.download_x_file,UIHelper.getFileDescriptionString(activity, m)));
}
diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index 2ab60800d..1712a717c 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -708,7 +708,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
}
@Override
- public void onKeyStatusUpdated() {
+ public void onKeyStatusUpdated(AxolotlService.FetchStatus report) {
refreshUi();
}
diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
index ab3130748..4bd0d42da 100644
--- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
@@ -8,6 +8,7 @@ import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.TextView;
+import android.widget.Toast;
import org.whispersystems.libaxolotl.IdentityKey;
@@ -16,10 +17,10 @@ import java.util.Map;
import java.util.Set;
import eu.siacs.conversations.R;
+import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
-import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
@@ -27,11 +28,9 @@ import eu.siacs.conversations.xmpp.jid.Jid;
public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdated {
private Jid accountJid;
private Jid contactJid;
- private boolean hasOtherTrustedKeys = false;
- private boolean hasPendingFetches = false;
- private boolean hasNoTrustedKeys = true;
private Contact contact;
+ private Account mAccount;
private TextView keyErrorMessage;
private LinearLayout keyErrorMessageCard;
private TextView ownKeysTitle;
@@ -50,10 +49,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
@Override
public void onClick(View v) {
commitTrusts();
- Intent data = new Intent();
- data.putExtra("choice", getIntent().getIntExtra("choice", ConversationActivity.ATTACHMENT_CHOICE_INVALID));
- setResult(RESULT_OK, data);
- finish();
+ finishOk();
}
};
@@ -92,7 +88,6 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
this.contactJid = Jid.fromString(getIntent().getExtras().getString("contact"));
} catch (final InvalidJidException ignored) {
}
- hasNoTrustedKeys = getIntent().getBooleanExtra("has_no_trusted", false);
keyErrorMessageCard = (LinearLayout) findViewById(R.id.key_error_message_card);
keyErrorMessage = (TextView) findViewById(R.id.key_error_message);
@@ -157,11 +152,11 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
foreignKeysTitle.setText(contactJid.toString());
foreignKeysCard.setVisibility(View.VISIBLE);
}
- if(hasPendingFetches) {
+ if(hasPendingKeyFetches()) {
setFetching();
lock();
} else {
- if (!hasForeignKeys && !hasOtherTrustedKeys) {
+ if (!hasForeignKeys && hasNoOtherTrustedKeys()) {
keyErrorMessageCard.setVisibility(View.VISIBLE);
keyErrorMessage.setText(R.string.error_no_keys_to_trust);
ownKeys.removeAllViews(); ownKeysCard.setVisibility(View.GONE);
@@ -172,12 +167,14 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
}
}
- private void getFingerprints(final Account account) {
- Set<IdentityKey> ownKeysSet = account.getAxolotlService().getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED);
- Set<IdentityKey> foreignKeysSet = account.getAxolotlService().getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, contact);
- if (hasNoTrustedKeys) {
- ownKeysSet.addAll(account.getAxolotlService().getKeysWithTrust(XmppAxolotlSession.Trust.UNTRUSTED));
- foreignKeysSet.addAll(account.getAxolotlService().getKeysWithTrust(XmppAxolotlSession.Trust.UNTRUSTED, contact));
+ private boolean reloadFingerprints() {
+ ownKeysToTrust.clear();
+ foreignKeysToTrust.clear();
+ AxolotlService service = this.mAccount.getAxolotlService();
+ Set<IdentityKey> ownKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED);
+ Set<IdentityKey> foreignKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, contact);
+ if (hasNoOtherTrustedKeys() && ownKeysSet.size() == 0) {
+ foreignKeysSet.addAll(service.getKeysWithTrust(XmppAxolotlSession.Trust.UNTRUSTED, contact));
}
for(final IdentityKey identityKey : ownKeysSet) {
if(!ownKeysToTrust.containsKey(identityKey)) {
@@ -189,39 +186,68 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
foreignKeysToTrust.put(identityKey.getFingerprint().replaceAll("\\s", ""), false);
}
}
+ return ownKeysSet.size() + foreignKeysSet.size() > 0;
}
@Override
public void onBackendConnected() {
if ((accountJid != null) && (contactJid != null)) {
- final Account account = xmppConnectionService
- .findAccountByJid(accountJid);
- if (account == null) {
+ this.mAccount = xmppConnectionService.findAccountByJid(accountJid);
+ if (this.mAccount == null) {
return;
}
- this.contact = account.getRoster().getContact(contactJid);
- ownKeysToTrust.clear();
- foreignKeysToTrust.clear();
- getFingerprints(account);
-
- if(account.getAxolotlService().getNumTrustedKeys(contact) > 0) {
- hasOtherTrustedKeys = true;
- }
- Conversation conversation = xmppConnectionService.findOrCreateConversation(account, contactJid, false);
- if(account.getAxolotlService().hasPendingKeyFetches(conversation)) {
- hasPendingFetches = true;
- }
-
+ this.contact = this.mAccount.getRoster().getContact(contactJid);
+ reloadFingerprints();
populateView();
}
}
+ private boolean hasNoOtherTrustedKeys() {
+ return mAccount == null || mAccount.getAxolotlService().getNumTrustedKeys(contact) == 0;
+ }
+
+ private boolean hasPendingKeyFetches() {
+ return mAccount != null && contact != null && mAccount.getAxolotlService().hasPendingKeyFetches(mAccount,contact);
+ }
+
+
@Override
- public void onKeyStatusUpdated() {
- final Account account = xmppConnectionService.findAccountByJid(accountJid);
- hasPendingFetches = false;
- getFingerprints(account);
- refreshUi();
+ public void onKeyStatusUpdated(final AxolotlService.FetchStatus report) {
+ if (report != null) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ switch (report) {
+ case ERROR:
+ Toast.makeText(TrustKeysActivity.this,R.string.error_fetching_omemo_key,Toast.LENGTH_SHORT).show();
+ break;
+ case SUCCESS_VERIFIED:
+ Toast.makeText(TrustKeysActivity.this,R.string.verified_omemo_key_with_certificate,Toast.LENGTH_LONG).show();
+ break;
+ }
+ }
+ });
+
+ }
+ boolean keysToTrust = reloadFingerprints();
+ if (keysToTrust || hasPendingKeyFetches() || hasNoOtherTrustedKeys()) {
+ refreshUi();
+ } else {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ finishOk();
+ }
+ });
+
+ }
+ }
+
+ private void finishOk() {
+ Intent data = new Intent();
+ data.putExtra("choice", getIntent().getIntExtra("choice", ConversationActivity.ATTACHMENT_CHOICE_INVALID));
+ setResult(RESULT_OK, data);
+ finish();
}
private void commitTrusts() {
@@ -248,7 +274,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
}
private void lockOrUnlockAsNeeded() {
- if (!hasOtherTrustedKeys && !foreignKeysToTrust.values().contains(true)){
+ if (hasNoOtherTrustedKeys() && !foreignKeysToTrust.values().contains(true)){
lock();
} else {
unlock();
diff --git a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
index e9ad71971..8091a9966 100644
--- a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
@@ -1,16 +1,21 @@
package eu.siacs.conversations.utils;
+import android.util.Log;
import android.util.Pair;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x500.style.IETFUtils;
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.bouncycastle.jce.PrincipalUtil;
import java.security.SecureRandom;
import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
+import java.security.cert.X509Extension;
import java.text.Normalizer;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
@@ -137,11 +142,26 @@ public final class CryptoHelper {
}
}
- public static Pair<Jid,String> extractJidAndName(X509Certificate certificate) throws CertificateEncodingException, InvalidJidException {
+ public static Pair<Jid,String> extractJidAndName(X509Certificate certificate) throws CertificateEncodingException, InvalidJidException, CertificateParsingException {
+ Collection<List<?>> alternativeNames = certificate.getSubjectAlternativeNames();
+ List<String> emails = new ArrayList<>();
+ if (alternativeNames != null) {
+ for(List<?> san : alternativeNames) {
+ Integer type = (Integer) san.get(0);
+ if (type == 1) {
+ emails.add((String) san.get(1));
+ }
+ }
+ }
X500Name x500name = new JcaX509CertificateHolder(certificate).getSubject();
- //String xmpp = IETFUtils.valueToString(x500name.getRDNs(new ASN1ObjectIdentifier("1.3.6.1.5.5.7.8.5"))[0].getFirst().getValue());
- String email = IETFUtils.valueToString(x500name.getRDNs(BCStyle.EmailAddress)[0].getFirst().getValue());
+ if (emails.size() == 0) {
+ emails.add(IETFUtils.valueToString(x500name.getRDNs(BCStyle.EmailAddress)[0].getFirst().getValue()));
+ }
String name = IETFUtils.valueToString(x500name.getRDNs(BCStyle.CN)[0].getFirst().getValue());
- return new Pair<>(Jid.fromString(email),name);
+ if (emails.size() >= 1) {
+ return new Pair<>(Jid.fromString(emails.get(0)), name);
+ } else {
+ return null;
+ }
}
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/OnKeyStatusUpdated.java b/src/main/java/eu/siacs/conversations/xmpp/OnKeyStatusUpdated.java
index 65ae133d5..e7fc582e4 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/OnKeyStatusUpdated.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/OnKeyStatusUpdated.java
@@ -1,5 +1,7 @@
package eu.siacs.conversations.xmpp;
+import eu.siacs.conversations.crypto.axolotl.AxolotlService;
+
public interface OnKeyStatusUpdated {
- public void onKeyStatusUpdated();
+ public void onKeyStatusUpdated(AxolotlService.FetchStatus report);
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
index d21682a79..186672488 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -783,7 +783,7 @@ public class XmppConnection implements Runnable {
String urlString = url.findChildContent("value");
URL uri = new URL(urlString);
captcha = BitmapFactory.decodeStream(uri.openConnection().getInputStream());
- } catch(IOException e) {
+ } catch (IOException e) {
Log.e(Config.LOGTAG, e.toString());
}
}
@@ -884,7 +884,7 @@ public class XmppConnection implements Runnable {
public void onIqPacketReceived(Account account, IqPacket packet) {
if (packet.getType() == IqPacket.TYPE.RESULT) {
sendPostBindInitialization();
- } else if (packet.getType() != IqPacket.TYPE.TIMEOUT){
+ } else if (packet.getType() != IqPacket.TYPE.TIMEOUT) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not init sessions");
disconnect(true);
}
@@ -947,11 +947,10 @@ public class XmppConnection implements Runnable {
}
}
disco.put(jid, info);
- if (account.getServer().equals(jid)) {
+ if ((jid.equals(account.getServer()) || jid.equals(account.getJid().toBareJid()))
+ && disco.containsKey(account.getServer())
+ && disco.containsKey(account.getJid().toBareJid())) {
enableAdvancedStreamFeatures();
- for (final OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) {
- listener.onAdvancedStreamFeaturesAvailable(account);
- }
}
} else {
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not query disco info for "+jid.toString());
@@ -969,6 +968,9 @@ public class XmppConnection implements Runnable {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": Requesting block list");
this.sendIqPacket(getIqGenerator().generateGetBlockList(), mXmppConnectionService.getIqParser());
}
+ for (final OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) {
+ listener.onAdvancedStreamFeaturesAvailable(account);
+ }
}
private void sendServiceDiscoveryItems(final Jid server) {
@@ -1139,44 +1141,41 @@ public class XmppConnection implements Runnable {
}
public void disconnect(final boolean force) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting");
- try {
- if (force) {
+ Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting force="+Boolean.valueOf(force));
+ if (force) {
+ try {
socket.close();
- return;
+ } catch(Exception e) {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": exception during force close ("+e.getMessage()+")");
}
- new Thread(new Runnable() {
-
- @Override
- public void run() {
- if (tagWriter.isActive()) {
- tagWriter.finish();
- try {
- int i = 0;
- boolean warned = false;
- while (!tagWriter.finished() && socket.isConnected() && i <= 10) {
- if (!warned) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid()+": waiting for tag writer to finish");
- warned = true;
- }
- Thread.sleep(200);
- i++;
- }
- if (warned) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": tag writer has finished");
- }
- tagWriter.writeTag(Tag.end("stream:stream"));
- socket.close();
- } catch (final IOException e) {
- Log.d(Config.LOGTAG,"io exception during disconnect");
- } catch (final InterruptedException e) {
- Log.d(Config.LOGTAG, "interrupted");
+ return;
+ } else {
+ resetStreamId();
+ if (tagWriter.isActive()) {
+ tagWriter.finish();
+ try {
+ int i = 0;
+ boolean warned = false;
+ while (!tagWriter.finished() && socket.isConnected() && i <= 10) {
+ if (!warned) {
+ Log.d(Config.LOGTAG, account.getJid().toBareJid()+": waiting for tag writer to finish");
+ warned = true;
}
+ Thread.sleep(200);
+ i++;
+ }
+ if (warned) {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": tag writer has finished");
}
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": closing stream");
+ tagWriter.writeTag(Tag.end("stream:stream"));
+ socket.close();
+ } catch (final IOException e) {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": io exception during disconnect ("+e.getMessage()+")");
+ } catch (final InterruptedException e) {
+ Log.d(Config.LOGTAG, "interrupted");
}
- }).start();
- } catch (final IOException e) {
- Log.d(Config.LOGTAG, "io exception during disconnect");
+ }
}
}
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index e6cc222a4..90aa7a8e5 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -546,5 +546,7 @@
<string name="certificate_chain_is_not_trusted">Certificate chain is not trusted</string>
<string name="jid_does_not_match_certificate">Jabber ID does not match certificate</string>
<string name="action_renew_certificate">Renew certificate</string>
+ <string name="error_fetching_omemo_key">Error fetching OMEMO key!</string>
+ <string name="verified_omemo_key_with_certificate">Verified OMEMO key with certificate!</string>
</resources>