diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contactselection/SelectableContactHolder.java b/briar-android/src/main/java/org/briarproject/briar/android/contactselection/SelectableContactHolder.java
index 21d5c7c52..85df76122 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/contactselection/SelectableContactHolder.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/contactselection/SelectableContactHolder.java
@@ -13,7 +13,9 @@ import androidx.annotation.UiThread;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
-import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITED;
+import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.ERROR;
+import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITE_RECEIVED;
+import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITE_SENT;
import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.NOT_SUPPORTED;
import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHARING;
@@ -35,10 +37,14 @@ class SelectableContactHolder
@StringRes int strRes;
if (item.getSharingStatus() == SHARING) {
strRes = R.string.forum_invitation_already_sharing;
- } else if (item.getSharingStatus() == INVITED) {
+ } else if (item.getSharingStatus() == INVITE_SENT) {
strRes = R.string.forum_invitation_already_invited;
+ } else if (item.getSharingStatus() == INVITE_RECEIVED) {
+ strRes = R.string.forum_invitation_invite_received;
} else if (item.getSharingStatus() == NOT_SUPPORTED) {
strRes = R.string.forum_invitation_not_supported;
+ } else if (item.getSharingStatus() == ERROR) {
+ strRes = R.string.forum_invitation_error;
} else throw new AssertionError("Unhandled SharingStatus");
info.setText(strRes);
info.setVisibility(VISIBLE);
diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml
index 3f6d4a93a..97fec719f 100644
--- a/briar-android/src/main/res/values/strings.xml
+++ b/briar-android/src/main/res/values/strings.xml
@@ -461,8 +461,10 @@
Invitation declined
Shared by %s
Already sharing
- Already invited
+ Invitation already sent
+ Invitation already received
Not supported by this contact
+ Error. This is a bug and not your fault
You accepted the forum invitation from %s.
You declined the forum invitation from %s.
The forum invitation from %s was automatically declined.
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java
index fc0feb5b0..73a60db14 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java
@@ -84,6 +84,8 @@ public interface GroupInvitationManager extends ConversationClient {
* and {@link PrivateGroup} identified by the given {@link GroupId}.
* This indicates whether the {@link PrivateGroup} can be shared
* with the contact.
+ *
+ * @throws ProtocolStateException if {@link PrivateGroup} was already left.
*/
SharingStatus getSharingStatus(Contact c, GroupId g) throws DbException;
}
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java
index aa0e5202f..023419126 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.sync.GroupId;
+import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.conversation.ConversationManager.ConversationClient;
import org.briarproject.nullsafety.NotNullByDefault;
@@ -24,10 +25,14 @@ public interface SharingManager
SHAREABLE,
/**
* The {@link Shareable} can not be shared with the requested contact,
- * because of an ongoing sharing session.
- * In most cases, this means that the contact was already invited.
+ * because the contact was already invited.
*/
- INVITED,
+ INVITE_SENT,
+ /**
+ * The {@link Shareable} can not be shared with the requested contact,
+ * because the contact has already invited us.
+ */
+ INVITE_RECEIVED,
/**
* The {@link Shareable} can not be shared with the requested contact,
* because it is already being shared.
@@ -38,7 +43,11 @@ public interface SharingManager
* because it is not supported by that contact.
* This could be a missing or outdated client.
*/
- NOT_SUPPORTED
+ NOT_SUPPORTED,
+ /**
+ * The sharing session has encountered an error.
+ */
+ ERROR
}
/**
@@ -106,6 +115,8 @@ public interface SharingManager
* and {@link Shareable} identified by the given {@link GroupId}.
* This indicates whether the {@link Shareable} can be shared
* with the contact.
+ *
+ * @throws ProtocolStateException if {@link Shareable} was already left.
*/
SharingStatus getSharingStatus(GroupId g, Contact c) throws DbException;
@@ -114,6 +125,8 @@ public interface SharingManager
* and {@link Shareable} identified by the given {@link GroupId}.
* This indicates whether the {@link Shareable} can be shared
* with the contact.
+ *
+ * @throws ProtocolStateException if {@link Shareable} was already left.
*/
SharingStatus getSharingStatus(Transaction txn, GroupId g, Contact c)
throws DbException;
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java
index 4f1ca7e9b..0373ad2da 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java
@@ -26,6 +26,7 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook;
import org.briarproject.briar.api.autodelete.event.ConversationMessagesDeletedEvent;
import org.briarproject.briar.api.client.MessageTracker;
+import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
import org.briarproject.briar.api.conversation.DeletionResult;
@@ -57,6 +58,9 @@ import javax.inject.Inject;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.validation.IncomingMessageHook.DeliveryAction.ACCEPT_DO_NOT_SHARE;
import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
+import static org.briarproject.briar.privategroup.invitation.CreatorState.DISSOLVED;
+import static org.briarproject.briar.privategroup.invitation.CreatorState.ERROR;
+import static org.briarproject.briar.privategroup.invitation.CreatorState.INVITED;
import static org.briarproject.briar.privategroup.invitation.CreatorState.JOINED;
import static org.briarproject.briar.privategroup.invitation.CreatorState.START;
import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT;
@@ -533,8 +537,14 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
.parseCreatorSession(contactGroupId, ss.bdfSession);
CreatorState state = session.getState();
if (state == START) return SharingStatus.SHAREABLE;
+ if (state == INVITED) return SharingStatus.INVITE_RECEIVED;
if (state == JOINED) return SharingStatus.SHARING;
- return SharingStatus.INVITED;
+ // The creator can also be a LEFT state, after re-adding a contact
+ // and re-creating the session with #recreateSession()
+ if (state == CreatorState.LEFT) return SharingStatus.SHARING;
+ if (state == DISSOLVED) throw new ProtocolStateException();
+ if (state == ERROR) return SharingStatus.ERROR;
+ throw new AssertionError("Unhandled state: " + state.name());
} catch (FormatException e) {
throw new DbException(e);
} finally {
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java
index a7c6854a3..b34b9965e 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java
@@ -26,6 +26,7 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook;
import org.briarproject.briar.api.autodelete.event.ConversationMessagesDeletedEvent;
import org.briarproject.briar.api.client.MessageTracker;
+import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
import org.briarproject.briar.api.conversation.ConversationRequest;
@@ -58,7 +59,11 @@ import static org.briarproject.briar.sharing.MessageType.DECLINE;
import static org.briarproject.briar.sharing.MessageType.INVITE;
import static org.briarproject.briar.sharing.MessageType.LEAVE;
import static org.briarproject.briar.sharing.State.LOCAL_INVITED;
+import static org.briarproject.briar.sharing.State.LOCAL_LEFT;
+import static org.briarproject.briar.sharing.State.REMOTE_HANGING;
+import static org.briarproject.briar.sharing.State.REMOTE_INVITED;
import static org.briarproject.briar.sharing.State.SHARING;
+import static org.briarproject.briar.sharing.State.START;
@NotNullByDefault
abstract class SharingManagerImpl
@@ -468,7 +473,8 @@ abstract class SharingManagerImpl
}
@Override
- public SharingStatus getSharingStatus(GroupId g, Contact c) throws DbException {
+ public SharingStatus getSharingStatus(GroupId g, Contact c)
+ throws DbException {
Transaction txn = db.startTransaction(true);
try {
SharingStatus sharingStatus = getSharingStatus(txn, g, c);
@@ -495,9 +501,14 @@ abstract class SharingManagerImpl
// If the session's in the right state, the contact can be invited
Session session =
sessionParser.parseSession(contactGroupId, ss.bdfSession);
- if (session.getState().canInvite()) return SharingStatus.SHAREABLE;
- if (session.getState().isSharing()) return SharingStatus.SHARING;
- return SharingStatus.INVITED;
+ State state = session.getState();
+ if (state == START) return SharingStatus.SHAREABLE;
+ if (state == LOCAL_INVITED) return SharingStatus.INVITE_RECEIVED;
+ if (state == REMOTE_INVITED) return SharingStatus.INVITE_SENT;
+ if (state == SHARING) return SharingStatus.SHARING;
+ if (state == LOCAL_LEFT || state == REMOTE_HANGING)
+ throw new ProtocolStateException();
+ throw new AssertionError("Unhandled state: " + state.name());
} catch (FormatException e) {
throw new DbException(e);
}
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/State.java b/briar-core/src/main/java/org/briarproject/briar/sharing/State.java
index 1f4bba1fd..d1703048e 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/State.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/State.java
@@ -46,14 +46,6 @@ enum State {
return visibility;
}
- public boolean canInvite() {
- return this == START;
- }
-
- public boolean isSharing() {
- return this == SHARING;
- }
-
public boolean isAwaitingResponse() {
return this == LOCAL_INVITED || this == REMOTE_INVITED;
}
diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java
index de7209497..5db86bea8 100644
--- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java
@@ -29,7 +29,7 @@ import javax.annotation.Nullable;
import static java.util.Collections.emptySet;
import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS;
-import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITED;
+import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITE_RECEIVED;
import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHAREABLE;
import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHARING;
import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount;
@@ -322,7 +322,7 @@ public class GroupInvitationIntegrationTest
sendInvitation(c0.getClock().currentTimeMillis(), null);
// invitation is not allowed before the first hasn't been answered
- assertEquals(INVITED, groupInvitationManager0
+ assertEquals(INVITE_RECEIVED, groupInvitationManager0
.getSharingStatus(contact1From0, privateGroup.getId()));
// deliver invitation and response
@@ -740,7 +740,7 @@ public class GroupInvitationIntegrationTest
addDefaultContacts();
// creator can still not invite again
- assertEquals(INVITED, groupInvitationManager0
+ assertEquals(SHARING, groupInvitationManager0
.getSharingStatus(contact1From0, privateGroup.getId()));
// finally invitee can remove group without issues
diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java
index aaa445f63..8f3c2398c 100644
--- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java
@@ -25,6 +25,7 @@ import org.briarproject.bramble.test.DbExpectations;
import org.briarproject.bramble.test.TestUtils;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.SessionId;
+import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
import org.briarproject.briar.api.privategroup.PrivateGroup;
import org.briarproject.briar.api.privategroup.PrivateGroupFactory;
@@ -62,7 +63,8 @@ import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROU
import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH;
import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID;
import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.MAJOR_VERSION;
-import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITED;
+import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.ERROR;
+import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITE_RECEIVED;
import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHAREABLE;
import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHARING;
import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT;
@@ -880,15 +882,20 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
@Test
public void testIsNotInvitationAllowed() throws Exception {
expectIsInvitationAllowed(CreatorState.DISSOLVED);
- assertEquals(INVITED, groupInvitationManager
- .getSharingStatus(contact, privateGroup.getId()));
+ try {
+ groupInvitationManager
+ .getSharingStatus(contact, privateGroup.getId());
+ fail();
+ } catch (ProtocolStateException e) {
+ // expected
+ }
expectIsInvitationAllowed(CreatorState.ERROR);
- assertEquals(INVITED, groupInvitationManager
+ assertEquals(ERROR, groupInvitationManager
.getSharingStatus(contact, privateGroup.getId()));
expectIsInvitationAllowed(CreatorState.INVITED);
- assertEquals(INVITED, groupInvitationManager
+ assertEquals(INVITE_RECEIVED, groupInvitationManager
.getSharingStatus(contact, privateGroup.getId()));
expectIsInvitationAllowed(CreatorState.JOINED);
@@ -896,7 +903,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
.getSharingStatus(contact, privateGroup.getId()));
expectIsInvitationAllowed(CreatorState.LEFT);
- assertEquals(INVITED, groupInvitationManager
+ assertEquals(SHARING, groupInvitationManager
.getSharingStatus(contact, privateGroup.getId()));
}
diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java
index bf0a799a7..b4d0a1bce 100644
--- a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java
@@ -13,6 +13,7 @@ import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.test.TestDatabaseConfigModule;
+import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
import org.briarproject.briar.api.conversation.ConversationResponse;
import org.briarproject.briar.api.conversation.DeletionResult;
@@ -43,11 +44,11 @@ import javax.annotation.Nullable;
import static java.util.Collections.emptySet;
import static junit.framework.Assert.assertNotNull;
+import static junit.framework.TestCase.fail;
import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS;
import static org.briarproject.briar.api.forum.ForumSharingManager.CLIENT_ID;
import static org.briarproject.briar.api.forum.ForumSharingManager.MAJOR_VERSION;
-import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITED;
import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHAREABLE;
import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHARING;
import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount;
@@ -349,8 +350,12 @@ public class ForumSharingIntegrationTest
assertEquals(SHAREABLE, forumSharingManager0
.getSharingStatus(forum.getId(), contact1From0));
// invitee that left can not yet share again
- assertEquals(INVITED, forumSharingManager1
- .getSharingStatus(forum.getId(), contact0From1));
+ try {
+ forumSharingManager1.getSharingStatus(forum.getId(), contact0From1);
+ fail();
+ } catch (ProtocolStateException e) {
+ // expected
+ }
// sharer responds with leave message
sync0To1(1, true);