diff options
Diffstat (limited to 'src/main/java/eu/siacs/conversations/entities')
7 files changed, 132 insertions, 180 deletions
diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index 2356ffb9..4c4a1916 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -5,7 +5,6 @@ import android.database.Cursor; import android.os.SystemClock; import android.util.Pair; -import eu.siacs.conversations.crypto.PgpDecryptionService; import net.java.otr4j.crypto.OtrCryptoEngineImpl; import net.java.otr4j.crypto.OtrCryptoException; @@ -20,10 +19,14 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; +import de.thedevstack.conversationsplus.ConversationsPlusPreferences; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.OtrService; +import eu.siacs.conversations.crypto.PgpDecryptionService; import eu.siacs.conversations.crypto.axolotl.AxolotlService; +import eu.siacs.conversations.crypto.axolotl.AxolotlServiceImpl; +import eu.siacs.conversations.crypto.axolotl.AxolotlServiceStub; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.jid.InvalidJidException; @@ -169,6 +172,10 @@ public class Account extends AbstractEntity { private List<Bookmark> bookmarks = new CopyOnWriteArrayList<>(); private final Collection<Jid> blocklist = new CopyOnWriteArraySet<>(); + public Account() { + this.uuid = "0"; + } + public Account(final Jid jid, final String password) { this(java.util.UUID.randomUUID().toString(), jid, password, 0, null, "", null, null, null, 5222); @@ -255,10 +262,6 @@ public class Account extends AbstractEntity { return this.hostname == null ? "" : this.hostname; } - public boolean isOnion() { - return getServer().toString().toLowerCase().endsWith(".onion"); - } - public void setPort(int port) { this.port = port; } @@ -356,10 +359,15 @@ 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); - } + if (ConversationsPlusPreferences.omemoEnabled()) { + this.axolotlService = new AxolotlServiceImpl(this, context); + if (xmppConnection != null) { + xmppConnection.addOnAdvancedStreamFeaturesAvailableListener(axolotlService); + } + } else { + this.axolotlService = new AxolotlServiceStub(); + } + this.pgpDecryptionService = new PgpDecryptionService(context); } diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java index 088dfd8a..fa30443d 100644 --- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java +++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java @@ -1,5 +1,7 @@ package eu.siacs.conversations.entities; +import android.graphics.Color; + import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -87,6 +89,11 @@ public class Bookmark extends Element implements ListItem { return tags; } + @Override + public int getStatusColor() { + return Color.parseColor("#259B23"); + } + public String getNick() { return this.findChildContent("nick"); } diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index 691fc3e4..9b4be366 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -2,6 +2,7 @@ package eu.siacs.conversations.entities; import android.content.ContentValues; import android.database.Cursor; +import android.graphics.Color; import org.json.JSONArray; import org.json.JSONException; @@ -167,11 +168,16 @@ public class Contact implements ListItem, Blockable { return tags; } + @Override + public int getStatusColor() { + return UIHelper.getStatusColor(getMostAvailableStatus()); + } + public boolean match(String needle) { if (needle == null || needle.isEmpty()) { return true; } - needle = needle.toLowerCase(Locale.US).trim(); + needle = needle.toLowerCase(Locale.US); String[] parts = needle.split("\\s+"); if (parts.length > 1) { for(int i = 0; i < parts.length; ++i) { diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index b1d597df..ab0e4966 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -21,6 +21,8 @@ import java.util.Comparator; import java.util.Iterator; import java.util.List; +import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import de.thedevstack.conversationsplus.utils.MessageUtil; import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.xmpp.chatstate.ChatState; @@ -259,16 +261,12 @@ public class Conversation extends AbstractEntity implements Blockable { return null; } + // TODO Check if this is really necessary public void populateWithMessages(final List<Message> messages) { synchronized (this.messages) { messages.clear(); messages.addAll(this.messages); } - for(Iterator<Message> iterator = messages.iterator(); iterator.hasNext();) { - if (iterator.next().wasMergedIntoPrevious()) { - iterator.remove(); - } - } } @Override @@ -308,14 +306,6 @@ public class Conversation extends AbstractEntity implements Blockable { return this.mFirstMamReference; } - public void setLastClearHistory(long time) { - setAttribute("last_clear_history",String.valueOf(time)); - } - - public long getLastClearHistory() { - return getLongAttribute("last_clear_history", 0); - } - public List<Jid> getAcceptedCryptoTargets() { if (mode == MODE_SINGLE) { return Arrays.asList(getJid().toBareJid()); @@ -773,7 +763,7 @@ public class Conversation extends AbstractEntity implements Blockable { if (message.hasFileOnRemoteHost()) { otherBody = message.getFileParams().url.toString(); } else { - otherBody = message.body; + otherBody = message.getBody(); } if (otherBody != null && otherBody.equals(body)) { return message; @@ -785,10 +775,6 @@ public class Conversation extends AbstractEntity implements Blockable { } public long getLastMessageTransmitted() { - long last_clear = getLastClearHistory(); - if (last_clear != 0) { - return last_clear; - } synchronized (this.messages) { for(int i = this.messages.size() - 1; i >= 0; --i) { Message message = this.messages.get(i); @@ -945,13 +931,19 @@ public class Conversation extends AbstractEntity implements Blockable { } public int unreadCount() { + if (getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL,0) == Long.MAX_VALUE) { + return 0; + } synchronized (this.messages) { int count = 0; for(int i = this.messages.size() - 1; i >= 0; --i) { - if (this.messages.get(i).isRead()) { + Message message = this.messages.get(i); + if (message.isRead()) { return count; } - ++count; + if (alwaysNotify() || MessageUtil.wasHighlightedOrPrivate(message)) { + ++count; + } } return count; } diff --git a/src/main/java/eu/siacs/conversations/entities/ListItem.java b/src/main/java/eu/siacs/conversations/entities/ListItem.java index 22aedd4b..56804fbf 100644 --- a/src/main/java/eu/siacs/conversations/entities/ListItem.java +++ b/src/main/java/eu/siacs/conversations/entities/ListItem.java @@ -11,6 +11,8 @@ public interface ListItem extends Comparable<ListItem> { Jid getJid(); + public int getStatusColor(); + List<Tag> getTags(); final class Tag { diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index f6a45533..7a5be8f8 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -5,13 +5,10 @@ import android.database.Cursor; import java.net.MalformedURLException; 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.FileUtils; import eu.siacs.conversations.utils.MimeUtils; -import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; @@ -66,7 +63,7 @@ public class Message extends AbstractEntity { protected String conversationUuid; protected Jid counterpart; protected Jid trueCounterpart; - protected String body; + private String body; protected String encryptedBody; protected long timeSent; protected int encryption; @@ -84,6 +81,7 @@ public class Message extends AbstractEntity { private Message mNextMessage = null; private Message mPreviousMessage = null; private String axolotlFingerprint = null; + private Decision mTreatAsDownloadAble = Decision.NOT_DECIDED; private Message() { @@ -189,14 +187,6 @@ public class Message extends AbstractEntity { return message; } - public static Message createLoadMoreMessage(Conversation conversation) { - final Message message = new Message(); - message.setType(Message.TYPE_STATUS); - message.setConversation(conversation); - message.setBody("LOAD_MORE"); - return message; - } - @Override public ContentValues getContentValues() { ContentValues values = new ContentValues(); @@ -353,10 +343,6 @@ public class Message extends AbstractEntity { this.carbon = carbon; } - public void setEdited(String edited) { - this.edited = edited; - } - public boolean edited() { return this.edited != null; } @@ -365,10 +351,6 @@ public class Message extends AbstractEntity { this.trueCounterpart = trueCounterpart; } - public Jid getTrueCounterpart() { - return this.trueCounterpart; - } - public Transferable getTransferable() { return this.transferable; } @@ -378,30 +360,40 @@ public class Message extends AbstractEntity { } public boolean equals(Message message) { - if (this.serverMsgId != null && message.getServerMsgId() != null) { - return this.serverMsgId.equals(message.getServerMsgId()); - } else if (this.body == null || this.counterpart == null) { + if (this.getServerMsgId() != null && message.getServerMsgId() != null) { + return this.getServerMsgId().equals(message.getServerMsgId()); + } else if (this.getBody() == null || this.getCounterpart() == null + || message.getBody() == null || message.getCounterpart() == null) { return false; } else { String body, otherBody; if (this.hasFileOnRemoteHost()) { - body = getFileParams().url.toString(); - otherBody = message.body == null ? null : message.body.trim(); + body = this.getFileParams().url.toString(); } else { - body = this.body; - otherBody = message.body; + body = this.getBody(); } - if (message.getRemoteMsgId() != null) { - return (message.getRemoteMsgId().equals(this.remoteMsgId) || message.getRemoteMsgId().equals(this.uuid)) - && this.counterpart.equals(message.getCounterpart()) + if (message.hasFileOnRemoteHost()) { + otherBody = message.getFileParams().url.toString(); + } else { + otherBody = message.getBody(); + } + + if (message.getRemoteMsgId() != null && this.getRemoteMsgId() != null) { + return (message.getRemoteMsgId().equals(this.getRemoteMsgId()) + || message.getRemoteMsgId().equals(this.getUuid()) + || message.getUuid().equals(this.getRemoteMsgId())) + && this.getCounterpart().equals(message.getCounterpart()) && (body.equals(otherBody) ||(message.getEncryption() == Message.ENCRYPTION_PGP && message.getRemoteMsgId().matches("[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}"))) ; } else { - return this.remoteMsgId == null - && this.counterpart.equals(message.getCounterpart()) - && body.equals(otherBody) - && Math.abs(this.getTimeSent() - message.getTimeSent()) < Config.MESSAGE_MERGE_WINDOW * 1000; + // existing (send) message with no remoteMsgId and MAM message with remoteMsgId + return ((this.getRemoteMsgId() == null && message.getRemoteMsgId() != null) + || (this.getRemoteMsgId() != null && message.getRemoteMsgId() == null) + // both null is also acceptable + || (this.getRemoteMsgId() == null && message.getRemoteMsgId() == null)) + && this.getCounterpart().equals(message.getCounterpart()) + && body.equals(otherBody); } } } @@ -434,97 +426,16 @@ public class Message extends AbstractEntity { } } - public boolean isLastCorrectableMessage() { - Message next = next(); - while(next != null) { - if (next.isCorrectable()) { - return false; - } - next = next.next(); - } - return isCorrectable(); - } - - private boolean isCorrectable() { - return getStatus() != STATUS_RECEIVED && !isCarbon(); - } - - public boolean mergeable(final Message message) { - return message != null && - (message.getType() == Message.TYPE_TEXT && - this.getTransferable() == null && - message.getTransferable() == null && - message.getEncryption() != Message.ENCRYPTION_PGP && - message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED && - this.getType() == message.getType() && - //this.getStatus() == message.getStatus() && - isStatusMergeable(this.getStatus(), message.getStatus()) && - this.getEncryption() == message.getEncryption() && - this.getCounterpart() != null && - this.getCounterpart().equals(message.getCounterpart()) && - this.edited() == message.edited() && - (message.getTimeSent() - this.getTimeSent()) <= (Config.MESSAGE_MERGE_WINDOW * 1000) && - !GeoHelper.isGeoUri(message.getBody()) && - !GeoHelper.isGeoUri(this.body) && - message.treatAsDownloadable() == Decision.NEVER && - this.treatAsDownloadable() == Decision.NEVER && - !message.getBody().startsWith(ME_COMMAND) && - !this.getBody().startsWith(ME_COMMAND) && - !this.bodyIsHeart() && - !message.bodyIsHeart() && - this.isTrusted() == message.isTrusted() - ); - } - - private static boolean isStatusMergeable(int a, int b) { - return a == b || ( - (a == Message.STATUS_SEND_RECEIVED && b == Message.STATUS_UNSEND) - || (a == Message.STATUS_SEND_RECEIVED && b == Message.STATUS_SEND) - || (a == Message.STATUS_UNSEND && b == Message.STATUS_SEND) - || (a == Message.STATUS_UNSEND && b == Message.STATUS_SEND_RECEIVED) - || (a == Message.STATUS_SEND && b == Message.STATUS_UNSEND) - || (a == Message.STATUS_SEND && b == Message.STATUS_SEND_RECEIVED) - ); - } - - public String 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().trim()); - } - return body.toString(); - } - public boolean hasMeCommand() { - return getMergedBody().startsWith(ME_COMMAND); + return getBody().startsWith(ME_COMMAND); } - public int getMergedStatus() { - int status = this.status; - Message current = this; - while(current.mergeable(current.next())) { - current = current.next(); - status = current.status; - } - return status; - } - - public long getMergedTimeSent() { - long time = this.timeSent; - Message current = this; - while(current.mergeable(current.next())) { - current = current.next(); - time = current.timeSent; + public String getBodyReplacedMeCommand(String replaceString) { + try { + return getBody().replaceAll("^" + Message.ME_COMMAND, replaceString + " "); + } catch (ArrayIndexOutOfBoundsException e) { + return getBody(); } - return time; - } - - public boolean wasMergedIntoPrevious() { - Message prev = this.prev(); - return prev != null && prev.mergeable(this); } public boolean trusted() { @@ -568,28 +479,33 @@ public class Message extends AbstractEntity { MUST, SHOULD, NEVER, + NOT_DECIDED, } - private static String extractRelevantExtension(URL url) { + private String extractRelevantExtension(URL url) { + if (url == null) { + return null; + } String path = url.getPath(); return extractRelevantExtension(path); } - private static String extractRelevantExtension(String path) { + private String extractRelevantExtension(String path) { if (path == null || path.isEmpty()) { return null; } String filename = path.substring(path.lastIndexOf('/') + 1).toLowerCase(); - int dotPosition = filename.lastIndexOf("."); - if (dotPosition != -1) { - String extension = filename.substring(dotPosition + 1); + final String lastPart = FileUtils.getLastExtension(filename); + + if (!lastPart.isEmpty()) { // we want the real file extension, not the crypto one - if (Transferable.VALID_CRYPTO_EXTENSIONS.contains(extension)) { - return extractRelevantExtension(filename.substring(0,dotPosition)); + final String secondToLastPart = FileUtils.getSecondToLastExtension(filename); + if (!secondToLastPart.isEmpty() && Transferable.VALID_CRYPTO_EXTENSIONS.contains(lastPart)) { + return secondToLastPart; } else { - return extension; + return lastPart; } } return null; @@ -605,53 +521,74 @@ public class Message extends AbstractEntity { } } else { try { - return MimeUtils.guessMimeTypeFromExtension(extractRelevantExtension(new URL(body.trim()))); + return MimeUtils.guessMimeTypeFromExtension(extractRelevantExtension(new URL(this.getBody()))); } catch (MalformedURLException e) { return null; } } } + /** + * in case of later found error with decision, set it to a value which does not affect anything, hopefully + */ + public void setNoDownloadable() { + mTreatAsDownloadAble = Decision.NEVER; + } + public Decision treatAsDownloadable() { - if (body.trim().contains(" ")) { - return Decision.NEVER; + // only test this ones, body will not change + if (mTreatAsDownloadAble != Decision.NOT_DECIDED) { + return mTreatAsDownloadAble; + } + /** + * there are a few cases where spaces result in an unwanted behavior, e.g. + * "http://example.com/image.jpg" text that will not be shown /abc.png" + * or more than one image link in one message. + */ + if (getBody().contains(" ")) { + mTreatAsDownloadAble = Decision.NEVER; + return mTreatAsDownloadAble; } try { URL url = new URL(body); if (!url.getProtocol().equalsIgnoreCase("http") && !url.getProtocol().equalsIgnoreCase("https")) { - return Decision.NEVER; + mTreatAsDownloadAble = Decision.NEVER; + return mTreatAsDownloadAble; } else if (oob) { - return Decision.MUST; + mTreatAsDownloadAble = Decision.MUST; + return mTreatAsDownloadAble; } String extension = extractRelevantExtension(url); if (extension == null) { - return Decision.NEVER; + mTreatAsDownloadAble = Decision.NEVER; + return mTreatAsDownloadAble; } String ref = url.getRef(); boolean encrypted = ref != null && ref.matches("([A-Fa-f0-9]{2}){48}"); if (encrypted) { if (MimeUtils.guessMimeTypeFromExtension(extension) != null) { - return Decision.MUST; + mTreatAsDownloadAble = Decision.MUST; + return mTreatAsDownloadAble; } else { - return Decision.NEVER; + mTreatAsDownloadAble = Decision.NEVER; + return mTreatAsDownloadAble; } } else if (Transferable.VALID_IMAGE_EXTENSIONS.contains(extension) || Transferable.WELL_KNOWN_EXTENSIONS.contains(extension)) { - return Decision.SHOULD; + mTreatAsDownloadAble = Decision.SHOULD; + return mTreatAsDownloadAble; } else { - return Decision.NEVER; + mTreatAsDownloadAble = Decision.NEVER; + return mTreatAsDownloadAble; } } catch (MalformedURLException e) { - return Decision.NEVER; + mTreatAsDownloadAble = Decision.NEVER; + return mTreatAsDownloadAble; } } - public boolean bodyIsHeart() { - return body != null && UIHelper.HEARTS.contains(body.trim()); - } - public FileParams getFileParams() { FileParams params = getLegacyFileParams(); if (params != null) { @@ -661,10 +598,10 @@ public class Message extends AbstractEntity { if (this.transferable != null) { params.size = this.transferable.getFileSize(); } - if (body == null) { + if (this.getBody() == null) { return params; } - String parts[] = body.split("\\|"); + String parts[] = this.getBody().split("\\|"); switch (parts.length) { case 1: try { @@ -723,10 +660,10 @@ public class Message extends AbstractEntity { public FileParams getLegacyFileParams() { FileParams params = new FileParams(); - if (body == null) { + if (this.getBody() == null) { return params; } - String parts[] = body.split(","); + String parts[] = this.getBody().split(","); if (parts.length == 3) { try { params.size = Long.parseLong(parts[0]); diff --git a/src/main/java/eu/siacs/conversations/entities/ServiceDiscoveryResult.java b/src/main/java/eu/siacs/conversations/entities/ServiceDiscoveryResult.java index c4fc30ab..a8f60e39 100644 --- a/src/main/java/eu/siacs/conversations/entities/ServiceDiscoveryResult.java +++ b/src/main/java/eu/siacs/conversations/entities/ServiceDiscoveryResult.java @@ -160,7 +160,7 @@ public class ServiceDiscoveryResult { } public String getVer() { - return new String(Base64.encode(this.ver, Base64.DEFAULT)).trim(); + return new String(Base64.encode(this.ver, Base64.DEFAULT)); } public ServiceDiscoveryResult(Cursor cursor) throws JSONException { |