diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java index c28c07fe9..1073cb6c0 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java @@ -283,6 +283,13 @@ public interface DatabaseComponent extends TransactionManager { */ Group getGroup(Transaction txn, GroupId g) throws DbException; + /** + * Returns the ID of the group containing the given message. + *

+ * Read-only. + */ + GroupId getGroupId(Transaction txn, MessageId m) throws DbException; + /** * Returns the metadata for the given group. *

diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/event/MessageSharedEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/event/MessageSharedEvent.java index e3745fd90..2d761187e 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/event/MessageSharedEvent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/event/MessageSharedEvent.java @@ -1,9 +1,13 @@ package org.briarproject.bramble.api.sync.event; +import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; +import java.util.Map; + import javax.annotation.concurrent.Immutable; /** @@ -14,12 +18,25 @@ import javax.annotation.concurrent.Immutable; public class MessageSharedEvent extends Event { private final MessageId messageId; + private final GroupId groupId; + private final Map groupVisibility; - public MessageSharedEvent(MessageId message) { + public MessageSharedEvent(MessageId message, GroupId groupId, + Map groupVisibility) { this.messageId = message; + this.groupId = groupId; + this.groupVisibility = groupVisibility; } public MessageId getMessageId() { return messageId; } + + public GroupId getGroupId() { + return groupId; + } + + public Map getGroupVisibility() { + return groupVisibility; + } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java index 1e53c1fe2..a8b660582 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java @@ -320,6 +320,13 @@ interface Database { */ Group getGroup(T txn, GroupId g) throws DbException; + /** + * Returns the ID of the group containing the given message. + *

+ * Read-only. + */ + GroupId getGroupId(T txn, MessageId m) throws DbException; + /** * Returns the metadata for the given group. *

diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java index cfc20ecce..21848b9b8 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java @@ -287,7 +287,12 @@ class DatabaseComponentImpl implements DatabaseComponent { transaction.attach(new MessageAddedEvent(m, null)); transaction.attach(new MessageStateChangedEvent(m.getId(), true, DELIVERED)); - if (shared) transaction.attach(new MessageSharedEvent(m.getId())); + if (shared) { + Map visibility = + db.getGroupVisibility(txn, m.getGroupId()); + transaction.attach(new MessageSharedEvent(m.getId(), + m.getGroupId(), visibility)); + } } db.mergeMessageMetadata(txn, m.getId(), meta); } @@ -550,6 +555,15 @@ class DatabaseComponentImpl implements DatabaseComponent { return db.getGroup(txn, g); } + @Override + public GroupId getGroupId(Transaction transaction, MessageId m) + throws DbException { + T txn = unbox(transaction); + if (!db.containsMessage(txn, m)) + throw new NoSuchMessageException(); + return db.getGroupId(txn, m); + } + @Override public Metadata getGroupMetadata(Transaction transaction, GroupId g) throws DbException { @@ -1184,7 +1198,9 @@ class DatabaseComponentImpl implements DatabaseComponent { if (db.getMessageState(txn, m) != DELIVERED) throw new IllegalArgumentException("Shared undelivered message"); db.setMessageShared(txn, m, true); - transaction.attach(new MessageSharedEvent(m)); + GroupId g = db.getGroupId(txn, m); + Map visibility = db.getGroupVisibility(txn, g); + transaction.attach(new MessageSharedEvent(m, g, visibility)); } @Override diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index 9dc143bfa..6085ec50a 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -1683,6 +1683,27 @@ abstract class JdbcDatabase implements Database { } } + @Override + public GroupId getGroupId(Connection txn, MessageId m) throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + String sql = "SELECT groupId FROM messages WHERE messageId = ?"; + ps = txn.prepareStatement(sql); + ps.setBytes(1, m.getBytes()); + rs = ps.executeQuery(); + if (!rs.next()) throw new DbStateException(); + GroupId g = new GroupId(rs.getBytes(1)); + rs.close(); + ps.close(); + return g; + } catch (SQLException e) { + tryToClose(rs, LOG, WARNING); + tryToClose(ps, LOG, WARNING); + throw new DbException(e); + } + } + @Override public Collection getGroups(Connection txn, ClientId c, int majorVersion) throws DbException { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java index 3dc74bd19..c4dfe4daa 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java @@ -44,6 +44,7 @@ import java.util.logging.Logger; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; +import static java.lang.Boolean.TRUE; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; @@ -233,7 +234,10 @@ class DuplexOutgoingSession implements SyncSession, EventListener { ContactRemovedEvent c = (ContactRemovedEvent) e; if (c.getContactId().equals(contactId)) interrupt(); } else if (e instanceof MessageSharedEvent) { - generateOffer(); + MessageSharedEvent m = (MessageSharedEvent) e; + if (m.getGroupVisibility().get(contactId) == TRUE) { + generateOffer(); + } } else if (e instanceof GroupVisibilityUpdatedEvent) { GroupVisibilityUpdatedEvent g = (GroupVisibilityUpdatedEvent) e; if (g.getVisibility() == SHARED && diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java index 2e342186a..931a56fe3 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java @@ -694,11 +694,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { throws Exception { context.checking(new Expectations() {{ // Check whether the message is in the DB (which it's not) - exactly(15).of(database).startTransaction(); + exactly(16).of(database).startTransaction(); will(returnValue(txn)); - exactly(15).of(database).containsMessage(txn, messageId); + exactly(16).of(database).containsMessage(txn, messageId); will(returnValue(false)); - exactly(15).of(database).abortTransaction(txn); + exactly(16).of(database).abortTransaction(txn); // Allow other checks to pass allowing(database).containsContact(txn, contactId); will(returnValue(true)); @@ -722,6 +722,14 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { // Expected } + try { + db.transaction(true, transaction -> + db.getGroupId(transaction, messageId)); + fail(); + } catch (NoSuchMessageException expected) { + // Expected + } + try { db.transaction(true, transaction -> db.getMessage(transaction, messageId)); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java index 35e091df3..be14b8b5a 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java @@ -168,6 +168,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { assertTrue(db.containsContact(txn, contactId)); assertTrue(db.containsGroup(txn, groupId)); assertTrue(db.containsMessage(txn, messageId)); + assertEquals(groupId, db.getGroupId(txn, messageId)); assertArrayEquals(message.getBody(), db.getMessage(txn, messageId).getBody());