aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu
diff options
context:
space:
mode:
authorChristian S <christian@pix-art.de>2015-08-26 20:02:36 +0200
committerChristian S <christian@pix-art.de>2015-08-26 20:02:36 +0200
commit0f0054ef8629a285726a9190a297a43f91494af4 (patch)
treeceb391c2b3f7cf098c0dff988e02dd4be941ac5d /src/main/java/eu
parentdfe58eaf341efe988f80faf5dc888900d28aa37a (diff)
parentc4a548ada00f5abd175e28ac1df5204f8bbc092f (diff)
Version 1.6.5
Diffstat (limited to 'src/main/java/eu')
-rw-r--r--src/main/java/eu/siacs/conversations/Config.java2
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java220
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Conversation.java21
-rw-r--r--src/main/java/eu/siacs/conversations/parser/IqParser.java2
-rw-r--r--src/main/java/eu/siacs/conversations/parser/MessageParser.java5
-rw-r--r--src/main/java/eu/siacs/conversations/persistance/FileBackend.java5
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java10
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationActivity.java11
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationFragment.java3
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java86
-rw-r--r--src/main/java/eu/siacs/conversations/utils/FileUtils.java8
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java21
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java26
13 files changed, 237 insertions, 183 deletions
diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java
index a92b1024a..249dcfc90 100644
--- a/src/main/java/eu/siacs/conversations/Config.java
+++ b/src/main/java/eu/siacs/conversations/Config.java
@@ -19,7 +19,7 @@ public final class Config {
public static final int PING_TIMEOUT = 10;
public static final int SOCKET_TIMEOUT = 15;
public static final int CONNECT_TIMEOUT = 90;
- public static final int CARBON_GRACE_PERIOD = 60;
+ public static final int CARBON_GRACE_PERIOD = 90;
public static final int MINI_GRACE_PERIOD = 750;
public static final int AVATAR_SIZE = 384;
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 d700b644b..17d911b44 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
@@ -50,6 +50,7 @@ public class AxolotlService {
public static final String LOGPREFIX = "AxolotlService";
public static final int NUM_KEYS_TO_PUBLISH = 100;
+ public static final int publishTriesThreshold = 3;
private final Account account;
private final XmppConnectionService mXmppConnectionService;
@@ -59,6 +60,8 @@ public class AxolotlService {
private final Map<String, XmppAxolotlMessage> messageCache;
private final FetchStatusMap fetchStatusMap;
private final SerialSingleThreadExecutor executor;
+ private int numPublishTriesOnEmptyPep = 0;
+ private boolean pepBroken = false;
private static class AxolotlAddressMap<T> {
protected Map<String, Map<Integer, T>> map;
@@ -228,8 +231,7 @@ public class AxolotlService {
axolotlStore.regenerate();
sessions.clear();
fetchStatusMap.clear();
- publishBundlesIfNeeded();
- publishOwnDeviceIdIfNeeded();
+ publishBundlesIfNeeded(true);
}
public int getOwnDeviceId() {
@@ -255,8 +257,15 @@ public class AxolotlService {
public void registerDevices(final Jid jid, @NonNull final Set<Integer> deviceIds) {
if (jid.toBareJid().equals(account.getJid().toBareJid())) {
+ if (!deviceIds.isEmpty()) {
+ Log.d(Config.LOGTAG, getLogprefix(account) + "Received non-empty own device list. Resetting publish attemps and pepBroken status.");
+ pepBroken = false;
+ numPublishTriesOnEmptyPep = 0;
+ }
if (deviceIds.contains(getOwnDeviceId())) {
deviceIds.remove(getOwnDeviceId());
+ } else {
+ publishOwnDeviceId(deviceIds);
}
for (Integer deviceId : deviceIds) {
AxolotlAddress ownDeviceAddress = new AxolotlAddress(jid.toBareJid().toString(), deviceId);
@@ -282,10 +291,13 @@ public class AxolotlService {
XmppAxolotlSession.Trust.UNTRUSTED);
this.deviceIds.put(jid, deviceIds);
mXmppConnectionService.keyStatusUpdated();
- publishOwnDeviceIdIfNeeded();
}
public void wipeOtherPepDevices() {
+ if (pepBroken) {
+ Log.d(Config.LOGTAG, getLogprefix(account) + "wipeOtherPepDevices called, but PEP is broken. Ignoring... ");
+ return;
+ }
Set<Integer> deviceIds = new HashSet<>();
deviceIds.add(getOwnDeviceId());
IqPacket publish = mXmppConnectionService.getIqGenerator().publishDeviceIds(deviceIds);
@@ -303,6 +315,10 @@ public class AxolotlService {
}
public void publishOwnDeviceIdIfNeeded() {
+ if (pepBroken) {
+ Log.d(Config.LOGTAG, getLogprefix(account) + "publishOwnDeviceIdIfNeeded called, but PEP is broken. Ignoring... ");
+ return;
+ }
IqPacket packet = mXmppConnectionService.getIqGenerator().retrieveDeviceIds(account.getJid().toBareJid());
mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
@Override
@@ -310,118 +326,148 @@ public class AxolotlService {
if (packet.getType() == IqPacket.TYPE.RESULT) {
Element item = mXmppConnectionService.getIqParser().getItem(packet);
Set<Integer> deviceIds = mXmppConnectionService.getIqParser().deviceIds(item);
- if (deviceIds == null) {
- deviceIds = new HashSet<Integer>();
- }
if (!deviceIds.contains(getOwnDeviceId())) {
- deviceIds.add(getOwnDeviceId());
- IqPacket publish = mXmppConnectionService.getIqGenerator().publishDeviceIds(deviceIds);
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Own device " + getOwnDeviceId() + " not in PEP devicelist. Publishing: " + publish);
- mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
- @Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- // TODO: implement this!
- }
- });
+ publishOwnDeviceId(deviceIds);
}
} else {
- Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while publishing device ID:" + packet.findChild("error"));
+ Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while retrieving Device Ids" + packet.findChild("error"));
}
}
});
}
- public void publishBundlesIfNeeded() {
+ public void publishOwnDeviceId(Set<Integer> deviceIds) {
+ if (!deviceIds.contains(getOwnDeviceId())) {
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Own device " + getOwnDeviceId() + " not in PEP devicelist.");
+ if (deviceIds.isEmpty()) {
+ if (numPublishTriesOnEmptyPep >= publishTriesThreshold) {
+ Log.w(Config.LOGTAG, getLogprefix(account) + "Own device publish attempt threshold exceeded, aborting...");
+ pepBroken = true;
+ return;
+ } else {
+ numPublishTriesOnEmptyPep++;
+ Log.w(Config.LOGTAG, getLogprefix(account) + "Own device list empty, attempting to publish (try " + numPublishTriesOnEmptyPep + ")");
+ }
+ } else {
+ numPublishTriesOnEmptyPep = 0;
+ }
+ deviceIds.add(getOwnDeviceId());
+ IqPacket publish = mXmppConnectionService.getIqGenerator().publishDeviceIds(deviceIds);
+ mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ if (packet.getType() != IqPacket.TYPE.RESULT) {
+ Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while publishing own device id" + packet.findChild("error"));
+ }
+ }
+ });
+ }
+ }
+
+ public void publishBundlesIfNeeded(final boolean announceAfter) {
+ if (pepBroken) {
+ Log.d(Config.LOGTAG, getLogprefix(account) + "publishBundlesIfNeeded called, but PEP is broken. Ignoring... ");
+ return;
+ }
IqPacket packet = mXmppConnectionService.getIqGenerator().retrieveBundlesForDevice(account.getJid().toBareJid(), getOwnDeviceId());
mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
- if (packet.getType() == IqPacket.TYPE.RESULT) {
- PreKeyBundle bundle = mXmppConnectionService.getIqParser().bundle(packet);
- Map<Integer, ECPublicKey> keys = mXmppConnectionService.getIqParser().preKeyPublics(packet);
- boolean flush = false;
- if (bundle == null) {
- Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received invalid bundle:" + packet);
- bundle = new PreKeyBundle(-1, -1, -1, null, -1, null, null, null);
- flush = true;
- }
- if (keys == null) {
- Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received invalid prekeys:" + packet);
+ PreKeyBundle bundle = mXmppConnectionService.getIqParser().bundle(packet);
+ Map<Integer, ECPublicKey> keys = mXmppConnectionService.getIqParser().preKeyPublics(packet);
+ boolean flush = false;
+ if (bundle == null) {
+ Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received invalid bundle:" + packet);
+ bundle = new PreKeyBundle(-1, -1, -1, null, -1, null, null, null);
+ flush = true;
+ }
+ if (keys == null) {
+ Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received invalid prekeys:" + packet);
+ }
+ try {
+ boolean changed = false;
+ // Validate IdentityKey
+ IdentityKeyPair identityKeyPair = axolotlStore.getIdentityKeyPair();
+ if (flush || !identityKeyPair.getPublicKey().equals(bundle.getIdentityKey())) {
+ Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding own IdentityKey " + identityKeyPair.getPublicKey() + " to PEP.");
+ changed = true;
}
- try {
- boolean changed = false;
- // Validate IdentityKey
- IdentityKeyPair identityKeyPair = axolotlStore.getIdentityKeyPair();
- if (flush || !identityKeyPair.getPublicKey().equals(bundle.getIdentityKey())) {
- Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding own IdentityKey " + identityKeyPair.getPublicKey() + " to PEP.");
- changed = true;
- }
- // Validate signedPreKeyRecord + ID
- SignedPreKeyRecord signedPreKeyRecord;
- int numSignedPreKeys = axolotlStore.loadSignedPreKeys().size();
- try {
- signedPreKeyRecord = axolotlStore.loadSignedPreKey(bundle.getSignedPreKeyId());
- if (flush
- || !bundle.getSignedPreKey().equals(signedPreKeyRecord.getKeyPair().getPublicKey())
- || !Arrays.equals(bundle.getSignedPreKeySignature(), signedPreKeyRecord.getSignature())) {
- Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding new signedPreKey with ID " + (numSignedPreKeys + 1) + " to PEP.");
- signedPreKeyRecord = KeyHelper.generateSignedPreKey(identityKeyPair, numSignedPreKeys + 1);
- axolotlStore.storeSignedPreKey(signedPreKeyRecord.getId(), signedPreKeyRecord);
- changed = true;
- }
- } catch (InvalidKeyIdException e) {
+ // Validate signedPreKeyRecord + ID
+ SignedPreKeyRecord signedPreKeyRecord;
+ int numSignedPreKeys = axolotlStore.loadSignedPreKeys().size();
+ try {
+ signedPreKeyRecord = axolotlStore.loadSignedPreKey(bundle.getSignedPreKeyId());
+ if (flush
+ || !bundle.getSignedPreKey().equals(signedPreKeyRecord.getKeyPair().getPublicKey())
+ || !Arrays.equals(bundle.getSignedPreKeySignature(), signedPreKeyRecord.getSignature())) {
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding new signedPreKey with ID " + (numSignedPreKeys + 1) + " to PEP.");
signedPreKeyRecord = KeyHelper.generateSignedPreKey(identityKeyPair, numSignedPreKeys + 1);
axolotlStore.storeSignedPreKey(signedPreKeyRecord.getId(), signedPreKeyRecord);
changed = true;
}
+ } catch (InvalidKeyIdException e) {
+ Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding new signedPreKey with ID " + (numSignedPreKeys + 1) + " to PEP.");
+ signedPreKeyRecord = KeyHelper.generateSignedPreKey(identityKeyPair, numSignedPreKeys + 1);
+ axolotlStore.storeSignedPreKey(signedPreKeyRecord.getId(), signedPreKeyRecord);
+ changed = true;
+ }
- // Validate PreKeys
- Set<PreKeyRecord> preKeyRecords = new HashSet<>();
- if (keys != null) {
- for (Integer id : keys.keySet()) {
- try {
- PreKeyRecord preKeyRecord = axolotlStore.loadPreKey(id);
- if (preKeyRecord.getKeyPair().getPublicKey().equals(keys.get(id))) {
- preKeyRecords.add(preKeyRecord);
- }
- } catch (InvalidKeyIdException ignored) {
+ // Validate PreKeys
+ Set<PreKeyRecord> preKeyRecords = new HashSet<>();
+ if (keys != null) {
+ for (Integer id : keys.keySet()) {
+ try {
+ PreKeyRecord preKeyRecord = axolotlStore.loadPreKey(id);
+ if (preKeyRecord.getKeyPair().getPublicKey().equals(keys.get(id))) {
+ preKeyRecords.add(preKeyRecord);
}
+ } catch (InvalidKeyIdException ignored) {
}
}
- int newKeys = NUM_KEYS_TO_PUBLISH - preKeyRecords.size();
- if (newKeys > 0) {
- List<PreKeyRecord> newRecords = KeyHelper.generatePreKeys(
- axolotlStore.getCurrentPreKeyId() + 1, newKeys);
- preKeyRecords.addAll(newRecords);
- for (PreKeyRecord record : newRecords) {
- axolotlStore.storePreKey(record.getId(), record);
- }
- changed = true;
- Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding " + newKeys + " new preKeys to PEP.");
+ }
+ int newKeys = NUM_KEYS_TO_PUBLISH - preKeyRecords.size();
+ if (newKeys > 0) {
+ List<PreKeyRecord> newRecords = KeyHelper.generatePreKeys(
+ axolotlStore.getCurrentPreKeyId() + 1, newKeys);
+ preKeyRecords.addAll(newRecords);
+ for (PreKeyRecord record : newRecords) {
+ axolotlStore.storePreKey(record.getId(), record);
}
+ changed = true;
+ Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding " + newKeys + " new preKeys to PEP.");
+ }
- if (changed) {
- IqPacket publish = mXmppConnectionService.getIqGenerator().publishBundles(
- signedPreKeyRecord, axolotlStore.getIdentityKeyPair().getPublicKey(),
- preKeyRecords, getOwnDeviceId());
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + ": Bundle " + getOwnDeviceId() + " in PEP not current. Publishing: " + publish);
- mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
- @Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- // TODO: implement this!
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Published bundle, got: " + packet);
+ if (changed) {
+ IqPacket publish = mXmppConnectionService.getIqGenerator().publishBundles(
+ signedPreKeyRecord, axolotlStore.getIdentityKeyPair().getPublicKey(),
+ preKeyRecords, getOwnDeviceId());
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + ": Bundle " + getOwnDeviceId() + " in PEP not current. Publishing: " + publish);
+ mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ if (packet.getType() == IqPacket.TYPE.RESULT) {
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Successfully published bundle. ");
+ if (announceAfter) {
+ Log.d(Config.LOGTAG, getLogprefix(account) + "Announcing device " + getOwnDeviceId());
+ publishOwnDeviceIdIfNeeded();
+ }
+ } else {
+ Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while publishing bundle: " + packet.findChild("error"));
}
- });
+ }
+ });
+ } else {
+ Log.d(Config.LOGTAG, getLogprefix(account) + "Bundle " + getOwnDeviceId() + " in PEP was current");
+ if (announceAfter) {
+ Log.d(Config.LOGTAG, getLogprefix(account) + "Announcing device " + getOwnDeviceId());
+ publishOwnDeviceIdIfNeeded();
}
- } catch (InvalidKeyException e) {
- Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Failed to publish bundle " + getOwnDeviceId() + ", reason: " + e.getMessage());
- return;
}
- } else {
- Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while publishing Bundle:" + packet.findChild("error"));
+ } catch (InvalidKeyException e) {
+ Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Failed to publish bundle " + getOwnDeviceId() + ", reason: " + e.getMessage());
+ return;
}
}
});
@@ -699,7 +745,7 @@ public class AxolotlService {
plaintextMessage = message.decrypt(session, getOwnDeviceId());
Integer preKeyId = session.getPreKeyId();
if (preKeyId != null) {
- publishBundlesIfNeeded();
+ publishBundlesIfNeeded(false);
session.resetPreKeyId();
}
} catch (CryptoFailedException e) {
diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java
index cea0d700f..ef52e3bb0 100644
--- a/src/main/java/eu/siacs/conversations/entities/Conversation.java
+++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java
@@ -202,14 +202,25 @@ public class Conversation extends AbstractEntity implements Blockable {
}
}
- public Message findSentMessageWithUuid(String uuid) {
+ public Message findSentMessageWithUuidOrRemoteId(String id) {
synchronized (this.messages) {
for (Message message : this.messages) {
- if (uuid.equals(message.getUuid())
- || (message.getStatus() >= Message.STATUS_SEND && uuid
- .equals(message.getRemoteMsgId()))) {
+ if (id.equals(message.getUuid())
+ || (message.getStatus() >= Message.STATUS_SEND
+ && id.equals(message.getRemoteMsgId()))) {
return message;
- }
+ }
+ }
+ }
+ return null;
+ }
+
+ public Message findSentMessageWithUuid(String id) {
+ synchronized (this.messages) {
+ for (Message message : this.messages) {
+ if (id.equals(message.getUuid())) {
+ return message;
+ }
}
}
return null;
diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java
index cef5b03d9..44e4bc089 100644
--- a/src/main/java/eu/siacs/conversations/parser/IqParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java
@@ -138,7 +138,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
}
try {
publicKey = Curve.decodePoint(Base64.decode(signedPreKeyPublic.getContent(),Base64.DEFAULT), 0);
- } catch (InvalidKeyException e) {
+ } catch (InvalidKeyException | IllegalArgumentException e) {
Log.e(Config.LOGTAG, AxolotlService.LOGPREFIX+" : "+"Invalid signedPreKeyPublic in PEP: " + e.getMessage());
}
return publicKey;
diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
index 025ed1e7e..ec900de4d 100644
--- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
@@ -311,10 +311,9 @@ public class MessageParser extends AbstractParser implements
status = Message.STATUS_SEND_RECEIVED;
if (mXmppConnectionService.markMessage(conversation, remoteMsgId, status)) {
return;
- } else {
- Message message = conversation.findSentMessageWithBody(body);
+ } else if (remoteMsgId == null) {
+ Message message = conversation.findSentMessageWithBody(packet.getBody());
if (message != null) {
- message.setRemoteMsgId(remoteMsgId);
mXmppConnectionService.markMessage(message, status);
return;
}
diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
index a0c676bf9..135d5648d 100644
--- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
@@ -1,6 +1,5 @@
package eu.siacs.conversations.persistance;
-import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
@@ -8,7 +7,6 @@ import android.graphics.Matrix;
import android.graphics.RectF;
import android.net.Uri;
import android.os.Environment;
-import android.provider.MediaStore;
import android.util.Base64;
import android.util.Base64OutputStream;
import android.util.Log;
@@ -137,6 +135,9 @@ public class FileBackend {
options.inJustDecodeBounds = true;
try {
BitmapFactory.decodeStream(mXmppConnectionService.getContentResolver().openInputStream(uri), null, options);
+ if (options == null || options.outMimeType == null) {
+ return false;
+ }
return (options.outWidth <= Config.IMAGE_SIZE && options.outHeight <= Config.IMAGE_SIZE && options.outMimeType.contains(Config.IMAGE_FORMAT.name().toLowerCase()));
} catch (FileNotFoundException e) {
return false;
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index b08a71bfa..4edaa324c 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -84,9 +84,9 @@ import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
+import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.OnMessageAcknowledged;
import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
-import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.OnPresencePacketReceived;
import eu.siacs.conversations.xmpp.OnStatusChanged;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
@@ -165,8 +165,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
mMessageArchiveService.executePendingQueries(account);
mJingleConnectionManager.cancelInTransmission();
syncDirtyContacts(account);
- account.getAxolotlService().publishOwnDeviceIdIfNeeded();
- account.getAxolotlService().publishBundlesIfNeeded();
+ account.getAxolotlService().publishBundlesIfNeeded(true);
}
};
private final OnMessageAcknowledged mOnMessageAcknowledgedListener = new OnMessageAcknowledged() {
@@ -2216,7 +2215,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
for (Conversation conversation : getConversations()) {
if (conversation.getJid().toBareJid().equals(recipient) && conversation.getAccount() == account) {
- final Message message = conversation.findSentMessageWithUuid(uuid);
+ final Message message = conversation.findSentMessageWithUuidOrRemoteId(uuid);
if (message != null) {
markMessage(message, status);
}
@@ -2226,8 +2225,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
return null;
}
- public boolean markMessage(Conversation conversation, String uuid,
- int status) {
+ public boolean markMessage(Conversation conversation, String uuid, int status) {
if (uuid == null) {
return false;
} else {
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
index 14fc83502..aaa46825d 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
@@ -985,6 +985,9 @@ public class ConversationActivity extends XmppActivity
mPendingGeoUri = null;
setSelectedConversation(conversationList.get(0));
this.mConversationFragment.reInit(getSelectedConversation());
+ } else {
+ this.mConversationFragment.messageListAdapter.updatePreferences();
+ this.mConversationFragment.messagesView.invalidateViews();
}
if(!forbidProcessingPendings) {
@@ -1163,7 +1166,7 @@ public class ConversationActivity extends XmppActivity
}
prepareFileToast = Toast.makeText(getApplicationContext(),getText(R.string.preparing_file), Toast.LENGTH_LONG);
prepareFileToast.show();
- xmppConnectionService.attachFileToConversation(conversation,uri, new UiCallback<Message>() {
+ xmppConnectionService.attachFileToConversation(conversation, uri, new UiCallback<Message>() {
@Override
public void success(Message message) {
hidePrepareFileToast();
@@ -1193,7 +1196,7 @@ public class ConversationActivity extends XmppActivity
@Override
public void userInputRequried(PendingIntent pi,
- Message object) {
+ Message object) {
hidePrepareFileToast();
}
@@ -1275,6 +1278,10 @@ public class ConversationActivity extends XmppActivity
return getPreferences().getBoolean("indicate_received", false);
}
+ public boolean useWhiteBackground() {
+ return getPreferences().getBoolean("use_white_background",false);
+ }
+
protected boolean trustKeysIfNeeded(int requestCode) {
return trustKeysIfNeeded(requestCode, ATTACHMENT_CHOICE_INVALID);
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index 49878463b..3adbc8431 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -327,7 +327,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
switch (conversation.getNextEncryption()) {
case Message.ENCRYPTION_NONE:
mEditMessage
- .setHint(getString(R.string.send_plain_text_message));
+ .setHint(getString(R.string.send_unencrypted_message));
break;
case Message.ENCRYPTION_OTR:
mEditMessage.setHint(getString(R.string.send_otr_message));
@@ -662,6 +662,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
this.mEditMessage.setText("");
this.mEditMessage.append(this.conversation.getNextMessage());
this.mEditMessage.setKeyboardListener(this);
+ messageListAdapter.updatePreferences();
this.messagesView.setAdapter(messageListAdapter);
updateMessages();
this.messagesLoaded = true;
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
index 323c67d6b..1dbf1b101 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -3,7 +3,6 @@ package eu.siacs.conversations.ui.adapter;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.graphics.Color;
import android.graphics.Typeface;
import android.net.Uri;
import android.text.Spannable;
@@ -60,11 +59,14 @@ public class MessageAdapter extends ArrayAdapter<Message> {
return true;
}
};
+ private boolean mIndicateReceived = false;
+ private boolean mUseWhiteBackground = false;
public MessageAdapter(ConversationActivity activity, List<Message> messages) {
super(activity, 0, messages);
this.activity = activity;
metrics = getContext().getResources().getDisplayMetrics();
+ updatePreferences();
}
public void setOnContactPictureClicked(OnContactPictureClicked listener) {
@@ -96,15 +98,15 @@ public class MessageAdapter extends ArrayAdapter<Message> {
return this.getItemViewType(getItem(position));
}
- private int getMessageTextColor(int type, boolean primary) {
- if (type == SENT) {
- return activity.getResources().getColor(primary ? R.color.black87 : R.color.black54);
- } else {
+ private int getMessageTextColor(boolean onDark, boolean primary) {
+ if (onDark) {
return activity.getResources().getColor(primary ? R.color.white : R.color.white70);
+ } else {
+ return activity.getResources().getColor(primary ? R.color.black87 : R.color.black54);
}
}
- private void displayStatus(ViewHolder viewHolder, Message message, int type) {
+ private void displayStatus(ViewHolder viewHolder, Message message, int type, boolean darkBackground) {
String filesize = null;
String info = null;
boolean error = false;
@@ -140,12 +142,12 @@ public class MessageAdapter extends ArrayAdapter<Message> {
info = getContext().getString(R.string.offering);
break;
case Message.STATUS_SEND_RECEIVED:
- if (activity.indicateReceived()) {
+ if (mIndicateReceived) {
viewHolder.indicatorReceived.setVisibility(View.VISIBLE);
}
break;
case Message.STATUS_SEND_DISPLAYED:
- if (activity.indicateReceived()) {
+ if (mIndicateReceived) {
viewHolder.indicatorReceived.setVisibility(View.VISIBLE);
}
break;
@@ -162,11 +164,12 @@ public class MessageAdapter extends ArrayAdapter<Message> {
if (error && type == SENT) {
viewHolder.time.setTextColor(activity.getWarningTextColor());
} else {
- viewHolder.time.setTextColor(this.getMessageTextColor(type,false));
+ viewHolder.time.setTextColor(this.getMessageTextColor(darkBackground,false));
}
if (message.getEncryption() == Message.ENCRYPTION_NONE) {
viewHolder.indicator.setVisibility(View.GONE);
} else {
+ viewHolder.indicator.setImageResource(darkBackground ? R.drawable.ic_secure_indicator_white : R.drawable.ic_secure_indicator);
viewHolder.indicator.setVisibility(View.VISIBLE);
if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
XmppAxolotlSession.Trust trust = message.getConversation()
@@ -178,18 +181,18 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.indicator.setAlpha(1.0f);
} else {
viewHolder.indicator.clearColorFilter();
- if (type == SENT) {
- viewHolder.indicator.setAlpha(0.57f);
- } else {
+ if (darkBackground) {
viewHolder.indicator.setAlpha(0.7f);
+ } else {
+ viewHolder.indicator.setAlpha(0.57f);
}
}
} else {
viewHolder.indicator.clearColorFilter();
- if (type == SENT) {
- viewHolder.indicator.setAlpha(0.57f);
- } else {
+ if (darkBackground) {
viewHolder.indicator.setAlpha(0.7f);
+ } else {
+ viewHolder.indicator.setAlpha(0.57f);
}
}
}
@@ -223,19 +226,19 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
}
- private void displayInfoMessage(ViewHolder viewHolder, String text, int type) {
+ private void displayInfoMessage(ViewHolder viewHolder, String text, boolean darkBackground) {
if (viewHolder.download_button != null) {
viewHolder.download_button.setVisibility(View.GONE);
}
viewHolder.image.setVisibility(View.GONE);
viewHolder.messageBody.setVisibility(View.VISIBLE);
viewHolder.messageBody.setText(text);
- viewHolder.messageBody.setTextColor(getMessageTextColor(type,false));
+ viewHolder.messageBody.setTextColor(getMessageTextColor(darkBackground, false));
viewHolder.messageBody.setTypeface(null, Typeface.ITALIC);
viewHolder.messageBody.setTextIsSelectable(false);
}
- private void displayDecryptionFailed(ViewHolder viewHolder, int type) {
+ private void displayDecryptionFailed(ViewHolder viewHolder, boolean darkBackground) {
if (viewHolder.download_button != null) {
viewHolder.download_button.setVisibility(View.GONE);
}
@@ -243,7 +246,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.messageBody.setVisibility(View.VISIBLE);
viewHolder.messageBody.setText(getContext().getString(
R.string.decryption_failed));
- viewHolder.messageBody.setTextColor(getMessageTextColor(type,false));
+ viewHolder.messageBody.setTextColor(getMessageTextColor(darkBackground, false));
viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
viewHolder.messageBody.setTextIsSelectable(false);
}
@@ -261,7 +264,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.messageBody.setText(span);
}
- private void displayTextMessage(final ViewHolder viewHolder, final Message message, int type) {
+ private void displayTextMessage(final ViewHolder viewHolder, final Message message, boolean darkBackground) {
if (viewHolder.download_button != null) {
viewHolder.download_button.setVisibility(View.GONE);
}
@@ -303,7 +306,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
final Spannable span = new SpannableString(privateMarker + " "
+ formattedBody);
- span.setSpan(new ForegroundColorSpan(getMessageTextColor(type,false)), 0, privateMarker
+ span.setSpan(new ForegroundColorSpan(getMessageTextColor(darkBackground,false)), 0, privateMarker
.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
span.setSpan(new StyleSpan(Typeface.BOLD), 0,
privateMarker.length(),
@@ -318,7 +321,8 @@ public class MessageAdapter extends ArrayAdapter<Message> {
} else {
viewHolder.messageBody.setText("");
}
- viewHolder.messageBody.setTextColor(this.getMessageTextColor(type,true));
+ viewHolder.messageBody.setTextColor(this.getMessageTextColor(darkBackground, true));
+ viewHolder.messageBody.setLinkTextColor(this.getMessageTextColor(darkBackground,true));
viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
viewHolder.messageBody.setTextIsSelectable(true);
}
@@ -388,7 +392,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
scalledH = (int) (params.height / ((double) params.width / target));
}
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(scalledW, scalledH);
- layoutParams.setMargins(0, (int)(metrics.density * 4), 0, (int)(metrics.density * 4));
+ layoutParams.setMargins(0, (int) (metrics.density * 4), 0, (int) (metrics.density * 4));
viewHolder.image.setLayoutParams(layoutParams);
activity.loadBitmap(message, viewHolder.image);
viewHolder.image.setOnClickListener(new OnClickListener() {
@@ -404,6 +408,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
@Override
public View getView(int position, View view, ViewGroup parent) {
final Message message = getItem(position);
+ final boolean isInValidSession = message.isValidInSession();
final Conversation conversation = message.getConversation();
final Account account = conversation.getAccount();
final int type = getItemViewType(position);
@@ -468,6 +473,8 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
}
+ boolean darkBackground = (type == RECEIVED && (!isInValidSession || !mUseWhiteBackground));
+
if (type == STATUS) {
if (conversation.getMode() == Conversation.MODE_SINGLE) {
viewHolder.contact_picture.setImageBitmap(activity
@@ -497,7 +504,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
public void onClick(View v) {
if (MessageAdapter.this.mOnContactPictureClickedListener != null) {
MessageAdapter.this.mOnContactPictureClickedListener
- .onContactPictureClicked(message);
+ .onContactPictureClicked(message);
}
}
@@ -509,7 +516,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
public boolean onLongClick(View v) {
if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) {
MessageAdapter.this.mOnContactPictureLongClickedListener
- .onContactPictureLongClicked(message);
+ .onContactPictureLongClicked(message);
return true;
} else {
return false;
@@ -524,7 +531,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
} else if (transferable.getStatus() == Transferable.STATUS_OFFER_CHECK_FILESIZE) {
displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message)));
} else {
- displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first,type);
+ displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first,darkBackground);
}
} else if (message.getType() == Message.TYPE_IMAGE && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) {
displayImageMessage(viewHolder, message);
@@ -536,9 +543,9 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
} else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
if (activity.hasPgp()) {
- displayInfoMessage(viewHolder,activity.getString(R.string.encrypted_message),type);
+ displayInfoMessage(viewHolder,activity.getString(R.string.encrypted_message),darkBackground);
} else {
- displayInfoMessage(viewHolder,activity.getString(R.string.install_openkeychain),type);
+ displayInfoMessage(viewHolder,activity.getString(R.string.install_openkeychain),darkBackground);
if (viewHolder != null) {
viewHolder.message_box
.setOnClickListener(new OnClickListener() {
@@ -551,7 +558,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
}
} else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
- displayDecryptionFailed(viewHolder,type);
+ displayDecryptionFailed(viewHolder,darkBackground);
} else {
if (GeoHelper.isGeoUri(message.getBody())) {
displayLocationMessage(viewHolder,message);
@@ -560,19 +567,23 @@ public class MessageAdapter extends ArrayAdapter<Message> {
} else if (message.treatAsDownloadable() == Message.Decision.MUST) {
displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message)));
} else {
- displayTextMessage(viewHolder, message, type);
+ displayTextMessage(viewHolder, message, darkBackground);
}
}
if (type == RECEIVED) {
- if(message.isValidInSession()) {
- viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received);
+ if(isInValidSession) {
+ if (mUseWhiteBackground) {
+ viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received_white);
+ } else {
+ viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received);
+ }
} else {
viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received_warning);
}
}
- displayStatus(viewHolder, message, type);
+ displayStatus(viewHolder, message, type, darkBackground);
return view;
}
@@ -616,12 +627,17 @@ public class MessageAdapter extends ArrayAdapter<Message> {
Toast.makeText(activity,R.string.no_application_found_to_display_location,Toast.LENGTH_SHORT).show();
}
+ public void updatePreferences() {
+ this.mIndicateReceived = activity.indicateReceived();
+ this.mUseWhiteBackground = activity.useWhiteBackground();
+ }
+
public interface OnContactPictureClicked {
- public void onContactPictureClicked(Message message);
+ void onContactPictureClicked(Message message);
}
public interface OnContactPictureLongClicked {
- public void onContactPictureLongClicked(Message message);
+ void onContactPictureLongClicked(Message message);
}
private static class ViewHolder {
diff --git a/src/main/java/eu/siacs/conversations/utils/FileUtils.java b/src/main/java/eu/siacs/conversations/utils/FileUtils.java
index a13300d43..c29841112 100644
--- a/src/main/java/eu/siacs/conversations/utils/FileUtils.java
+++ b/src/main/java/eu/siacs/conversations/utils/FileUtils.java
@@ -104,15 +104,17 @@ public class FileUtils {
};
try {
- cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
- null);
+ cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
+ } catch(Exception e) {
+ return null;
} finally {
- if (cursor != null)
+ if (cursor != null) {
cursor.close();
+ }
}
return null;
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
index 376858323..bb0c3987b 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -318,7 +318,6 @@ public class XmppConnection implements Runnable {
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
+ ": stream management(" + smVersion + ") enabled");
}
- this.lastSessionStarted = SystemClock.elapsedRealtime();
this.stanzasReceived = 0;
final RequestPacket r = new RequestPacket(smVersion);
tagWriter.writeStanzaAsync(r);
@@ -473,29 +472,33 @@ public class XmppConnection implements Runnable {
this.jingleListener.onJinglePacketReceived(account,(JinglePacket) packet);
}
} else {
+ OnIqPacketReceived callback = null;
synchronized (this.packetCallbacks) {
if (packetCallbacks.containsKey(packet.getId())) {
final Pair<IqPacket, OnIqPacketReceived> packetCallbackDuple = packetCallbacks.get(packet.getId());
// Packets to the server should have responses from the server
if (packetCallbackDuple.first.toServer(account)) {
if (packet.fromServer(account)) {
- packetCallbackDuple.second.onIqPacketReceived(account, packet);
+ callback = packetCallbackDuple.second;
packetCallbacks.remove(packet.getId());
} else {
Log.e(Config.LOGTAG, account.getJid().toBareJid().toString() + ": ignoring spoofed iq packet");
}
} else {
if (packet.getFrom().equals(packetCallbackDuple.first.getTo())) {
- packetCallbackDuple.second.onIqPacketReceived(account, packet);
+ callback = packetCallbackDuple.second;
packetCallbacks.remove(packet.getId());
} else {
Log.e(Config.LOGTAG, account.getJid().toBareJid().toString() + ": ignoring spoofed iq packet");
}
}
} else if (packet.getType() == IqPacket.TYPE.GET || packet.getType() == IqPacket.TYPE.SET) {
- this.unregisteredIqListener.onIqPacketReceived(account, packet);
+ callback = this.unregisteredIqListener;
}
}
+ if (callback != null) {
+ callback.onIqPacketReceived(account,packet);
+ }
}
}
@@ -784,6 +787,7 @@ public class XmppConnection implements Runnable {
sendServiceDiscoveryInfo(account.getJid().toBareJid());
sendServiceDiscoveryItems(account.getServer());
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": online with resource " + account.getResource());
+ this.lastSessionStarted = SystemClock.elapsedRealtime();
changeStatus(Account.State.ONLINE);
if (bindListener != null) {
bindListener.onBind(account);
@@ -954,7 +958,7 @@ public class XmppConnection implements Runnable {
AbstractAcknowledgeableStanza stanza = (AbstractAcknowledgeableStanza) packet;
++stanzasSent;
this.mStanzaQueue.put(stanzasSent, stanza);
- if (stanza instanceof MessagePacket && stanza.getId() != null && this.streamId != null) {
+ if (stanza instanceof MessagePacket && stanza.getId() != null && getFeatures().sm()) {
if (Config.EXTENDED_SM_LOGGING) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": requesting ack for message stanza #" + stanzasSent);
}
@@ -1100,12 +1104,7 @@ public class XmppConnection implements Runnable {
}
public long getLastSessionEstablished() {
- final long diff;
- if (this.lastSessionStarted == 0) {
- diff = SystemClock.elapsedRealtime() - this.lastConnect;
- } else {
- diff = SystemClock.elapsedRealtime() - this.lastSessionStarted;
- }
+ final long diff = SystemClock.elapsedRealtime() - this.lastSessionStarted;
return System.currentTimeMillis() - diff;
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java
index b32111584..e832d3f58 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java
@@ -1,31 +1,5 @@
package eu.siacs.conversations.xmpp.jingle;
-import android.util.Log;
-import android.util.Pair;
-
-import org.bouncycastle.crypto.engines.AESEngine;
-import org.bouncycastle.crypto.modes.AEADBlockCipher;
-import org.bouncycastle.crypto.modes.GCMBlockCipher;
-import org.bouncycastle.crypto.params.AEADParameters;
-import org.bouncycastle.crypto.params.KeyParameter;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-
-import javax.crypto.Cipher;
-import javax.crypto.CipherInputStream;
-import javax.crypto.CipherOutputStream;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.DownloadableFile;
public abstract class JingleTransport {