From ee1c938f2a4a4c862837b08a58a6026d703f7af2 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 11 Mar 2023 12:10:26 +0100 Subject: [PATCH] look up sender in group chats --- .../android/database/dao/PresenceDao.java | 24 ++++++++ .../transformer/TransformationFactory.java | 60 +++++++++++++++++-- .../android/xmpp/manager/ArchiveManager.java | 21 ++++++- .../xmpp/processor/MessageProcessor.java | 3 +- 4 files changed, 101 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/im/conversations/android/database/dao/PresenceDao.java b/app/src/main/java/im/conversations/android/database/dao/PresenceDao.java index 00905751b..62db01910 100644 --- a/app/src/main/java/im/conversations/android/database/dao/PresenceDao.java +++ b/app/src/main/java/im/conversations/android/database/dao/PresenceDao.java @@ -13,6 +13,7 @@ import im.conversations.android.database.model.PresenceType; import im.conversations.android.xmpp.model.muc.user.MucUser; import java.util.Arrays; import org.jxmpp.jid.BareJid; +import org.jxmpp.jid.Jid; import org.jxmpp.jid.parts.Resourcepart; @Dao @@ -66,4 +67,27 @@ public abstract class PresenceDao { mucUser); insert(entity); } + + @Query( + "SELECT mucUserJid FROM presence WHERE accountId=:account AND address=:address AND" + + " occupantId=:occupantId") + protected abstract Jid getMucUserJidByOccupantId( + long account, BareJid address, String occupantId); + + @Query( + "SELECT mucUserJid FROM presence WHERE accountId=:account AND address=:address AND" + + " resource=:resource") + protected abstract Jid getMucUserJidByResource( + long account, BareJid address, Resourcepart resource); + + public BareJid getMucUserJidByOccupantId(Account account, BareJid address, String occupantId) { + final var jid = getMucUserJidByOccupantId(account.id, address, occupantId); + return jid == null ? null : jid.asBareJid(); + } + + public BareJid getMucUserJidByResource( + final Account account, final BareJid address, final Resourcepart resource) { + final var jid = getMucUserJidByResource(account.id, address, resource); + return jid == null ? null : jid.asBareJid(); + } } 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 e9ff843a9..84657f348 100644 --- a/app/src/main/java/im/conversations/android/transformer/TransformationFactory.java +++ b/app/src/main/java/im/conversations/android/transformer/TransformationFactory.java @@ -1,29 +1,49 @@ package im.conversations.android.transformer; import android.content.Context; +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; import im.conversations.android.database.model.StanzaId; import im.conversations.android.xml.Namespace; import im.conversations.android.xmpp.Entity; import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.manager.DiscoManager; +import im.conversations.android.xmpp.model.Extension; +import im.conversations.android.xmpp.model.muc.user.MucUser; import im.conversations.android.xmpp.model.occupant.OccupantId; import im.conversations.android.xmpp.model.stanza.Message; import java.time.Instant; +import java.util.List; import org.jxmpp.jid.BareJid; import org.jxmpp.jid.Jid; public class TransformationFactory extends XmppConnection.Delegate { - public TransformationFactory(Context context, XmppConnection connection) { + private final Mode mode; + + public TransformationFactory(Context context, XmppConnection connection, final Mode mode) { super(context, connection); + this.mode = mode; } public MessageTransformation create(final Message message, final StanzaId stanzaId) { - return create(message, stanzaId == null ? null : stanzaId.id, Instant.now()); + Preconditions.checkState( + mode == Mode.LIVE, + "Creating a MessageTransformation with automatic timestamp is only allowed in live" + + " mode"); + return create(message, stanzaId == null ? null : stanzaId.id, Instant.now(), null); } public MessageTransformation create( - final Message message, final String stanzaId, final Instant receivedAt) { + final Message message, + final String stanzaId, + final Instant receivedAt, + final List privilegedExtensions) { + if (privilegedExtensions != null) { + Preconditions.checkArgument( + this.mode == Mode.ARCHIVE, + "Privileged extensions can only supplied in archive mode"); + } final var boundAddress = connection.getBoundAddress().asBareJid(); final var from = message.getFrom(); final var to = message.getTo(); @@ -48,11 +68,43 @@ public class TransformationFactory extends XmppConnection.Delegate { } final BareJid senderIdentity; if (message.getType() == Message.Type.GROUPCHAT) { - senderIdentity = null; // TODO discover real jid + final var mucUser = + mode == Mode.ARCHIVE ? getExtension(privilegedExtensions, MucUser.class) : null; + final var mucUserItem = mucUser == null ? null : mucUser.getItem(); + final Jid mucUserJid = mucUserItem == null ? null : mucUserItem.getJid(); + if (mucUserJid != null) { + senderIdentity = mucUserJid.asBareJid(); + } else if (occupantId != null) { + senderIdentity = + getDatabase() + .presenceDao() + .getMucUserJidByOccupantId( + getAccount(), from.asBareJid(), occupantId); + } else if (mode == Mode.LIVE && from != null && from.hasResource()) { + senderIdentity = + getDatabase() + .presenceDao() + .getMucUserJidByResource( + getAccount(), from.asBareJid(), from.getResourceOrThrow()); + } else { + senderIdentity = null; + } } else { senderIdentity = from == null ? boundAddress : from.asBareJid(); } return MessageTransformation.of( message, receivedAt, remote, stanzaId, senderIdentity, occupantId); } + + private static E getExtension( + final List extensions, final Class clazz) { + final var extension = + extensions == null ? null : Iterables.find(extensions, clazz::isInstance, null); + return extension == null ? null : clazz.cast(extension); + } + + public enum Mode { + LIVE, + ARCHIVE + } } diff --git a/app/src/main/java/im/conversations/android/xmpp/manager/ArchiveManager.java b/app/src/main/java/im/conversations/android/xmpp/manager/ArchiveManager.java index c2b55c5d9..f84f34018 100644 --- a/app/src/main/java/im/conversations/android/xmpp/manager/ArchiveManager.java +++ b/app/src/main/java/im/conversations/android/xmpp/manager/ArchiveManager.java @@ -17,13 +17,17 @@ import im.conversations.android.database.ConversationsDatabase; import im.conversations.android.transformer.MessageTransformation; import im.conversations.android.transformer.TransformationFactory; import im.conversations.android.transformer.Transformer; +import im.conversations.android.xml.Namespace; +import im.conversations.android.xmpp.Entity; import im.conversations.android.xmpp.Page; import im.conversations.android.xmpp.Range; import im.conversations.android.xmpp.XmppConnection; +import im.conversations.android.xmpp.model.Extension; import im.conversations.android.xmpp.model.delay.Delay; import im.conversations.android.xmpp.model.mam.Fin; import im.conversations.android.xmpp.model.mam.Query; import im.conversations.android.xmpp.model.mam.Result; +import im.conversations.android.xmpp.model.muc.user.MucUser; import im.conversations.android.xmpp.model.rsm.Set; import im.conversations.android.xmpp.model.stanza.Iq; import im.conversations.android.xmpp.model.stanza.Message; @@ -47,7 +51,8 @@ public class ArchiveManager extends AbstractManager { public ArchiveManager(Context context, XmppConnection connection) { super(context, connection); - this.transformationFactory = new TransformationFactory(context, connection); + this.transformationFactory = + new TransformationFactory(context, connection, TransformationFactory.Mode.ARCHIVE); } public void handle(final Message message) { @@ -78,8 +83,20 @@ public class ArchiveManager extends AbstractManager { return; } + final ImmutableList.Builder privilegedExtensionBuilder = + new ImmutableList.Builder<>(); + if (forwardedMessage.getType() == Message.Type.GROUPCHAT) { + final var mucUser = forwardedMessage.getExtension(MucUser.class); + if (mucUser != null + && getManager(DiscoManager.class) + .hasFeature(Entity.discoItem(archive), Namespace.MUC)) { + privilegedExtensionBuilder.add(mucUser); + } + } + final var transformation = - this.transformationFactory.create(forwardedMessage, stanzaId, receivedAt); + this.transformationFactory.create( + forwardedMessage, stanzaId, receivedAt, privilegedExtensionBuilder.build()); // TODO only when there is something to transform runningQuery.addTransformation(transformation); } 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 d57ae7405..4e48c0b83 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 @@ -39,7 +39,8 @@ public class MessageProcessor extends XmppConnection.Delegate implements Consume final Context context, final XmppConnection connection, final Level level) { super(context, connection); this.level = level; - this.transformationFactory = new TransformationFactory(context, connection); + this.transformationFactory = + new TransformationFactory(context, connection, TransformationFactory.Mode.LIVE); } @Override