From cc79d8f6b300b3c7661e39c3af81fb3bddad8f2e Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 4 Dec 2019 19:15:30 +0100 Subject: [PATCH] properly restore LMC edits. switch to LMC v1.1 fixes #3566 closes #3592 --- .../java/eu/siacs/conversations/Config.java | 2 +- .../eu/siacs/conversations/entities/Edit.java | 97 +++++++++++++++++++ .../siacs/conversations/entities/Edited.java | 80 --------------- .../siacs/conversations/entities/Message.java | 21 ++-- .../persistance/DatabaseBackend.java | 6 +- .../conversations/utils/CursorUtils.java | 2 +- 6 files changed, 116 insertions(+), 92 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/entities/Edit.java delete mode 100644 src/main/java/eu/siacs/conversations/entities/Edited.java diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 016f44870..b86e2b65d 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -117,7 +117,7 @@ public final class Config { public static final boolean IGNORE_ID_REWRITE_IN_MUC = true; public static final boolean MUC_LEAVE_BEFORE_JOIN = true; - public static final boolean USE_LMC_VERSION_1_1 = false; + public static final boolean USE_LMC_VERSION_1_1 = true; public static final long MAM_MAX_CATCHUP = MILLISECONDS_IN_DAY * 5; public static final int MAM_MAX_MESSAGES = 750; diff --git a/src/main/java/eu/siacs/conversations/entities/Edit.java b/src/main/java/eu/siacs/conversations/entities/Edit.java new file mode 100644 index 000000000..a3865bdd0 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/entities/Edit.java @@ -0,0 +1,97 @@ +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 Edit { + + private final String editedId; + private final String serverMsgId; + + Edit(String editedId, String serverMsgId) { + this.editedId = editedId; + this.serverMsgId = serverMsgId; + } + + static String toJson(List edits) throws JSONException { + JSONArray jsonArray = new JSONArray(); + for (Edit edit : edits) { + jsonArray.put(edit.toJson()); + } + return jsonArray.toString(); + } + + static boolean wasPreviouslyEditedRemoteMsgId(List edits, String remoteMsgId) { + for (Edit edit : edits) { + if (edit.editedId != null && edit.editedId.equals(remoteMsgId)) { + return true; + } + } + return false; + } + + static boolean wasPreviouslyEditedServerMsgId(List edits, String serverMsgId) { + for (Edit edit : edits) { + if (edit.serverMsgId != null && edit.serverMsgId.equals(serverMsgId)) { + return true; + } + } + return false; + } + + private static Edit fromJson(JSONObject jsonObject) throws JSONException { + String edited = jsonObject.has("edited_id") ? jsonObject.getString("edited_id") : null; + String serverMsgId = jsonObject.has("server_msg_id") ? jsonObject.getString("server_msg_id") : null; + return new Edit(edited, serverMsgId); + } + + static List fromJson(String input) { + final ArrayList list = new ArrayList<>(); + if (input == null) { + return list; + } + try { + final JSONArray jsonArray = new JSONArray(input); + for (int i = 0; i < jsonArray.length(); ++i) { + list.add(fromJson(jsonArray.getJSONObject(i))); + } + return list; + } catch (JSONException e) { + return list; + } + } + + private JSONObject toJson() throws JSONException { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("edited_id", editedId); + jsonObject.put("server_msg_id", serverMsgId); + return jsonObject; + } + + String getEditedId() { + return editedId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Edit edit = (Edit) o; + + if (editedId != null ? !editedId.equals(edit.editedId) : edit.editedId != null) + return false; + return serverMsgId != null ? serverMsgId.equals(edit.serverMsgId) : edit.serverMsgId == null; + } + + @Override + public int hashCode() { + int result = editedId != null ? editedId.hashCode() : 0; + result = 31 * result + (serverMsgId != null ? serverMsgId.hashCode() : 0); + return result; + } +} diff --git a/src/main/java/eu/siacs/conversations/entities/Edited.java b/src/main/java/eu/siacs/conversations/entities/Edited.java deleted file mode 100644 index 3e5b3ec0c..000000000 --- a/src/main/java/eu/siacs/conversations/entities/Edited.java +++ /dev/null @@ -1,80 +0,0 @@ -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 2035d8ac8..cc73222c5 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -97,7 +97,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable protected boolean deleted = false; protected boolean carbon = false; protected boolean oob = false; - protected List edits = new ArrayList<>(); + protected List edits = new ArrayList<>(); protected String relativeFilePath; protected boolean read = true; protected String remoteMsgId = null; @@ -174,7 +174,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable this.serverMsgId = serverMsgId; this.axolotlFingerprint = fingerprint; this.read = read; - this.edits = Edited.fromJson(edited); + this.edits = Edit.fromJson(edited); this.oob = oob; this.errorMessage = errorMessage; this.readByMarkers = readByMarkers == null ? new HashSet<>() : readByMarkers; @@ -263,7 +263,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable values.put(FINGERPRINT, axolotlFingerprint); values.put(READ, read ? 1 : 0); try { - values.put(EDITED, Edited.toJson(edits)); + values.put(EDITED, Edit.toJson(edits)); } catch (JSONException e) { Log.e(Config.LOGTAG,"error persisting json for edits",e); } @@ -434,11 +434,14 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable } public void putEdited(String edited, String serverMsgId) { - this.edits.add(new Edited(edited, serverMsgId)); + final Edit edit = new Edit(edited, serverMsgId); + if (this.edits.size() < 128 && !this.edits.contains(edit)) { + this.edits.add(edit); + } } - public boolean remoteMsgIdMatchInEdit(String id) { - for(Edited edit : this.edits) { + boolean remoteMsgIdMatchInEdit(String id) { + for(Edit edit : this.edits) { if (id.equals(edit.getEditedId())) { return true; } @@ -507,8 +510,8 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable boolean similar(Message message) { if (!isPrivateMessage() && this.serverMsgId != null && message.getServerMsgId() != null) { - return this.serverMsgId.equals(message.getServerMsgId()) || Edited.wasPreviouslyEditedServerMsgId(edits, message.getServerMsgId()); - } else if (Edited.wasPreviouslyEditedServerMsgId(edits, message.getServerMsgId())) { + return this.serverMsgId.equals(message.getServerMsgId()) || Edit.wasPreviouslyEditedServerMsgId(edits, message.getServerMsgId()); + } else if (Edit.wasPreviouslyEditedServerMsgId(edits, message.getServerMsgId())) { return true; } else if (this.body == null || this.counterpart == null) { return false; @@ -524,7 +527,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable final boolean matchingCounterpart = this.counterpart.equals(message.getCounterpart()); if (message.getRemoteMsgId() != null) { final boolean hasUuid = CryptoHelper.UUID_PATTERN.matcher(message.getRemoteMsgId()).matches(); - if (hasUuid && matchingCounterpart && Edited.wasPreviouslyEditedRemoteMsgId(edits, message.getRemoteMsgId())) { + if (hasUuid && matchingCounterpart && Edit.wasPreviouslyEditedRemoteMsgId(edits, message.getRemoteMsgId())) { return true; } return (message.getRemoteMsgId().equals(this.remoteMsgId) || message.getRemoteMsgId().equals(this.uuid)) diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 5b0db42d7..823ac8d28 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -63,7 +63,7 @@ import rocks.xmpp.addr.Jid; public class DatabaseBackend extends SQLiteOpenHelper { private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 45; + private static final int DATABASE_VERSION = 46; private static DatabaseBackend instance = null; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -546,6 +546,10 @@ public class DatabaseBackend extends SQLiteOpenHelper { if (oldVersion < 45 && newVersion >= 45) { db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.BODY_LANGUAGE); } + + if (oldVersion < 46 && newVersion >= 46) { + db.execSQL("update "+Message.TABLENAME+" set "+Message.EDITED+"=NULL"); + } } private void canonicalizeJids(SQLiteDatabase db) { diff --git a/src/main/java/eu/siacs/conversations/utils/CursorUtils.java b/src/main/java/eu/siacs/conversations/utils/CursorUtils.java index 832bed7dc..28f17b585 100644 --- a/src/main/java/eu/siacs/conversations/utils/CursorUtils.java +++ b/src/main/java/eu/siacs/conversations/utils/CursorUtils.java @@ -11,7 +11,7 @@ public class CursorUtils { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) { if (cursor instanceof AbstractWindowedCursor) { final AbstractWindowedCursor windowedCursor = (AbstractWindowedCursor) cursor; - windowedCursor.setWindow(new CursorWindow("8M", 8 * 1024 * 1024)); + windowedCursor.setWindow(new CursorWindow("4M", 8 * 1024 * 1024)); } if (cursor instanceof SQLiteCursor) { ((SQLiteCursor) cursor).setFillWindowForwardOnly(true);