diff --git a/app/src/androidTest/java/im/conversations/android/xmpp/TransformationTest.java b/app/src/androidTest/java/im/conversations/android/xmpp/MessageTransformationTest.java similarity index 86% rename from app/src/androidTest/java/im/conversations/android/xmpp/TransformationTest.java rename to app/src/androidTest/java/im/conversations/android/xmpp/MessageTransformationTest.java index 021ebf0ef..eab2b61c5 100644 --- a/app/src/androidTest/java/im/conversations/android/xmpp/TransformationTest.java +++ b/app/src/androidTest/java/im/conversations/android/xmpp/MessageTransformationTest.java @@ -11,7 +11,7 @@ import im.conversations.android.database.entity.AccountEntity; import im.conversations.android.database.model.MessageEmbedded; import im.conversations.android.database.model.Modification; import im.conversations.android.database.model.PartType; -import im.conversations.android.transformer.Transformation; +import im.conversations.android.transformer.MessageTransformation; import im.conversations.android.transformer.Transformer; import im.conversations.android.xmpp.model.correction.Replace; import im.conversations.android.xmpp.model.jabber.Body; @@ -33,7 +33,7 @@ import org.jxmpp.jid.parts.Resourcepart; import org.jxmpp.stringprep.XmppStringprepException; @RunWith(AndroidJUnit4.class) -public class TransformationTest { +public class MessageTransformationTest { private static final BareJid ACCOUNT = JidCreate.bareFromOrThrowUnchecked("user@example.com"); private static final BareJid REMOTE = JidCreate.bareFromOrThrowUnchecked("juliet@example.com"); @@ -68,7 +68,7 @@ public class TransformationTest { final var reaction = reactions.addExtension(new Reaction()); reaction.setContent("Y"); this.transformer.transform( - Transformation.of(reactionMessage, Instant.now(), REMOTE, "stanza-b", null)); + MessageTransformation.of(reactionMessage, Instant.now(), REMOTE, "stanza-b", null)); final var originalMessage = new Message(); originalMessage.setId("1"); originalMessage.setTo(REMOTE); @@ -76,7 +76,7 @@ public class TransformationTest { final var body = originalMessage.addExtension(new Body()); body.setContent(GREETING); this.transformer.transform( - Transformation.of(originalMessage, Instant.now(), REMOTE, "stanza-a", null)); + MessageTransformation.of(originalMessage, Instant.now(), REMOTE, "stanza-a", null)); final var messages = database.messageDao().getMessages(1L); Assert.assertEquals(1, messages.size()); @@ -95,19 +95,21 @@ public class TransformationTest { message.addExtension(new Body("Please give me a thumbs up")); message.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a"))); this.transformer.transform( - Transformation.of(message, Instant.now(), REMOTE, "stanza-a", "id-user-a")); + MessageTransformation.of(message, Instant.now(), REMOTE, "stanza-a", "id-user-a")); final var reactionA = new Message(Message.Type.GROUPCHAT); reactionA.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-b"))); reactionA.addExtension(Reactions.to("stanza-a")).addExtension(new Reaction("Y")); this.transformer.transform( - Transformation.of(reactionA, Instant.now(), REMOTE, "stanza-b", "id-user-b")); + MessageTransformation.of( + reactionA, Instant.now(), REMOTE, "stanza-b", "id-user-b")); final var reactionB = new Message(Message.Type.GROUPCHAT); reactionB.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-c"))); reactionB.addExtension(Reactions.to("stanza-a")).addExtension(new Reaction("Y")); this.transformer.transform( - Transformation.of(reactionB, Instant.now(), REMOTE, "stanza-c", "id-user-c")); + MessageTransformation.of( + reactionB, Instant.now(), REMOTE, "stanza-c", "id-user-c")); final var reactionC = new Message(Message.Type.GROUPCHAT); reactionC.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-d"))); @@ -115,7 +117,8 @@ public class TransformationTest { reactions.addExtension(new Reaction("Y")); reactions.addExtension(new Reaction("Z")); this.transformer.transform( - Transformation.of(reactionC, Instant.now(), REMOTE, "stanza-d", "id-user-d")); + MessageTransformation.of( + reactionC, Instant.now(), REMOTE, "stanza-d", "id-user-d")); final var messages = database.messageDao().getMessages(1L); Assert.assertEquals(1, messages.size()); @@ -141,7 +144,8 @@ public class TransformationTest { messageCorrection.addExtension(new Replace()).setId("1"); this.transformer.transform( - Transformation.of(messageCorrection, Instant.now(), REMOTE, "stanza-a", null)); + MessageTransformation.of( + messageCorrection, Instant.now(), REMOTE, "stanza-a", null)); // the correction should not show up as a message Assert.assertEquals(0, database.messageDao().getMessages(1L).size()); @@ -153,7 +157,7 @@ public class TransformationTest { messageWithTypo.addExtension(new Body()).setContent("Hii example!"); this.transformer.transform( - Transformation.of(messageWithTypo, Instant.now(), REMOTE, "stanza-b", null)); + MessageTransformation.of(messageWithTypo, Instant.now(), REMOTE, "stanza-b", null)); final var messages = database.messageDao().getMessages(1L); @@ -175,7 +179,7 @@ public class TransformationTest { messageWithTypo.addExtension(new Body()).setContent("Hii example!"); this.transformer.transform( - Transformation.of(messageWithTypo, Instant.now(), REMOTE, "stanza-a", null)); + MessageTransformation.of(messageWithTypo, Instant.now(), REMOTE, "stanza-a", null)); Assert.assertEquals(1, database.messageDao().getMessages(1L).size()); @@ -187,7 +191,8 @@ public class TransformationTest { messageCorrection.addExtension(new Replace()).setId("1"); this.transformer.transform( - Transformation.of(messageCorrection, Instant.now(), REMOTE, "stanza-b", null)); + MessageTransformation.of( + messageCorrection, Instant.now(), REMOTE, "stanza-b", null)); final var messages = database.messageDao().getMessages(1L); @@ -206,19 +211,21 @@ public class TransformationTest { message.addExtension(new Body("Please give me a thumbs up")); message.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a"))); this.transformer.transform( - Transformation.of(message, Instant.now(), REMOTE, "stanza-a", "id-user-a")); + MessageTransformation.of(message, Instant.now(), REMOTE, "stanza-a", "id-user-a")); final var reactionA = new Message(Message.Type.GROUPCHAT); reactionA.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-b"))); reactionA.addExtension(Reactions.to("stanza-a")).addExtension(new Reaction("N")); this.transformer.transform( - Transformation.of(reactionA, Instant.now(), REMOTE, "stanza-b", "id-user-b")); + MessageTransformation.of( + reactionA, Instant.now(), REMOTE, "stanza-b", "id-user-b")); final var reactionB = new Message(Message.Type.GROUPCHAT); reactionB.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-b"))); reactionB.addExtension(Reactions.to("stanza-a")).addExtension(new Reaction("Y")); this.transformer.transform( - Transformation.of(reactionB, Instant.now(), REMOTE, "stanza-c", "id-user-b")); + MessageTransformation.of( + reactionB, Instant.now(), REMOTE, "stanza-c", "id-user-b")); final var messages = database.messageDao().getMessages(1L); Assert.assertEquals(1, messages.size()); @@ -240,7 +247,7 @@ public class TransformationTest { m1.addExtension(new Replace()).setId(ogMessageId); m1.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a"))); this.transformer.transform( - Transformation.of( + MessageTransformation.of( m1, Instant.ofEpochMilli(2000), REMOTE, @@ -254,7 +261,7 @@ public class TransformationTest { m2.addExtension(new Replace()).setId(ogMessageId); m2.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a"))); this.transformer.transform( - Transformation.of( + MessageTransformation.of( m2, Instant.ofEpochMilli(3000), REMOTE, @@ -266,7 +273,7 @@ public class TransformationTest { reactionB.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-b"))); reactionB.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y")); this.transformer.transform( - Transformation.of( + MessageTransformation.of( reactionB, Instant.now(), REMOTE, "irrelevant-stanza-id3", "id-user-b")); // the original message @@ -275,7 +282,8 @@ public class TransformationTest { m4.addExtension(new Body("Please give me thumbs up")); m4.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a"))); this.transformer.transform( - Transformation.of(m4, Instant.ofEpochMilli(1000), REMOTE, ogStanzaId, "id-user-a")); + MessageTransformation.of( + m4, Instant.ofEpochMilli(1000), REMOTE, ogStanzaId, "id-user-a")); final var messages = database.messageDao().getMessages(1L); Assert.assertEquals(1, messages.size()); @@ -298,7 +306,7 @@ public class TransformationTest { reactionA.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-b"))); reactionA.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y")); this.transformer.transform( - Transformation.of( + MessageTransformation.of( reactionA, Instant.now(), REMOTE, "irrelevant-stanza-id1", "id-user-b")); // second reaction @@ -306,7 +314,7 @@ public class TransformationTest { reactionB.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-c"))); reactionB.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y")); this.transformer.transform( - Transformation.of( + MessageTransformation.of( reactionB, Instant.now(), REMOTE, "irrelevant-stanza-id2", "id-user-c")); // a correction @@ -315,7 +323,7 @@ public class TransformationTest { m1.addExtension(new Replace()).setId(ogMessageId); m1.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a"))); this.transformer.transform( - Transformation.of( + MessageTransformation.of( m1, Instant.ofEpochMilli(2000), REMOTE, @@ -328,7 +336,8 @@ public class TransformationTest { m4.addExtension(new Body("Please give me thumbs up (Typo)")); m4.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a"))); this.transformer.transform( - Transformation.of(m4, Instant.ofEpochMilli(1000), REMOTE, ogStanzaId, "id-user-a")); + MessageTransformation.of( + m4, Instant.ofEpochMilli(1000), REMOTE, ogStanzaId, "id-user-a")); final var messages = database.messageDao().getMessages(1L); Assert.assertEquals(1, messages.size()); @@ -353,14 +362,15 @@ public class TransformationTest { m4.addExtension(new Body("Please give me a thumbs up")); m4.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a"))); this.transformer.transform( - Transformation.of(m4, Instant.ofEpochMilli(1000), REMOTE, ogStanzaId, "id-user-a")); + MessageTransformation.of( + m4, Instant.ofEpochMilli(1000), REMOTE, ogStanzaId, "id-user-a")); // first reaction final var reactionA = new Message(Message.Type.GROUPCHAT); reactionA.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-b"))); reactionA.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y")); this.transformer.transform( - Transformation.of( + MessageTransformation.of( reactionA, Instant.now(), REMOTE, "irrelevant-stanza-id1", "id-user-b")); // second reaction @@ -368,7 +378,7 @@ public class TransformationTest { reactionB.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-c"))); reactionB.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y")); this.transformer.transform( - Transformation.of( + MessageTransformation.of( reactionB, Instant.now(), REMOTE, "irrelevant-stanza-id2", "id-user-c")); final var messages = database.messageDao().getMessages(1L); @@ -390,7 +400,8 @@ public class TransformationTest { m1.setFrom(JidCreate.fullFrom(REMOTE, Resourcepart.from("junit"))); m1.addExtension(new Body("Hi. How are you?")); - this.transformer.transform(Transformation.of(m1, Instant.now(), REMOTE, "stanza-a", null)); + this.transformer.transform( + MessageTransformation.of(m1, Instant.now(), REMOTE, "stanza-a", null)); final var m2 = new Message(); m2.setId("2"); @@ -401,7 +412,8 @@ public class TransformationTest { reply.setId("1"); reply.setTo(REMOTE); - this.transformer.transform(Transformation.of(m2, Instant.now(), REMOTE, "stanza-b", null)); + this.transformer.transform( + MessageTransformation.of(m2, Instant.now(), REMOTE, "stanza-b", null)); final var messages = database.messageDao().getMessages(1L); Assert.assertEquals(2, messages.size()); @@ -423,14 +435,14 @@ public class TransformationTest { m1.setFrom(JidCreate.fullFrom(ACCOUNT, Resourcepart.from("junit"))); m1.addExtension(new Body("Hi. How are you?")); - this.transformer.transform(Transformation.of(m1, Instant.now(), REMOTE, null, null)); + this.transformer.transform(MessageTransformation.of(m1, Instant.now(), REMOTE, null, null)); final var m2 = new Message(); m2.setTo(JidCreate.fullFrom(ACCOUNT, Resourcepart.from("junit"))); m2.setFrom(JidCreate.fullFrom(REMOTE, Resourcepart.from("junit"))); m2.addExtension(new Received()).setId("1"); - this.transformer.transform(Transformation.of(m2, Instant.now(), REMOTE, null, null)); + this.transformer.transform(MessageTransformation.of(m2, Instant.now(), REMOTE, null, null)); final var messages = database.messageDao().getMessages(1L); final var message = Iterables.getOnlyElement(messages); @@ -446,14 +458,14 @@ public class TransformationTest { m1.setId("m1"); m1.addExtension(new Body("It is raining outside")); - this.transformer.transform(Transformation.of(m1, Instant.now(), REMOTE, null, null)); + this.transformer.transform(MessageTransformation.of(m1, Instant.now(), REMOTE, null, null)); final var m2 = new Message(); m2.setTo(ACCOUNT); m2.setFrom(JidCreate.fullFrom(REMOTE, Resourcepart.from("junit"))); m2.addExtension(new Retract()).setId("m1"); - this.transformer.transform(Transformation.of(m2, Instant.now(), REMOTE, null, null)); + this.transformer.transform(MessageTransformation.of(m2, Instant.now(), REMOTE, null, null)); final var messages = database.messageDao().getMessages(1L); final var message = Iterables.getOnlyElement(messages); diff --git a/app/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/app/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java index 1c1910ab7..af532ec65 100644 --- a/app/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/app/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java @@ -31,7 +31,7 @@ import im.conversations.android.axolotl.AxolotlEncryptionException; import im.conversations.android.axolotl.AxolotlService; import im.conversations.android.dns.IP; import im.conversations.android.notification.RtpSessionNotification; -import im.conversations.android.transformer.CallLogEntry; +import im.conversations.android.transformer.CallLogTransformation; import im.conversations.android.util.BooleanFutures; import im.conversations.android.xml.Element; import im.conversations.android.xml.Namespace; @@ -179,7 +179,8 @@ public class JingleRtpConnection extends AbstractJingleConnection private final Queue stateHistory = new LinkedList<>(); private final RtpSessionNotification rtpSessionNotification; private ScheduledFuture ringingTimeoutFuture; - private CallLogEntry message = null; + private final CallLogTransformation.Builder callLogTransformationBuilder = + new CallLogTransformation.Builder(); private final ListenableFuture remoteHasVideoFeature; public JingleRtpConnection( @@ -1346,9 +1347,10 @@ public class JingleRtpConnection extends AbstractJingleConnection private void acceptedOnOtherDevice(final String serverMsgId) { if (serverMsgId != null) { - this.message.setServerMsgId(serverMsgId); + this.callLogTransformationBuilder.setServerMsgId(serverMsgId); } - this.message.setCarbon(true); // indicate that call was accepted on other device + this.callLogTransformationBuilder.setCarbon( + true); // indicate that call was accepted on other device this.writeLogMessageSuccess(0); this.rtpSessionNotification.cancelIncomingCallNotification(); this.finish(); @@ -1386,9 +1388,10 @@ public class JingleRtpConnection extends AbstractJingleConnection this.rtpSessionNotification.cancelIncomingCallNotification(); this.finish(); if (serverMsgId != null) { - this.message.setServerMsgId(serverMsgId); + this.callLogTransformationBuilder.setServerMsgId(serverMsgId); } - this.message.setCarbon(true); // indicate that call was rejected on other device + this.callLogTransformationBuilder.setCarbon( + true); // indicate that call was rejected on other device writeLogMessageMissed(); } else { LOGGER.debug("not able to transition into REJECTED because already in " + this.state); @@ -1445,7 +1448,7 @@ public class JingleRtpConnection extends AbstractJingleConnection this.proposedMedia = Sets.newHashSet(media); })) { if (serverMsgId != null) { - this.message.setServerMsgId(serverMsgId); + this.callLogTransformationBuilder.setServerMsgId(serverMsgId); } startRinging(); } else { @@ -1472,15 +1475,15 @@ public class JingleRtpConnection extends AbstractJingleConnection LOGGER.debug(connection.getAccount().address + ": timeout reached for ringing"); switch (this.state) { case PROPOSED: - message.markUnread(); + callLogTransformationBuilder.markUnread(); rejectCallFromProposed(); break; case SESSION_INITIALIZED: - message.markUnread(); + callLogTransformationBuilder.markUnread(); rejectCallFromSessionInitiate(); break; } - rtpSessionNotification.pushMissedCallNow(message); + rtpSessionNotification.pushMissedCallNow(callLogTransformationBuilder.build()); } private void cancelRingingTimeout() { @@ -1499,7 +1502,7 @@ public class JingleRtpConnection extends AbstractJingleConnection if (isInitiator()) { if (transition(State.PROCEED)) { if (serverMsgId != null) { - this.message.setServerMsgId(serverMsgId); + this.callLogTransformationBuilder.setServerMsgId(serverMsgId); } final Integer remoteDeviceId = proceed.getDeviceId(); if (isOmemoEnabled()) { @@ -1549,7 +1552,7 @@ public class JingleRtpConnection extends AbstractJingleConnection this.state == State.PROCEED ? State.RETRACTED_RACED : State.RETRACTED; if (transition(target)) { rtpSessionNotification.cancelIncomingCallNotification(); - rtpSessionNotification.pushMissedCallNow(message); + rtpSessionNotification.pushMissedCallNow(callLogTransformationBuilder.build()); LOGGER.debug( connection.getAccount().address + ": session with " @@ -1558,10 +1561,10 @@ public class JingleRtpConnection extends AbstractJingleConnection + serverMsgId + ")"); if (serverMsgId != null) { - this.message.setServerMsgId(serverMsgId); + this.callLogTransformationBuilder.setServerMsgId(serverMsgId); } if (target == State.RETRACTED) { - this.message.markUnread(); + this.callLogTransformationBuilder.markUnread(); } writeLogMessageMissed(); finish(); @@ -2615,7 +2618,7 @@ public class JingleRtpConnection extends AbstractJingleConnection } private void writeLogMessageSuccess(final long duration) { - this.message.setDuration(duration); + this.callLogTransformationBuilder.setDuration(duration); // this.message.setBody(new RtpSessionStatus(true, duration).toString()); this.writeMessage(); } diff --git a/app/src/main/java/im/conversations/android/database/dao/MessageDao.java b/app/src/main/java/im/conversations/android/database/dao/MessageDao.java index a3c31019d..af51c50c1 100644 --- a/app/src/main/java/im/conversations/android/database/dao/MessageDao.java +++ b/app/src/main/java/im/conversations/android/database/dao/MessageDao.java @@ -21,7 +21,7 @@ import im.conversations.android.database.model.MessageIdentifier; import im.conversations.android.database.model.MessageState; import im.conversations.android.database.model.MessageWithContentReactions; import im.conversations.android.database.model.Modification; -import im.conversations.android.transformer.Transformation; +import im.conversations.android.transformer.MessageTransformation; import im.conversations.android.xmpp.model.reactions.Reactions; import im.conversations.android.xmpp.model.stanza.Message; import java.util.Collection; @@ -72,7 +72,7 @@ public abstract class MessageDao { // will be upgraded to an original message (missing information filled in) @Transaction public MessageIdentifier getOrCreateMessage( - ChatIdentifier chatIdentifier, final Transformation transformation) { + ChatIdentifier chatIdentifier, final MessageTransformation transformation) { final MessageIdentifier messageIdentifier = get( chatIdentifier.id, @@ -140,7 +140,7 @@ public abstract class MessageDao { private void mergeMessageStubs( ChatIdentifier chatIdentifier, MessageIdentifier messageIdentifier, - final Transformation transformation) { + final MessageTransformation transformation) { final Long stub; if (messageIdentifier.messageId == null && transformation.messageId != null) { stub = getMessageStubByMessageId(chatIdentifier.id, transformation.messageId); @@ -199,7 +199,7 @@ public abstract class MessageDao { public MessageIdentifier getOrCreateVersion( ChatIdentifier chat, - Transformation transformation, + MessageTransformation transformation, final String messageId, final Modification modification) { Preconditions.checkArgument( @@ -366,7 +366,7 @@ public abstract class MessageDao { protected abstract void insertReactions(Collection reactionEntities); public void insertReactions( - ChatIdentifier chat, Reactions reactions, Transformation transformation) { + ChatIdentifier chat, Reactions reactions, MessageTransformation transformation) { final Message.Type messageType = transformation.type; final MessageIdentifier messageIdentifier = getOrCreateStub(chat, messageType, reactions.getId()); diff --git a/app/src/main/java/im/conversations/android/database/entity/MessageEntity.java b/app/src/main/java/im/conversations/android/database/entity/MessageEntity.java index a3b7f7134..74e087d1f 100644 --- a/app/src/main/java/im/conversations/android/database/entity/MessageEntity.java +++ b/app/src/main/java/im/conversations/android/database/entity/MessageEntity.java @@ -6,7 +6,7 @@ import androidx.room.Entity; import androidx.room.ForeignKey; import androidx.room.Index; import androidx.room.PrimaryKey; -import im.conversations.android.transformer.Transformation; +import im.conversations.android.transformer.MessageTransformation; import java.time.Instant; import java.util.Objects; import org.jxmpp.jid.BareJid; @@ -69,7 +69,7 @@ public class MessageEntity { public String inReplyToStanzaId; @Nullable public Long inReplyToMessageEntityId; - public static MessageEntity of(final long chatId, final Transformation transformation) { + public static MessageEntity of(final long chatId, final MessageTransformation transformation) { final var entity = new MessageEntity(); entity.chatId = chatId; entity.receivedAt = transformation.receivedAt; @@ -87,7 +87,7 @@ public class MessageEntity { } public static MessageEntity stub( - final long chatId, String messageId, Transformation transformation) { + final long chatId, String messageId, MessageTransformation transformation) { final var entity = new MessageEntity(); entity.chatId = chatId; entity.fromBare = transformation.fromBare(); diff --git a/app/src/main/java/im/conversations/android/database/entity/MessageReactionEntity.java b/app/src/main/java/im/conversations/android/database/entity/MessageReactionEntity.java index f0a93a773..b237ab5d4 100644 --- a/app/src/main/java/im/conversations/android/database/entity/MessageReactionEntity.java +++ b/app/src/main/java/im/conversations/android/database/entity/MessageReactionEntity.java @@ -5,7 +5,7 @@ import androidx.room.Entity; import androidx.room.ForeignKey; import androidx.room.Index; import androidx.room.PrimaryKey; -import im.conversations.android.transformer.Transformation; +import im.conversations.android.transformer.MessageTransformation; import java.time.Instant; import org.jxmpp.jid.BareJid; import org.jxmpp.jid.parts.Resourcepart; @@ -37,7 +37,9 @@ public class MessageReactionEntity { public String reaction; public static MessageReactionEntity of( - long messageEntityId, final String reaction, final Transformation transformation) { + long messageEntityId, + final String reaction, + final MessageTransformation transformation) { final var entity = new MessageReactionEntity(); entity.messageEntityId = messageEntityId; entity.reaction = reaction; diff --git a/app/src/main/java/im/conversations/android/database/entity/MessageVersionEntity.java b/app/src/main/java/im/conversations/android/database/entity/MessageVersionEntity.java index 98834b431..3a89208e7 100644 --- a/app/src/main/java/im/conversations/android/database/entity/MessageVersionEntity.java +++ b/app/src/main/java/im/conversations/android/database/entity/MessageVersionEntity.java @@ -7,7 +7,7 @@ import androidx.room.Index; import androidx.room.PrimaryKey; import com.google.common.base.Preconditions; import im.conversations.android.database.model.Modification; -import im.conversations.android.transformer.Transformation; +import im.conversations.android.transformer.MessageTransformation; import im.conversations.android.xmpp.model.stanza.Message; import java.time.Instant; import org.jxmpp.jid.BareJid; @@ -45,7 +45,7 @@ public class MessageVersionEntity { public static MessageVersionEntity of( long messageEntityId, final Modification modification, - final Transformation transformation) { + final MessageTransformation transformation) { if (transformation.type == Message.Type.GROUPCHAT && modification != Modification.ORIGINAL) { Preconditions.checkState( diff --git a/app/src/main/java/im/conversations/android/database/model/MessageState.java b/app/src/main/java/im/conversations/android/database/model/MessageState.java index d9cfe3bb8..24ff41293 100644 --- a/app/src/main/java/im/conversations/android/database/model/MessageState.java +++ b/app/src/main/java/im/conversations/android/database/model/MessageState.java @@ -1,7 +1,7 @@ package im.conversations.android.database.model; import com.google.common.base.Preconditions; -import im.conversations.android.transformer.Transformation; +import im.conversations.android.transformer.MessageTransformation; import im.conversations.android.xmpp.model.error.Condition; import im.conversations.android.xmpp.model.error.Error; import im.conversations.android.xmpp.model.error.Text; @@ -34,7 +34,7 @@ public class MessageState { this.errorText = errorText; } - public static MessageState error(final Transformation transformation) { + public static MessageState error(final MessageTransformation transformation) { Preconditions.checkArgument(transformation.type == Message.Type.ERROR); final Error error = transformation.getExtension(Error.class); final Condition condition = error == null ? null : error.getCondition(); @@ -47,7 +47,7 @@ public class MessageState { text == null ? null : text.getContent()); } - public static MessageState delivered(final Transformation transformation) { + public static MessageState delivered(final MessageTransformation transformation) { return new MessageState( transformation.fromBare(), transformation.fromResource(), @@ -56,7 +56,7 @@ public class MessageState { null); } - public static MessageState displayed(final Transformation transformation) { + public static MessageState displayed(final MessageTransformation transformation) { return new MessageState( transformation.fromBare(), transformation.fromResource(), diff --git a/app/src/main/java/im/conversations/android/notification/RtpSessionNotification.java b/app/src/main/java/im/conversations/android/notification/RtpSessionNotification.java index e62638f12..7b6a6804f 100644 --- a/app/src/main/java/im/conversations/android/notification/RtpSessionNotification.java +++ b/app/src/main/java/im/conversations/android/notification/RtpSessionNotification.java @@ -27,7 +27,7 @@ import eu.siacs.conversations.xmpp.jingle.Media; import im.conversations.android.R; import im.conversations.android.database.model.Account; import im.conversations.android.service.RtpSessionService; -import im.conversations.android.transformer.CallLogEntry; +import im.conversations.android.transformer.CallLogTransformation; import im.conversations.android.ui.activity.RtpSessionActivity; import java.util.Set; import java.util.concurrent.ScheduledFuture; @@ -271,7 +271,7 @@ public class RtpSessionNotification extends AbstractNotification { mBuilder.setColor(ContextCompat.getColor(context, R.color.seed)); } - public void pushMissedCallNow(CallLogEntry message) {} + public void pushMissedCallNow(CallLogTransformation message) {} private class VibrationRunnable implements Runnable { diff --git a/app/src/main/java/im/conversations/android/transformer/CallLogEntry.java b/app/src/main/java/im/conversations/android/transformer/CallLogEntry.java deleted file mode 100644 index 4a6b64c38..000000000 --- a/app/src/main/java/im/conversations/android/transformer/CallLogEntry.java +++ /dev/null @@ -1,11 +0,0 @@ -package im.conversations.android.transformer; - -public class CallLogEntry { - public void setServerMsgId(String serverMsgId) {} - - public void setCarbon(boolean b) {} - - public void markUnread() {} - - public void setDuration(long duration) {} -} diff --git a/app/src/main/java/im/conversations/android/transformer/CallLogTransformation.java b/app/src/main/java/im/conversations/android/transformer/CallLogTransformation.java new file mode 100644 index 000000000..c6da9a1b9 --- /dev/null +++ b/app/src/main/java/im/conversations/android/transformer/CallLogTransformation.java @@ -0,0 +1,38 @@ +package im.conversations.android.transformer; + +import im.conversations.android.xmpp.model.stanza.Message; +import java.time.Duration; +import java.time.Instant; +import org.jxmpp.jid.Jid; + +public class CallLogTransformation extends Transformation { + + public final Duration duration; + + private CallLogTransformation( + final Instant receivedAt, + final Jid to, + final Jid from, + final Jid remote, + final String messageId, + final String stanzaId, + final Duration duration) { + super(receivedAt, to, from, remote, Message.Type.NORMAL, messageId, stanzaId, null); + this.duration = duration; + } + + public static class Builder { + + public void setServerMsgId(String serverMsgId) {} + + public void setCarbon(boolean b) {} + + public void markUnread() {} + + public void setDuration(long duration) {} + + public CallLogTransformation build() { + return new CallLogTransformation(null, null, null, null, null, null, null); + } + } +} diff --git a/app/src/main/java/im/conversations/android/transformer/MessageTransformation.java b/app/src/main/java/im/conversations/android/transformer/MessageTransformation.java new file mode 100644 index 000000000..453db7ab0 --- /dev/null +++ b/app/src/main/java/im/conversations/android/transformer/MessageTransformation.java @@ -0,0 +1,128 @@ +package im.conversations.android.transformer; + +import androidx.annotation.NonNull; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import im.conversations.android.xmpp.model.DeliveryReceipt; +import im.conversations.android.xmpp.model.DeliveryReceiptRequest; +import im.conversations.android.xmpp.model.Extension; +import im.conversations.android.xmpp.model.axolotl.Encrypted; +import im.conversations.android.xmpp.model.correction.Replace; +import im.conversations.android.xmpp.model.error.Error; +import im.conversations.android.xmpp.model.jabber.Body; +import im.conversations.android.xmpp.model.jabber.Thread; +import im.conversations.android.xmpp.model.markers.Displayed; +import im.conversations.android.xmpp.model.muc.user.MultiUserChat; +import im.conversations.android.xmpp.model.oob.OutOfBandData; +import im.conversations.android.xmpp.model.reactions.Reactions; +import im.conversations.android.xmpp.model.reply.Reply; +import im.conversations.android.xmpp.model.retract.Retract; +import im.conversations.android.xmpp.model.stanza.Message; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import org.jxmpp.jid.Jid; + +public class MessageTransformation extends Transformation { + + private static final List> EXTENSION_FOR_TRANSFORMATION = + Arrays.asList( + Body.class, + Thread.class, + Encrypted.class, + OutOfBandData.class, + DeliveryReceipt.class, + MultiUserChat.class, + Displayed.class, + Replace.class, + Reactions.class, + Reply.class, + Retract.class); + + private final List extensions; + + public final Collection deliveryReceiptRequests; + + private MessageTransformation( + final Instant receivedAt, + final Jid to, + final Jid from, + final Jid remote, + final Message.Type type, + final String messageId, + final String stanzaId, + final String occupantId, + final List extensions, + final Collection deliveryReceiptRequests) { + super(receivedAt, to, from, remote, type, messageId, stanzaId, occupantId); + this.extensions = extensions; + this.deliveryReceiptRequests = deliveryReceiptRequests; + } + + public boolean isAnythingToTransform() { + return this.extensions.size() > 0; + } + + @Override + public Instant sentAt() { + // TODO get Delay that matches sender; return receivedAt if not found + return receivedAt; + } + + public E getExtension(final Class clazz) { + checkArgument(clazz); + final var extension = Iterables.find(this.extensions, clazz::isInstance, null); + return extension == null ? null : clazz.cast(extension); + } + + private void checkArgument(final Class clazz) { + if (EXTENSION_FOR_TRANSFORMATION.contains(clazz) || clazz == Error.class) { + return; + } + throw new IllegalArgumentException( + String.format("%s has not been registered for transformation", clazz.getName())); + } + + public Collection getExtensions(final Class clazz) { + checkArgument(clazz); + return Collections2.transform( + Collections2.filter(this.extensions, clazz::isInstance), clazz::cast); + } + + public static MessageTransformation of( + @NonNull final Message message, + @NonNull final Instant receivedAt, + @NonNull final Jid remote, + final String stanzaId, + final String occupantId) { + final var to = message.getTo(); + final var from = message.getFrom(); + final var type = message.getType(); + final var messageId = message.getId(); + final ImmutableList.Builder extensionListBuilder = new ImmutableList.Builder<>(); + final Collection requests; + if (type == Message.Type.ERROR) { + extensionListBuilder.add(message.getError()); + requests = Collections.emptyList(); + } else { + for (final Class clazz : EXTENSION_FOR_TRANSFORMATION) { + extensionListBuilder.addAll(message.getExtensions(clazz)); + } + requests = message.getExtensions(DeliveryReceiptRequest.class); + } + return new MessageTransformation( + receivedAt, + to, + from, + remote, + type, + messageId, + stanzaId, + occupantId, + extensionListBuilder.build(), + requests); + } +} diff --git a/app/src/main/java/im/conversations/android/transformer/Transformation.java b/app/src/main/java/im/conversations/android/transformer/Transformation.java index b83aad847..5a5b4a464 100644 --- a/app/src/main/java/im/conversations/android/transformer/Transformation.java +++ b/app/src/main/java/im/conversations/android/transformer/Transformation.java @@ -1,48 +1,12 @@ package im.conversations.android.transformer; -import androidx.annotation.NonNull; -import com.google.common.collect.Collections2; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; -import im.conversations.android.xmpp.model.DeliveryReceipt; -import im.conversations.android.xmpp.model.DeliveryReceiptRequest; -import im.conversations.android.xmpp.model.Extension; -import im.conversations.android.xmpp.model.axolotl.Encrypted; -import im.conversations.android.xmpp.model.correction.Replace; -import im.conversations.android.xmpp.model.error.Error; -import im.conversations.android.xmpp.model.jabber.Body; -import im.conversations.android.xmpp.model.jabber.Thread; -import im.conversations.android.xmpp.model.markers.Displayed; -import im.conversations.android.xmpp.model.muc.user.MultiUserChat; -import im.conversations.android.xmpp.model.oob.OutOfBandData; -import im.conversations.android.xmpp.model.reactions.Reactions; -import im.conversations.android.xmpp.model.reply.Reply; -import im.conversations.android.xmpp.model.retract.Retract; import im.conversations.android.xmpp.model.stanza.Message; import java.time.Instant; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; import org.jxmpp.jid.BareJid; import org.jxmpp.jid.Jid; import org.jxmpp.jid.parts.Resourcepart; -public class Transformation { - - private static final List> EXTENSION_FOR_TRANSFORMATION = - Arrays.asList( - Body.class, - Thread.class, - Encrypted.class, - OutOfBandData.class, - DeliveryReceipt.class, - MultiUserChat.class, - Displayed.class, - Replace.class, - Reactions.class, - Reply.class, - Retract.class); +abstract class Transformation { public final Instant receivedAt; public final Jid to; @@ -54,11 +18,7 @@ public class Transformation { public final String occupantId; - private final List extensions; - - public final Collection deliveryReceiptRequests; - - private Transformation( + public Transformation( final Instant receivedAt, final Jid to, final Jid from, @@ -66,9 +26,7 @@ public class Transformation { final Message.Type type, final String messageId, final String stanzaId, - final String occupantId, - final List extensions, - final Collection deliveryReceiptRequests) { + final String occupantId) { this.receivedAt = receivedAt; this.to = to; this.from = from; @@ -77,12 +35,6 @@ public class Transformation { this.messageId = messageId; this.stanzaId = stanzaId; this.occupantId = occupantId; - this.extensions = extensions; - this.deliveryReceiptRequests = deliveryReceiptRequests; - } - - public boolean isAnythingToTransform() { - return this.extensions.size() > 0; } public BareJid fromBare() { @@ -110,58 +62,4 @@ public class Transformation { // TODO handle case for self addressed (to == from) return remote.asBareJid().equals(toBare()); } - - public E getExtension(final Class clazz) { - checkArgument(clazz); - final var extension = Iterables.find(this.extensions, clazz::isInstance, null); - return extension == null ? null : clazz.cast(extension); - } - - private void checkArgument(final Class clazz) { - if (EXTENSION_FOR_TRANSFORMATION.contains(clazz) || clazz == Error.class) { - return; - } - throw new IllegalArgumentException( - String.format("%s has not been registered for transformation", clazz.getName())); - } - - public Collection getExtensions(final Class clazz) { - checkArgument(clazz); - return Collections2.transform( - Collections2.filter(this.extensions, clazz::isInstance), clazz::cast); - } - - public static Transformation of( - @NonNull final Message message, - @NonNull final Instant receivedAt, - @NonNull final Jid remote, - final String stanzaId, - final String occupantId) { - final var to = message.getTo(); - final var from = message.getFrom(); - final var type = message.getType(); - final var messageId = message.getId(); - final ImmutableList.Builder extensionListBuilder = new ImmutableList.Builder<>(); - final Collection requests; - if (type == Message.Type.ERROR) { - extensionListBuilder.add(message.getError()); - requests = Collections.emptyList(); - } else { - for (final Class clazz : EXTENSION_FOR_TRANSFORMATION) { - extensionListBuilder.addAll(message.getExtensions(clazz)); - } - requests = message.getExtensions(DeliveryReceiptRequest.class); - } - return new Transformation( - receivedAt, - to, - from, - remote, - type, - messageId, - stanzaId, - occupantId, - extensionListBuilder.build(), - requests); - } } diff --git a/app/src/main/java/im/conversations/android/transformer/TransformationFactory.java b/app/src/main/java/im/conversations/android/transformer/TransformationFactory.java index 617bc8605..a32d102ee 100644 --- a/app/src/main/java/im/conversations/android/transformer/TransformationFactory.java +++ b/app/src/main/java/im/conversations/android/transformer/TransformationFactory.java @@ -16,11 +16,11 @@ public class TransformationFactory extends XmppConnection.Delegate { super(context, connection); } - public Transformation create(final Message message, final String stanzaId) { + public MessageTransformation create(final Message message, final String stanzaId) { return create(message, stanzaId, Instant.now()); } - public Transformation create( + public MessageTransformation create( final Message message, final String stanzaId, final Instant receivedAt) { final var boundAddress = connection.getBoundAddress().asBareJid(); final var from = message.getFrom(); @@ -44,6 +44,6 @@ public class TransformationFactory extends XmppConnection.Delegate { } else { occupantId = null; } - return Transformation.of(message, receivedAt, remote, stanzaId, occupantId); + return MessageTransformation.of(message, receivedAt, remote, stanzaId, occupantId); } } diff --git a/app/src/main/java/im/conversations/android/transformer/Transformer.java b/app/src/main/java/im/conversations/android/transformer/Transformer.java index b8e6d8e3d..c37c433f3 100644 --- a/app/src/main/java/im/conversations/android/transformer/Transformer.java +++ b/app/src/main/java/im/conversations/android/transformer/Transformer.java @@ -42,7 +42,7 @@ public class Transformer { this.account = account; } - public boolean transform(final Transformation transformation) { + public boolean transform(final MessageTransformation transformation) { return database.runInTransaction(() -> transform(database, transformation)); } @@ -53,7 +53,7 @@ public class Transformer { * updated a status somewhere */ private boolean transform( - final ConversationsDatabase database, final Transformation transformation) { + final ConversationsDatabase database, final MessageTransformation transformation) { final var remote = transformation.remote; final var messageType = transformation.type; final var muc = transformation.getExtension(MultiUserChat.class); @@ -141,7 +141,7 @@ public class Transformer { return true; } - protected List parseContent(final Transformation transformation) { + protected List parseContent(final MessageTransformation transformation) { final var encrypted = transformation.getExtension(Encrypted.class); final var encryptedWithPayload = encrypted != null && encrypted.hasPayload(); final Collection bodies = transformation.getExtensions(Body.class); @@ -178,7 +178,7 @@ public class Transformer { } private void transformMessageState( - final ChatIdentifier chat, final Transformation transformation) { + final ChatIdentifier chat, final MessageTransformation transformation) { final var displayed = transformation.getExtension(Displayed.class); if (displayed != null) { if (transformation.outgoing()) { diff --git a/app/src/main/java/im/conversations/android/xmpp/manager/DiscoManager.java b/app/src/main/java/im/conversations/android/xmpp/manager/DiscoManager.java index c24e3a73d..49e896462 100644 --- a/app/src/main/java/im/conversations/android/xmpp/manager/DiscoManager.java +++ b/app/src/main/java/im/conversations/android/xmpp/manager/DiscoManager.java @@ -66,8 +66,8 @@ public class DiscoManager extends AbstractManager { Namespace.JINGLE_FEATURE_AUDIO, Namespace.JINGLE_FEATURE_VIDEO, Namespace.JINGLE_APPS_RTP, - Namespace.JINGLE_APPS_DTLS /*, - Namespace.JINGLE_MESSAGE*/); + Namespace.JINGLE_APPS_DTLS, + Namespace.JINGLE_MESSAGE); private static final Collection FEATURES_IMPACTING_PRIVACY = Collections.singleton(Namespace.VERSION); diff --git a/app/src/main/java/im/conversations/android/xmpp/manager/JingleConnectionManager.java b/app/src/main/java/im/conversations/android/xmpp/manager/JingleConnectionManager.java index 08b3593e3..a7b5c8ed1 100644 --- a/app/src/main/java/im/conversations/android/xmpp/manager/JingleConnectionManager.java +++ b/app/src/main/java/im/conversations/android/xmpp/manager/JingleConnectionManager.java @@ -226,11 +226,18 @@ public class JingleConnectionManager extends AbstractManager { private void respondWithJingleError( final Iq original, String jingleCondition, final Error.Type type, Condition condition) { - // TODO add jingle condation + // TODO add jingle condition connection.sendErrorFor(original, type, condition); } - public void deliverMessage( + public void handle(final Message message) { + final String id = message.getId(); + final String stanzaId = getManager(StanzaIdManager.class).getStanzaId(message); + final JingleMessage jingleMessage = message.getExtension(JingleMessage.class); + this.deliverMessage(message.getTo(), message.getFrom(), jingleMessage, id, stanzaId); + } + + private void deliverMessage( final Jid to, final Jid from, final JingleMessage message, diff --git a/app/src/main/java/im/conversations/android/xmpp/model/jmi/Accept.java b/app/src/main/java/im/conversations/android/xmpp/model/jmi/Accept.java index 562c3d6fe..20ae15aee 100644 --- a/app/src/main/java/im/conversations/android/xmpp/model/jmi/Accept.java +++ b/app/src/main/java/im/conversations/android/xmpp/model/jmi/Accept.java @@ -1,5 +1,8 @@ package im.conversations.android.xmpp.model.jmi; +import im.conversations.android.annotation.XmlElement; + +@XmlElement public class Accept extends JingleMessage { public Accept() { diff --git a/app/src/main/java/im/conversations/android/xmpp/model/jmi/Proceed.java b/app/src/main/java/im/conversations/android/xmpp/model/jmi/Proceed.java index 6324d5fc0..42e274a01 100644 --- a/app/src/main/java/im/conversations/android/xmpp/model/jmi/Proceed.java +++ b/app/src/main/java/im/conversations/android/xmpp/model/jmi/Proceed.java @@ -1,8 +1,10 @@ package im.conversations.android.xmpp.model.jmi; import com.google.common.primitives.Ints; +import im.conversations.android.annotation.XmlElement; import im.conversations.android.xml.Element; +@XmlElement public class Proceed extends JingleMessage { public Proceed() { diff --git a/app/src/main/java/im/conversations/android/xmpp/model/jmi/Propose.java b/app/src/main/java/im/conversations/android/xmpp/model/jmi/Propose.java index 9ac28638b..365d22d70 100644 --- a/app/src/main/java/im/conversations/android/xmpp/model/jmi/Propose.java +++ b/app/src/main/java/im/conversations/android/xmpp/model/jmi/Propose.java @@ -4,10 +4,12 @@ import com.google.common.collect.ImmutableList; import eu.siacs.conversations.xmpp.jingle.stanzas.FileTransferDescription; import eu.siacs.conversations.xmpp.jingle.stanzas.GenericDescription; import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription; +import im.conversations.android.annotation.XmlElement; import im.conversations.android.xml.Element; import im.conversations.android.xml.Namespace; import java.util.List; +@XmlElement public class Propose extends JingleMessage { public Propose() { diff --git a/app/src/main/java/im/conversations/android/xmpp/model/jmi/Reject.java b/app/src/main/java/im/conversations/android/xmpp/model/jmi/Reject.java index 3ed513885..e71206fd6 100644 --- a/app/src/main/java/im/conversations/android/xmpp/model/jmi/Reject.java +++ b/app/src/main/java/im/conversations/android/xmpp/model/jmi/Reject.java @@ -1,5 +1,8 @@ package im.conversations.android.xmpp.model.jmi; +import im.conversations.android.annotation.XmlElement; + +@XmlElement public class Reject extends JingleMessage { public Reject() { diff --git a/app/src/main/java/im/conversations/android/xmpp/model/jmi/Retract.java b/app/src/main/java/im/conversations/android/xmpp/model/jmi/Retract.java index 6e9b29603..7c507156d 100644 --- a/app/src/main/java/im/conversations/android/xmpp/model/jmi/Retract.java +++ b/app/src/main/java/im/conversations/android/xmpp/model/jmi/Retract.java @@ -1,5 +1,8 @@ package im.conversations.android.xmpp.model.jmi; +import im.conversations.android.annotation.XmlElement; + +@XmlElement public class Retract extends JingleMessage { public Retract() { diff --git a/app/src/main/java/im/conversations/android/xmpp/processor/MessageProcessor.java b/app/src/main/java/im/conversations/android/xmpp/processor/MessageProcessor.java index db34bc1e6..7e60fd254 100644 --- a/app/src/main/java/im/conversations/android/xmpp/processor/MessageProcessor.java +++ b/app/src/main/java/im/conversations/android/xmpp/processor/MessageProcessor.java @@ -8,11 +8,13 @@ import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.manager.ArchiveManager; import im.conversations.android.xmpp.manager.CarbonsManager; import im.conversations.android.xmpp.manager.ChatStateManager; +import im.conversations.android.xmpp.manager.JingleConnectionManager; import im.conversations.android.xmpp.manager.PubSubManager; import im.conversations.android.xmpp.manager.ReceiptManager; import im.conversations.android.xmpp.manager.StanzaIdManager; import im.conversations.android.xmpp.model.carbons.Received; import im.conversations.android.xmpp.model.carbons.Sent; +import im.conversations.android.xmpp.model.jmi.JingleMessage; import im.conversations.android.xmpp.model.mam.Result; import im.conversations.android.xmpp.model.pubsub.event.Event; import im.conversations.android.xmpp.model.stanza.Message; @@ -62,7 +64,16 @@ public class MessageProcessor extends XmppConnection.Delegate implements Consume return; } - // LOGGER.info("Message from {} with {}", message.getFrom(), message.getExtensionIds()); + if (message.hasExtension(JingleMessage.class)) { + getManager(JingleConnectionManager.class).handle(message); + return; + } + + LOGGER.info( + "Message from {} with {} in level {}", + message.getFrom(), + message.getExtensionIds(), + this.level); final var from = message.getFrom();