Show relevant decline responses in the conversation

* If the user has already declined, we don't show that the other
  introducee has declined as well. The backend doesn't have that information, so
  this is compatible with the principle of showing what we know.
* If the user has already accepted or hasn't yet responded, we show the
  decline response in the private conversation with the introducer. If
  the user hasn't yet responded, we hide the accept/decline buttons
  in the introduction request message.

Messages an introducee receives in a `FINISHED` state are now being
ignored and deleted.

Closes #295
This commit is contained in:
Torsten Grote
2016-04-20 13:55:59 -03:00
parent 5457588dbd
commit 11e6d64e4d
11 changed files with 219 additions and 54 deletions

View File

@@ -51,6 +51,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.OUR_TIME;
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY;
import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID;
import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US;
import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCEE;
import static org.briarproject.api.introduction.IntroductionConstants.SESSION_ID;
import static org.briarproject.api.introduction.IntroductionConstants.STATE;
import static org.briarproject.api.introduction.IntroductionConstants.TASK;
@@ -195,14 +196,11 @@ public class IntroduceeEngine
messages = Collections.emptyList();
events = Collections.emptyList();
}
// we are done (probably declined response) and ignore this message
// we are done (probably declined response), ignore & delete message
else if (currentState == FINISHED) {
if(action == REMOTE_DECLINE || action == REMOTE_ACCEPT) {
// record response data,
// so we later know which response was ours
addResponseData(localState, msg);
}
return noUpdate(localState);
return new StateUpdate<BdfDictionary, BdfDictionary>(true,
false, localState, new ArrayList<BdfDictionary>(0),
new ArrayList<Event>(0));
}
// this should not happen
else {
@@ -341,8 +339,8 @@ public class IntroduceeEngine
localState.getBoolean(REMOTE_AUTHOR_IS_US);
IntroductionRequest ir = new IntroductionRequest(sessionId, messageId,
time, false, false, false, false, authorId, name, false,
message, false, exists, introducesOtherIdentity);
ROLE_INTRODUCEE, time, false, false, false, false, authorId,
name, false, message, false, exists, introducesOtherIdentity);
return new IntroductionRequestReceivedEvent(contactId, ir);
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.introduction;
import org.briarproject.api.Bytes;
import org.briarproject.api.FormatException;
import org.briarproject.api.TransportId;
@@ -39,6 +38,7 @@ import java.util.logging.Logger;
import javax.inject.Inject;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.introduction.IntroduceeProtocolState.AWAIT_REQUEST;
import static org.briarproject.api.introduction.IntroductionConstants.ACCEPT;
@@ -51,6 +51,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.E_PUBLIC_K
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID;
import static org.briarproject.api.introduction.IntroductionConstants.INTRODUCER;
import static org.briarproject.api.introduction.IntroductionConstants.LOCAL_AUTHOR_ID;
import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_ID;
import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_TIME;
import static org.briarproject.api.introduction.IntroductionConstants.NAME;
import static org.briarproject.api.introduction.IntroductionConstants.NOT_OUR_RESPONSE;
@@ -170,7 +171,7 @@ class IntroduceeManager {
BdfDictionary message) throws DbException, FormatException {
IntroduceeEngine engine = new IntroduceeEngine();
processStateUpdate(txn, engine.onMessageReceived(state, message));
processStateUpdate(txn, message, engine.onMessageReceived(state, message));
}
public void acceptIntroduction(Transaction txn, BdfDictionary state,
@@ -200,7 +201,7 @@ class IntroduceeManager {
// start engine and process its state update
IntroduceeEngine engine = new IntroduceeEngine();
processStateUpdate(txn, engine.onLocalAction(state, localAction));
processStateUpdate(txn, null, engine.onLocalAction(state, localAction));
}
public void declineIntroduction(Transaction txn, BdfDictionary state,
@@ -217,11 +218,11 @@ class IntroduceeManager {
// start engine and process its state update
IntroduceeEngine engine = new IntroduceeEngine();
processStateUpdate(txn,
processStateUpdate(txn, null,
engine.onLocalAction(state, localAction));
}
private void processStateUpdate(Transaction txn,
private void processStateUpdate(Transaction txn, BdfDictionary msg,
IntroduceeEngine.StateUpdate<BdfDictionary, BdfDictionary>
result) throws DbException, FormatException {
@@ -242,6 +243,16 @@ class IntroduceeManager {
for (Event event : result.toBroadcast) {
txn.attach(event);
}
// delete message
if (result.deleteMessage && msg != null) {
MessageId messageId = new MessageId(msg.getRaw(MESSAGE_ID));
if (LOG.isLoggable(INFO)) {
LOG.info("Deleting message with id " + messageId.hashCode());
}
db.deleteMessage(txn, messageId);
db.deleteMessageMetadata(txn, messageId);
}
}
private void performTasks(Transaction txn, BdfDictionary localState)
@@ -253,8 +264,6 @@ class IntroduceeManager {
long task = localState.getLong(TASK);
localState.put(TASK, BdfDictionary.NULL_VALUE);
if (task == TASK_ADD_CONTACT) {
if (localState.getBoolean(EXISTS)) {
// we have this contact already, so do not perform actions
@@ -374,7 +383,7 @@ class IntroduceeManager {
BdfDictionary localAction = new BdfDictionary();
localAction.put(TYPE, TYPE_ABORT);
try {
processStateUpdate(txn,
processStateUpdate(txn, null,
engine.onLocalAction(state, localAction));
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);

View File

@@ -55,6 +55,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY2;
import static org.briarproject.api.introduction.IntroductionConstants.RESPONSE_1;
import static org.briarproject.api.introduction.IntroductionConstants.RESPONSE_2;
import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCER;
import static org.briarproject.api.introduction.IntroductionConstants.SESSION_ID;
import static org.briarproject.api.introduction.IntroductionConstants.STATE;
import static org.briarproject.api.introduction.IntroductionConstants.TYPE;
@@ -302,8 +303,9 @@ public class IntroducerEngine
boolean accept = msg.getBoolean(ACCEPT);
IntroductionResponse ir =
new IntroductionResponse(sessionId, messageId, time, false,
false, false, false, authorId, name, accept);
new IntroductionResponse(sessionId, messageId, ROLE_INTRODUCER,
time, false, false, false, false, authorId, name,
accept);
return new IntroductionResponseReceivedEvent(contactId, ir);
}

View File

@@ -41,6 +41,7 @@ import java.util.logging.Logger;
import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.introduction.IntroduceeProtocolState.FINISHED;
import static org.briarproject.api.introduction.IntroductionConstants.ACCEPT;
import static org.briarproject.api.introduction.IntroductionConstants.ANSWERED;
import static org.briarproject.api.introduction.IntroductionConstants.AUTHOR_ID_1;
@@ -331,6 +332,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
BdfDictionary state =
getSessionState(txn, g, sessionId.getBytes());
int role = state.getLong(ROLE).intValue();
boolean local;
long time = msg.getLong(MESSAGE_TIME);
boolean accepted = msg.getBoolean(ACCEPT, false);
@@ -338,7 +340,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
AuthorId authorId;
String name;
if (type == TYPE_RESPONSE) {
if (state.getLong(ROLE) == ROLE_INTRODUCER) {
if (role == ROLE_INTRODUCER) {
if (!concernsThisContact(contactId, messageId, state)) {
// this response is not from contactId
continue;
@@ -350,22 +352,30 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
} else {
if (Arrays.equals(state.getRaw(NOT_OUR_RESPONSE),
messageId.getBytes())) {
// this response is not ours, don't include it
continue;
// this response is not ours,
// check if it was a decline
if (!accepted) {
local = false;
} else {
// don't include positive responses
continue;
}
} else {
local = true;
}
local = true;
authorId = new AuthorId(
state.getRaw(REMOTE_AUTHOR_ID));
name = state.getString(NAME);
}
IntroductionResponse ir = new IntroductionResponse(
sessionId, messageId, time, local, s.isSent(),
s.isSeen(), read, authorId, name, accepted);
sessionId, messageId, role, time, local,
s.isSent(), s.isSeen(), read, authorId, name,
accepted);
list.add(ir);
} else if (type == TYPE_REQUEST) {
String message;
boolean answered, exists, introducesOtherIdentity;
if (state.getLong(ROLE) == ROLE_INTRODUCER) {
if (role == ROLE_INTRODUCER) {
local = true;
authorId =
getAuthorIdForIntroducer(contactId, state);
@@ -380,15 +390,17 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
state.getRaw(REMOTE_AUTHOR_ID));
name = state.getString(NAME);
message = state.getOptionalString(MSG);
answered = state.getBoolean(ANSWERED);
boolean finished = state.getLong(STATE) ==
FINISHED.getValue();
answered = finished || state.getBoolean(ANSWERED);
exists = state.getBoolean(EXISTS);
introducesOtherIdentity =
state.getBoolean(REMOTE_AUTHOR_IS_US);
}
IntroductionRequest ir = new IntroductionRequest(
sessionId, messageId, time, local, s.isSent(),
s.isSeen(), read, authorId, name, accepted,
message, answered, exists,
sessionId, messageId, role, time, local,
s.isSent(), s.isSeen(), read, authorId, name,
accepted, message, answered, exists,
introducesOtherIdentity);
list.add(ir);
}