From f1e1c4a78df5e2f299c085eb93b73f64fd5dc65d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 1 Dec 2018 15:52:44 +0100 Subject: [PATCH] keep track of previously edited ids --- .../siacs/conversations/entities/Edited.java | 80 +++++++++++++++++++ .../siacs/conversations/entities/Message.java | 34 +++++--- .../conversations/parser/MessageParser.java | 2 +- .../persistance/DatabaseBackend.java | 5 +- .../services/XmppConnectionService.java | 12 ++- .../ui/ConversationFragment.java | 3 +- 6 files changed, 118 insertions(+), 18 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/entities/Edited.java diff --git a/src/main/java/eu/siacs/conversations/entities/Edited.java b/src/main/java/eu/siacs/conversations/entities/Edited.java new file mode 100644 index 000000000..3e5b3ec0c --- /dev/null +++ b/src/main/java/eu/siacs/conversations/entities/Edited.java @@ -0,0 +1,80 @@ +package eu.siacs.conversations.entities; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +public class Edited { + + private final String editedId; + private final String serverMsgId; + + public Edited(String editedId, String serverMsgId) { + this.editedId = editedId; + this.serverMsgId = serverMsgId; + } + + public static String toJson(List edits) throws JSONException { + JSONArray jsonArray = new JSONArray(); + for (Edited edited : edits) { + jsonArray.put(edited.toJson()); + } + return jsonArray.toString(); + } + + public static boolean wasPreviouslyEditedRemoteMsgId(List editeds, String remoteMsgId) { + for (Edited edited : editeds) { + if (edited.editedId != null && edited.editedId.equals(remoteMsgId)) { + return true; + } + } + return false; + } + + public static boolean wasPreviouslyEditedServerMsgId(List editeds, String serverMsgId) { + for (Edited edited : editeds) { + if (edited.serverMsgId != null && edited.serverMsgId.equals(serverMsgId)) { + return true; + } + } + return false; + } + + public static Edited fromJson(JSONObject jsonObject) throws JSONException { + String edited = jsonObject.getString("edited_id"); + String serverMsgId = jsonObject.getString("server_msg_id"); + return new Edited(edited, serverMsgId); + } + + public static List fromJson(String input) { + ArrayList list = new ArrayList<>(); + if (input == null) { + return list; + } + try { + JSONArray jsonArray = new JSONArray(input); + for (int i = 0; i < jsonArray.length(); ++i) { + list.add(fromJson(jsonArray.getJSONObject(i))); + } + + } catch (JSONException e) { + list = new ArrayList<>(); + list.add(new Edited(input, null)); + } + return list; + } + + public JSONObject toJson() throws JSONException { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("edited_id", editedId); + jsonObject.put("server_msg_id", serverMsgId); + return jsonObject; + } + + public String getEditedId() { + return editedId; + } +} diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 6cefba222..b57ea8e20 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -3,10 +3,14 @@ package eu.siacs.conversations.entities; import android.content.ContentValues; import android.database.Cursor; import android.text.SpannableStringBuilder; +import android.util.Log; + +import org.json.JSONException; import java.lang.ref.WeakReference; import java.net.MalformedURLException; import java.net.URL; +import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; @@ -86,7 +90,7 @@ public class Message extends AbstractEntity { protected int type; protected boolean carbon = false; protected boolean oob = false; - protected String edited = null; + protected List edits = new ArrayList<>(); protected String relativeFilePath; protected boolean read = true; protected String remoteMsgId = null; @@ -160,10 +164,10 @@ public class Message extends AbstractEntity { this.serverMsgId = serverMsgId; this.axolotlFingerprint = fingerprint; this.read = read; - this.edited = edited; + this.edits = Edited.fromJson(edited); this.oob = oob; this.errorMessage = errorMessage; - this.readByMarkers = readByMarkers == null ? new HashSet() : readByMarkers; + this.readByMarkers = readByMarkers == null ? new HashSet<>() : readByMarkers; this.markable = markable; } @@ -256,7 +260,11 @@ public class Message extends AbstractEntity { values.put(SERVER_MSG_ID, serverMsgId); values.put(FINGERPRINT, axolotlFingerprint); values.put(READ, read ? 1 : 0); - values.put(EDITED, edited); + try { + values.put(EDITED, Edited.toJson(edits)); + } catch (JSONException e) { + Log.e(Config.LOGTAG,"error persisting json for edits",e); + } values.put(OOB, oob ? 1 : 0); values.put(ERROR_MESSAGE, errorMessage); values.put(READ_BY_MARKERS, ReadByMarker.toJson(readByMarkers).toString()); @@ -413,12 +421,12 @@ public class Message extends AbstractEntity { this.carbon = carbon; } - public void setEdited(String edited) { - this.edited = edited; + public void putEdited(String edited, String serverMsgId) { + this.edits.add(new Edited(edited, serverMsgId)); } public boolean edited() { - return this.edited != null; + return this.edits.size() > 0; } public void setTrueCounterpart(Jid trueCounterpart) { @@ -470,7 +478,9 @@ public class Message extends AbstractEntity { public boolean similar(Message message) { if (type != TYPE_PRIVATE && this.serverMsgId != null && message.getServerMsgId() != null) { - return this.serverMsgId.equals(message.getServerMsgId()); + return this.serverMsgId.equals(message.getServerMsgId()) || Edited.wasPreviouslyEditedServerMsgId(edits, message.getServerMsgId()); + } else if (Edited.wasPreviouslyEditedServerMsgId(edits, message.getServerMsgId())) { + return true; } else if (this.body == null || this.counterpart == null) { return false; } else { @@ -485,7 +495,7 @@ public class Message extends AbstractEntity { final boolean matchingCounterpart = this.counterpart.equals(message.getCounterpart()); if (message.getRemoteMsgId() != null) { final boolean hasUuid = CryptoHelper.UUID_PATTERN.matcher(message.getRemoteMsgId()).matches(); - if (hasUuid && this.edited != null && matchingCounterpart && this.edited.equals(message.getRemoteMsgId())) { + if (hasUuid && matchingCounterpart && Edited.wasPreviouslyEditedRemoteMsgId(edits, message.getRemoteMsgId())) { return true; } return (message.getRemoteMsgId().equals(this.remoteMsgId) || message.getRemoteMsgId().equals(this.uuid)) @@ -686,7 +696,11 @@ public class Message extends AbstractEntity { } public String getEditedId() { - return edited; + if (edits.size() > 0) { + return edits.get(edits.size() - 1).getEditedId(); + } else { + throw new IllegalStateException("Attempting to store unedited message"); + } } public void setOob(boolean isOob) { diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index e21c759f8..aa3f1f784 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -518,7 +518,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece final String uuid = replacedMessage.getUuid(); replacedMessage.setUuid(UUID.randomUUID().toString()); replacedMessage.setBody(message.getBody()); - replacedMessage.setEdited(replacedMessage.getRemoteMsgId()); + replacedMessage.putEdited(replacedMessage.getRemoteMsgId(), replacedMessage.getServerMsgId()); replacedMessage.setRemoteMsgId(remoteMsgId); if (replacedMessage.getServerMsgId() == null || message.getServerMsgId() != null) { replacedMessage.setServerMsgId(message.getServerMsgId()); diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 072e706ee..b8e9e43e7 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -902,11 +902,10 @@ public class DatabaseBackend extends SQLiteOpenHelper { return db.update(Message.TABLENAME, message.getContentValues(), Message.UUID + "=?", args) == 1; } - public void updateMessage(Message message, String uuid) { + public boolean updateMessage(Message message, String uuid) { SQLiteDatabase db = this.getWritableDatabase(); String[] args = {uuid}; - db.update(Message.TABLENAME, message.getContentValues(), Message.UUID - + "=?", args); + return db.update(Message.TABLENAME, message.getContentValues(), Message.UUID + "=?", args) == 1; } public void readRoster(Roster roster) { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 2b43acd60..d53be0dd7 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1316,7 +1316,9 @@ public class XmppConnectionService extends Service { if (message.edited()) { message.setBody(decryptedBody); message.setEncryption(Message.ENCRYPTION_DECRYPTED); - databaseBackend.updateMessage(message, message.getEditedId()); + if (!databaseBackend.updateMessage(message, message.getEditedId())) { + Log.e(Config.LOGTAG,"error updated message in DB after edit"); + } updateConversationUi(); return; } else { @@ -1354,7 +1356,9 @@ public class XmppConnectionService extends Service { if (saveInDb) { databaseBackend.createMessage(message); } else if (message.edited()) { - databaseBackend.updateMessage(message, message.getEditedId()); + if (!databaseBackend.updateMessage(message, message.getEditedId())) { + Log.e(Config.LOGTAG,"error updated message in DB after edit"); + } } updateConversationUi(); } @@ -2825,7 +2829,9 @@ public class XmppConnectionService extends Service { } public void updateMessage(Message message, String uuid) { - databaseBackend.updateMessage(message, uuid); + if (!databaseBackend.updateMessage(message, uuid)) { + Log.e(Config.LOGTAG,"error updated message in DB after edit"); + } updateConversationUi(); } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 2d56703e5..a72abd115 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -746,7 +746,8 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke } else { message = conversation.getCorrectingMessage(); message.setBody(body); - message.setEdited(message.getUuid()); + message.putEdited(message.getUuid(), message.getServerMsgId()); + message.setServerMsgId(null); message.setUuid(UUID.randomUUID().toString()); } switch (conversation.getNextEncryption()) {