diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java
index 30c1401197607a10ad93dba778f84d49860f0177..cc1049683b01023120f4e6f50d756f39d1cfcd9a 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java
@@ -174,6 +174,17 @@ abstract class AbstractProtocolEngine<S extends Session>
 			markMessageAvailableToAnswer(txn, m, false);
 	}
 
+	void markInviteAccepted(Transaction txn, MessageId m, boolean accepted)
+			throws DbException {
+		BdfDictionary meta = new BdfDictionary();
+		messageEncoder.setInvitationAccepted(meta, accepted);
+		try {
+			clientHelper.mergeMessageMetadata(txn, m, meta);
+		} catch (FormatException e) {
+			throw new AssertionError(e);
+		}
+	}
+
 	void subscribeToPrivateGroup(Transaction txn, MessageId inviteId)
 			throws DbException, FormatException {
 		InviteMessage invite = messageParser.getInviteMessage(txn, inviteId);
@@ -199,8 +210,9 @@ abstract class AbstractProtocolEngine<S extends Session>
 	private void sendMessage(Transaction txn, Message m, MessageType type,
 			GroupId privateGroupId, boolean visibleInConversation)
 			throws DbException {
-		BdfDictionary meta = messageEncoder.encodeMetadata(type, privateGroupId,
-				m.getTimestamp(), true, true, visibleInConversation, false);
+		BdfDictionary meta = messageEncoder
+				.encodeMetadata(type, privateGroupId, m.getTimestamp(), true,
+						true, visibleInConversation, false, false);
 		try {
 			clientHelper.addLocalMessage(txn, m, meta, true);
 		} catch (FormatException e) {
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java
index c55bc19f4f6b6dc2a66f61d7c059b21a12ee9d3f..a9a6ef0929eadae2009d368e7bb51c8c9ecfff75 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java
@@ -12,6 +12,7 @@ interface GroupInvitationConstants {
 	String MSG_KEY_LOCAL = "local";
 	String MSG_KEY_VISIBLE_IN_UI = "visibleInUi";
 	String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer";
+	String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted";
 
 	// Session keys
 	String SESSION_KEY_SESSION_ID = "sessionId";
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 1fac77c630aa1e049776b518c0217df1f7f0f141..cbc26bb4a66f81efc710796c4d1bc4affbb86d7a 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
@@ -405,7 +405,9 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
 		PrivateGroup pg = privateGroupFactory
 				.createPrivateGroup(invite.getGroupName(), invite.getCreator(),
 						invite.getSalt());
-		boolean canBeOpened = db.containsGroup(txn, invite.getPrivateGroupId());
+		// Find out whether the private group can be opened
+		boolean canBeOpened = meta.wasAccepted() &&
+				db.containsGroup(txn, invite.getPrivateGroupId());
 		return new GroupInvitationRequest(m, contactGroupId,
 				meta.getTimestamp(), meta.isLocal(), status.isSent(),
 				status.isSeen(), meta.isRead(), sessionId, pg, c,
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java
index 125588cabc85b3a61acae90182e8b2a4bf4e5637..1b111f5dc9687a5427d69fa86a92cf52fbc0dcd6 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java
@@ -112,7 +112,7 @@ class GroupInvitationValidator extends BdfMessageValidator {
 		// Create the metadata
 		BdfDictionary meta = messageEncoder.encodeMetadata(INVITE,
 				privateGroup.getId(), m.getTimestamp(), false, false, false,
-				false);
+				false, false);
 		return new BdfMessageContext(meta);
 	}
 
@@ -125,7 +125,7 @@ class GroupInvitationValidator extends BdfMessageValidator {
 		checkLength(previousMessageId, UniqueId.LENGTH);
 		BdfDictionary meta = messageEncoder.encodeMetadata(JOIN,
 				new GroupId(privateGroupId), m.getTimestamp(), false, false,
-				false, false);
+				false, false, false);
 		if (previousMessageId == null) {
 			return new BdfMessageContext(meta);
 		} else {
@@ -144,7 +144,7 @@ class GroupInvitationValidator extends BdfMessageValidator {
 		checkLength(previousMessageId, UniqueId.LENGTH);
 		BdfDictionary meta = messageEncoder.encodeMetadata(LEAVE,
 				new GroupId(privateGroupId), m.getTimestamp(), false, false,
-				false, false);
+				false, false, false);
 		if (previousMessageId == null) {
 			return new BdfMessageContext(meta);
 		} else {
@@ -161,7 +161,7 @@ class GroupInvitationValidator extends BdfMessageValidator {
 		checkLength(privateGroupId, UniqueId.LENGTH);
 		BdfDictionary meta = messageEncoder.encodeMetadata(ABORT,
 				new GroupId(privateGroupId), m.getTimestamp(), false, false,
-				false, false);
+				false, false, false);
 		return new BdfMessageContext(meta);
 	}
 }
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java
index bf30f96edd34a182c3f7f3e8b7c8682427736a74..f4782a387552fa59586ded708d8d2d461449f061 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java
@@ -172,6 +172,8 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
 		MessageId inviteId = s.getLastRemoteMessageId();
 		if (inviteId == null) throw new IllegalStateException();
 		markMessageAvailableToAnswer(txn, inviteId, false);
+		// Record the response
+		markInviteAccepted(txn, inviteId, true);
 		// Send a JOIN message
 		Message sent = sendJoinMessage(txn, s, true);
 		// Track the message
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoder.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoder.java
index 4312e519d5d0beb88e66a7180beee84fea630b04..ee6b98a84a475e88ef1a1dc25680c9f66c2653cd 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoder.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoder.java
@@ -14,12 +14,14 @@ interface MessageEncoder {
 
 	BdfDictionary encodeMetadata(MessageType type, GroupId privateGroupId,
 			long timestamp, boolean local, boolean read, boolean visible,
-			boolean available);
+			boolean available, boolean accepted);
 
 	void setVisibleInUi(BdfDictionary meta, boolean visible);
 
 	void setAvailableToAnswer(BdfDictionary meta, boolean available);
 
+	void setInvitationAccepted(BdfDictionary meta, boolean accepted);
+
 	Message encodeInviteMessage(GroupId contactGroupId, GroupId privateGroupId,
 			long timestamp, String groupName, Author creator, byte[] salt,
 			@Nullable String message, byte[] signature);
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoderImpl.java
index 17e0843d71d3a077b2229df0523f659ced14d11e..a9ff4ac9e3f6e7a56e0f83941af62c6e7098a8ab 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoderImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoderImpl.java
@@ -17,6 +17,7 @@ import javax.inject.Inject;
 
 import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AVAILABLE_TO_ANSWER;
+import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_INVITATION_ACCEPTED;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_LOCAL;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_MESSAGE_TYPE;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_PRIVATE_GROUP_ID;
@@ -44,7 +45,7 @@ class MessageEncoderImpl implements MessageEncoder {
 	@Override
 	public BdfDictionary encodeMetadata(MessageType type,
 			GroupId privateGroupId, long timestamp, boolean local, boolean read,
-			boolean visible, boolean available) {
+			boolean visible, boolean available, boolean accepted) {
 		BdfDictionary meta = new BdfDictionary();
 		meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue());
 		meta.put(MSG_KEY_PRIVATE_GROUP_ID, privateGroupId);
@@ -53,6 +54,7 @@ class MessageEncoderImpl implements MessageEncoder {
 		meta.put(MSG_KEY_READ, read);
 		meta.put(MSG_KEY_VISIBLE_IN_UI, visible);
 		meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available);
+		meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted);
 		return meta;
 	}
 
@@ -66,6 +68,11 @@ class MessageEncoderImpl implements MessageEncoder {
 		meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available);
 	}
 
+	@Override
+	public void setInvitationAccepted(BdfDictionary meta, boolean accepted) {
+		meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted);
+	}
+
 	@Override
 	public Message encodeInviteMessage(GroupId contactGroupId,
 			GroupId privateGroupId, long timestamp, String groupName,
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageMetadata.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageMetadata.java
index 92c62748dfadaa0ca66872acc3c1aea91d1b4659..c4490641d4f8251b9d50f527fb969375d464b9eb 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageMetadata.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageMetadata.java
@@ -12,11 +12,11 @@ class MessageMetadata {
 	private final MessageType type;
 	private final GroupId privateGroupId;
 	private final long timestamp;
-	private final boolean local, read, visible, available;
+	private final boolean local, read, visible, available, accepted;
 
 	MessageMetadata(MessageType type, GroupId privateGroupId,
 			long timestamp, boolean local, boolean read, boolean visible,
-			boolean available) {
+			boolean available, boolean accepted) {
 		this.privateGroupId = privateGroupId;
 		this.type = type;
 		this.timestamp = timestamp;
@@ -24,6 +24,7 @@ class MessageMetadata {
 		this.read = read;
 		this.visible = visible;
 		this.available = available;
+		this.accepted = accepted;
 	}
 
 	MessageType getMessageType() {
@@ -53,4 +54,14 @@ class MessageMetadata {
 	boolean isAvailableToAnswer() {
 		return available;
 	}
+
+	/**
+	 * Returns true if the invitation was accepted.
+	 *
+	 * Only applies to messages of type INVITE.
+	 */
+	public boolean wasAccepted() {
+		return accepted;
+	}
+
 }
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageParserImpl.java
index 1cf35ee9c32b740382678c5bdcdcb7de473c678e..d5160b0d84ec5a2284b70727f4eaa74a7a8b7cac 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageParserImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageParserImpl.java
@@ -21,6 +21,7 @@ import javax.inject.Inject;
 
 import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AVAILABLE_TO_ANSWER;
+import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_INVITATION_ACCEPTED;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_LOCAL;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_MESSAGE_TYPE;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_PRIVATE_GROUP_ID;
@@ -79,8 +80,9 @@ class MessageParserImpl implements MessageParser {
 		boolean read = meta.getBoolean(MSG_KEY_READ, false);
 		boolean visible = meta.getBoolean(MSG_KEY_VISIBLE_IN_UI, false);
 		boolean available = meta.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false);
+		boolean accepted = meta.getBoolean(MSG_KEY_INVITATION_ACCEPTED, false);
 		return new MessageMetadata(type, privateGroupId, timestamp, local, read,
-				visible, available);
+				visible, available, accepted);
 	}
 
 	@Override
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoder.java b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoder.java
index 33ce9b3fc1b160398913f7b205c89080dad838a3..b53d4fbadfa1a43bdfd0e5581e54a2ca5b5e5fb7 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoder.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoder.java
@@ -14,12 +14,14 @@ interface MessageEncoder {
 
 	BdfDictionary encodeMetadata(MessageType type, GroupId shareableId,
 			long timestamp, boolean local, boolean read, boolean visible,
-			boolean available);
+			boolean available, boolean accepted);
 
 	void setVisibleInUi(BdfDictionary meta, boolean visible);
 
 	void setAvailableToAnswer(BdfDictionary meta, boolean available);
 
+	void setInvitationAccepted(BdfDictionary meta, boolean accepted);
+
 	Message encodeInviteMessage(GroupId contactGroupId, long timestamp,
 			@Nullable MessageId previousMessageId, BdfList descriptor,
 			@Nullable String message);
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoderImpl.java
index 1047df487e05596c61a603bc6973e759a2842809..17938b8e21188479041889fbe33ab7935252fbcf 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoderImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoderImpl.java
@@ -20,10 +20,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.SharingConstants.MSG_KEY_AVAILABLE_TO_ANSWER;
+import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_INVITATION_ACCEPTED;
 import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_LOCAL;
 import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_MESSAGE_TYPE;
-import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_SHAREABLE_ID;
 import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_READ;
+import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_SHAREABLE_ID;
 import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_TIMESTAMP;
 import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_VISIBLE_IN_UI;
 
@@ -44,7 +45,7 @@ class MessageEncoderImpl implements MessageEncoder {
 	@Override
 	public BdfDictionary encodeMetadata(MessageType type,
 			GroupId shareableId, long timestamp, boolean local, boolean read,
-			boolean visible, boolean available) {
+			boolean visible, boolean available, boolean accepted) {
 		BdfDictionary meta = new BdfDictionary();
 		meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue());
 		meta.put(MSG_KEY_SHAREABLE_ID, shareableId);
@@ -53,6 +54,7 @@ class MessageEncoderImpl implements MessageEncoder {
 		meta.put(MSG_KEY_READ, read);
 		meta.put(MSG_KEY_VISIBLE_IN_UI, visible);
 		meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available);
+		meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted);
 		return meta;
 	}
 
@@ -66,6 +68,11 @@ class MessageEncoderImpl implements MessageEncoder {
 		meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available);
 	}
 
+	@Override
+	public void setInvitationAccepted(BdfDictionary meta, boolean accepted) {
+		meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted);
+	}
+
 	@Override
 	public Message encodeInviteMessage(GroupId contactGroupId, long timestamp,
 			@Nullable MessageId previousMessageId, BdfList descriptor,
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageMetadata.java b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageMetadata.java
index 031676249a047b696efd1ec47247637d092dec7f..a9f1662d57436aea07458906c2b62818d936fc02 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageMetadata.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageMetadata.java
@@ -12,10 +12,11 @@ class MessageMetadata {
 	private final MessageType type;
 	private final GroupId shareableId;
 	private final long timestamp;
-	private final boolean local, read, visible, available;
+	private final boolean local, read, visible, available, accepted;
 
 	MessageMetadata(MessageType type, GroupId shareableId, long timestamp,
-			boolean local, boolean read, boolean visible, boolean available) {
+			boolean local, boolean read, boolean visible, boolean available,
+			boolean accepted) {
 		this.shareableId = shareableId;
 		this.type = type;
 		this.timestamp = timestamp;
@@ -23,6 +24,7 @@ class MessageMetadata {
 		this.read = read;
 		this.visible = visible;
 		this.available = available;
+		this.accepted = accepted;
 	}
 
 	MessageType getMessageType() {
@@ -53,4 +55,13 @@ class MessageMetadata {
 		return available;
 	}
 
+	/**
+	 * Returns true if the invitation was accepted.
+	 *
+	 * Only applies to messages of type INVITE.
+	 */
+	public boolean wasAccepted() {
+		return accepted;
+	}
+
 }
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageParserImpl.java
index 4384941179563df52a39de121ef693ea38e581d8..d09055626e8cb84f54681151623b27f7fd2af916 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageParserImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageParserImpl.java
@@ -20,6 +20,7 @@ import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_AVAILABLE_
 import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_LOCAL;
 import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_MESSAGE_TYPE;
 import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_READ;
+import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_INVITATION_ACCEPTED;
 import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_SHAREABLE_ID;
 import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_TIMESTAMP;
 import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_VISIBLE_IN_UI;
@@ -68,8 +69,9 @@ abstract class MessageParserImpl<S extends Shareable>
 		boolean read = meta.getBoolean(MSG_KEY_READ, false);
 		boolean visible = meta.getBoolean(MSG_KEY_VISIBLE_IN_UI, false);
 		boolean available = meta.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false);
+		boolean accepted = meta.getBoolean(MSG_KEY_INVITATION_ACCEPTED, false);
 		return new MessageMetadata(type, shareableId, timestamp, local, read,
-				visible, available);
+				visible, available, accepted);
 	}
 
 	@Override
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java
index ad017942a98cf34d0c24a31b4e69f5d9fa9649ab..971c42df65bf421a6b7364abceea719d62cde703 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java
@@ -148,6 +148,8 @@ abstract class ProtocolEngineImpl<S extends Shareable>
 		MessageId inviteId = s.getLastRemoteMessageId();
 		if (inviteId == null) throw new IllegalStateException();
 		markMessageAvailableToAnswer(txn, inviteId, false);
+		// Mark the invite message as accepted
+		markInvitationAccepted(txn, inviteId, true);
 		// Send a ACCEPT message
 		Message sent = sendAcceptMessage(txn, s);
 		// Track the message
@@ -568,8 +570,9 @@ abstract class ProtocolEngineImpl<S extends Shareable>
 	private void sendMessage(Transaction txn, Message m, MessageType type,
 			GroupId shareableId, boolean visibleInConversation)
 			throws DbException {
-		BdfDictionary meta = messageEncoder.encodeMetadata(type, shareableId,
-				m.getTimestamp(), true, true, visibleInConversation, false);
+		BdfDictionary meta = messageEncoder
+				.encodeMetadata(type, shareableId, m.getTimestamp(), true, true,
+						visibleInConversation, false, false);
 		try {
 			clientHelper.addLocalMessage(txn, m, meta, true);
 		} catch (FormatException e) {
@@ -599,6 +602,17 @@ abstract class ProtocolEngineImpl<S extends Shareable>
 		}
 	}
 
+	private void markInvitationAccepted(Transaction txn, MessageId m,
+			boolean accepted) throws DbException {
+		BdfDictionary meta = new BdfDictionary();
+		messageEncoder.setInvitationAccepted(meta, accepted);
+		try {
+			clientHelper.mergeMessageMetadata(txn, m, meta);
+		} catch (FormatException e) {
+			throw new AssertionError(e);
+		}
+	}
+
 	private void setShareableVisibility(Transaction txn, Session session,
 			Visibility v) throws DbException, FormatException {
 		ContactId contactId = getContactId(txn, session.getContactGroupId());
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java
index d860abc8f2b993e61adb46664c51575e41a9a546..d98099e27b2ff30a024ce7a2efbe4b72c01c26e1 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java
@@ -15,6 +15,7 @@ interface SharingConstants {
 	String MSG_KEY_LOCAL = "local";
 	String MSG_KEY_VISIBLE_IN_UI = "visibleInUi";
 	String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer";
+	String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted";
 
 	// Session keys
 	String SESSION_KEY_STATE = "state";
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 76ba8d1cf0789a34064507eafee760584af79a3f..fc61bf49dfb266f986d1a88130409d2f136c5357 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
@@ -319,7 +319,9 @@ abstract class SharingManagerImpl<S extends Shareable>
 			MessageStatus status) throws DbException, FormatException {
 		// Look up the invite message to get the details of the private group
 		InviteMessage<S> invite = messageParser.getInviteMessage(txn, m);
-		boolean canBeOpened = db.containsGroup(txn, invite.getShareableId());
+		// Find out whether the shareable can be opened
+		boolean canBeOpened = meta.wasAccepted() &&
+				db.containsGroup(txn, invite.getShareableId());
 		return invitationFactory
 				.createInvitationRequest(meta.isLocal(), status.isSent(),
 						status.isSeen(), meta.isRead(), invite, c,
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java
index e8f9287f8f43162acd224d6ce0dc43dcc78c7fb3..a7eadcd154080582539267018628b8441ec277d3 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java
@@ -65,7 +65,7 @@ abstract class SharingValidator extends BdfMessageValidator {
 
 		BdfDictionary meta = messageEncoder
 				.encodeMetadata(INVITE, shareableId, m.getTimestamp(), false,
-						false, false, false);
+						false, false, false, false);
 		if (previousMessageId == null) {
 			return new BdfMessageContext(meta);
 		} else {
@@ -88,7 +88,7 @@ abstract class SharingValidator extends BdfMessageValidator {
 
 		BdfDictionary meta = messageEncoder
 				.encodeMetadata(type, new GroupId(shareableId),
-						m.getTimestamp(), false, false, false, false);
+						m.getTimestamp(), false, false, false, false, false);
 		if (previousMessageId == null) {
 			return new BdfMessageContext(meta);
 		} else {
diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java
index 9ce107eee18c71b1660a108f0b9ab3bd0020cc1d..aafa34f116d5bc0a2c9a704695324ef2377fa080 100644
--- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java
@@ -169,7 +169,7 @@ public abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
 			final boolean visible) throws Exception {
 		context.checking(new Expectations() {{
 			oneOf(messageEncoder).encodeMetadata(type, privateGroupId,
-					message.getTimestamp(), true, true, visible, false);
+					message.getTimestamp(), true, true, visible, false, false);
 			will(returnValue(meta));
 			oneOf(clientHelper).addLocalMessage(txn, message, meta, true);
 		}});
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 fe4142331256902e70f9f581ff1098aa98f30bc0..66a0bdb0329ff4efdad0ebcf71c8cd0a6fcc4c50 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
@@ -104,6 +104,7 @@ public class GroupInvitationIntegrationTest
 		assertEquals(privateGroup0.getName(), request.getShareable().getName());
 		assertFalse(request.isLocal());
 		assertFalse(request.isRead());
+		assertFalse(request.canBeOpened());
 	}
 
 	@Test
@@ -175,6 +176,8 @@ public class GroupInvitationIntegrationTest
 				foundResponse = true;
 				InvitationResponse response = (GroupInvitationResponse) m;
 				assertTrue(response.wasAccepted());
+			} else {
+				assertTrue(((GroupInvitationRequest) m).canBeOpened());
 			}
 		}
 		assertTrue(foundResponse);
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 37c7b76e321a1e89a0d9ceb7c105499465dd5d31..c197bb73c0d0dd63f96750599dd48ecf6dc3875e 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
@@ -638,10 +638,10 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 		final long time1 = 1L, time2 = 2L;
 		final MessageMetadata messageMetadata1 =
 				new MessageMetadata(INVITE, privateGroup.getId(), time1, true,
-						true, true, false);
+						true, true, false, true);
 		final MessageMetadata messageMetadata2 =
 				new MessageMetadata(JOIN, privateGroup.getId(), time2, true,
-						true, true, true);
+						true, true, true, false);
 		final InviteMessage invite =
 				new InviteMessage(message.getId(), contactGroup.getId(),
 						privateGroup.getId(), time1, "name", author,
diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java
index fe79b36784dbb412633e331e15442e551a786f4c..cc8f025f08ec13d3a3f4db51447732a7a2b61dd9 100644
--- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java
@@ -311,7 +311,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
 			} else {
 				oneOf(messageEncoder).encodeMetadata(INVITE,
 						message.getGroupId(), message.getTimestamp(), false,
-						false, false, false);
+						false, false, false, false);
 				will(returnValue(meta));
 			}
 		}});
@@ -389,7 +389,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
 		BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), null);
 		context.checking(new Expectations() {{
 			oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(),
-					message.getTimestamp(), false, false, false, false);
+					message.getTimestamp(), false, false, false, false, false);
 			will(returnValue(meta));
 		}});
 		BdfMessageContext messageContext =
@@ -404,7 +404,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
 				previousMessageId);
 		context.checking(new Expectations() {{
 			oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(),
-					message.getTimestamp(), false, false, false, false);
+					message.getTimestamp(), false, false, false, false, false);
 			will(returnValue(meta));
 		}});
 		BdfMessageContext messageContext =
@@ -487,7 +487,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
 		BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), null);
 		context.checking(new Expectations() {{
 			oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(),
-					message.getTimestamp(), false, false, false, false);
+					message.getTimestamp(), false, false, false, false, false);
 			will(returnValue(meta));
 		}});
 		BdfMessageContext messageContext =
@@ -500,7 +500,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
 	public void testAcceptsValidLeaveMessage() throws Exception {
 		context.checking(new Expectations() {{
 			oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(),
-					message.getTimestamp(), false, false, false, false);
+					message.getTimestamp(), false, false, false, false, false);
 			will(returnValue(meta));
 		}});
 		BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(),
@@ -557,7 +557,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
 	public void testAcceptsValidAbortMessage() throws Exception {
 		context.checking(new Expectations() {{
 			oneOf(messageEncoder).encodeMetadata(ABORT, message.getGroupId(),
-					message.getTimestamp(), false, false, false, false);
+					message.getTimestamp(), false, false, false, false, false);
 			will(returnValue(meta));
 		}});
 		BdfList body = BdfList.of(ABORT.getValue(), privateGroup.getId());
diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java
index 6e427277087c8550dfedfc14031106dd2b3f2ea4..1165c7ceeba4805a5cfb5cf14978b226b67ae985 100644
--- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java
@@ -3,11 +3,9 @@ package org.briarproject.briar.privategroup.invitation;
 import org.briarproject.bramble.api.contact.Contact;
 import org.briarproject.bramble.api.data.BdfDictionary;
 import org.briarproject.bramble.api.data.BdfEntry;
-import org.briarproject.bramble.api.data.BdfList;
 import org.briarproject.bramble.api.identity.Author;
 import org.briarproject.bramble.api.identity.AuthorId;
 import org.briarproject.bramble.api.identity.LocalAuthor;
-import org.briarproject.bramble.api.sync.Message;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.briar.api.client.ProtocolStateException;
 import org.briarproject.briar.api.privategroup.GroupMessage;
@@ -132,15 +130,17 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
 		final JoinMessage properJoinMessage =
 				new JoinMessage(messageId, contactGroupId, privateGroupId,
 						messageTimestamp, lastRemoteMessageId);
-		final Message inviteMsg =
-				new Message(lastRemoteMessageId, contactGroupId, 1337L,
-						getRandomBytes(42));
-		final BdfList inviteList = BdfList.of("inviteMessage");
 		final long timestamp = 0L;
 		final GroupMessage joinGroupMessage =
 				new GroupMessage(message, null, localAuthor);
+		final BdfDictionary meta = new BdfDictionary();
 
 		expectMarkMessageAvailableToAnswer(lastRemoteMessageId, false);
+		context.checking(new Expectations() {{
+			oneOf(messageEncoder).setInvitationAccepted(meta, true);
+			oneOf(clientHelper)
+					.mergeMessageMetadata(txn, lastRemoteMessageId, meta);
+		}});
 		expectSendJoinMessage(properJoinMessage, true);
 		context.checking(new Expectations() {{
 			oneOf(messageTracker).trackOutgoingMessage(txn, message);
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 537e2b64b8b45a5480767d124d15ea6510c2083b..6f351f708755124824d8bcd8e9dfe37e6f6f7289 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
@@ -136,6 +136,7 @@ public class ForumSharingIntegrationTest
 				assertEquals(forum0.getName(), invitation.getForumName());
 				assertEquals(contactId1From0, invitation.getContactId());
 				assertEquals("Hi!", invitation.getMessage());
+				assertTrue(invitation.canBeOpened());
 			} else {
 				ForumInvitationResponse response =
 						(ForumInvitationResponse) m;
@@ -195,6 +196,7 @@ public class ForumSharingIntegrationTest
 				assertEquals(forum0.getName(), invitation.getForumName());
 				assertEquals(contactId1From0, invitation.getContactId());
 				assertEquals(null, invitation.getMessage());
+				assertFalse(invitation.canBeOpened());
 			} else {
 				ForumInvitationResponse response =
 						(ForumInvitationResponse) m;
diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java
index c8e688ce1f0801c23cc74d8216b09ffb3a1d9cfc..f0c87e9d7319bcefa84432c4675c1a8990576456 100644
--- a/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java
@@ -147,7 +147,7 @@ public abstract class SharingValidatorTest extends ValidatorTestCase {
 		context.checking(new Expectations() {{
 			oneOf(messageEncoder)
 					.encodeMetadata(type, groupId, timestamp, false, false,
-							false, false);
+							false, false, false);
 			will(returnValue(meta));
 		}});
 	}