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());