aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu/siacs/conversations/entities
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/eu/siacs/conversations/entities')
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Account.java12
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Contact.java141
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Conversation.java76
-rw-r--r--src/main/java/eu/siacs/conversations/entities/DownloadableFile.java130
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Message.java113
-rw-r--r--src/main/java/eu/siacs/conversations/entities/MucOptions.java13
6 files changed, 262 insertions, 223 deletions
diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java
index 90c10199..a8b9252f 100644
--- a/src/main/java/eu/siacs/conversations/entities/Account.java
+++ b/src/main/java/eu/siacs/conversations/entities/Account.java
@@ -20,6 +20,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.OtrService;
+import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
@@ -122,6 +123,7 @@ public class Account extends AbstractEntity {
protected String avatar;
protected boolean online = false;
private OtrService mOtrService = null;
+ private AxolotlService axolotlService = null;
private XmppConnection xmppConnection = null;
private long mEndGracePeriod = 0L;
private String otrFingerprint;
@@ -255,6 +257,10 @@ public class Account extends AbstractEntity {
return keys;
}
+ public String getKey(final String name) {
+ return this.keys.optString(name, null);
+ }
+
public boolean setKey(final String keyName, final String keyValue) {
try {
this.keys.put(keyName, keyValue);
@@ -278,9 +284,13 @@ public class Account extends AbstractEntity {
return values;
}
+ public AxolotlService getAxolotlService() {
+ return axolotlService;
+ }
+
public void initAccountServices(final XmppConnectionService context) {
- this.mXmppConnectionService = context;
this.mOtrService = new OtrService(context, this);
+ this.axolotlService = new AxolotlService(this, context);
}
public OtrService getOtrService() {
diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java
index 81f6568b..2d103faf 100644
--- a/src/main/java/eu/siacs/conversations/entities/Contact.java
+++ b/src/main/java/eu/siacs/conversations/entities/Contact.java
@@ -189,20 +189,22 @@ public class Contact implements ListItem, Blockable {
}
public ContentValues getContentValues() {
- final ContentValues values = new ContentValues();
- values.put(ACCOUNT, accountUuid);
- values.put(SYSTEMNAME, systemName);
- values.put(SERVERNAME, serverName);
- values.put(JID, jid.toString());
- values.put(OPTIONS, subscription);
- values.put(SYSTEMACCOUNT, systemAccount);
- values.put(PHOTOURI, photoUri);
- values.put(KEYS, keys.toString());
- values.put(AVATAR, avatar == null ? null : avatar.getFilename());
- values.put(LAST_PRESENCE, lastseen.presence);
- values.put(LAST_TIME, lastseen.time);
- values.put(GROUPS, groups.toString());
- return values;
+ synchronized (this.keys) {
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNT, accountUuid);
+ values.put(SYSTEMNAME, systemName);
+ values.put(SERVERNAME, serverName);
+ values.put(JID, jid.toString());
+ values.put(OPTIONS, subscription);
+ values.put(SYSTEMACCOUNT, systemAccount);
+ values.put(PHOTOURI, photoUri);
+ values.put(KEYS, keys.toString());
+ values.put(AVATAR, avatar == null ? null : avatar.getFilename());
+ values.put(LAST_PRESENCE, lastseen.presence);
+ values.put(LAST_TIME, lastseen.time);
+ values.put(GROUPS, groups.toString());
+ return values;
+ }
}
public int getSubscription() {
@@ -287,60 +289,65 @@ public class Contact implements ListItem, Blockable {
}
public ArrayList<String> getOtrFingerprints() {
- final ArrayList<String> fingerprints = new ArrayList<String>();
- try {
- if (this.keys.has("otr_fingerprints")) {
- final JSONArray prints = this.keys.getJSONArray("otr_fingerprints");
- for (int i = 0; i < prints.length(); ++i) {
- final String print = prints.isNull(i) ? null : prints.getString(i);
- if (print != null && !print.isEmpty()) {
- fingerprints.add(prints.getString(i));
+ synchronized (this.keys) {
+ final ArrayList<String> fingerprints = new ArrayList<String>();
+ try {
+ if (this.keys.has("otr_fingerprints")) {
+ final JSONArray prints = this.keys.getJSONArray("otr_fingerprints");
+ for (int i = 0; i < prints.length(); ++i) {
+ final String print = prints.isNull(i) ? null : prints.getString(i);
+ if (print != null && !print.isEmpty()) {
+ fingerprints.add(prints.getString(i));
+ }
}
}
- }
- } catch (final JSONException ignored) {
+ } catch (final JSONException ignored) {
+ }
+ return fingerprints;
}
- return fingerprints;
}
-
public boolean addOtrFingerprint(String print) {
- if (getOtrFingerprints().contains(print)) {
- return false;
- }
- try {
- JSONArray fingerprints;
- if (!this.keys.has("otr_fingerprints")) {
- fingerprints = new JSONArray();
-
- } else {
- fingerprints = this.keys.getJSONArray("otr_fingerprints");
+ synchronized (this.keys) {
+ if (getOtrFingerprints().contains(print)) {
+ return false;
+ }
+ try {
+ JSONArray fingerprints;
+ if (!this.keys.has("otr_fingerprints")) {
+ fingerprints = new JSONArray();
+ } else {
+ fingerprints = this.keys.getJSONArray("otr_fingerprints");
+ }
+ fingerprints.put(print);
+ this.keys.put("otr_fingerprints", fingerprints);
+ return true;
+ } catch (final JSONException ignored) {
+ return false;
}
- fingerprints.put(print);
- this.keys.put("otr_fingerprints", fingerprints);
- return true;
- } catch (final JSONException ignored) {
- return false;
}
}
public long getPgpKeyId() {
- if (this.keys.has("pgp_keyid")) {
- try {
- return this.keys.getLong("pgp_keyid");
- } catch (JSONException e) {
+ synchronized (this.keys) {
+ if (this.keys.has("pgp_keyid")) {
+ try {
+ return this.keys.getLong("pgp_keyid");
+ } catch (JSONException e) {
+ return 0;
+ }
+ } else {
return 0;
}
- } else {
- return 0;
}
}
public void setPgpKeyId(long keyId) {
- try {
- this.keys.put("pgp_keyid", keyId);
- } catch (final JSONException ignored) {
-
+ synchronized (this.keys) {
+ try {
+ this.keys.put("pgp_keyid", keyId);
+ } catch (final JSONException ignored) {
+ }
}
}
@@ -447,24 +454,26 @@ public class Contact implements ListItem, Blockable {
}
public boolean deleteOtrFingerprint(String fingerprint) {
- boolean success = false;
- try {
- if (this.keys.has("otr_fingerprints")) {
- JSONArray newPrints = new JSONArray();
- JSONArray oldPrints = this.keys
- .getJSONArray("otr_fingerprints");
- for (int i = 0; i < oldPrints.length(); ++i) {
- if (!oldPrints.getString(i).equals(fingerprint)) {
- newPrints.put(oldPrints.getString(i));
- } else {
- success = true;
+ synchronized (this.keys) {
+ boolean success = false;
+ try {
+ if (this.keys.has("otr_fingerprints")) {
+ JSONArray newPrints = new JSONArray();
+ JSONArray oldPrints = this.keys
+ .getJSONArray("otr_fingerprints");
+ for (int i = 0; i < oldPrints.length(); ++i) {
+ if (!oldPrints.getString(i).equals(fingerprint)) {
+ newPrints.put(oldPrints.getString(i));
+ } else {
+ success = true;
+ }
}
+ this.keys.put("otr_fingerprints", newPrints);
}
- this.keys.put("otr_fingerprints", newPrints);
+ return success;
+ } catch (JSONException e) {
+ return false;
}
- return success;
- } catch (JSONException e) {
- return false;
}
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java
index 6ff0e270..1c985e2f 100644
--- a/src/main/java/eu/siacs/conversations/entities/Conversation.java
+++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java
@@ -179,13 +179,13 @@ public class Conversation extends AbstractEntity implements Blockable {
}
}
- public void findUnsentMessagesWithOtrEncryption(OnMessageFound onMessageFound) {
+ public void findUnsentMessagesWithEncryption(int encryptionType, OnMessageFound onMessageFound) {
synchronized (this.messages) {
for (Message message : this.messages) {
if ((message.getStatus() == Message.STATUS_UNSEND || message.getStatus() == Message.STATUS_WAITING)
- && (message.getEncryption() == Message.ENCRYPTION_OTR)) {
+ && (message.getEncryption() == encryptionType)) {
onMessageFound.onMessageFound(message);
- }
+ }
}
}
}
@@ -519,6 +519,13 @@ public class Conversation extends AbstractEntity implements Blockable {
return getContact().getOtrFingerprints().contains(getOtrFingerprint());
}
+ /**
+ * short for is Private and Non-anonymous
+ */
+ public boolean isPnNA() {
+ return mode == MODE_SINGLE || (getMucOptions().membersOnly() && getMucOptions().nonanonymous());
+ }
+
public synchronized MucOptions getMucOptions() {
if (this.mucOptions == null) {
this.mucOptions = new MucOptions(this);
@@ -542,42 +549,51 @@ public class Conversation extends AbstractEntity implements Blockable {
return this.nextCounterpart;
}
- public int getLatestEncryption() {
- int latestEncryption = this.getLatestMessage().getEncryption();
- if ((latestEncryption == Message.ENCRYPTION_DECRYPTED)
- || (latestEncryption == Message.ENCRYPTION_DECRYPTION_FAILED)) {
- return Message.ENCRYPTION_PGP;
- } else {
- return latestEncryption;
+ private int getMostRecentlyUsedOutgoingEncryption() {
+ synchronized (this.messages) {
+ for(int i = this.messages.size() -1; i >= 0; --i) {
+ final Message m = this.messages.get(i);
+ if (!m.isCarbon() && m.getStatus() != Message.STATUS_RECEIVED) {
+ final int e = m.getEncryption();
+ if (e == Message.ENCRYPTION_DECRYPTED || e == Message.ENCRYPTION_DECRYPTION_FAILED) {
+ return Message.ENCRYPTION_PGP;
+ } else {
+ return e;
+ }
+ }
+ }
}
+ return Message.ENCRYPTION_NONE;
}
- public int getNextEncryption(boolean force) {
- int next = this.getIntAttribute(ATTRIBUTE_NEXT_ENCRYPTION, -1);
- if (next == -1) {
- int latest = this.getLatestEncryption();
- if (latest == Message.ENCRYPTION_NONE) {
- if (force && getMode() == MODE_SINGLE) {
- return Message.ENCRYPTION_OTR;
- } else if (getContact().getPresences().size() == 1) {
- if (getContact().getOtrFingerprints().size() >= 1) {
- return Message.ENCRYPTION_OTR;
+ private int getMostRecentlyUsedIncomingEncryption() {
+ synchronized (this.messages) {
+ for(int i = this.messages.size() -1; i >= 0; --i) {
+ final Message m = this.messages.get(i);
+ if (m.getStatus() == Message.STATUS_RECEIVED) {
+ final int e = m.getEncryption();
+ if (e == Message.ENCRYPTION_DECRYPTED || e == Message.ENCRYPTION_DECRYPTION_FAILED) {
+ return Message.ENCRYPTION_PGP;
} else {
- return latest;
+ return e;
}
- } else {
- return latest;
}
- } else {
- return latest;
}
}
- if (next == Message.ENCRYPTION_NONE && force
- && getMode() == MODE_SINGLE) {
- return Message.ENCRYPTION_OTR;
- } else {
- return next;
+ return Message.ENCRYPTION_NONE;
+ }
+
+ public int getNextEncryption() {
+ int next = this.getIntAttribute(ATTRIBUTE_NEXT_ENCRYPTION, -1);
+ if (next == -1) {
+ int outgoing = this.getMostRecentlyUsedOutgoingEncryption();
+ if (outgoing == Message.ENCRYPTION_NONE) {
+ return this.getMostRecentlyUsedIncomingEncryption();
+ } else {
+ return outgoing;
+ }
}
+ return next;
}
public void setNextEncryption(int encryption) {
diff --git a/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java b/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java
index ae9ba1f1..d35a4b01 100644
--- a/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java
+++ b/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java
@@ -1,28 +1,8 @@
package eu.siacs.conversations.entities;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URLConnection;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-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.utils.MimeUtils;
-import android.util.Log;
+import eu.siacs.conversations.utils.MimeUtils;
public class DownloadableFile extends File {
@@ -30,8 +10,7 @@ public class DownloadableFile extends File {
private long expectedSize = 0;
private String sha1sum;
- private Key aeskey;
- private String mime;
+ private byte[] aeskey;
private byte[] iv = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0xf };
@@ -45,15 +24,7 @@ public class DownloadableFile extends File {
}
public long getExpectedSize() {
- if (this.aeskey != null) {
- if (this.expectedSize == 0) {
- return 0;
- } else {
- return (this.expectedSize / 16 + 1) * 16;
- }
- } else {
- return this.expectedSize;
- }
+ return this.expectedSize;
}
public String getMimeType() {
@@ -79,91 +50,38 @@ public class DownloadableFile extends File {
this.sha1sum = sum;
}
- public void setKey(byte[] key) {
- if (key.length == 48) {
+ public void setKeyAndIv(byte[] keyIvCombo) {
+ if (keyIvCombo.length == 48) {
byte[] secretKey = new byte[32];
byte[] iv = new byte[16];
- System.arraycopy(key, 0, iv, 0, 16);
- System.arraycopy(key, 16, secretKey, 0, 32);
- this.aeskey = new SecretKeySpec(secretKey, "AES");
+ System.arraycopy(keyIvCombo, 0, iv, 0, 16);
+ System.arraycopy(keyIvCombo, 16, secretKey, 0, 32);
+ this.aeskey = secretKey;
this.iv = iv;
- } else if (key.length >= 32) {
+ } else if (keyIvCombo.length >= 32) {
byte[] secretKey = new byte[32];
- System.arraycopy(key, 0, secretKey, 0, 32);
- this.aeskey = new SecretKeySpec(secretKey, "AES");
- } else if (key.length >= 16) {
+ System.arraycopy(keyIvCombo, 0, secretKey, 0, 32);
+ this.aeskey = secretKey;
+ } else if (keyIvCombo.length >= 16) {
byte[] secretKey = new byte[16];
- System.arraycopy(key, 0, secretKey, 0, 16);
- this.aeskey = new SecretKeySpec(secretKey, "AES");
+ System.arraycopy(keyIvCombo, 0, secretKey, 0, 16);
+ this.aeskey = secretKey;
}
}
- public Key getKey() {
- return this.aeskey;
+ public void setKey(byte[] key) {
+ this.aeskey = key;
}
- public InputStream createInputStream() {
- if (this.getKey() == null) {
- try {
- return new FileInputStream(this);
- } catch (FileNotFoundException e) {
- return null;
- }
- } else {
- try {
- IvParameterSpec ips = new IvParameterSpec(iv);
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- cipher.init(Cipher.ENCRYPT_MODE, this.getKey(), ips);
- Log.d(Config.LOGTAG, "opening encrypted input stream");
- return new CipherInputStream(new FileInputStream(this), cipher);
- } catch (NoSuchAlgorithmException e) {
- Log.d(Config.LOGTAG, "no such algo: " + e.getMessage());
- return null;
- } catch (NoSuchPaddingException e) {
- Log.d(Config.LOGTAG, "no such padding: " + e.getMessage());
- return null;
- } catch (InvalidKeyException e) {
- Log.d(Config.LOGTAG, "invalid key: " + e.getMessage());
- return null;
- } catch (InvalidAlgorithmParameterException e) {
- Log.d(Config.LOGTAG, "invavid iv:" + e.getMessage());
- return null;
- } catch (FileNotFoundException e) {
- return null;
- }
- }
+ public void setIv(byte[] iv) {
+ this.iv = iv;
}
- public OutputStream createOutputStream() {
- if (this.getKey() == null) {
- try {
- return new FileOutputStream(this);
- } catch (FileNotFoundException e) {
- return null;
- }
- } else {
- try {
- IvParameterSpec ips = new IvParameterSpec(this.iv);
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- cipher.init(Cipher.DECRYPT_MODE, this.getKey(), ips);
- Log.d(Config.LOGTAG, "opening encrypted output stream");
- return new CipherOutputStream(new FileOutputStream(this),
- cipher);
- } catch (NoSuchAlgorithmException e) {
- Log.d(Config.LOGTAG, "no such algo: " + e.getMessage());
- return null;
- } catch (NoSuchPaddingException e) {
- Log.d(Config.LOGTAG, "no such padding: " + e.getMessage());
- return null;
- } catch (InvalidKeyException e) {
- Log.d(Config.LOGTAG, "invalid key: " + e.getMessage());
- return null;
- } catch (InvalidAlgorithmParameterException e) {
- Log.d(Config.LOGTAG, "invavid iv:" + e.getMessage());
- return null;
- } catch (FileNotFoundException e) {
- return null;
- }
- }
+ public byte[] getKey() {
+ return this.aeskey;
+ }
+
+ public byte[] getIv() {
+ return this.iv;
}
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java
index d04dff87..6a878e90 100644
--- a/src/main/java/eu/siacs/conversations/entities/Message.java
+++ b/src/main/java/eu/siacs/conversations/entities/Message.java
@@ -8,6 +8,7 @@ import java.net.URL;
import java.util.Arrays;
import eu.siacs.conversations.Config;
+import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
import eu.siacs.conversations.utils.GeoHelper;
import eu.siacs.conversations.utils.MimeUtils;
import eu.siacs.conversations.utils.UIHelper;
@@ -34,6 +35,7 @@ public class Message extends AbstractEntity {
public static final int ENCRYPTION_OTR = 2;
public static final int ENCRYPTION_DECRYPTED = 3;
public static final int ENCRYPTION_DECRYPTION_FAILED = 4;
+ public static final int ENCRYPTION_AXOLOTL = 5;
public static final int TYPE_TEXT = 0;
public static final int TYPE_IMAGE = 1;
@@ -49,9 +51,11 @@ public class Message extends AbstractEntity {
public static final String ENCRYPTION = "encryption";
public static final String STATUS = "status";
public static final String TYPE = "type";
+ public static final String CARBON = "carbon";
public static final String REMOTE_MSG_ID = "remoteMsgId";
public static final String SERVER_MSG_ID = "serverMsgId";
public static final String RELATIVE_FILE_PATH = "relativeFilePath";
+ public static final String FINGERPRINT = "axolotl_fingerprint";
public static final String ME_COMMAND = "/me ";
@@ -65,6 +69,7 @@ public class Message extends AbstractEntity {
protected int encryption;
protected int status;
protected int type;
+ protected boolean carbon = false;
protected String relativeFilePath;
protected boolean read = true;
protected String remoteMsgId = null;
@@ -73,6 +78,7 @@ public class Message extends AbstractEntity {
protected Transferable transferable = null;
private Message mNextMessage = null;
private Message mPreviousMessage = null;
+ private String axolotlFingerprint = null;
private Message() {
@@ -81,8 +87,11 @@ public class Message extends AbstractEntity {
public Message(Conversation conversation, String body, int encryption) {
this(conversation, body, encryption, STATUS_UNSEND);
}
-
public Message(Conversation conversation, String body, int encryption, int status) {
+ this(conversation, body, encryption, status, false);
+ }
+
+ public Message(Conversation conversation, String body, int encryption, int status, boolean carbon) {
this(java.util.UUID.randomUUID().toString(),
conversation.getUuid(),
conversation.getJid() == null ? null : conversation.getJid().toBareJid(),
@@ -92,6 +101,8 @@ public class Message extends AbstractEntity {
encryption,
status,
TYPE_TEXT,
+ false,
+ null,
null,
null,
null);
@@ -100,8 +111,9 @@ public class Message extends AbstractEntity {
private Message(final String uuid, final String conversationUUid, final Jid counterpart,
final Jid trueCounterpart, final String body, final long timeSent,
- final int encryption, final int status, final int type, final String remoteMsgId,
- final String relativeFilePath, final String serverMsgId) {
+ final int encryption, final int status, final int type, final boolean carbon,
+ final String remoteMsgId, final String relativeFilePath,
+ final String serverMsgId, final String fingerprint) {
this.uuid = uuid;
this.conversationUuid = conversationUUid;
this.counterpart = counterpart;
@@ -111,9 +123,11 @@ public class Message extends AbstractEntity {
this.encryption = encryption;
this.status = status;
this.type = type;
+ this.carbon = carbon;
this.remoteMsgId = remoteMsgId;
this.relativeFilePath = relativeFilePath;
this.serverMsgId = serverMsgId;
+ this.axolotlFingerprint = fingerprint;
}
public static Message fromCursor(Cursor cursor) {
@@ -148,9 +162,11 @@ public class Message extends AbstractEntity {
cursor.getInt(cursor.getColumnIndex(ENCRYPTION)),
cursor.getInt(cursor.getColumnIndex(STATUS)),
cursor.getInt(cursor.getColumnIndex(TYPE)),
+ cursor.getInt(cursor.getColumnIndex(CARBON))>0,
cursor.getString(cursor.getColumnIndex(REMOTE_MSG_ID)),
cursor.getString(cursor.getColumnIndex(RELATIVE_FILE_PATH)),
- cursor.getString(cursor.getColumnIndex(SERVER_MSG_ID)));
+ cursor.getString(cursor.getColumnIndex(SERVER_MSG_ID)),
+ cursor.getString(cursor.getColumnIndex(FINGERPRINT)));
}
public static Message createStatusMessage(Conversation conversation, String body) {
@@ -181,9 +197,11 @@ public class Message extends AbstractEntity {
values.put(ENCRYPTION, encryption);
values.put(STATUS, status);
values.put(TYPE, type);
+ values.put(CARBON, carbon ? 1 : 0);
values.put(REMOTE_MSG_ID, remoteMsgId);
values.put(RELATIVE_FILE_PATH, relativeFilePath);
values.put(SERVER_MSG_ID, serverMsgId);
+ values.put(FINGERPRINT, axolotlFingerprint);
return values;
}
@@ -304,6 +322,14 @@ public class Message extends AbstractEntity {
this.type = type;
}
+ public boolean isCarbon() {
+ return carbon;
+ }
+
+ public void setCarbon(boolean carbon) {
+ this.carbon = carbon;
+ }
+
public void setTrueCounterpart(Jid trueCounterpart) {
this.trueCounterpart = trueCounterpart;
}
@@ -389,7 +415,8 @@ public class Message extends AbstractEntity {
message.treatAsDownloadable() == Decision.NEVER &&
this.treatAsDownloadable() == Decision.NEVER &&
!message.getBody().startsWith(ME_COMMAND) &&
- !this.getBody().startsWith(ME_COMMAND)
+ !this.getBody().startsWith(ME_COMMAND) &&
+ this.isTrusted() == message.isTrusted()
);
}
@@ -405,11 +432,14 @@ public class Message extends AbstractEntity {
}
public String getMergedBody() {
- final Message next = this.next();
- if (this.mergeable(next)) {
- return getBody() + MERGE_SEPARATOR + next.getMergedBody();
+ StringBuilder body = new StringBuilder(this.body.trim());
+ Message current = this;
+ while(current.mergeable(current.next())) {
+ current = current.next();
+ body.append(MERGE_SEPARATOR);
+ body.append(current.getBody());
}
- return getBody();
+ return body.toString();
}
public boolean hasMeCommand() {
@@ -417,20 +447,23 @@ public class Message extends AbstractEntity {
}
public int getMergedStatus() {
- final Message next = this.next();
- if (this.mergeable(next)) {
- return next.getStatus();
+ int status = this.status;
+ Message current = this;
+ while(current.mergeable(current.next())) {
+ current = current.next();
+ status = current.status;
}
- return getStatus();
+ return status;
}
public long getMergedTimeSent() {
- Message next = this.next();
- if (this.mergeable(next)) {
- return next.getMergedTimeSent();
- } else {
- return getTimeSent();
+ long time = this.timeSent;
+ Message current = this;
+ while(current.mergeable(current.next())) {
+ current = current.next();
+ time = current.timeSent;
}
+ return time;
}
public boolean wasMergedIntoPrevious() {
@@ -673,4 +706,48 @@ public class Message extends AbstractEntity {
public int width = 0;
public int height = 0;
}
+
+ public void setAxolotlFingerprint(String fingerprint) {
+ this.axolotlFingerprint = fingerprint;
+ }
+
+ public String getAxolotlFingerprint() {
+ return axolotlFingerprint;
+ }
+
+ public boolean isTrusted() {
+ return conversation.getAccount().getAxolotlService().getFingerprintTrust(axolotlFingerprint)
+ == XmppAxolotlSession.Trust.TRUSTED;
+ }
+
+ private int getPreviousEncryption() {
+ for (Message iterator = this.prev(); iterator != null; iterator = iterator.prev()){
+ if( iterator.isCarbon() || iterator.getStatus() == STATUS_RECEIVED ) {
+ continue;
+ }
+ return iterator.getEncryption();
+ }
+ return ENCRYPTION_NONE;
+ }
+
+ private int getNextEncryption() {
+ for (Message iterator = this.next(); iterator != null; iterator = iterator.next()){
+ if( iterator.isCarbon() || iterator.getStatus() == STATUS_RECEIVED ) {
+ continue;
+ }
+ return iterator.getEncryption();
+ }
+ return conversation.getNextEncryption();
+ }
+
+ public boolean isValidInSession() {
+ int pastEncryption = this.getPreviousEncryption();
+ int futureEncryption = this.getNextEncryption();
+
+ boolean inUnencryptedSession = pastEncryption == ENCRYPTION_NONE
+ || futureEncryption == ENCRYPTION_NONE
+ || pastEncryption != futureEncryption;
+
+ return inUnencryptedSession || this.getEncryption() == pastEncryption;
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
index d867a370..52a862ef 100644
--- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
@@ -1,5 +1,7 @@
package eu.siacs.conversations.entities;
+import android.annotation.SuppressLint;
+
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -11,8 +13,6 @@ import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
-import android.annotation.SuppressLint;
-
@SuppressLint("DefaultLocale")
public class MucOptions {
@@ -264,6 +264,15 @@ public class MucOptions {
users.add(user);
}
+ public boolean isUserInRoom(String name) {
+ for (int i = 0; i < users.size(); ++i) {
+ if (users.get(i).getName().equals(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public void processPacket(PresencePacket packet, PgpEngine pgp) {
final Jid from = packet.getFrom();
if (!from.isBareJid()) {