Merge branch 'conversation-manager' into 'master'

Use ConversationManager for private message retrieval

See merge request briar/briar!912
This commit is contained in:
akwizgran
2018-09-20 13:01:53 +00:00
74 changed files with 983 additions and 1497 deletions

View File

@@ -0,0 +1,10 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface Nameable {
String getName();
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.api.identity; package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.Nameable;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils; import org.briarproject.bramble.util.StringUtils;
@@ -13,7 +14,7 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_K
*/ */
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class Author { public class Author implements Nameable {
public enum Status { public enum Status {
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES

View File

@@ -41,13 +41,9 @@ import org.briarproject.briar.android.util.BriarNotificationBuilder;
import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.blog.event.BlogPostAddedEvent; import org.briarproject.briar.api.blog.event.BlogPostAddedEvent;
import org.briarproject.briar.api.forum.event.ForumPostReceivedEvent; import org.briarproject.briar.api.forum.event.ForumPostReceivedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent; import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent;
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent; import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import org.briarproject.briar.api.privategroup.event.GroupMessageAddedEvent; import org.briarproject.briar.api.privategroup.event.GroupMessageAddedEvent;
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
@@ -235,19 +231,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
} else if (e instanceof BlogPostAddedEvent) { } else if (e instanceof BlogPostAddedEvent) {
BlogPostAddedEvent b = (BlogPostAddedEvent) e; BlogPostAddedEvent b = (BlogPostAddedEvent) e;
showBlogPostNotification(b.getGroupId()); showBlogPostNotification(b.getGroupId());
} else if (e instanceof IntroductionRequestReceivedEvent) {
ContactId c = ((IntroductionRequestReceivedEvent) e).getContactId();
showContactNotification(c);
} else if (e instanceof IntroductionResponseReceivedEvent) {
ContactId c =
((IntroductionResponseReceivedEvent) e).getContactId();
showContactNotification(c);
} else if (e instanceof InvitationRequestReceivedEvent) {
ContactId c = ((InvitationRequestReceivedEvent) e).getContactId();
showContactNotification(c);
} else if (e instanceof InvitationResponseReceivedEvent) {
ContactId c = ((InvitationResponseReceivedEvent) e).getContactId();
showContactNotification(c);
} else if (e instanceof IntroductionSucceededEvent) { } else if (e instanceof IntroductionSucceededEvent) {
showIntroductionNotification(); showIntroductionNotification();
} }

View File

@@ -21,11 +21,11 @@ import org.briarproject.briar.android.controller.ActivityLifecycleController;
import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.Blog;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.blog.BlogManager; import org.briarproject.briar.api.blog.BlogManager;
import org.briarproject.briar.api.blog.BlogSharingManager; import org.briarproject.briar.api.blog.BlogSharingManager;
import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent; import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent;
import org.briarproject.briar.api.blog.event.BlogPostAddedEvent; import org.briarproject.briar.api.blog.event.BlogPostAddedEvent;
import org.briarproject.briar.api.sharing.InvitationResponse;
import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent; import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent;
import java.util.ArrayList; import java.util.ArrayList;
@@ -107,7 +107,7 @@ class BlogControllerImpl extends BaseControllerImpl
} else if (e instanceof BlogInvitationResponseReceivedEvent) { } else if (e instanceof BlogInvitationResponseReceivedEvent) {
BlogInvitationResponseReceivedEvent b = BlogInvitationResponseReceivedEvent b =
(BlogInvitationResponseReceivedEvent) e; (BlogInvitationResponseReceivedEvent) e;
InvitationResponse r = b.getResponse(); BlogInvitationResponse r = b.getMessageHeader();
if (r.getShareableId().equals(groupId) && r.wasAccepted()) { if (r.getShareableId().equals(groupId) && r.wasAccepted()) {
LOG.info("Blog invitation accepted"); LOG.info("Blog invitation accepted");
onBlogInvitationAccepted(b.getContactId()); onBlogInvitationAccepted(b.getContactId());

View File

@@ -36,19 +36,10 @@ import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.keyagreement.ContactExchangeActivity; import org.briarproject.briar.android.keyagreement.ContactExchangeActivity;
import org.briarproject.briar.android.view.BriarRecyclerView; import org.briarproject.briar.android.view.BriarRecyclerView;
import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.client.BaseMessageHeader;
import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.client.MessageTracker.GroupCount;
import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
import org.briarproject.briar.api.messaging.ConversationManager; import org.briarproject.briar.api.messaging.ConversationManager;
import org.briarproject.briar.api.messaging.PrivateMessageHeader; import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent; import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import org.briarproject.briar.api.sharing.InvitationRequest;
import org.briarproject.briar.api.sharing.InvitationResponse;
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -256,40 +247,16 @@ public class ContactListFragment extends BaseFragment implements EventListener {
PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e; PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
PrivateMessageHeader h = p.getMessageHeader(); PrivateMessageHeader h = p.getMessageHeader();
updateItem(p.getContactId(), h); updateItem(p.getContactId(), h);
} else if (e instanceof IntroductionRequestReceivedEvent) {
LOG.info("Introduction request received, updating item");
IntroductionRequestReceivedEvent m =
(IntroductionRequestReceivedEvent) e;
IntroductionRequest ir = m.getIntroductionRequest();
updateItem(m.getContactId(), ir);
} else if (e instanceof IntroductionResponseReceivedEvent) {
LOG.info("Introduction response received, updating item");
IntroductionResponseReceivedEvent m =
(IntroductionResponseReceivedEvent) e;
IntroductionResponse ir = m.getIntroductionResponse();
updateItem(m.getContactId(), ir);
} else if (e instanceof InvitationRequestReceivedEvent) {
LOG.info("Invitation Request received, update item");
InvitationRequestReceivedEvent m =
(InvitationRequestReceivedEvent) e;
InvitationRequest ir = m.getRequest();
updateItem(m.getContactId(), ir);
} else if (e instanceof InvitationResponseReceivedEvent) {
LOG.info("Invitation response received, updating item");
InvitationResponseReceivedEvent m =
(InvitationResponseReceivedEvent) e;
InvitationResponse ir = m.getResponse();
updateItem(m.getContactId(), ir);
} }
} }
private void updateItem(ContactId c, BaseMessageHeader h) { private void updateItem(ContactId c, PrivateMessageHeader h) {
runOnUiThreadUnlessDestroyed(() -> { runOnUiThreadUnlessDestroyed(() -> {
adapter.incrementRevision(); adapter.incrementRevision();
int position = adapter.findItemPosition(c); int position = adapter.findItemPosition(c);
ContactListItem item = adapter.getItemAt(position); ContactListItem item = adapter.getItemAt(position);
if (item != null) { if (item != null) {
ConversationItem i = ConversationItem.from(getContext(), h); ConversationItem i = ConversationItem.from(getContext(), "", h);
item.addMessage(i); item.addMessage(i);
adapter.updateItemAt(position, item); adapter.updateItemAt(position, item);
} }

View File

@@ -1,8 +1,11 @@
package org.briarproject.briar.android.contact; package org.briarproject.briar.android.contact;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.Observer;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread; import android.support.annotation.UiThread;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
@@ -62,24 +65,15 @@ import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.forum.ForumSharingManager; import org.briarproject.briar.api.forum.ForumSharingManager;
import org.briarproject.briar.api.introduction.IntroductionManager; import org.briarproject.briar.api.introduction.IntroductionManager;
import org.briarproject.briar.api.introduction.IntroductionMessage; import org.briarproject.briar.api.messaging.ConversationManager;
import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.MessagingManager;
import org.briarproject.briar.api.messaging.PrivateMessage; import org.briarproject.briar.api.messaging.PrivateMessage;
import org.briarproject.briar.api.messaging.PrivateMessageFactory; import org.briarproject.briar.api.messaging.PrivateMessageFactory;
import org.briarproject.briar.api.messaging.PrivateMessageHeader; import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.messaging.PrivateResponse;
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent; import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
import org.briarproject.briar.api.sharing.InvitationMessage;
import org.briarproject.briar.api.sharing.InvitationRequest;
import org.briarproject.briar.api.sharing.InvitationResponse;
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
import org.thoughtcrime.securesms.components.util.FutureTaskListener;
import org.thoughtcrime.securesms.components.util.ListenableFutureTask;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@@ -87,13 +81,10 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import de.hdodenhof.circleimageview.CircleImageView; import de.hdodenhof.circleimageview.CircleImageView;
@@ -138,6 +129,7 @@ public class ConversationActivity extends BriarActivity
Executor cryptoExecutor; Executor cryptoExecutor;
private final Map<MessageId, String> bodyCache = new ConcurrentHashMap<>(); private final Map<MessageId, String> bodyCache = new ConcurrentHashMap<>();
private final MutableLiveData<String> contactName = new MutableLiveData<>();
private ConversationAdapter adapter; private ConversationAdapter adapter;
private Toolbar toolbar; private Toolbar toolbar;
@@ -147,24 +139,14 @@ public class ConversationActivity extends BriarActivity
private BriarRecyclerView list; private BriarRecyclerView list;
private TextInputView textInputView; private TextInputView textInputView;
private final ListenableFutureTask<String> contactNameTask =
new ListenableFutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
Contact c = contactManager.getContact(contactId);
contactName = c.getAuthor().getName();
return c.getAuthor().getName();
}
});
private final AtomicBoolean contactNameTaskStarted =
new AtomicBoolean(false);
// Fields that are accessed from background threads must be volatile // Fields that are accessed from background threads must be volatile
@Inject @Inject
volatile ContactManager contactManager; volatile ContactManager contactManager;
@Inject @Inject
volatile MessagingManager messagingManager; volatile MessagingManager messagingManager;
@Inject @Inject
volatile ConversationManager conversationManager;
@Inject
volatile EventBus eventBus; volatile EventBus eventBus;
@Inject @Inject
volatile SettingsManager settingsManager; volatile SettingsManager settingsManager;
@@ -181,8 +163,6 @@ public class ConversationActivity extends BriarActivity
private volatile ContactId contactId; private volatile ContactId contactId;
@Nullable @Nullable
private volatile String contactName;
@Nullable
private volatile AuthorId contactAuthorId; private volatile AuthorId contactAuthorId;
@Nullable @Nullable
private volatile GroupId messagingGroupId; private volatile GroupId messagingGroupId;
@@ -294,9 +274,9 @@ public class ConversationActivity extends BriarActivity
runOnDbThread(() -> { runOnDbThread(() -> {
try { try {
long start = now(); long start = now();
if (contactName == null || contactAuthorId == null) { if (contactAuthorId == null) {
Contact contact = contactManager.getContact(contactId); Contact contact = contactManager.getContact(contactId);
contactName = contact.getAuthor().getName(); contactName.postValue(contact.getAuthor().getName());
contactAuthorId = contact.getAuthor().getId(); contactAuthorId = contact.getAuthor().getId();
} }
logDuration(LOG, "Loading contact", start); logDuration(LOG, "Loading contact", start);
@@ -310,12 +290,13 @@ public class ConversationActivity extends BriarActivity
}); });
} }
// contactAuthorId and contactName are expected to be set
private void displayContactDetails() { private void displayContactDetails() {
runOnUiThreadUnlessDestroyed(() -> { runOnUiThreadUnlessDestroyed(() -> {
//noinspection ConstantConditions //noinspection ConstantConditions
toolbarAvatar.setImageDrawable( toolbarAvatar.setImageDrawable(
new IdenticonDrawable(contactAuthorId.getBytes())); new IdenticonDrawable(contactAuthorId.getBytes()));
toolbarTitle.setText(contactName); toolbarTitle.setText(contactName.getValue());
}); });
} }
@@ -343,23 +324,9 @@ public class ConversationActivity extends BriarActivity
try { try {
long start = now(); long start = now();
Collection<PrivateMessageHeader> headers = Collection<PrivateMessageHeader> headers =
messagingManager.getMessageHeaders(contactId); conversationManager.getMessageHeaders(contactId);
Collection<IntroductionMessage> introductions =
introductionManager.getIntroductionMessages(contactId);
Collection<InvitationMessage> forumInvitations =
forumSharingManager.getInvitationMessages(contactId);
Collection<InvitationMessage> blogInvitations =
blogSharingManager.getInvitationMessages(contactId);
Collection<InvitationMessage> groupInvitations =
groupInvitationManager.getInvitationMessages(contactId);
List<InvitationMessage> invitations = new ArrayList<>(
forumInvitations.size() + blogInvitations.size() +
groupInvitations.size());
invitations.addAll(forumInvitations);
invitations.addAll(blogInvitations);
invitations.addAll(groupInvitations);
logDuration(LOG, "Loading messages", start); logDuration(LOG, "Loading messages", start);
displayMessages(revision, headers, introductions, invitations); displayMessages(revision, headers);
} catch (NoSuchContactException e) { } catch (NoSuchContactException e) {
finishOnUiThread(); finishOnUiThread();
} catch (DbException e) { } catch (DbException e) {
@@ -369,15 +336,12 @@ public class ConversationActivity extends BriarActivity
} }
private void displayMessages(int revision, private void displayMessages(int revision,
Collection<PrivateMessageHeader> headers, Collection<PrivateMessageHeader> headers) {
Collection<IntroductionMessage> introductions,
Collection<InvitationMessage> invitations) {
runOnUiThreadUnlessDestroyed(() -> { runOnUiThreadUnlessDestroyed(() -> {
if (revision == adapter.getRevision()) { if (revision == adapter.getRevision()) {
adapter.incrementRevision(); adapter.incrementRevision();
textInputView.setSendButtonEnabled(true); textInputView.setSendButtonEnabled(true);
List<ConversationItem> items = createItems(headers, List<ConversationItem> items = createItems(headers);
introductions, invitations);
adapter.addAll(items); adapter.addAll(items);
list.showData(); list.showData();
// Scroll to the bottom // Scroll to the bottom
@@ -396,38 +360,17 @@ public class ConversationActivity extends BriarActivity
*/ */
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
private List<ConversationItem> createItems( private List<ConversationItem> createItems(
Collection<PrivateMessageHeader> headers, Collection<PrivateMessageHeader> headers) {
Collection<IntroductionMessage> introductions, List<ConversationItem> items = new ArrayList<>(headers.size());
Collection<InvitationMessage> invitations) {
int size =
headers.size() + introductions.size() + invitations.size();
List<ConversationItem> items = new ArrayList<>(size);
for (PrivateMessageHeader h : headers) { for (PrivateMessageHeader h : headers) {
ConversationItem item = ConversationItem.from(h);
String body = bodyCache.get(h.getId());
if (body == null) loadMessageBody(h.getId());
else item.setBody(body);
items.add(item);
}
for (IntroductionMessage m : introductions) {
ConversationItem item; ConversationItem item;
if (m instanceof IntroductionRequest) { if (h instanceof PrivateRequest || h instanceof PrivateResponse) {
IntroductionRequest i = (IntroductionRequest) m; item = ConversationItem.from(this, contactName.getValue(), h);
item = ConversationItem.from(this, contactName, i);
} else { } else {
IntroductionResponse i = (IntroductionResponse) m; item = ConversationItem.from(h);
item = ConversationItem.from(this, contactName, i); String body = bodyCache.get(h.getId());
} if (body == null) loadMessageBody(h.getId());
items.add(item); else item.setBody(body);
}
for (InvitationMessage i : invitations) {
ConversationItem item;
if (i instanceof InvitationRequest) {
InvitationRequest r = (InvitationRequest) i;
item = ConversationItem.from(this, contactName, r);
} else {
InvitationResponse r = (InvitationResponse) i;
item = ConversationItem.from(this, contactName, r);
} }
items.add(item); items.add(item);
} }
@@ -476,9 +419,7 @@ public class ConversationActivity extends BriarActivity
PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e; PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
if (p.getContactId().equals(contactId)) { if (p.getContactId().equals(contactId)) {
LOG.info("Message received, adding"); LOG.info("Message received, adding");
PrivateMessageHeader h = p.getMessageHeader(); onNewPrivateMessage(p.getMessageHeader());
addConversationItem(ConversationItem.from(h));
loadMessageBody(h.getId());
} }
} else if (e instanceof MessagesSentEvent) { } else if (e instanceof MessagesSentEvent) {
MessagesSentEvent m = (MessagesSentEvent) e; MessagesSentEvent m = (MessagesSentEvent) e;
@@ -504,38 +445,6 @@ public class ConversationActivity extends BriarActivity
LOG.info("Contact disconnected"); LOG.info("Contact disconnected");
displayContactOnlineStatus(); displayContactOnlineStatus();
} }
} else if (e instanceof IntroductionRequestReceivedEvent) {
IntroductionRequestReceivedEvent event =
(IntroductionRequestReceivedEvent) e;
if (event.getContactId().equals(contactId)) {
LOG.info("Introduction request received, adding...");
IntroductionRequest ir = event.getIntroductionRequest();
handleIntroductionRequest(ir);
}
} else if (e instanceof IntroductionResponseReceivedEvent) {
IntroductionResponseReceivedEvent event =
(IntroductionResponseReceivedEvent) e;
if (event.getContactId().equals(contactId)) {
LOG.info("Introduction response received, adding...");
IntroductionResponse ir = event.getIntroductionResponse();
handleIntroductionResponse(ir);
}
} else if (e instanceof InvitationRequestReceivedEvent) {
InvitationRequestReceivedEvent event =
(InvitationRequestReceivedEvent) e;
if (event.getContactId().equals(contactId)) {
LOG.info("Invitation received, adding...");
InvitationRequest ir = event.getRequest();
handleInvitationRequest(ir);
}
} else if (e instanceof InvitationResponseReceivedEvent) {
InvitationResponseReceivedEvent event =
(InvitationResponseReceivedEvent) e;
if (event.getContactId().equals(contactId)) {
LOG.info("Invitation response received, adding...");
InvitationResponse ir = event.getResponse();
handleInvitationResponse(ir);
}
} }
} }
@@ -548,84 +457,39 @@ public class ConversationActivity extends BriarActivity
}); });
} }
private void handleIntroductionRequest(IntroductionRequest m) { private void onNewPrivateMessage(PrivateMessageHeader h) {
getContactNameTask().addListener(new FutureTaskListener<String>() { runOnUiThreadUnlessDestroyed(() -> {
@Override if (h instanceof PrivateRequest || h instanceof PrivateResponse) {
public void onSuccess(String contactName) { String cName = contactName.getValue();
runOnUiThreadUnlessDestroyed(() -> { if (cName == null) {
ConversationItem item = ConversationItem // Wait for the contact name to be loaded
.from(ConversationActivity.this, contactName, m); contactName.observe(this, new Observer<String>() {
addConversationItem(item); @Override
}); public void onChanged(@Nullable String cName) {
} if (cName != null) {
onNewPrivateRequestOrResponse(h, cName);
@Override contactName.removeObserver(this);
public void onFailure(Throwable exception) { }
runOnUiThreadUnlessDestroyed( }
() -> handleDbException((DbException) exception)); });
} else {
onNewPrivateRequestOrResponse(h, cName);
}
} else {
addConversationItem(ConversationItem.from(h));
loadMessageBody(h.getId());
} }
}); });
} }
private void handleIntroductionResponse(IntroductionResponse m) { @UiThread
getContactNameTask().addListener(new FutureTaskListener<String>() { private void onNewPrivateRequestOrResponse(PrivateMessageHeader h,
@Override String cName) {
public void onSuccess(String contactName) { addConversationItem(ConversationItem.from(this, cName, h));
runOnUiThreadUnlessDestroyed(() -> {
ConversationItem item = ConversationItem
.from(ConversationActivity.this, contactName, m);
addConversationItem(item);
});
}
@Override
public void onFailure(Throwable exception) {
runOnUiThreadUnlessDestroyed(
() -> handleDbException((DbException) exception));
}
});
} }
private void handleInvitationRequest(InvitationRequest m) { private void markMessages(Collection<MessageId> messageIds, boolean sent,
getContactNameTask().addListener(new FutureTaskListener<String>() { boolean seen) {
@Override
public void onSuccess(String contactName) {
runOnUiThreadUnlessDestroyed(() -> {
ConversationItem item = ConversationItem
.from(ConversationActivity.this, contactName, m);
addConversationItem(item);
});
}
@Override
public void onFailure(Throwable exception) {
runOnUiThreadUnlessDestroyed(
() -> handleDbException((DbException) exception));
}
});
}
private void handleInvitationResponse(InvitationResponse m) {
getContactNameTask().addListener(new FutureTaskListener<String>() {
@Override
public void onSuccess(String contactName) {
runOnUiThreadUnlessDestroyed(() -> {
ConversationItem item = ConversationItem
.from(ConversationActivity.this, contactName, m);
addConversationItem(item);
});
}
@Override
public void onFailure(Throwable exception) {
runOnUiThreadUnlessDestroyed(
() -> handleDbException((DbException) exception));
}
});
}
private void markMessages(Collection<MessageId> messageIds,
boolean sent, boolean seen) {
runOnUiThreadUnlessDestroyed(() -> { runOnUiThreadUnlessDestroyed(() -> {
adapter.incrementRevision(); adapter.incrementRevision();
Set<MessageId> messages = new HashSet<>(messageIds); Set<MessageId> messages = new HashSet<>(messageIds);
@@ -678,7 +542,8 @@ public class ConversationActivity extends BriarActivity
//noinspection ConstantConditions init in loadGroupId() //noinspection ConstantConditions init in loadGroupId()
storeMessage(privateMessageFactory.createPrivateMessage( storeMessage(privateMessageFactory.createPrivateMessage(
messagingGroupId, timestamp, body), body); messagingGroupId, timestamp, body), body);
} catch (FormatException e) {throw new RuntimeException(e); } catch (FormatException e) {
throw new RuntimeException(e);
} }
}); });
} }
@@ -823,7 +688,7 @@ public class ConversationActivity extends BriarActivity
@UiThread @UiThread
@Override @Override
public void respondToRequest(ConversationRequestItem item, boolean accept) { public void respondToRequest(ConversationRequestItem item, boolean accept) {
item.setAnswered(true); item.setAnswered();
int position = adapter.findItemPosition(item); int position = adapter.findItemPosition(item);
if (position != INVALID_POSITION) { if (position != INVALID_POSITION) {
adapter.notifyItemChanged(position, item); adapter.notifyItemChanged(position, item);
@@ -908,11 +773,4 @@ public class ConversationActivity extends BriarActivity
throws DbException { throws DbException {
groupInvitationManager.respondToInvitation(contactId, id, accept); groupInvitationManager.respondToInvitation(contactId, id, accept);
} }
private ListenableFutureTask<String> getContactNameTask() {
if (!contactNameTaskStarted.getAndSet(true))
runOnDbThread(contactNameTask);
return contactNameTask;
}
} }

View File

@@ -2,39 +2,23 @@ package org.briarproject.briar.android.contact;
import android.content.Context; import android.content.Context;
import android.support.annotation.LayoutRes; import android.support.annotation.LayoutRes;
import android.support.annotation.StringRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.R;
import org.briarproject.briar.android.contact.ConversationRequestItem.RequestType;
import org.briarproject.briar.api.blog.BlogInvitationRequest;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.client.BaseMessageHeader;
import org.briarproject.briar.api.forum.ForumInvitationRequest;
import org.briarproject.briar.api.forum.ForumInvitationResponse;
import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.messaging.PrivateMessageHeader; import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest; import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse; import org.briarproject.briar.api.messaging.PrivateResponse;
import org.briarproject.briar.api.sharing.InvitationRequest;
import org.briarproject.briar.api.sharing.InvitationResponse;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.NotThreadSafe;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.BLOG;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.FORUM;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.GROUP;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.INTRODUCTION;
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
abstract class ConversationItem { abstract class ConversationItem {
protected @Nullable String body; @Nullable
protected String body;
private final MessageId id; private final MessageId id;
private final GroupId groupId; private final GroupId groupId;
private final long time; private final long time;
@@ -88,205 +72,37 @@ abstract class ConversationItem {
} }
static ConversationItem from(Context ctx, String contactName, static ConversationItem from(Context ctx, String contactName,
IntroductionRequest ir) { PrivateMessageHeader h) {
if (ir.isLocal()) { if (h.isLocal()) {
String text = ctx.getString(R.string.introduction_request_sent, return fromLocal(ctx, contactName, h);
contactName, ir.getName());
return new ConversationNoticeOutItem(ir.getMessageId(),
ir.getGroupId(), text, ir.getMessage(), ir.getTimestamp(),
ir.isSent(), ir.isSeen());
} else { } else {
String text; return fromRemote(ctx, contactName, h);
if (ir.wasAnswered()) {
text = ctx.getString(
R.string.introduction_request_answered_received,
contactName, ir.getName());
} else if (ir.contactExists()){
text = ctx.getString(
R.string.introduction_request_exists_received,
contactName, ir.getName());
} else {
text = ctx.getString(R.string.introduction_request_received,
contactName, ir.getName());
}
return new ConversationRequestItem(ir.getMessageId(),
ir.getGroupId(), INTRODUCTION, ir.getSessionId(), text,
ir.getMessage(), ir.getTimestamp(), ir.isRead(), null,
ir.wasAnswered(), false);
} }
} }
static ConversationItem from(Context ctx, String contactName, private static ConversationItem fromLocal(Context ctx, String contactName,
IntroductionResponse ir) { PrivateMessageHeader h) {
if (ir.isLocal()) { if (h instanceof PrivateRequest) {
String text; PrivateRequest r = (PrivateRequest) h;
if (ir.wasAccepted()) { return new ConversationNoticeOutItem(ctx, contactName, r);
text = ctx.getString( } else if (h instanceof PrivateResponse) {
R.string.introduction_response_accepted_sent, PrivateResponse r = (PrivateResponse) h;
ir.getName()); return new ConversationNoticeOutItem(ctx, contactName, r);
text += "\n\n" + ctx.getString(
R.string.introduction_response_accepted_sent_info,
ir.getName());
} else {
text = ctx.getString(
R.string.introduction_response_declined_sent,
ir.getName());
}
return new ConversationNoticeOutItem(ir.getMessageId(),
ir.getGroupId(), text, null, ir.getTimestamp(), ir.isSent(),
ir.isSeen());
} else { } else {
String text; return new ConversationMessageOutItem(h);
if (ir.wasAccepted()) {
text = ctx.getString(
R.string.introduction_response_accepted_received,
contactName, ir.getName());
} else {
if (ir.isIntroducer()) {
text = ctx.getString(
R.string.introduction_response_declined_received,
contactName, ir.getName());
} else {
text = ctx.getString(
R.string.introduction_response_declined_received_by_introducee,
contactName, ir.getName());
}
}
return new ConversationNoticeInItem(ir.getMessageId(),
ir.getGroupId(), text, null, ir.getTimestamp(),
ir.isRead());
} }
} }
static ConversationItem from(Context ctx, String contactName, private static ConversationItem fromRemote(Context ctx, String contactName,
InvitationRequest ir) { PrivateMessageHeader h) {
if (ir.isLocal()) { if (h instanceof PrivateRequest) {
String text; PrivateRequest r = (PrivateRequest) h;
if (ir instanceof ForumInvitationRequest) { return new ConversationRequestItem(ctx, contactName, r);
text = ctx.getString(R.string.forum_invitation_sent, } else if (h instanceof PrivateResponse) {
((ForumInvitationRequest) ir).getForumName(), PrivateResponse r = (PrivateResponse) h;
contactName); return new ConversationNoticeInItem(ctx, contactName, r);
} else if (ir instanceof BlogInvitationRequest) {
text = ctx.getString(R.string.blogs_sharing_invitation_sent,
((BlogInvitationRequest) ir).getBlogAuthorName(),
contactName);
} else if (ir instanceof GroupInvitationRequest) {
text = ctx.getString(
R.string.groups_invitations_invitation_sent,
contactName, ir.getShareable().getName());
} else {
throw new IllegalArgumentException("Unknown InvitationRequest");
}
return new ConversationNoticeOutItem(ir.getId(), ir.getGroupId(),
text, ir.getMessage(), ir.getTimestamp(), ir.isSent(),
ir.isSeen());
} else { } else {
String text; return new ConversationMessageInItem(h);
RequestType type;
if (ir instanceof ForumInvitationRequest) {
text = ctx.getString(R.string.forum_invitation_received,
contactName,
((ForumInvitationRequest) ir).getForumName());
type = FORUM;
} else if (ir instanceof BlogInvitationRequest) {
text = ctx.getString(R.string.blogs_sharing_invitation_received,
contactName,
((BlogInvitationRequest) ir).getBlogAuthorName());
type = BLOG;
} else if (ir instanceof GroupInvitationRequest) {
text = ctx.getString(
R.string.groups_invitations_invitation_received,
contactName, ir.getShareable().getName());
type = GROUP;
} else {
throw new IllegalArgumentException("Unknown InvitationRequest");
}
return new ConversationRequestItem(ir.getId(),
ir.getGroupId(), type, ir.getSessionId(), text,
ir.getMessage(), ir.getTimestamp(), ir.isRead(),
ir.getShareable().getId(), !ir.isAvailable(),
ir.canBeOpened());
}
}
static ConversationItem from(Context ctx, String contactName,
InvitationResponse ir) {
@StringRes int res;
if (ir.isLocal()) {
if (ir.wasAccepted()) {
if (ir instanceof ForumInvitationResponse) {
res = R.string.forum_invitation_response_accepted_sent;
} else if (ir instanceof BlogInvitationResponse) {
res = R.string.blogs_sharing_response_accepted_sent;
} else if (ir instanceof GroupInvitationResponse) {
res = R.string.groups_invitations_response_accepted_sent;
} else {
throw new IllegalArgumentException(
"Unknown InvitationResponse");
}
} else {
if (ir instanceof ForumInvitationResponse) {
res = R.string.forum_invitation_response_declined_sent;
} else if (ir instanceof BlogInvitationResponse) {
res = R.string.blogs_sharing_response_declined_sent;
} else if (ir instanceof GroupInvitationResponse) {
res = R.string.groups_invitations_response_declined_sent;
} else {
throw new IllegalArgumentException(
"Unknown InvitationResponse");
}
}
String text = ctx.getString(res, contactName);
return new ConversationNoticeOutItem(ir.getId(), ir.getGroupId(),
text, null, ir.getTimestamp(), ir.isSent(), ir.isSeen());
} else {
if (ir.wasAccepted()) {
if (ir instanceof ForumInvitationResponse) {
res = R.string.forum_invitation_response_accepted_received;
} else if (ir instanceof BlogInvitationResponse) {
res = R.string.blogs_sharing_response_accepted_received;
} else if (ir instanceof GroupInvitationResponse) {
res = R.string.groups_invitations_response_accepted_received;
} else {
throw new IllegalArgumentException(
"Unknown InvitationResponse");
}
} else {
if (ir instanceof ForumInvitationResponse) {
res = R.string.forum_invitation_response_declined_received;
} else if (ir instanceof BlogInvitationResponse) {
res = R.string.blogs_sharing_response_declined_received;
} else if (ir instanceof GroupInvitationResponse) {
res = R.string.groups_invitations_response_declined_received;
} else {
throw new IllegalArgumentException(
"Unknown InvitationResponse");
}
}
String text = ctx.getString(res, contactName);
return new ConversationNoticeInItem(ir.getId(), ir.getGroupId(),
text, null, ir.getTimestamp(), ir.isRead());
}
}
/**
* This method should not be used to display the resulting ConversationItem
* in the UI, but only to update list information based on the
* BaseMessageHeader.
**/
static ConversationItem from(Context ctx, BaseMessageHeader h) {
if (h instanceof PrivateMessageHeader) {
return from((PrivateMessageHeader) h);
} else if(h instanceof IntroductionRequest) {
return from(ctx, "", (IntroductionRequest) h);
} else if(h instanceof IntroductionResponse) {
return from(ctx, "", (IntroductionResponse) h);
} else if(h instanceof InvitationRequest) {
return from(ctx, "", (InvitationRequest) h);
} else if(h instanceof InvitationResponse) {
return from(ctx, "", (InvitationResponse) h);
} else {
throw new IllegalArgumentException("Unknown message header");
} }
} }

View File

@@ -1,11 +1,18 @@
package org.briarproject.briar.android.contact; package org.briarproject.briar.android.contact;
import android.content.Context;
import android.support.annotation.LayoutRes; import android.support.annotation.LayoutRes;
import android.support.annotation.StringRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.forum.ForumInvitationResponse;
import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.messaging.PrivateResponse;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.NotThreadSafe;
@@ -24,6 +31,13 @@ class ConversationNoticeInItem extends ConversationItem {
this.msgText = msgText; this.msgText = msgText;
} }
public ConversationNoticeInItem(Context ctx, String contactName,
PrivateResponse r) {
super(r.getId(), r.getGroupId(), getText(ctx, contactName, r),
r.getTimestamp(), r.isRead());
this.msgText = null;
}
@Nullable @Nullable
String getMsgText() { String getMsgText() {
return msgText; return msgText;
@@ -40,4 +54,54 @@ class ConversationNoticeInItem extends ConversationItem {
return R.layout.list_item_conversation_notice_in; return R.layout.list_item_conversation_notice_in;
} }
private static String getText(Context ctx, String contactName,
PrivateResponse r) {
if (r.wasAccepted()) {
if (r instanceof IntroductionResponse) {
IntroductionResponse ir = (IntroductionResponse) r;
return ctx.getString(
R.string.introduction_response_accepted_received,
contactName, ir.getIntroducedAuthor().getName());
} else if (r instanceof ForumInvitationResponse) {
return ctx.getString(
R.string.forum_invitation_response_accepted_received,
contactName);
} else if (r instanceof BlogInvitationResponse) {
return ctx.getString(
R.string.blogs_sharing_response_accepted_received,
contactName);
} else if (r instanceof GroupInvitationResponse) {
return ctx.getString(
R.string.groups_invitations_response_accepted_received,
contactName);
}
} else {
if (r instanceof IntroductionResponse) {
IntroductionResponse ir = (IntroductionResponse) r;
@StringRes int res;
if (ir.isIntroducer()) {
res = R.string.introduction_response_declined_received;
} else {
res =
R.string.introduction_response_declined_received_by_introducee;
}
return ctx.getString(res, contactName,
ir.getIntroducedAuthor().getName());
} else if (r instanceof ForumInvitationResponse) {
return ctx.getString(
R.string.forum_invitation_response_declined_received,
contactName);
} else if (r instanceof BlogInvitationResponse) {
return ctx.getString(
R.string.blogs_sharing_response_declined_received,
contactName);
} else if (r instanceof GroupInvitationResponse) {
return ctx.getString(
R.string.groups_invitations_response_declined_received,
contactName);
}
}
throw new IllegalArgumentException("Unknown PrivateResponse");
}
} }

View File

@@ -1,11 +1,20 @@
package org.briarproject.briar.android.contact; package org.briarproject.briar.android.contact;
import android.content.Context;
import android.support.annotation.LayoutRes; import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.api.blog.BlogInvitationRequest;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.forum.ForumInvitationRequest;
import org.briarproject.briar.api.forum.ForumInvitationResponse;
import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.messaging.PrivateResponse;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.NotThreadSafe;
@@ -17,11 +26,18 @@ class ConversationNoticeOutItem extends ConversationOutItem {
@Nullable @Nullable
private final String msgText; private final String msgText;
ConversationNoticeOutItem(MessageId id, GroupId groupId, ConversationNoticeOutItem(Context ctx, String contactName,
String text, @Nullable String msgText, long time, PrivateRequest r) {
boolean sent, boolean seen) { super(r.getId(), r.getGroupId(), getText(ctx, contactName, r),
super(id, groupId, text, time, sent, seen); r.getTimestamp(), r.isSent(), r.isSeen());
this.msgText = msgText; this.msgText = r.getMessage();
}
ConversationNoticeOutItem(Context ctx, String contactName,
PrivateResponse r) {
super(r.getId(), r.getGroupId(), getText(ctx, contactName, r),
r.getTimestamp(), r.isSent(), r.isSeen());
this.msgText = null;
} }
@Nullable @Nullable
@@ -35,4 +51,57 @@ class ConversationNoticeOutItem extends ConversationOutItem {
return R.layout.list_item_conversation_notice_out; return R.layout.list_item_conversation_notice_out;
} }
private static String getText(Context ctx, String contactName,
PrivateRequest r) {
if (r instanceof IntroductionRequest) {
return ctx.getString(R.string.introduction_request_sent,
contactName, r.getName());
} else if (r instanceof ForumInvitationRequest) {
return ctx.getString(R.string.forum_invitation_sent,
r.getName(), contactName);
} else if (r instanceof BlogInvitationRequest) {
return ctx.getString(R.string.blogs_sharing_invitation_sent,
r.getName(), contactName);
} else if (r instanceof GroupInvitationRequest) {
return ctx.getString(R.string.groups_invitations_invitation_sent,
contactName, r.getName());
}
throw new IllegalArgumentException("Unknown PrivateRequest");
}
private static String getText(Context ctx, String contactName,
PrivateResponse r) {
if (r.wasAccepted()) {
if (r instanceof IntroductionResponse) {
String name = ((IntroductionResponse) r).getIntroducedAuthor()
.getName();
return ctx.getString(
R.string.introduction_response_accepted_sent,
name) + "\n\n" + ctx.getString(
R.string.introduction_response_accepted_sent_info,
name);
} else if (r instanceof ForumInvitationResponse) {
return ctx.getString(R.string.forum_invitation_response_accepted_sent, contactName);
} else if (r instanceof BlogInvitationResponse) {
return ctx.getString(R.string.blogs_sharing_response_accepted_sent, contactName);
} else if (r instanceof GroupInvitationResponse) {
return ctx.getString(R.string.groups_invitations_response_accepted_sent, contactName);
}
} else {
if (r instanceof IntroductionResponse) {
String name = ((IntroductionResponse) r).getIntroducedAuthor()
.getName();
return ctx.getString(
R.string.introduction_response_declined_sent, name);
} else if (r instanceof ForumInvitationResponse) {
return ctx.getString(R.string.forum_invitation_response_declined_sent, contactName);
} else if (r instanceof BlogInvitationResponse) {
return ctx.getString(R.string.blogs_sharing_response_declined_sent, contactName);
} else if (r instanceof GroupInvitationResponse) {
return ctx.getString(R.string.groups_invitations_response_declined_sent, contactName);
}
}
throw new IllegalArgumentException("Unknown PrivateResponse");
}
} }

View File

@@ -1,16 +1,28 @@
package org.briarproject.briar.android.contact; package org.briarproject.briar.android.contact;
import android.content.Context;
import android.support.annotation.LayoutRes; import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.api.blog.BlogInvitationRequest;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.forum.ForumInvitationRequest;
import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.sharing.InvitationRequest;
import org.briarproject.briar.api.sharing.Shareable;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.NotThreadSafe;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.BLOG;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.FORUM;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.GROUP;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.INTRODUCTION;
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
class ConversationRequestItem extends ConversationNoticeInItem { class ConversationRequestItem extends ConversationNoticeInItem {
@@ -24,17 +36,20 @@ class ConversationRequestItem extends ConversationNoticeInItem {
private final boolean canBeOpened; private final boolean canBeOpened;
private boolean answered; private boolean answered;
ConversationRequestItem(MessageId id, GroupId groupId, ConversationRequestItem(Context ctx, String contactName,
RequestType requestType, SessionId sessionId, String text, PrivateRequest r) {
@Nullable String msgText, long time, boolean read, super(r.getId(), r.getGroupId(), getText(ctx, contactName, r),
@Nullable GroupId requestedGroupId, boolean answered, r.getMessage(), r.getTimestamp(), r.isRead());
boolean canBeOpened) { this.requestType = getType(r);
super(id, groupId, text, msgText, time, read); this.sessionId = r.getSessionId();
this.requestType = requestType; this.answered = r.wasAnswered();
this.sessionId = sessionId; if (r instanceof InvitationRequest) {
this.requestedGroupId = requestedGroupId; this.requestedGroupId = ((Shareable) r.getNameable()).getId();
this.answered = answered; this.canBeOpened = ((InvitationRequest) r).canBeOpened();
this.canBeOpened = canBeOpened; } else {
this.requestedGroupId = null;
this.canBeOpened = false;
}
} }
RequestType getRequestType() { RequestType getRequestType() {
@@ -54,8 +69,8 @@ class ConversationRequestItem extends ConversationNoticeInItem {
return answered; return answered;
} }
void setAnswered(boolean answered) { void setAnswered() {
this.answered = answered; this.answered = true;
} }
public boolean canBeOpened() { public boolean canBeOpened() {
@@ -68,4 +83,46 @@ class ConversationRequestItem extends ConversationNoticeInItem {
return R.layout.list_item_conversation_request; return R.layout.list_item_conversation_request;
} }
private static String getText(Context ctx, String contactName,
PrivateRequest r) {
if (r instanceof IntroductionRequest) {
if (r.wasAnswered()) {
return ctx.getString(
R.string.introduction_request_answered_received,
contactName, r.getName());
} else if (((IntroductionRequest) r).isContact()) {
return ctx.getString(
R.string.introduction_request_exists_received,
contactName, r.getName());
} else {
return ctx.getString(R.string.introduction_request_received,
contactName, r.getName());
}
} else if (r instanceof ForumInvitationRequest) {
return ctx.getString(R.string.forum_invitation_received,
contactName, r.getName());
} else if (r instanceof BlogInvitationRequest) {
return ctx.getString(R.string.blogs_sharing_invitation_received,
contactName, r.getName());
} else if (r instanceof GroupInvitationRequest) {
return ctx.getString(
R.string.groups_invitations_invitation_received,
contactName, r.getName());
}
throw new IllegalArgumentException("Unknown PrivateRequest");
}
private static RequestType getType(PrivateRequest r) {
if (r instanceof IntroductionRequest) {
return INTRODUCTION;
} else if (r instanceof ForumInvitationRequest) {
return FORUM;
} else if (r instanceof BlogInvitationRequest) {
return BLOG;
} else if (r instanceof GroupInvitationRequest) {
return GROUP;
}
throw new IllegalArgumentException("Unknown PrivateRequest");
}
} }

View File

@@ -84,11 +84,10 @@ class ForumControllerImpl extends
} else if (e instanceof ForumInvitationResponseReceivedEvent) { } else if (e instanceof ForumInvitationResponseReceivedEvent) {
ForumInvitationResponseReceivedEvent f = ForumInvitationResponseReceivedEvent f =
(ForumInvitationResponseReceivedEvent) e; (ForumInvitationResponseReceivedEvent) e;
ForumInvitationResponse r = ForumInvitationResponse r = f.getMessageHeader();
(ForumInvitationResponse) f.getResponse();
if (r.getShareableId().equals(getGroupId()) && r.wasAccepted()) { if (r.getShareableId().equals(getGroupId()) && r.wasAccepted()) {
LOG.info("Forum invitation was accepted"); LOG.info("Forum invitation was accepted");
onForumInvitationAccepted(r.getContactId()); onForumInvitationAccepted(f.getContactId());
} }
} else if (e instanceof ContactLeftShareableEvent) { } else if (e instanceof ContactLeftShareableEvent) {
ContactLeftShareableEvent c = (ContactLeftShareableEvent) e; ContactLeftShareableEvent c = (ContactLeftShareableEvent) e;

View File

@@ -99,11 +99,10 @@ class GroupControllerImpl extends
} else if (e instanceof GroupInvitationResponseReceivedEvent) { } else if (e instanceof GroupInvitationResponseReceivedEvent) {
GroupInvitationResponseReceivedEvent g = GroupInvitationResponseReceivedEvent g =
(GroupInvitationResponseReceivedEvent) e; (GroupInvitationResponseReceivedEvent) e;
GroupInvitationResponse r = GroupInvitationResponse r = g.getMessageHeader();
(GroupInvitationResponse) g.getResponse();
if (getGroupId().equals(r.getShareableId()) && r.wasAccepted()) { if (getGroupId().equals(r.getShareableId()) && r.wasAccepted()) {
listener.runOnUiThreadUnlessDestroyed( listener.runOnUiThreadUnlessDestroyed(
() -> listener.onInvitationAccepted(r.getContactId())); () -> listener.onInvitationAccepted(g.getContactId()));
} }
} else if (e instanceof GroupDissolvedEvent) { } else if (e instanceof GroupDissolvedEvent) {
GroupDissolvedEvent g = (GroupDissolvedEvent) e; GroupDissolvedEvent g = (GroupDissolvedEvent) e;

View File

@@ -1,23 +0,0 @@
/**
* Copyright (C) 2014 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.components.util;
public interface FutureTaskListener<V> {
void onSuccess(V result);
void onFailure(Throwable error);
}

View File

@@ -1,105 +0,0 @@
/*
* Copyright (C) 2014 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.components.util;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import javax.annotation.Nullable;
public class ListenableFutureTask<V> extends FutureTask<V> {
private final List<FutureTaskListener<V>> listeners = new LinkedList<>();
@Nullable
private final Object identifier;
public ListenableFutureTask(Callable<V> callable) {
this(callable, null);
}
private ListenableFutureTask(Callable<V> callable,
@Nullable Object identifier) {
super(callable);
this.identifier = identifier;
}
public ListenableFutureTask(V result) {
this(result, null);
}
private ListenableFutureTask(V result, @Nullable Object identifier) {
super(() -> result);
this.identifier = identifier;
this.run();
}
public synchronized void addListener(FutureTaskListener<V> listener) {
if (this.isDone()) {
callback(listener);
} else {
this.listeners.add(listener);
}
}
public synchronized void removeListener(FutureTaskListener<V> listener) {
this.listeners.remove(listener);
}
@Override
protected synchronized void done() {
callback();
}
private void callback() {
for (FutureTaskListener<V> listener : listeners) {
callback(listener);
}
}
private void callback(FutureTaskListener<V> listener) {
if (listener != null) {
try {
listener.onSuccess(get());
} catch (InterruptedException e) {
throw new AssertionError(e);
} catch (ExecutionException e) {
listener.onFailure(e);
}
}
}
@Override
public boolean equals(Object other) {
if (other != null && other instanceof ListenableFutureTask &&
this.identifier != null) {
return identifier.equals(other);
} else {
return super.equals(other);
}
}
@Override
public int hashCode() {
if (identifier != null) return identifier.hashCode();
else return super.hashCode();
}
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.briar.api.blog; package org.briarproject.briar.api.blog;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
@@ -14,14 +13,10 @@ public class BlogInvitationRequest extends InvitationRequest<Blog> {
public BlogInvitationRequest(MessageId id, GroupId groupId, long time, public BlogInvitationRequest(MessageId id, GroupId groupId, long time,
boolean local, boolean sent, boolean seen, boolean read, boolean local, boolean sent, boolean seen, boolean read,
SessionId sessionId, Blog blog, ContactId contactId, SessionId sessionId, Blog blog, @Nullable String message,
@Nullable String message, boolean available, boolean canBeOpened) { boolean available, boolean canBeOpened) {
super(id, groupId, time, local, sent, seen, read, sessionId, blog, super(id, groupId, time, local, sent, seen, read, sessionId, blog,
contactId, message, available, canBeOpened); message, available, canBeOpened);
}
public String getBlogAuthorName() {
return getShareable().getName();
} }
} }

View File

@@ -1,6 +1,5 @@
package org.briarproject.briar.api.blog; package org.briarproject.briar.api.blog;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
@@ -12,10 +11,9 @@ public class BlogInvitationResponse extends InvitationResponse {
public BlogInvitationResponse(MessageId id, GroupId groupId, long time, public BlogInvitationResponse(MessageId id, GroupId groupId, long time,
boolean local, boolean sent, boolean seen, boolean read, boolean local, boolean sent, boolean seen, boolean read,
SessionId sessionId, GroupId blogId, ContactId contactId, SessionId sessionId, boolean accept, GroupId shareableId) {
boolean accept) { super(id, groupId, time, local, sent, seen, read, sessionId,
super(id, groupId, time, local, sent, seen, read, sessionId, blogId, accept, shareableId);
contactId, accept);
} }
} }

View File

@@ -3,19 +3,19 @@ package org.briarproject.briar.api.blog.event;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.Blog;
import org.briarproject.briar.api.sharing.InvitationRequest; import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent; import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class BlogInvitationRequestReceivedEvent extends public class BlogInvitationRequestReceivedEvent extends
InvitationRequestReceivedEvent<Blog> { PrivateMessageReceivedEvent<PrivateRequest<Blog>> {
public BlogInvitationRequestReceivedEvent(Blog blog, ContactId contactId, public BlogInvitationRequestReceivedEvent(PrivateRequest<Blog> request,
InvitationRequest<Blog> request) { ContactId contactId) {
super(blog, contactId, request); super(request, contactId);
} }
} }

View File

@@ -3,18 +3,18 @@ package org.briarproject.briar.api.blog.event;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.blog.BlogInvitationResponse; import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent; import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class BlogInvitationResponseReceivedEvent public class BlogInvitationResponseReceivedEvent
extends InvitationResponseReceivedEvent { extends PrivateMessageReceivedEvent<BlogInvitationResponse> {
public BlogInvitationResponseReceivedEvent(ContactId contactId, public BlogInvitationResponseReceivedEvent(BlogInvitationResponse response,
BlogInvitationResponse response) { ContactId contactId) {
super(contactId, response); super(response, contactId);
} }
} }

View File

@@ -1,58 +0,0 @@
package org.briarproject.briar.api.client;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public abstract class BaseMessageHeader {
private final MessageId id;
private final GroupId groupId;
private final long timestamp;
private final boolean local, sent, seen, read;
public BaseMessageHeader(MessageId id, GroupId groupId, long timestamp,
boolean local, boolean sent, boolean seen, boolean read) {
this.id = id;
this.groupId = groupId;
this.timestamp = timestamp;
this.local = local;
this.sent = sent;
this.seen = seen;
this.read = read;
}
public MessageId getId() {
return id;
}
public GroupId getGroupId() {
return groupId;
}
public long getTimestamp() {
return timestamp;
}
public boolean isLocal() {
return local;
}
public boolean isSent() {
return sent;
}
public boolean isSeen() {
return seen;
}
public boolean isRead() {
return read;
}
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.briar.api.forum; package org.briarproject.briar.api.forum;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
@@ -16,14 +15,10 @@ public class ForumInvitationRequest extends InvitationRequest<Forum> {
public ForumInvitationRequest(MessageId id, GroupId groupId, long time, public ForumInvitationRequest(MessageId id, GroupId groupId, long time,
boolean local, boolean sent, boolean seen, boolean read, boolean local, boolean sent, boolean seen, boolean read,
SessionId sessionId, Forum forum, ContactId contactId, SessionId sessionId, Forum forum, @Nullable String message,
@Nullable String message, boolean available, boolean canBeOpened) { boolean available, boolean canBeOpened) {
super(id, groupId, time, local, sent, seen, read, sessionId, forum, super(id, groupId, time, local, sent, seen, read, sessionId, forum,
contactId, message, available, canBeOpened); message, available, canBeOpened);
}
public String getForumName() {
return getShareable().getName();
} }
} }

View File

@@ -1,6 +1,5 @@
package org.briarproject.briar.api.forum; package org.briarproject.briar.api.forum;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
@@ -15,10 +14,9 @@ public class ForumInvitationResponse extends InvitationResponse {
public ForumInvitationResponse(MessageId id, GroupId groupId, long time, public ForumInvitationResponse(MessageId id, GroupId groupId, long time,
boolean local, boolean sent, boolean seen, boolean read, boolean local, boolean sent, boolean seen, boolean read,
SessionId sessionId, GroupId forumId, ContactId contactId, SessionId sessionId, boolean accept, GroupId shareableId) {
boolean accept) { super(id, groupId, time, local, sent, seen, read, sessionId,
super(id, groupId, time, local, sent, seen, read, sessionId, forumId, accept, shareableId);
contactId, accept);
} }
} }

View File

@@ -3,19 +3,19 @@ package org.briarproject.briar.api.forum.event;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.forum.Forum; import org.briarproject.briar.api.forum.Forum;
import org.briarproject.briar.api.sharing.InvitationRequest; import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent; import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class ForumInvitationRequestReceivedEvent extends public class ForumInvitationRequestReceivedEvent extends
InvitationRequestReceivedEvent<Forum> { PrivateMessageReceivedEvent<PrivateRequest<Forum>> {
public ForumInvitationRequestReceivedEvent(Forum forum, ContactId contactId, public ForumInvitationRequestReceivedEvent(PrivateRequest<Forum> request,
InvitationRequest<Forum> request) { ContactId contactId) {
super(forum, contactId, request); super(request, contactId);
} }
} }

View File

@@ -3,18 +3,18 @@ package org.briarproject.briar.api.forum.event;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.forum.ForumInvitationResponse; import org.briarproject.briar.api.forum.ForumInvitationResponse;
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent; import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class ForumInvitationResponseReceivedEvent extends public class ForumInvitationResponseReceivedEvent extends
InvitationResponseReceivedEvent { PrivateMessageReceivedEvent<ForumInvitationResponse> {
public ForumInvitationResponseReceivedEvent(ContactId contactId, public ForumInvitationResponseReceivedEvent(
ForumInvitationResponse response) { ForumInvitationResponse response, ContactId contactId) {
super(contactId, response); super(response, contactId);
} }
} }

View File

@@ -8,8 +8,6 @@ import org.briarproject.bramble.api.sync.ClientId;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.messaging.ConversationManager.ConversationClient; import org.briarproject.briar.api.messaging.ConversationManager.ConversationClient;
import java.util.Collection;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@NotNullByDefault @NotNullByDefault
@@ -47,10 +45,4 @@ public interface IntroductionManager extends ConversationClient {
void respondToIntroduction(ContactId contactId, SessionId sessionId, void respondToIntroduction(ContactId contactId, SessionId sessionId,
long timestamp, boolean accept) throws DbException; long timestamp, boolean accept) throws DbException;
/**
* Returns all introduction messages for the given contact.
*/
Collection<IntroductionMessage> getIntroductionMessages(ContactId contactId)
throws DbException;
} }

View File

@@ -1,43 +0,0 @@
package org.briarproject.briar.api.introduction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.BaseMessageHeader;
import org.briarproject.briar.api.client.SessionId;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.briar.api.introduction.Role.INTRODUCER;
@Immutable
@NotNullByDefault
public class IntroductionMessage extends BaseMessageHeader {
private final SessionId sessionId;
private final MessageId messageId;
private final Role role;
IntroductionMessage(SessionId sessionId, MessageId messageId,
GroupId groupId, Role role, long time, boolean local, boolean sent,
boolean seen, boolean read) {
super(messageId, groupId, time, local, sent, seen, read);
this.sessionId = sessionId;
this.messageId = messageId;
this.role = role;
}
public SessionId getSessionId() {
return sessionId;
}
public MessageId getMessageId() {
return messageId;
}
public boolean isIntroducer() {
return role == INTRODUCER;
}
}

View File

@@ -1,44 +1,31 @@
package org.briarproject.briar.api.introduction; package org.briarproject.briar.api.introduction;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.messaging.PrivateRequest;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class IntroductionRequest extends IntroductionResponse { public class IntroductionRequest extends PrivateRequest<Author> {
@Nullable private final boolean contact;
private final String message;
private final boolean answered, exists;
public IntroductionRequest(SessionId sessionId, MessageId messageId, public IntroductionRequest(MessageId messageId, GroupId groupId,
GroupId groupId, Role role, long time, boolean local, boolean sent, long time, boolean local, boolean sent, boolean seen, boolean read,
boolean seen, boolean read, String name, boolean accepted, SessionId sessionId, Author author, @Nullable String message,
@Nullable String message, boolean answered, boolean exists) { boolean answered, boolean contact) {
super(messageId, groupId, time, local, sent, seen, read, sessionId,
super(sessionId, messageId, groupId, role, time, local, sent, seen, author, message, answered);
read, name, accepted); this.contact = contact;
this.message = message;
this.answered = answered;
this.exists = exists;
} }
@Nullable public boolean isContact() {
public String getMessage() { return contact;
return message;
}
public boolean wasAnswered() {
return answered;
}
public boolean contactExists() {
return exists;
} }
} }

View File

@@ -1,35 +1,38 @@
package org.briarproject.briar.api.introduction; package org.briarproject.briar.api.introduction;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.messaging.PrivateResponse;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static org.briarproject.briar.api.introduction.Role.INTRODUCER;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class IntroductionResponse extends IntroductionMessage { public class IntroductionResponse extends PrivateResponse {
private final String name; private final Author introducedAuthor;
private final boolean accepted; private final Role ourRole;
public IntroductionResponse(SessionId sessionId, MessageId messageId, public IntroductionResponse(MessageId messageId, GroupId groupId, long time,
GroupId groupId, Role role, long time, boolean local, boolean sent, boolean local, boolean sent, boolean seen, boolean read,
boolean seen, boolean read, String name, boolean accepted) { SessionId sessionId, boolean accepted, Author author, Role role) {
super(sessionId, messageId, groupId, role, time, local, sent, seen, super(messageId, groupId, time, local, sent, seen, read, sessionId,
read); accepted);
this.introducedAuthor = author;
this.name = name; this.ourRole = role;
this.accepted = accepted;
} }
public String getName() { public Author getIntroducedAuthor() {
return name; return introducedAuthor;
} }
public boolean wasAccepted() { public boolean isIntroducer() {
return accepted; return ourRole == INTRODUCER;
} }
} }

View File

@@ -1,32 +1,20 @@
package org.briarproject.briar.api.introduction.event; package org.briarproject.briar.api.introduction.event;
import org.briarproject.bramble.api.contact.ContactId; 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.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.introduction.IntroductionRequest; import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class IntroductionRequestReceivedEvent extends Event { public class IntroductionRequestReceivedEvent extends
PrivateMessageReceivedEvent<IntroductionRequest> {
private final ContactId contactId; public IntroductionRequestReceivedEvent(
private final IntroductionRequest introductionRequest; IntroductionRequest introductionRequest, ContactId contactId) {
super(introductionRequest, contactId);
public IntroductionRequestReceivedEvent(ContactId contactId,
IntroductionRequest introductionRequest) {
this.contactId = contactId;
this.introductionRequest = introductionRequest;
}
public ContactId getContactId() {
return contactId;
}
public IntroductionRequest getIntroductionRequest() {
return introductionRequest;
} }
} }

View File

@@ -1,31 +1,20 @@
package org.briarproject.briar.api.introduction.event; package org.briarproject.briar.api.introduction.event;
import org.briarproject.bramble.api.contact.ContactId; 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.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.introduction.IntroductionResponse; import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class IntroductionResponseReceivedEvent extends Event { public class IntroductionResponseReceivedEvent extends
PrivateMessageReceivedEvent<IntroductionResponse> {
private final ContactId contactId; public IntroductionResponseReceivedEvent(
private final IntroductionResponse introductionResponse; IntroductionResponse introductionResponse, ContactId contactId) {
super(introductionResponse, contactId);
public IntroductionResponseReceivedEvent(ContactId contactId,
IntroductionResponse introductionResponse) {
this.contactId = contactId;
this.introductionResponse = introductionResponse;
} }
public ContactId getContactId() {
return contactId;
}
public IntroductionResponse getIntroductionResponse() {
return introductionResponse;
}
} }

View File

@@ -10,6 +10,8 @@ import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.client.MessageTracker.GroupCount;
import java.util.Collection;
@NotNullByDefault @NotNullByDefault
public interface ConversationManager { public interface ConversationManager {
@@ -19,6 +21,15 @@ public interface ConversationManager {
*/ */
void registerConversationClient(ConversationClient client); void registerConversationClient(ConversationClient client);
/**
* Returns the headers of all messages in the given private conversation.
*
* Only {@link MessagingManager} returns only headers.
* The others also return the message body.
*/
Collection<PrivateMessageHeader> getMessageHeaders(ContactId c)
throws DbException;
/** /**
* Returns the unified group count for all private conversation messages. * Returns the unified group count for all private conversation messages.
*/ */
@@ -29,6 +40,9 @@ public interface ConversationManager {
Group getContactGroup(Contact c); Group getContactGroup(Contact c);
Collection<PrivateMessageHeader> getMessageHeaders(Transaction txn,
ContactId contactId) throws DbException;
GroupCount getGroupCount(Transaction txn, ContactId c) GroupCount getGroupCount(Transaction txn, ContactId c)
throws DbException; throws DbException;

View File

@@ -8,8 +8,6 @@ import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.messaging.ConversationManager.ConversationClient; import org.briarproject.briar.api.messaging.ConversationManager.ConversationClient;
import java.util.Collection;
@NotNullByDefault @NotNullByDefault
public interface MessagingManager extends ConversationClient { public interface MessagingManager extends ConversationClient {
@@ -43,12 +41,6 @@ public interface MessagingManager extends ConversationClient {
*/ */
GroupId getConversationId(ContactId c) throws DbException; GroupId getConversationId(ContactId c) throws DbException;
/**
* Returns the headers of all messages in the given private conversation.
*/
Collection<PrivateMessageHeader> getMessageHeaders(ContactId c)
throws DbException;
/** /**
* Returns the body of the private message with the given ID. * Returns the body of the private message with the given ID.
*/ */

View File

@@ -3,18 +3,55 @@ package org.briarproject.briar.api.messaging;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.BaseMessageHeader;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class PrivateMessageHeader extends BaseMessageHeader { public class PrivateMessageHeader {
private final MessageId id;
private final GroupId groupId;
private final long timestamp;
private final boolean local, sent, seen, read;
public PrivateMessageHeader(MessageId id, GroupId groupId, long timestamp, public PrivateMessageHeader(MessageId id, GroupId groupId, long timestamp,
boolean local, boolean read, boolean sent, boolean seen) { boolean local, boolean read, boolean sent, boolean seen) {
this.id = id;
this.groupId = groupId;
this.timestamp = timestamp;
this.local = local;
this.sent = sent;
this.seen = seen;
this.read = read;
}
super(id, groupId, timestamp, local, sent, seen, read); public MessageId getId() {
return id;
}
public GroupId getGroupId() {
return groupId;
}
public long getTimestamp() {
return timestamp;
}
public boolean isLocal() {
return local;
}
public boolean isSent() {
return sent;
}
public boolean isSeen() {
return seen;
}
public boolean isRead() {
return read;
} }
} }

View File

@@ -0,0 +1,53 @@
package org.briarproject.briar.api.messaging;
import org.briarproject.bramble.api.Nameable;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.SessionId;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class PrivateRequest<N extends Nameable> extends PrivateMessageHeader {
private final SessionId sessionId;
private final N nameable;
@Nullable
private final String message;
private final boolean answered;
public PrivateRequest(MessageId messageId, GroupId groupId, long time,
boolean local, boolean sent, boolean seen, boolean read,
SessionId sessionId, N nameable, @Nullable String message,
boolean answered) {
super(messageId, groupId, time, local, sent, seen, read);
this.sessionId = sessionId;
this.nameable = nameable;
this.message = message;
this.answered = answered;
}
public SessionId getSessionId() {
return sessionId;
}
public N getNameable() {
return nameable;
}
public String getName() {
return nameable.getName();
}
@Nullable
public String getMessage() {
return message;
}
public boolean wasAnswered() {
return answered;
}
}

View File

@@ -1,36 +1,33 @@
package org.briarproject.briar.api.sharing; package org.briarproject.briar.api.messaging;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.BaseMessageHeader;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class InvitationMessage extends BaseMessageHeader { public abstract class PrivateResponse extends PrivateMessageHeader {
private final SessionId sessionId; private final SessionId sessionId;
private final ContactId contactId; private final boolean accepted;
public InvitationMessage(MessageId id, GroupId groupId, long time, public PrivateResponse(MessageId id, GroupId groupId, long time,
boolean local, boolean sent, boolean seen, boolean read, boolean local, boolean sent, boolean seen, boolean read,
SessionId sessionId, ContactId contactId) { SessionId sessionId, boolean accepted) {
super(id, groupId, time, local, sent, seen, read); super(id, groupId, time, local, sent, seen, read);
this.sessionId = sessionId; this.sessionId = sessionId;
this.contactId = contactId; this.accepted = accepted;
} }
public SessionId getSessionId() { public SessionId getSessionId() {
return sessionId; return sessionId;
} }
public ContactId getContactId() { public boolean wasAccepted() {
return contactId; return accepted;
} }
} }

View File

@@ -3,7 +3,6 @@ package org.briarproject.briar.api.messaging.event;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.briar.api.messaging.PrivateMessageHeader; import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@@ -13,28 +12,22 @@ import javax.annotation.concurrent.Immutable;
*/ */
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class PrivateMessageReceivedEvent extends Event { public class PrivateMessageReceivedEvent<H extends PrivateMessageHeader>
extends Event {
private final PrivateMessageHeader messageHeader; private final H messageHeader;
private final ContactId contactId; private final ContactId contactId;
private final GroupId groupId;
public PrivateMessageReceivedEvent(PrivateMessageHeader messageHeader, public PrivateMessageReceivedEvent(H messageHeader, ContactId contactId) {
ContactId contactId, GroupId groupId) {
this.messageHeader = messageHeader; this.messageHeader = messageHeader;
this.contactId = contactId; this.contactId = contactId;
this.groupId = groupId;
} }
public PrivateMessageHeader getMessageHeader() { public H getMessageHeader() {
return messageHeader; return messageHeader;
} }
public ContactId getContactId() { public ContactId getContactId() {
return contactId; return contactId;
} }
public GroupId getGroupId() {
return groupId;
}
} }

View File

@@ -2,20 +2,19 @@ package org.briarproject.briar.api.privategroup.event;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class GroupInvitationRequestReceivedEvent extends public class GroupInvitationRequestReceivedEvent extends
InvitationRequestReceivedEvent<PrivateGroup> { PrivateMessageReceivedEvent<GroupInvitationRequest> {
public GroupInvitationRequestReceivedEvent(PrivateGroup group, public GroupInvitationRequestReceivedEvent(GroupInvitationRequest request,
ContactId contactId, GroupInvitationRequest request) { ContactId contactId) {
super(group, contactId, request); super(request, contactId);
} }
} }

View File

@@ -2,18 +2,18 @@ package org.briarproject.briar.api.privategroup.event;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.sharing.InvitationResponse; import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class GroupInvitationResponseReceivedEvent public class GroupInvitationResponseReceivedEvent
extends InvitationResponseReceivedEvent { extends PrivateMessageReceivedEvent<GroupInvitationResponse> {
public GroupInvitationResponseReceivedEvent(ContactId contactId, public GroupInvitationResponseReceivedEvent(
InvitationResponse response) { GroupInvitationResponse response, ContactId contactId) {
super(contactId, response); super(response, contactId);
} }
} }

View File

@@ -10,7 +10,6 @@ import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.messaging.ConversationManager.ConversationClient; import org.briarproject.briar.api.messaging.ConversationManager.ConversationClient;
import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroup;
import org.briarproject.briar.api.sharing.InvitationMessage;
import java.util.Collection; import java.util.Collection;
@@ -73,13 +72,6 @@ public interface GroupInvitationManager extends ConversationClient {
*/ */
void revealRelationship(ContactId c, GroupId g) throws DbException; void revealRelationship(ContactId c, GroupId g) throws DbException;
/**
* Returns all private group invitation messages related to the given
* contact.
*/
Collection<InvitationMessage> getInvitationMessages(ContactId c)
throws DbException;
/** /**
* Returns all private groups to which the user has been invited. * Returns all private groups to which the user has been invited.
*/ */

View File

@@ -1,6 +1,5 @@
package org.briarproject.briar.api.privategroup.invitation; package org.briarproject.briar.api.privategroup.invitation;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
@@ -17,10 +16,10 @@ public class GroupInvitationRequest extends InvitationRequest<PrivateGroup> {
public GroupInvitationRequest(MessageId id, GroupId groupId, long time, public GroupInvitationRequest(MessageId id, GroupId groupId, long time,
boolean local, boolean sent, boolean seen, boolean read, boolean local, boolean sent, boolean seen, boolean read,
SessionId sessionId, PrivateGroup shareable, ContactId contactId, SessionId sessionId, PrivateGroup shareable,
@Nullable String message, boolean available, boolean canBeOpened) { @Nullable String message, boolean available, boolean canBeOpened) {
super(id, groupId, time, local, sent, seen, read, sessionId, shareable, super(id, groupId, time, local, sent, seen, read, sessionId, shareable,
contactId, message, available, canBeOpened); message, available, canBeOpened);
} }
} }

View File

@@ -1,6 +1,5 @@
package org.briarproject.briar.api.privategroup.invitation; package org.briarproject.briar.api.privategroup.invitation;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
@@ -15,10 +14,9 @@ public class GroupInvitationResponse extends InvitationResponse {
public GroupInvitationResponse(MessageId id, GroupId groupId, long time, public GroupInvitationResponse(MessageId id, GroupId groupId, long time,
boolean local, boolean sent, boolean seen, boolean read, boolean local, boolean sent, boolean seen, boolean read,
SessionId sessionId, GroupId shareableId, ContactId contactId, SessionId sessionId, boolean accept, GroupId shareableId) {
boolean accept) {
super(id, groupId, time, local, sent, seen, read, sessionId, super(id, groupId, time, local, sent, seen, read, sessionId,
shareableId, contactId, accept); accept, shareableId);
} }
} }

View File

@@ -1,49 +1,27 @@
package org.briarproject.briar.api.sharing; package org.briarproject.briar.api.sharing;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.messaging.PrivateRequest;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@Immutable public abstract class InvitationRequest<S extends Shareable> extends
@NotNullByDefault PrivateRequest<S> {
public class InvitationRequest<S extends Shareable> extends InvitationMessage {
private final S shareable; private final boolean canBeOpened;
@Nullable
private final String message;
private final boolean available, canBeOpened;
public InvitationRequest(MessageId id, GroupId groupId, long time, public InvitationRequest(MessageId messageId, GroupId groupId, long time,
boolean local, boolean sent, boolean seen, boolean read, boolean local, boolean sent, boolean seen, boolean read,
SessionId sessionId, S shareable, ContactId contactId, SessionId sessionId, S object, @Nullable String message,
@Nullable String message, boolean available, boolean canBeOpened) { boolean available, boolean canBeOpened) {
super(id, groupId, time, local, sent, seen, read, sessionId, contactId); super(messageId, groupId, time, local, sent, seen, read, sessionId,
this.shareable = shareable; object, message, !available);
this.message = message;
this.available = available;
this.canBeOpened = canBeOpened; this.canBeOpened = canBeOpened;
} }
@Nullable
public String getMessage() {
return message;
}
public boolean isAvailable() {
return available;
}
public boolean canBeOpened() { public boolean canBeOpened() {
return canBeOpened; return canBeOpened;
} }
public S getShareable() {
return shareable;
}
} }

View File

@@ -1,31 +1,19 @@
package org.briarproject.briar.api.sharing; package org.briarproject.briar.api.sharing;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.messaging.PrivateResponse;
import javax.annotation.concurrent.Immutable; public abstract class InvitationResponse extends PrivateResponse {
@Immutable
@NotNullByDefault
public class InvitationResponse extends InvitationMessage {
private final GroupId shareableId; private final GroupId shareableId;
private final boolean accept;
public InvitationResponse(MessageId id, GroupId groupId, public InvitationResponse(MessageId id, GroupId groupId, long time,
long time, boolean local, boolean sent, boolean seen, boolean local, boolean sent, boolean seen, boolean read,
boolean read, SessionId sessionId, GroupId shareableId, SessionId sessionId, boolean accepted, GroupId shareableId) {
ContactId contactId, boolean accept) { super(id, groupId, time, local, sent, seen, read, sessionId, accepted);
super(id, groupId, time, local, sent, seen, read, sessionId, contactId);
this.shareableId = shareableId; this.shareableId = shareableId;
this.accept = accept;
}
public boolean wasAccepted() {
return accept;
} }
public GroupId getShareableId() { public GroupId getShareableId() {

View File

@@ -1,16 +1,12 @@
package org.briarproject.briar.api.sharing; package org.briarproject.briar.api.sharing;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.Nameable;
@NotNullByDefault @NotNullByDefault
public interface Shareable { public interface Shareable extends Nameable {
GroupId getId(); GroupId getId();
Group getGroup();
String getName();
} }

View File

@@ -35,13 +35,6 @@ public interface SharingManager<S extends Shareable>
void respondToInvitation(ContactId c, SessionId id, boolean accept) void respondToInvitation(ContactId c, SessionId id, boolean accept)
throws DbException; throws DbException;
/**
* Returns all group sharing messages sent by the Contact
* identified by contactId.
*/
Collection<InvitationMessage> getInvitationMessages(
ContactId contactId) throws DbException;
/** /**
* Returns all invitations to groups. * Returns all invitations to groups.
*/ */

View File

@@ -1,38 +0,0 @@
package org.briarproject.briar.api.sharing.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.briar.api.sharing.InvitationRequest;
import org.briarproject.briar.api.sharing.Shareable;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public abstract class InvitationRequestReceivedEvent<S extends Shareable>
extends Event {
private final S shareable;
private final ContactId contactId;
private final InvitationRequest request;
protected InvitationRequestReceivedEvent(S shareable, ContactId contactId,
InvitationRequest request) {
this.shareable = shareable;
this.contactId = contactId;
this.request = request;
}
public ContactId getContactId() {
return contactId;
}
public InvitationRequest getRequest() {
return request;
}
public S getShareable() {
return shareable;
}
}

View File

@@ -1,30 +0,0 @@
package org.briarproject.briar.api.sharing.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.briar.api.sharing.InvitationResponse;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public abstract class InvitationResponseReceivedEvent extends Event {
private final ContactId contactId;
private final InvitationResponse response;
public InvitationResponseReceivedEvent(ContactId contactId,
InvitationResponse response) {
this.contactId = contactId;
this.response = response;
}
public ContactId getContactId() {
return contactId;
}
public InvitationResponse getResponse() {
return response;
}
}

View File

@@ -150,12 +150,12 @@ abstract class AbstractProtocolEngine<S extends Session>
AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId(); AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId();
Contact c = contactManager.getContact(txn, sender, localAuthorId); Contact c = contactManager.getContact(txn, sender, localAuthorId);
IntroductionResponse response = IntroductionResponse response =
new IntroductionResponse(s.getSessionId(), m.getMessageId(), new IntroductionResponse(m.getMessageId(), m.getGroupId(),
m.getGroupId(), s.getRole(), m.getTimestamp(), false, m.getTimestamp(), false, false, false, false,
false, false, false, otherAuthor.getName(), s.getSessionId(), m instanceof AcceptMessage,
m instanceof AcceptMessage); otherAuthor, s.getRole());
IntroductionResponseReceivedEvent e = IntroductionResponseReceivedEvent e =
new IntroductionResponseReceivedEvent(c.getId(), response); new IntroductionResponseReceivedEvent(response, c.getId());
txn.attach(e); txn.attach(e);
} }

View File

@@ -41,7 +41,6 @@ import javax.inject.Inject;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.briar.api.introduction.Role.INTRODUCEE;
import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_AUTH; import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_AUTH;
import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_RESPONSES; import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_RESPONSES;
import static org.briarproject.briar.introduction.IntroduceeState.LOCAL_ACCEPTED; import static org.briarproject.briar.introduction.IntroduceeState.LOCAL_ACCEPTED;
@@ -255,13 +254,12 @@ class IntroduceeProtocolEngine
localAuthor.getId()); localAuthor.getId());
boolean contactExists = contactManager boolean contactExists = contactManager
.contactExists(txn, m.getAuthor().getId(), localAuthor.getId()); .contactExists(txn, m.getAuthor().getId(), localAuthor.getId());
IntroductionRequest request = IntroductionRequest request = new IntroductionRequest(m.getMessageId(),
new IntroductionRequest(s.getSessionId(), m.getMessageId(), m.getGroupId(), m.getTimestamp(), false, false, false, false,
m.getGroupId(), INTRODUCEE, m.getTimestamp(), false, s.getSessionId(), m.getAuthor(), m.getMessage(), false,
false, false, false, m.getAuthor().getName(), false, contactExists);
m.getMessage(), false, contactExists);
IntroductionRequestReceivedEvent e = IntroductionRequestReceivedEvent e =
new IntroductionRequestReceivedEvent(c.getId(), request); new IntroductionRequestReceivedEvent(request, c.getId());
txn.attach(e); txn.attach(e);
// Move to the AWAIT_RESPONSES state // Move to the AWAIT_RESPONSES state

View File

@@ -30,10 +30,10 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVer
import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.introduction.IntroductionManager; import org.briarproject.briar.api.introduction.IntroductionManager;
import org.briarproject.briar.api.introduction.IntroductionMessage;
import org.briarproject.briar.api.introduction.IntroductionRequest; import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.introduction.IntroductionResponse; import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.introduction.Role; import org.briarproject.briar.api.introduction.Role;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.client.ConversationClientImpl; import org.briarproject.briar.client.ConversationClientImpl;
import org.briarproject.briar.introduction.IntroducerSession.Introducee; import org.briarproject.briar.introduction.IntroducerSession.Introducee;
@@ -398,17 +398,16 @@ class IntroductionManagerImpl extends ConversationClientImpl
} }
@Override @Override
public Collection<IntroductionMessage> getIntroductionMessages(ContactId c) public Collection<PrivateMessageHeader> getMessageHeaders(Transaction txn,
throws DbException { ContactId c) throws DbException {
List<IntroductionMessage> messages;
Transaction txn = db.startTransaction(true);
try { try {
Contact contact = db.getContact(txn, c); Contact contact = db.getContact(txn, c);
GroupId contactGroupId = getContactGroup(contact).getId(); GroupId contactGroupId = getContactGroup(contact).getId();
BdfDictionary query = messageParser.getMessagesVisibleInUiQuery(); BdfDictionary query = messageParser.getMessagesVisibleInUiQuery();
Map<MessageId, BdfDictionary> results = clientHelper Map<MessageId, BdfDictionary> results = clientHelper
.getMessageMetadataAsDictionary(txn, contactGroupId, query); .getMessageMetadataAsDictionary(txn, contactGroupId, query);
messages = new ArrayList<>(results.size()); List<PrivateMessageHeader> messages =
new ArrayList<>(results.size());
for (Entry<MessageId, BdfDictionary> e : results.entrySet()) { for (Entry<MessageId, BdfDictionary> e : results.entrySet()) {
MessageId m = e.getKey(); MessageId m = e.getKey();
MessageMetadata meta = MessageMetadata meta =
@@ -431,13 +430,10 @@ class IntroductionManagerImpl extends ConversationClientImpl
status, ss.bdfSession, false)); status, ss.bdfSession, false));
} }
} }
db.commitTransaction(txn); return messages;
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} finally {
db.endTransaction(txn);
} }
return messages;
} }
private IntroductionRequest parseInvitationRequest(Transaction txn, private IntroductionRequest parseInvitationRequest(Transaction txn,
@@ -470,11 +466,9 @@ class IntroductionManagerImpl extends ConversationClientImpl
boolean contactExists = contactManager boolean contactExists = contactManager
.contactExists(txn, rm.getAuthor().getId(), .contactExists(txn, rm.getAuthor().getId(),
localAuthor.getId()); localAuthor.getId());
return new IntroductionRequest(m, contactGroupId, meta.getTimestamp(),
return new IntroductionRequest(sessionId, m, contactGroupId, meta.isLocal(), status.isSent(), status.isSeen(), meta.isRead(),
role, meta.getTimestamp(), meta.isLocal(), sessionId, author, message, !meta.isAvailableToAnswer(),
status.isSent(), status.isSeen(), meta.isRead(),
author.getName(), false, message, !meta.isAvailableToAnswer(),
contactExists); contactExists);
} }
@@ -499,9 +493,9 @@ class IntroductionManagerImpl extends ConversationClientImpl
sessionId = session.getSessionId(); sessionId = session.getSessionId();
author = session.getRemote().author; author = session.getRemote().author;
} else throw new AssertionError(); } else throw new AssertionError();
return new IntroductionResponse(sessionId, m, contactGroupId, return new IntroductionResponse(m, contactGroupId, meta.getTimestamp(),
role, meta.getTimestamp(), meta.isLocal(), status.isSent(), meta.isLocal(), status.isSent(), status.isSeen(), meta.isRead(),
status.isSeen(), meta.isRead(), author.getName(), accept); sessionId, accept, author, role);
} }
private void removeSessionWithIntroducer(Transaction txn, private void removeSessionWithIntroducer(Transaction txn,

View File

@@ -7,7 +7,11 @@ import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.client.MessageTracker.GroupCount;
import org.briarproject.briar.api.messaging.ConversationManager; import org.briarproject.briar.api.messaging.ConversationManager;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
@@ -33,6 +37,22 @@ class ConversationManagerImpl implements ConversationManager {
throw new IllegalStateException("Client is already registered"); throw new IllegalStateException("Client is already registered");
} }
@Override
public Collection<PrivateMessageHeader> getMessageHeaders(ContactId c)
throws DbException {
List<PrivateMessageHeader> messages = new ArrayList<>();
Transaction txn = db.startTransaction(true);
try {
for (ConversationClient client : clients) {
messages.addAll(client.getMessageHeaders(txn, c));
}
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return messages;
}
@Override @Override
public GroupCount getGroupCount(ContactId contactId) throws DbException { public GroupCount getGroupCount(ContactId contactId) throws DbException {
int msgCount = 0, unreadCount = 0; int msgCount = 0, unreadCount = 0;

View File

@@ -116,8 +116,8 @@ class MessagingManagerImpl extends ConversationClientImpl
PrivateMessageHeader header = new PrivateMessageHeader( PrivateMessageHeader header = new PrivateMessageHeader(
m.getId(), groupId, timestamp, local, read, false, false); m.getId(), groupId, timestamp, local, read, false, false);
ContactId contactId = getContactId(txn, groupId); ContactId contactId = getContactId(txn, groupId);
PrivateMessageReceivedEvent event = new PrivateMessageReceivedEvent( PrivateMessageReceivedEvent<PrivateMessageHeader> event =
header, contactId, groupId); new PrivateMessageReceivedEvent<>(header, contactId);
txn.attach(event); txn.attach(event);
messageTracker.trackIncomingMessage(txn, m); messageTracker.trackIncomingMessage(txn, m);
@@ -178,21 +178,17 @@ class MessagingManagerImpl extends ConversationClientImpl
} }
@Override @Override
public Collection<PrivateMessageHeader> getMessageHeaders(ContactId c) public Collection<PrivateMessageHeader> getMessageHeaders(Transaction txn,
throws DbException { ContactId c) throws DbException {
Map<MessageId, BdfDictionary> metadata; Map<MessageId, BdfDictionary> metadata;
Collection<MessageStatus> statuses; Collection<MessageStatus> statuses;
GroupId g; GroupId g;
Transaction txn = db.startTransaction(true);
try { try {
g = getContactGroup(db.getContact(txn, c)).getId(); g = getContactGroup(db.getContact(txn, c)).getId();
metadata = clientHelper.getMessageMetadataAsDictionary(txn, g); metadata = clientHelper.getMessageMetadataAsDictionary(txn, g);
statuses = db.getMessageStatus(txn, c, g); statuses = db.getMessageStatus(txn, c, g);
db.commitTransaction(txn);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} finally {
db.endTransaction(txn);
} }
Collection<PrivateMessageHeader> headers = new ArrayList<>(); Collection<PrivateMessageHeader> headers = new ArrayList<>();
for (MessageStatus s : statuses) { for (MessageStatus s : statuses) {
@@ -203,9 +199,8 @@ class MessagingManagerImpl extends ConversationClientImpl
long timestamp = meta.getLong("timestamp"); long timestamp = meta.getLong("timestamp");
boolean local = meta.getBoolean("local"); boolean local = meta.getBoolean("local");
boolean read = meta.getBoolean("read"); boolean read = meta.getBoolean("read");
headers.add( headers.add(new PrivateMessageHeader(id, g, timestamp, local,
new PrivateMessageHeader(id, g, timestamp, local, read, read, s.isSent(), s.isSeen()));
s.isSent(), s.isSeen()));
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }

View File

@@ -68,8 +68,7 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> {
} }
@Override @Override
public CreatorSession onJoinAction(Transaction txn, CreatorSession s) public CreatorSession onJoinAction(Transaction txn, CreatorSession s) {
throws DbException {
throw new UnsupportedOperationException(); // Invalid in this role throw new UnsupportedOperationException(); // Invalid in this role
} }
@@ -91,8 +90,8 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> {
} }
@Override @Override
public CreatorSession onMemberAddedAction(Transaction txn, CreatorSession s) public CreatorSession onMemberAddedAction(Transaction txn,
throws DbException { CreatorSession s) {
return s; // Ignored in this role return s; // Ignored in this role
} }
@@ -193,8 +192,8 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> {
setPrivateGroupVisibility(txn, s, SHARED); setPrivateGroupVisibility(txn, s, SHARED);
// Broadcast an event // Broadcast an event
ContactId contactId = getContactId(txn, m.getContactGroupId()); ContactId contactId = getContactId(txn, m.getContactGroupId());
txn.attach(new GroupInvitationResponseReceivedEvent(contactId, txn.attach(new GroupInvitationResponseReceivedEvent(
createInvitationResponse(m, contactId, true))); createInvitationResponse(m, true), contactId));
// Move to the JOINED state // Move to the JOINED state
return new CreatorSession(s.getContactGroupId(), s.getPrivateGroupId(), return new CreatorSession(s.getContactGroupId(), s.getPrivateGroupId(),
sent.getId(), m.getId(), sent.getTimestamp(), sent.getId(), m.getId(), sent.getTimestamp(),
@@ -215,8 +214,8 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> {
m.getTimestamp(), false); m.getTimestamp(), false);
// Broadcast an event // Broadcast an event
ContactId contactId = getContactId(txn, m.getContactGroupId()); ContactId contactId = getContactId(txn, m.getContactGroupId());
txn.attach(new GroupInvitationResponseReceivedEvent(contactId, txn.attach(new GroupInvitationResponseReceivedEvent(
createInvitationResponse(m, contactId, false))); createInvitationResponse(m, false), contactId));
// Move to the START state // Move to the START state
return new CreatorSession(s.getContactGroupId(), s.getPrivateGroupId(), return new CreatorSession(s.getContactGroupId(), s.getPrivateGroupId(),
s.getLastLocalMessageId(), m.getId(), s.getLocalTimestamp(), s.getLastLocalMessageId(), m.getId(), s.getLocalTimestamp(),
@@ -254,10 +253,10 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> {
} }
private GroupInvitationResponse createInvitationResponse( private GroupInvitationResponse createInvitationResponse(
GroupInvitationMessage m, ContactId c, boolean accept) { GroupInvitationMessage m, boolean accept) {
SessionId sessionId = new SessionId(m.getPrivateGroupId().getBytes()); SessionId sessionId = new SessionId(m.getPrivateGroupId().getBytes());
return new GroupInvitationResponse(m.getId(), m.getContactGroupId(), return new GroupInvitationResponse(m.getId(), m.getContactGroupId(),
m.getTimestamp(), false, false, true, false, sessionId, m.getTimestamp(), false, false, false, false, sessionId,
m.getPrivateGroupId(), c, accept); accept, m.getPrivateGroupId());
} }
} }

View File

@@ -26,6 +26,7 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook; import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook;
import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroup;
import org.briarproject.briar.api.privategroup.PrivateGroupFactory; import org.briarproject.briar.api.privategroup.PrivateGroupFactory;
import org.briarproject.briar.api.privategroup.PrivateGroupManager; import org.briarproject.briar.api.privategroup.PrivateGroupManager;
@@ -34,7 +35,6 @@ import org.briarproject.briar.api.privategroup.invitation.GroupInvitationItem;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import org.briarproject.briar.api.sharing.InvitationMessage;
import org.briarproject.briar.client.ConversationClientImpl; import org.briarproject.briar.client.ConversationClientImpl;
import java.util.ArrayList; import java.util.ArrayList;
@@ -353,7 +353,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
private <S extends Session> S handleAction(Transaction txn, private <S extends Session> S handleAction(Transaction txn,
LocalAction type, S session, ProtocolEngine<S> engine) LocalAction type, S session, ProtocolEngine<S> engine)
throws DbException, FormatException { throws DbException {
if (type == LocalAction.INVITE) { if (type == LocalAction.INVITE) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} else if (type == LocalAction.JOIN) { } else if (type == LocalAction.JOIN) {
@@ -368,17 +368,16 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
} }
@Override @Override
public Collection<InvitationMessage> getInvitationMessages(ContactId c) public Collection<PrivateMessageHeader> getMessageHeaders(Transaction txn,
throws DbException { ContactId c) throws DbException {
List<InvitationMessage> messages;
Transaction txn = db.startTransaction(true);
try { try {
Contact contact = db.getContact(txn, c); Contact contact = db.getContact(txn, c);
GroupId contactGroupId = getContactGroup(contact).getId(); GroupId contactGroupId = getContactGroup(contact).getId();
BdfDictionary query = messageParser.getMessagesVisibleInUiQuery(); BdfDictionary query = messageParser.getMessagesVisibleInUiQuery();
Map<MessageId, BdfDictionary> results = clientHelper Map<MessageId, BdfDictionary> results = clientHelper
.getMessageMetadataAsDictionary(txn, contactGroupId, query); .getMessageMetadataAsDictionary(txn, contactGroupId, query);
messages = new ArrayList<>(results.size()); List<PrivateMessageHeader> messages =
new ArrayList<>(results.size());
for (Entry<MessageId, BdfDictionary> e : results.entrySet()) { for (Entry<MessageId, BdfDictionary> e : results.entrySet()) {
MessageId m = e.getKey(); MessageId m = e.getKey();
MessageMetadata meta = MessageMetadata meta =
@@ -386,31 +385,25 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
MessageStatus status = db.getMessageStatus(txn, c, m); MessageStatus status = db.getMessageStatus(txn, c, m);
MessageType type = meta.getMessageType(); MessageType type = meta.getMessageType();
if (type == INVITE) { if (type == INVITE) {
messages.add(parseInvitationRequest(txn, c, contactGroupId, messages.add(parseInvitationRequest(txn, contactGroupId, m,
m, meta, status)); meta, status));
} else if (type == JOIN) { } else if (type == JOIN) {
messages.add( messages.add(parseInvitationResponse(contactGroupId, m,
parseInvitationResponse(c, contactGroupId, m, meta, meta, status, true));
status, true));
} else if (type == LEAVE) { } else if (type == LEAVE) {
messages.add( messages.add(parseInvitationResponse(contactGroupId, m,
parseInvitationResponse(c, contactGroupId, m, meta, meta, status, false));
status, false));
} }
} }
db.commitTransaction(txn); return messages;
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} finally {
db.endTransaction(txn);
} }
return messages;
} }
private GroupInvitationRequest parseInvitationRequest(Transaction txn, private GroupInvitationRequest parseInvitationRequest(Transaction txn,
ContactId c, GroupId contactGroupId, MessageId m, GroupId contactGroupId, MessageId m, MessageMetadata meta,
MessageMetadata meta, MessageStatus status) MessageStatus status) throws DbException, FormatException {
throws DbException, FormatException {
SessionId sessionId = getSessionId(meta.getPrivateGroupId()); SessionId sessionId = getSessionId(meta.getPrivateGroupId());
// Look up the invite message to get the details of the private group // Look up the invite message to get the details of the private group
InviteMessage invite = messageParser.getInviteMessage(txn, m); InviteMessage invite = messageParser.getInviteMessage(txn, m);
@@ -422,19 +415,19 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
db.containsGroup(txn, invite.getPrivateGroupId()); db.containsGroup(txn, invite.getPrivateGroupId());
return new GroupInvitationRequest(m, contactGroupId, return new GroupInvitationRequest(m, contactGroupId,
meta.getTimestamp(), meta.isLocal(), status.isSent(), meta.getTimestamp(), meta.isLocal(), status.isSent(),
status.isSeen(), meta.isRead(), sessionId, pg, c, status.isSeen(), meta.isRead(), sessionId, pg,
invite.getMessage(), meta.isAvailableToAnswer(), canBeOpened); invite.getMessage(), meta.isAvailableToAnswer(), canBeOpened);
} }
private GroupInvitationResponse parseInvitationResponse(ContactId c, private GroupInvitationResponse parseInvitationResponse(
GroupId contactGroupId, MessageId m, MessageMetadata meta, GroupId contactGroupId, MessageId m, MessageMetadata meta,
MessageStatus status, boolean accept) MessageStatus status, boolean accept) {
throws DbException, FormatException {
SessionId sessionId = getSessionId(meta.getPrivateGroupId()); SessionId sessionId = getSessionId(meta.getPrivateGroupId());
return new GroupInvitationResponse(m, contactGroupId, return new GroupInvitationResponse(m, contactGroupId,
meta.getTimestamp(), meta.isLocal(), status.isSent(), meta.getTimestamp(), meta.isLocal(), status.isSent(),
status.isSeen(), meta.isRead(), sessionId, status.isSeen(), meta.isRead(), sessionId, accept,
meta.getPrivateGroupId(), c, accept); meta.getPrivateGroupId()
);
} }
@Override @Override

View File

@@ -56,8 +56,7 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
@Override @Override
public InviteeSession onInviteAction(Transaction txn, InviteeSession s, public InviteeSession onInviteAction(Transaction txn, InviteeSession s,
@Nullable String message, long timestamp, byte[] signature) @Nullable String message, long timestamp, byte[] signature) {
throws DbException {
throw new UnsupportedOperationException(); // Invalid in this role throw new UnsupportedOperationException(); // Invalid in this role
} }
@@ -99,8 +98,8 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
} }
@Override @Override
public InviteeSession onMemberAddedAction(Transaction txn, InviteeSession s) public InviteeSession onMemberAddedAction(Transaction txn,
throws DbException { InviteeSession s) {
return s; // Ignored in this role return s; // Ignored in this role
} }
@@ -244,9 +243,8 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
// Broadcast an event // Broadcast an event
PrivateGroup privateGroup = privateGroupFactory.createPrivateGroup( PrivateGroup privateGroup = privateGroupFactory.createPrivateGroup(
m.getGroupName(), m.getCreator(), m.getSalt()); m.getGroupName(), m.getCreator(), m.getSalt());
txn.attach( txn.attach(new GroupInvitationRequestReceivedEvent(
new GroupInvitationRequestReceivedEvent(privateGroup, contactId, createInvitationRequest(m, privateGroup), contactId));
createInvitationRequest(m, privateGroup, contactId)));
// Move to the INVITED state // Move to the INVITED state
return new InviteeSession(s.getContactGroupId(), s.getPrivateGroupId(), return new InviteeSession(s.getContactGroupId(), s.getPrivateGroupId(),
s.getLastLocalMessageId(), m.getId(), s.getLocalTimestamp(), s.getLastLocalMessageId(), m.getId(), s.getLocalTimestamp(),
@@ -328,10 +326,10 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
} }
private GroupInvitationRequest createInvitationRequest(InviteMessage m, private GroupInvitationRequest createInvitationRequest(InviteMessage m,
PrivateGroup pg, ContactId c) { PrivateGroup pg) {
SessionId sessionId = new SessionId(m.getPrivateGroupId().getBytes()); SessionId sessionId = new SessionId(m.getPrivateGroupId().getBytes());
return new GroupInvitationRequest(m.getId(), m.getContactGroupId(), return new GroupInvitationRequest(m.getId(), m.getContactGroupId(),
m.getTimestamp(), false, false, true, false, sessionId, pg, c, m.getTimestamp(), false, false, true, false, sessionId, pg,
m.getMessage(), true, false); m.getMessage(), true, false);
} }

View File

@@ -24,17 +24,16 @@ public class BlogInvitationFactoryImpl
SessionId sessionId = new SessionId(m.getShareableId().getBytes()); SessionId sessionId = new SessionId(m.getShareableId().getBytes());
return new BlogInvitationRequest(m.getId(), m.getContactGroupId(), return new BlogInvitationRequest(m.getId(), m.getContactGroupId(),
m.getTimestamp(), local, sent, seen, read, sessionId, m.getTimestamp(), local, sent, seen, read, sessionId,
m.getShareable(), c, m.getMessage(), available, canBeOpened); m.getShareable(), m.getMessage(), available, canBeOpened);
} }
@Override @Override
public BlogInvitationResponse createInvitationResponse(MessageId id, public BlogInvitationResponse createInvitationResponse(MessageId id,
GroupId contactGroupId, long time, boolean local, boolean sent, GroupId contactGroupId, long time, boolean local, boolean sent,
boolean seen, boolean read, GroupId shareableId, boolean seen, boolean read, boolean accept, GroupId shareableId) {
ContactId contactId, boolean accept) {
SessionId sessionId = new SessionId(shareableId.getBytes()); SessionId sessionId = new SessionId(shareableId.getBytes());
return new BlogInvitationResponse(id, contactGroupId, time, local, return new BlogInvitationResponse(id, contactGroupId, time, local, sent,
sent, seen, read, sessionId, shareableId, contactId, accept); seen, read, sessionId, accept, shareableId);
} }
} }

View File

@@ -30,7 +30,7 @@ class BlogMessageParserImpl extends MessageParserImpl<Blog> {
} }
@Override @Override
protected Blog createShareable(BdfList descriptor) throws FormatException { public Blog createShareable(BdfList descriptor) throws FormatException {
// Author, RSS // Author, RSS
BdfList authorList = descriptor.getList(0); BdfList authorList = descriptor.getList(0);
boolean rssFeed = descriptor.getBoolean(1); boolean rssFeed = descriptor.getBoolean(1);

View File

@@ -18,7 +18,7 @@ import org.briarproject.briar.api.blog.BlogManager;
import org.briarproject.briar.api.blog.event.BlogInvitationRequestReceivedEvent; import org.briarproject.briar.api.blog.event.BlogInvitationRequestReceivedEvent;
import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent; import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent;
import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.sharing.InvitationRequest; import org.briarproject.briar.api.messaging.PrivateRequest;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import javax.inject.Inject; import javax.inject.Inject;
@@ -50,11 +50,10 @@ class BlogProtocolEngineImpl extends ProtocolEngineImpl<Blog> {
@Override @Override
Event getInvitationRequestReceivedEvent(InviteMessage<Blog> m, Event getInvitationRequestReceivedEvent(InviteMessage<Blog> m,
ContactId contactId, boolean available, boolean canBeOpened) { ContactId contactId, boolean available, boolean canBeOpened) {
InvitationRequest<Blog> request = invitationFactory PrivateRequest<Blog> request = invitationFactory
.createInvitationRequest(false, false, true, false, m, .createInvitationRequest(false, false, true, false, m,
contactId, available, canBeOpened); contactId, available, canBeOpened);
return new BlogInvitationRequestReceivedEvent(m.getShareable(), return new BlogInvitationRequestReceivedEvent(request, contactId);
contactId, request);
} }
@Override @Override
@@ -62,9 +61,9 @@ class BlogProtocolEngineImpl extends ProtocolEngineImpl<Blog> {
ContactId contactId) { ContactId contactId) {
BlogInvitationResponse response = invitationFactory BlogInvitationResponse response = invitationFactory
.createInvitationResponse(m.getId(), m.getContactGroupId(), .createInvitationResponse(m.getId(), m.getContactGroupId(),
m.getTimestamp(), false, false, true, false, m.getTimestamp(), false, false, false, false,
m.getShareableId(), contactId, true); true, m.getShareableId());
return new BlogInvitationResponseReceivedEvent(contactId, response); return new BlogInvitationResponseReceivedEvent(response, contactId);
} }
@Override @Override
@@ -72,9 +71,9 @@ class BlogProtocolEngineImpl extends ProtocolEngineImpl<Blog> {
ContactId contactId) { ContactId contactId) {
BlogInvitationResponse response = invitationFactory BlogInvitationResponse response = invitationFactory
.createInvitationResponse(m.getId(), m.getContactGroupId(), .createInvitationResponse(m.getId(), m.getContactGroupId(),
m.getTimestamp(), false, false, true, false, m.getTimestamp(), false, false, false, false,
m.getShareableId(), contactId, true); false, m.getShareableId());
return new BlogInvitationResponseReceivedEvent(contactId, response); return new BlogInvitationResponseReceivedEvent(response, contactId);
} }
@Override @Override

View File

@@ -80,8 +80,8 @@ class BlogSharingManagerImpl extends SharingManagerImpl<Blog>
// Pre-share both blogs, if they have not been shared already // Pre-share both blogs, if they have not been shared already
try { try {
preShareShareable(txn, c, ourBlog); preShareGroup(txn, c, ourBlog.getGroup());
preShareShareable(txn, c, theirBlog); preShareGroup(txn, c, theirBlog.getGroup());
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }

View File

@@ -24,17 +24,16 @@ public class ForumInvitationFactoryImpl
SessionId sessionId = new SessionId(m.getShareableId().getBytes()); SessionId sessionId = new SessionId(m.getShareableId().getBytes());
return new ForumInvitationRequest(m.getId(), m.getContactGroupId(), return new ForumInvitationRequest(m.getId(), m.getContactGroupId(),
m.getTimestamp(), local, sent, seen, read, sessionId, m.getTimestamp(), local, sent, seen, read, sessionId,
m.getShareable(), c, m.getMessage(), available, canBeOpened); m.getShareable(), m.getMessage(), available, canBeOpened);
} }
@Override @Override
public ForumInvitationResponse createInvitationResponse(MessageId id, public ForumInvitationResponse createInvitationResponse(MessageId id,
GroupId contactGroupId, long time, boolean local, boolean sent, GroupId contactGroupId, long time, boolean local, boolean sent,
boolean seen, boolean read, GroupId shareableId, boolean seen, boolean read, boolean accept, GroupId shareableId) {
ContactId contactId, boolean accept) {
SessionId sessionId = new SessionId(shareableId.getBytes()); SessionId sessionId = new SessionId(shareableId.getBytes());
return new ForumInvitationResponse(id, contactGroupId, time, local, return new ForumInvitationResponse(id, contactGroupId, time, local,
sent, seen, read, sessionId, shareableId, contactId, accept); sent, seen, read, sessionId, accept, shareableId);
} }
} }

View File

@@ -24,7 +24,7 @@ class ForumMessageParserImpl extends MessageParserImpl<Forum> {
} }
@Override @Override
protected Forum createShareable(BdfList descriptor) throws FormatException { public Forum createShareable(BdfList descriptor) throws FormatException {
// Name, salt // Name, salt
String name = descriptor.getString(0); String name = descriptor.getString(0);
byte[] salt = descriptor.getRaw(1); byte[] salt = descriptor.getRaw(1);

View File

@@ -18,7 +18,7 @@ import org.briarproject.briar.api.forum.ForumInvitationResponse;
import org.briarproject.briar.api.forum.ForumManager; import org.briarproject.briar.api.forum.ForumManager;
import org.briarproject.briar.api.forum.event.ForumInvitationRequestReceivedEvent; import org.briarproject.briar.api.forum.event.ForumInvitationRequestReceivedEvent;
import org.briarproject.briar.api.forum.event.ForumInvitationResponseReceivedEvent; import org.briarproject.briar.api.forum.event.ForumInvitationResponseReceivedEvent;
import org.briarproject.briar.api.sharing.InvitationRequest; import org.briarproject.briar.api.messaging.PrivateRequest;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import javax.inject.Inject; import javax.inject.Inject;
@@ -31,8 +31,7 @@ import static org.briarproject.briar.api.forum.ForumManager.MAJOR_VERSION;
class ForumProtocolEngineImpl extends ProtocolEngineImpl<Forum> { class ForumProtocolEngineImpl extends ProtocolEngineImpl<Forum> {
private final ForumManager forumManager; private final ForumManager forumManager;
private final InvitationFactory<Forum, ForumInvitationResponse> private final InvitationFactory<Forum, ForumInvitationResponse> invitationFactory;
invitationFactory;
@Inject @Inject
ForumProtocolEngineImpl(DatabaseComponent db, ForumProtocolEngineImpl(DatabaseComponent db,
@@ -52,11 +51,10 @@ class ForumProtocolEngineImpl extends ProtocolEngineImpl<Forum> {
@Override @Override
Event getInvitationRequestReceivedEvent(InviteMessage<Forum> m, Event getInvitationRequestReceivedEvent(InviteMessage<Forum> m,
ContactId contactId, boolean available, boolean canBeOpened) { ContactId contactId, boolean available, boolean canBeOpened) {
InvitationRequest<Forum> request = invitationFactory PrivateRequest<Forum> request = invitationFactory
.createInvitationRequest(false, false, true, false, m, .createInvitationRequest(false, false, true, false, m,
contactId, available, canBeOpened); contactId, available, canBeOpened);
return new ForumInvitationRequestReceivedEvent(m.getShareable(), return new ForumInvitationRequestReceivedEvent(request, contactId);
contactId, request);
} }
@Override @Override
@@ -65,8 +63,8 @@ class ForumProtocolEngineImpl extends ProtocolEngineImpl<Forum> {
ForumInvitationResponse response = invitationFactory ForumInvitationResponse response = invitationFactory
.createInvitationResponse(m.getId(), m.getContactGroupId(), .createInvitationResponse(m.getId(), m.getContactGroupId(),
m.getTimestamp(), false, false, true, false, m.getTimestamp(), false, false, true, false,
m.getShareableId(), contactId, true); true, m.getShareableId());
return new ForumInvitationResponseReceivedEvent(contactId, response); return new ForumInvitationResponseReceivedEvent(response, contactId);
} }
@Override @Override
@@ -75,8 +73,8 @@ class ForumProtocolEngineImpl extends ProtocolEngineImpl<Forum> {
ForumInvitationResponse response = invitationFactory ForumInvitationResponse response = invitationFactory
.createInvitationResponse(m.getId(), m.getContactGroupId(), .createInvitationResponse(m.getId(), m.getContactGroupId(),
m.getTimestamp(), false, false, true, false, m.getTimestamp(), false, false, true, false,
m.getShareableId(), contactId, true); false, m.getShareableId());
return new ForumInvitationResponseReceivedEvent(contactId, response); return new ForumInvitationResponseReceivedEvent(response, contactId);
} }
@Override @Override

View File

@@ -3,19 +3,18 @@ package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.sharing.InvitationRequest; import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.sharing.InvitationResponse; import org.briarproject.briar.api.sharing.InvitationResponse;
import org.briarproject.briar.api.sharing.Shareable; import org.briarproject.briar.api.sharing.Shareable;
public interface InvitationFactory<S extends Shareable, I extends InvitationResponse> { public interface InvitationFactory<S extends Shareable, R extends InvitationResponse> {
InvitationRequest<S> createInvitationRequest(boolean local, boolean sent, PrivateRequest<S> createInvitationRequest(boolean local, boolean sent,
boolean seen, boolean read, InviteMessage<S> m, ContactId c, boolean seen, boolean read, InviteMessage<S> m, ContactId c,
boolean available, boolean canBeOpened); boolean available, boolean canBeOpened);
I createInvitationResponse(MessageId id, R createInvitationResponse(MessageId id, GroupId contactGroupId, long time,
GroupId contactGroupId, long time, boolean local, boolean sent, boolean local, boolean sent, boolean seen, boolean read,
boolean seen, boolean read, GroupId shareableId, boolean accept, GroupId shareableId);
ContactId contactId, boolean accept);
} }

View File

@@ -22,6 +22,8 @@ interface MessageParser<S extends Shareable> {
MessageMetadata parseMetadata(BdfDictionary meta) throws FormatException; MessageMetadata parseMetadata(BdfDictionary meta) throws FormatException;
S createShareable(BdfList descriptor) throws FormatException;
InviteMessage<S> getInviteMessage(Transaction txn, MessageId m) InviteMessage<S> getInviteMessage(Transaction txn, MessageId m)
throws DbException, FormatException; throws DbException, FormatException;

View File

@@ -94,9 +94,6 @@ abstract class MessageParserImpl<S extends Shareable>
m.getGroupId(), shareable, message, m.getTimestamp()); m.getGroupId(), shareable, message, m.getTimestamp());
} }
protected abstract S createShareable(BdfList descriptor)
throws FormatException;
@Override @Override
public AcceptMessage parseAcceptMessage(Message m, BdfList body) public AcceptMessage parseAcceptMessage(Message m, BdfList body)
throws FormatException { throws FormatException {

View File

@@ -293,7 +293,7 @@ abstract class ProtocolEngineImpl<S extends Shareable>
if (m.getTimestamp() <= s.getInviteTimestamp()) if (m.getTimestamp() <= s.getInviteTimestamp())
return abortWithMessage(txn, s); return abortWithMessage(txn, s);
// The dependency, if any, must be the last remote message // The dependency, if any, must be the last remote message
if (!isValidDependency(s, m.getPreviousMessageId())) if (isInvalidDependency(s, m.getPreviousMessageId()))
return abortWithMessage(txn, s); return abortWithMessage(txn, s);
// Mark the invite message visible in the UI and (un)available to answer // Mark the invite message visible in the UI and (un)available to answer
markMessageVisibleInUi(txn, m.getId()); markMessageVisibleInUi(txn, m.getId());
@@ -317,7 +317,7 @@ abstract class ProtocolEngineImpl<S extends Shareable>
if (m.getTimestamp() <= s.getInviteTimestamp()) if (m.getTimestamp() <= s.getInviteTimestamp())
return abortWithMessage(txn, s); return abortWithMessage(txn, s);
// The dependency, if any, must be the last remote message // The dependency, if any, must be the last remote message
if (!isValidDependency(s, m.getPreviousMessageId())) if (isInvalidDependency(s, m.getPreviousMessageId()))
return abortWithMessage(txn, s); return abortWithMessage(txn, s);
// Mark the invite message visible in the UI and unavailable to answer // Mark the invite message visible in the UI and unavailable to answer
markMessageVisibleInUi(txn, m.getId()); markMessageVisibleInUi(txn, m.getId());
@@ -364,7 +364,7 @@ abstract class ProtocolEngineImpl<S extends Shareable>
if (m.getTimestamp() <= s.getInviteTimestamp()) if (m.getTimestamp() <= s.getInviteTimestamp())
return abortWithMessage(txn, s); return abortWithMessage(txn, s);
// The dependency, if any, must be the last remote message // The dependency, if any, must be the last remote message
if (!isValidDependency(s, m.getPreviousMessageId())) if (isInvalidDependency(s, m.getPreviousMessageId()))
return abortWithMessage(txn, s); return abortWithMessage(txn, s);
// Mark the response visible in the UI // Mark the response visible in the UI
markMessageVisibleInUi(txn, m.getId()); markMessageVisibleInUi(txn, m.getId());
@@ -416,7 +416,7 @@ abstract class ProtocolEngineImpl<S extends Shareable>
if (m.getTimestamp() <= s.getInviteTimestamp()) if (m.getTimestamp() <= s.getInviteTimestamp())
return abortWithMessage(txn, s); return abortWithMessage(txn, s);
// The dependency, if any, must be the last remote message // The dependency, if any, must be the last remote message
if (!isValidDependency(s, m.getPreviousMessageId())) if (isInvalidDependency(s, m.getPreviousMessageId()))
return abortWithMessage(txn, s); return abortWithMessage(txn, s);
// Mark the response visible in the UI // Mark the response visible in the UI
markMessageVisibleInUi(txn, m.getId()); markMessageVisibleInUi(txn, m.getId());
@@ -463,7 +463,7 @@ abstract class ProtocolEngineImpl<S extends Shareable>
private Session onRemoteLeaveWhenInvited(Transaction txn, Session s, private Session onRemoteLeaveWhenInvited(Transaction txn, Session s,
LeaveMessage m) throws DbException, FormatException { LeaveMessage m) throws DbException, FormatException {
// The dependency, if any, must be the last remote message // The dependency, if any, must be the last remote message
if (!isValidDependency(s, m.getPreviousMessageId())) if (isInvalidDependency(s, m.getPreviousMessageId()))
return abortWithMessage(txn, s); return abortWithMessage(txn, s);
// Mark any invite messages in the session unavailable to answer // Mark any invite messages in the session unavailable to answer
markInvitesUnavailableToAnswer(txn, s); markInvitesUnavailableToAnswer(txn, s);
@@ -476,7 +476,7 @@ abstract class ProtocolEngineImpl<S extends Shareable>
private Session onRemoteLeaveWhenLocalLeft(Transaction txn, Session s, private Session onRemoteLeaveWhenLocalLeft(Transaction txn, Session s,
LeaveMessage m) throws DbException, FormatException { LeaveMessage m) throws DbException, FormatException {
// The dependency, if any, must be the last remote message // The dependency, if any, must be the last remote message
if (!isValidDependency(s, m.getPreviousMessageId())) if (isInvalidDependency(s, m.getPreviousMessageId()))
return abortWithMessage(txn, s); return abortWithMessage(txn, s);
// Move to the next state // Move to the next state
return new Session(START, s.getContactGroupId(), s.getShareableId(), return new Session(START, s.getContactGroupId(), s.getShareableId(),
@@ -487,7 +487,7 @@ abstract class ProtocolEngineImpl<S extends Shareable>
private Session onRemoteLeaveWhenSharing(Transaction txn, Session s, private Session onRemoteLeaveWhenSharing(Transaction txn, Session s,
LeaveMessage m) throws DbException, FormatException { LeaveMessage m) throws DbException, FormatException {
// The dependency, if any, must be the last remote message // The dependency, if any, must be the last remote message
if (!isValidDependency(s, m.getPreviousMessageId())) if (isInvalidDependency(s, m.getPreviousMessageId()))
return abortWithMessage(txn, s); return abortWithMessage(txn, s);
// Broadcast event informing that contact left // Broadcast event informing that contact left
ContactId contactId = getContactId(txn, s.getContactGroupId()); ContactId contactId = getContactId(txn, s.getContactGroupId());
@@ -623,11 +623,11 @@ abstract class ProtocolEngineImpl<S extends Shareable>
return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue());
} }
private boolean isValidDependency(Session session, private boolean isInvalidDependency(Session session,
@Nullable MessageId dependency) { @Nullable MessageId dependency) {
MessageId expected = session.getLastRemoteMessageId(); MessageId expected = session.getLastRemoteMessageId();
if (dependency == null) return expected == null; if (dependency == null) return expected != null;
return expected != null && dependency.equals(expected); return expected == null || !dependency.equals(expected);
} }
private long getLocalTimestamp(Session session) { private long getLocalTimestamp(Session session) {

View File

@@ -26,8 +26,8 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook; import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook;
import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.sharing.InvitationMessage; import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.sharing.InvitationRequest; import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.sharing.InvitationResponse; import org.briarproject.briar.api.sharing.InvitationResponse;
import org.briarproject.briar.api.sharing.Shareable; import org.briarproject.briar.api.sharing.Shareable;
import org.briarproject.briar.api.sharing.SharingInvitationItem; import org.briarproject.briar.api.sharing.SharingInvitationItem;
@@ -156,29 +156,29 @@ abstract class SharingManagerImpl<S extends Shareable>
} }
/** /**
* Adds the given Shareable and initializes a session between us * Adds the given Group and initializes a session between us
* and the Contact c in state SHARING. * and the Contact c in state SHARING.
* If a session already exists, this does nothing. * If a session already exists, this does nothing.
*/ */
void preShareShareable(Transaction txn, Contact c, S shareable) void preShareGroup(Transaction txn, Contact c, Group g)
throws DbException, FormatException { throws DbException, FormatException {
// Return if a session already exists with the contact // Return if a session already exists with the contact
GroupId contactGroupId = getContactGroup(c).getId(); GroupId contactGroupId = getContactGroup(c).getId();
StoredSession existingSession = getSession(txn, contactGroupId, StoredSession existingSession = getSession(txn, contactGroupId,
getSessionId(shareable.getId())); getSessionId(g.getId()));
if (existingSession != null) return; if (existingSession != null) return;
// Add the shareable // Add the shareable's group
db.addGroup(txn, shareable.getGroup()); db.addGroup(txn, g);
// Apply the client's visibility // Apply the client's visibility
Visibility client = clientVersioningManager.getClientVisibility(txn, Visibility client = clientVersioningManager.getClientVisibility(txn,
c.getId(), getShareableClientId(), getShareableMajorVersion()); c.getId(), getShareableClientId(), getShareableMajorVersion());
db.setGroupVisibility(txn, c.getId(), shareable.getId(), client); db.setGroupVisibility(txn, c.getId(), g.getId(), client);
// Initialize session in sharing state // Initialize session in sharing state
Session session = new Session(SHARING, contactGroupId, Session session = new Session(SHARING, contactGroupId, g.getId(),
shareable.getId(), null, null, 0, 0); null, null, 0, 0);
MessageId storageId = createStorageId(txn, contactGroupId); MessageId storageId = createStorageId(txn, contactGroupId);
storeSession(txn, storageId, session); storeSession(txn, storageId, session);
} }
@@ -321,17 +321,16 @@ abstract class SharingManagerImpl<S extends Shareable>
} }
@Override @Override
public Collection<InvitationMessage> getInvitationMessages(ContactId c) public Collection<PrivateMessageHeader> getMessageHeaders(Transaction txn,
throws DbException { ContactId c) throws DbException {
List<InvitationMessage> messages;
Transaction txn = db.startTransaction(true);
try { try {
Contact contact = db.getContact(txn, c); Contact contact = db.getContact(txn, c);
GroupId contactGroupId = getContactGroup(contact).getId(); GroupId contactGroupId = getContactGroup(contact).getId();
BdfDictionary query = messageParser.getMessagesVisibleInUiQuery(); BdfDictionary query = messageParser.getMessagesVisibleInUiQuery();
Map<MessageId, BdfDictionary> results = clientHelper Map<MessageId, BdfDictionary> results = clientHelper
.getMessageMetadataAsDictionary(txn, contactGroupId, query); .getMessageMetadataAsDictionary(txn, contactGroupId, query);
messages = new ArrayList<>(results.size()); Collection<PrivateMessageHeader> messages =
new ArrayList<>(results.size());
for (Entry<MessageId, BdfDictionary> e : results.entrySet()) { for (Entry<MessageId, BdfDictionary> e : results.entrySet()) {
MessageId m = e.getKey(); MessageId m = e.getKey();
MessageMetadata meta = MessageMetadata meta =
@@ -339,28 +338,23 @@ abstract class SharingManagerImpl<S extends Shareable>
MessageStatus status = db.getMessageStatus(txn, c, m); MessageStatus status = db.getMessageStatus(txn, c, m);
MessageType type = meta.getMessageType(); MessageType type = meta.getMessageType();
if (type == INVITE) { if (type == INVITE) {
messages.add( messages.add(parseInvitationRequest(txn, c, m,
parseInvitationRequest(txn, c, m, meta, status)); meta, status));
} else if (type == ACCEPT) { } else if (type == ACCEPT) {
messages.add( messages.add(parseInvitationResponse(contactGroupId, m,
parseInvitationResponse(c, contactGroupId, m, meta, meta, status, true));
status, true));
} else if (type == DECLINE) { } else if (type == DECLINE) {
messages.add( messages.add(parseInvitationResponse(contactGroupId, m,
parseInvitationResponse(c, contactGroupId, m, meta, meta, status, false));
status, false));
} }
} }
db.commitTransaction(txn); return messages;
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} finally {
db.endTransaction(txn);
} }
return messages;
} }
private InvitationRequest parseInvitationRequest(Transaction txn, private PrivateRequest<S> parseInvitationRequest(Transaction txn,
ContactId c, MessageId m, MessageMetadata meta, ContactId c, MessageId m, MessageMetadata meta,
MessageStatus status) throws DbException, FormatException { MessageStatus status) throws DbException, FormatException {
// Look up the invite message to get the details of the private group // Look up the invite message to get the details of the private group
@@ -374,14 +368,12 @@ abstract class SharingManagerImpl<S extends Shareable>
meta.isAvailableToAnswer(), canBeOpened); meta.isAvailableToAnswer(), canBeOpened);
} }
private InvitationResponse parseInvitationResponse(ContactId c, private InvitationResponse parseInvitationResponse(GroupId contactGroupId,
GroupId contactGroupId, MessageId m, MessageMetadata meta, MessageId m, MessageMetadata meta, MessageStatus status,
MessageStatus status, boolean accept) boolean accept) {
throws DbException, FormatException {
return invitationFactory.createInvitationResponse(m, contactGroupId, return invitationFactory.createInvitationResponse(m, contactGroupId,
meta.getTimestamp(), meta.isLocal(), status.isSent(), meta.getTimestamp(), meta.isLocal(), status.isSent(),
status.isSeen(), meta.isRead(), meta.getShareableId(), c, status.isSeen(), meta.isRead(), accept, meta.getShareableId());
accept);
} }
@Override @Override

View File

@@ -1,6 +1,5 @@
package org.briarproject.briar.blog; package org.briarproject.briar.blog;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
@@ -63,10 +62,7 @@ public class BlogManagerIntegrationTest
blog1 = blogFactory.createBlog(author1); blog1 = blogFactory.createBlog(author1);
rssBlog = blogFactory.createFeedBlog(rssAuthor); rssBlog = blogFactory.createFeedBlog(rssAuthor);
Transaction txn = db0.startTransaction(false); withinTransaction(db0, txn -> blogManager0.addBlog(txn, rssBlog));
blogManager0.addBlog(txn, rssBlog);
db0.commitTransaction(txn);
db0.endTransaction(txn);
} }
@Override @Override

View File

@@ -9,8 +9,8 @@ import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.data.BdfEntry;
import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
@@ -25,13 +25,13 @@ import org.briarproject.bramble.test.TestDatabaseModule;
import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.introduction.IntroductionManager; import org.briarproject.briar.api.introduction.IntroductionManager;
import org.briarproject.briar.api.introduction.IntroductionMessage;
import org.briarproject.briar.api.introduction.IntroductionRequest; import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.introduction.IntroductionResponse; import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent; import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent; import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent; import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent; import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.test.BriarIntegrationTest; import org.briarproject.briar.test.BriarIntegrationTest;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -159,7 +159,7 @@ public class IntroductionIntegrationTest
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertTrue(listener0.response1Received); assertTrue(listener0.response1Received);
assertEquals(introducee2.getAuthor().getName(), assertEquals(introducee2.getAuthor().getName(),
listener0.getResponse().getName()); listener0.getResponse().getIntroducedAuthor().getName());
assertGroupCount(messageTracker0, g1.getId(), 2, 1); assertGroupCount(messageTracker0, g1.getId(), 2, 1);
// sync second ACCEPT message // sync second ACCEPT message
@@ -167,7 +167,7 @@ public class IntroductionIntegrationTest
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertTrue(listener0.response2Received); assertTrue(listener0.response2Received);
assertEquals(introducee1.getAuthor().getName(), assertEquals(introducee1.getAuthor().getName(),
listener0.getResponse().getName()); listener0.getResponse().getIntroducedAuthor().getName());
assertGroupCount(messageTracker0, g2.getId(), 2, 1); assertGroupCount(messageTracker0, g2.getId(), 2, 1);
// sync forwarded ACCEPT messages to introducees // sync forwarded ACCEPT messages to introducees
@@ -265,7 +265,7 @@ public class IntroductionIntegrationTest
// assert that the name on the decline event is correct // assert that the name on the decline event is correct
assertEquals(introducee2.getAuthor().getName(), assertEquals(introducee2.getAuthor().getName(),
listener0.getResponse().getName()); listener0.getResponse().getIntroducedAuthor().getName());
// sync second response // sync second response
sync2To0(1, true); sync2To0(1, true);
@@ -282,7 +282,7 @@ public class IntroductionIntegrationTest
// assert that the name on the decline event is correct // assert that the name on the decline event is correct
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertEquals(introducee1.getAuthor().getName(), assertEquals(introducee1.getAuthor().getName(),
listener2.getResponse().getName()); listener2.getResponse().getIntroducedAuthor().getName());
// note how the introducer does not forward the second response, // note how the introducer does not forward the second response,
// because after the first decline the protocol finished // because after the first decline the protocol finished
@@ -297,22 +297,23 @@ public class IntroductionIntegrationTest
Group g1 = introductionManager0.getContactGroup(introducee1); Group g1 = introductionManager0.getContactGroup(introducee1);
Group g2 = introductionManager0.getContactGroup(introducee2); Group g2 = introductionManager0.getContactGroup(introducee2);
assertEquals(2, Collection<PrivateMessageHeader> messages =
introductionManager0.getIntroductionMessages(contactId1From0) withinTransactionReturns(db0, txn -> introductionManager0
.size()); .getMessageHeaders(txn, contactId1From0));
assertEquals(2, messages.size());
assertGroupCount(messageTracker0, g1.getId(), 2, 1); assertGroupCount(messageTracker0, g1.getId(), 2, 1);
assertEquals(2, messages = withinTransactionReturns(db0,
introductionManager0.getIntroductionMessages(contactId2From0) txn -> introductionManager0.getMessageHeaders(txn, contactId2From0));
.size()); assertEquals(2, messages.size());
assertGroupCount(messageTracker0, g2.getId(), 2, 1); assertGroupCount(messageTracker0, g2.getId(), 2, 1);
assertEquals(2, messages = withinTransactionReturns(db1,
introductionManager1.getIntroductionMessages(contactId0From1) txn -> introductionManager1.getMessageHeaders(txn, contactId0From1));
.size()); assertEquals(2, messages.size());
assertGroupCount(messageTracker1, g1.getId(), 2, 1); assertGroupCount(messageTracker1, g1.getId(), 2, 1);
// introducee2 should also have the decline response of introducee1 // introducee2 should also have the decline response of introducee1
assertEquals(3, messages = withinTransactionReturns(db2,
introductionManager2.getIntroductionMessages(contactId0From2) txn -> introductionManager2.getMessageHeaders(txn, contactId0From2));
.size()); assertEquals(3, messages.size());
assertGroupCount(messageTracker2, g2.getId(), 3, 2); assertGroupCount(messageTracker2, g2.getId(), 3, 2);
assertFalse(listener0.aborted); assertFalse(listener0.aborted);
@@ -355,25 +356,29 @@ public class IntroductionIntegrationTest
// assert that the name on the decline event is correct // assert that the name on the decline event is correct
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertEquals(contact2From0.getAuthor().getName(), assertEquals(contact2From0.getAuthor().getName(),
listener1.getResponse().getName()); listener1.getResponse().getIntroducedAuthor().getName());
assertFalse(contactManager1 assertFalse(contactManager1
.contactExists(author2.getId(), author1.getId())); .contactExists(author2.getId(), author1.getId()));
assertFalse(contactManager2 assertFalse(contactManager2
.contactExists(author1.getId(), author2.getId())); .contactExists(author1.getId(), author2.getId()));
assertEquals(2, Collection<PrivateMessageHeader> messages =
introductionManager0.getIntroductionMessages(contactId1From0) withinTransactionReturns(db0, txn -> introductionManager0
.size()); .getMessageHeaders(txn, contactId1From0));
assertEquals(2, assertEquals(2, messages.size());
introductionManager0.getIntroductionMessages(contactId2From0) messages = withinTransactionReturns(db0,
.size()); txn -> introductionManager0
assertEquals(3, .getMessageHeaders(txn, contactId2From0));
introductionManager1.getIntroductionMessages(contactId0From1) assertEquals(2, messages.size());
.size()); messages = withinTransactionReturns(db1,
assertEquals(3, txn -> introductionManager1
introductionManager2.getIntroductionMessages(contactId0From2) .getMessageHeaders(txn, contactId0From1));
.size()); assertEquals(3, messages.size());
messages = withinTransactionReturns(db2,
txn -> introductionManager2
.getMessageHeaders(txn, contactId0From2));
assertEquals(3, messages.size());
assertFalse(listener0.aborted); assertFalse(listener0.aborted);
assertFalse(listener1.aborted); assertFalse(listener1.aborted);
assertFalse(listener2.aborted); assertFalse(listener2.aborted);
@@ -482,7 +487,7 @@ public class IntroductionIntegrationTest
// assert that the name on the decline event is correct // assert that the name on the decline event is correct
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertEquals(introducee1.getAuthor().getName(), assertEquals(introducee1.getAuthor().getName(),
listener2.getResponse().getName()); listener2.getResponse().getIntroducedAuthor().getName());
// assert that introducee2 is in correct state // assert that introducee2 is in correct state
introduceeSession = getIntroduceeSession(c2); introduceeSession = getIntroduceeSession(c2);
@@ -519,21 +524,21 @@ public class IntroductionIntegrationTest
Group g1 = introductionManager0.getContactGroup(introducee1); Group g1 = introductionManager0.getContactGroup(introducee1);
Group g2 = introductionManager0.getContactGroup(introducee2); Group g2 = introductionManager0.getContactGroup(introducee2);
assertEquals(2, assertEquals(2, withinTransactionReturns(db0,
introductionManager0.getIntroductionMessages(contactId1From0) txn -> introductionManager0.getMessageHeaders(txn, contactId1From0))
.size()); .size());
assertGroupCount(messageTracker0, g1.getId(), 2, 1); assertGroupCount(messageTracker0, g1.getId(), 2, 1);
assertEquals(2, assertEquals(2, withinTransactionReturns(db0,
introductionManager0.getIntroductionMessages(contactId2From0) txn -> introductionManager0.getMessageHeaders(txn, contactId2From0))
.size()); .size());
assertGroupCount(messageTracker0, g2.getId(), 2, 1); assertGroupCount(messageTracker0, g2.getId(), 2, 1);
assertEquals(3, assertEquals(3, withinTransactionReturns(db1,
introductionManager1.getIntroductionMessages(contactId0From1) txn -> introductionManager1.getMessageHeaders(txn, contactId0From1))
.size()); .size());
assertGroupCount(messageTracker1, g1.getId(), 3, 2); assertGroupCount(messageTracker1, g1.getId(), 3, 2);
assertEquals(3, assertEquals(3, withinTransactionReturns(db2,
introductionManager2.getIntroductionMessages(contactId0From2) txn -> introductionManager2.getMessageHeaders(txn, contactId0From2))
.size()); .size());
assertGroupCount(messageTracker2, g2.getId(), 3, 2); assertGroupCount(messageTracker2, g2.getId(), 3, 2);
assertFalse(listener0.aborted); assertFalse(listener0.aborted);
@@ -557,7 +562,8 @@ public class IntroductionIntegrationTest
assertFalse(listener1.requestReceived); assertFalse(listener1.requestReceived);
// make really sure we don't have that request // make really sure we don't have that request
assertTrue(introductionManager1.getIntroductionMessages(contactId0From1) assertTrue(withinTransactionReturns(db1,
txn -> introductionManager1.getMessageHeaders(txn, contactId0From1))
.isEmpty()); .isEmpty());
// The message was invalid, so no abort message was sent // The message was invalid, so no abort message was sent
@@ -606,12 +612,12 @@ public class IntroductionIntegrationTest
sync0To2(1, true); sync0To2(1, true);
// assert that introducees get notified about the existing contact // assert that introducees get notified about the existing contact
IntroductionRequest ir1 = IntroductionRequest ir1 = getIntroductionRequest(db1,
getIntroductionRequest(introductionManager1, contactId0From1); introductionManager1, contactId0From1);
assertTrue(ir1.contactExists()); assertTrue(ir1.isContact());
IntroductionRequest ir2 = IntroductionRequest ir2 = getIntroductionRequest(db2,
getIntroductionRequest(introductionManager2, contactId0From2); introductionManager2, contactId0From2);
assertTrue(ir2.contactExists()); assertTrue(ir2.isContact());
// sync ACCEPT messages back to introducer // sync ACCEPT messages back to introducer
sync1To0(1, true); sync1To0(1, true);
@@ -991,8 +997,7 @@ public class IntroductionIntegrationTest
AcceptMessage m = visitor.visit(message); AcceptMessage m = visitor.visit(message);
// replace original response with modified one // replace original response with modified one
Transaction txn = db0.startTransaction(false); withinTransaction(db0, txn -> {
try {
db0.removeMessage(txn, message.getMessageId()); db0.removeMessage(txn, message.getMessageId());
Message msg = c0.getMessageEncoder() Message msg = c0.getMessageEncoder()
.encodeAcceptMessage(m.getGroupId(), m.getTimestamp(), .encodeAcceptMessage(m.getGroupId(), m.getTimestamp(),
@@ -1012,10 +1017,7 @@ public class IntroductionIntegrationTest
session.getValue(), msg.getId()); session.getValue(), msg.getId());
c0.getClientHelper().mergeMessageMetadata(txn, session.getKey(), c0.getClientHelper().mergeMessageMetadata(txn, session.getKey(),
session.getValue()); session.getValue());
db0.commitTransaction(txn); });
} finally {
db0.endTransaction(txn);
}
// sync second response // sync second response
sync2To0(1, true); sync2To0(1, true);
@@ -1100,30 +1102,31 @@ public class IntroductionIntegrationTest
} }
private void assertDefaultUiMessages() throws DbException { private void assertDefaultUiMessages() throws DbException {
Collection<IntroductionMessage> messages = Collection<PrivateMessageHeader> messages =
introductionManager0.getIntroductionMessages(contactId1From0); withinTransactionReturns(db0, txn -> introductionManager0
.getMessageHeaders(txn, contactId1From0));
assertEquals(2, messages.size()); assertEquals(2, messages.size());
assertMessagesAreAcked(messages); assertMessagesAreAcked(messages);
messages = introductionManager0.getIntroductionMessages( messages = withinTransactionReturns(db0,
contactId2From0); txn -> introductionManager0.getMessageHeaders(txn, contactId2From0));
assertEquals(2, messages.size()); assertEquals(2, messages.size());
assertMessagesAreAcked(messages); assertMessagesAreAcked(messages);
messages = introductionManager1.getIntroductionMessages( messages = withinTransactionReturns(db1,
contactId0From1); txn -> introductionManager1.getMessageHeaders(txn, contactId0From1));
assertEquals(2, messages.size()); assertEquals(2, messages.size());
assertMessagesAreAcked(messages); assertMessagesAreAcked(messages);
messages = introductionManager2.getIntroductionMessages( messages = withinTransactionReturns(db2,
contactId0From2); txn -> introductionManager2.getMessageHeaders(txn, contactId0From2));
assertEquals(2, messages.size()); assertEquals(2, messages.size());
assertMessagesAreAcked(messages); assertMessagesAreAcked(messages);
} }
private void assertMessagesAreAcked( private void assertMessagesAreAcked(
Collection<IntroductionMessage> messages) { Collection<PrivateMessageHeader> messages) {
for (IntroductionMessage msg : messages) { for (PrivateMessageHeader msg : messages) {
if (msg.isLocal()) assertTrue(msg.isSeen()); if (msg.isLocal()) assertTrue(msg.isSeen());
} }
} }
@@ -1150,7 +1153,7 @@ public class IntroductionIntegrationTest
assertTrue( assertTrue(
latestEvent instanceof IntroductionResponseReceivedEvent); latestEvent instanceof IntroductionResponseReceivedEvent);
return ((IntroductionResponseReceivedEvent) latestEvent) return ((IntroductionResponseReceivedEvent) latestEvent)
.getIntroductionResponse(); .getMessageHeader();
} }
} }
@@ -1178,7 +1181,7 @@ public class IntroductionIntegrationTest
IntroductionRequestReceivedEvent introEvent = IntroductionRequestReceivedEvent introEvent =
((IntroductionRequestReceivedEvent) e); ((IntroductionRequestReceivedEvent) e);
requestReceived = true; requestReceived = true;
IntroductionRequest ir = introEvent.getIntroductionRequest(); IntroductionRequest ir = introEvent.getMessageHeader();
ContactId contactId = introEvent.getContactId(); ContactId contactId = introEvent.getContactId();
sessionId = ir.getSessionId(); sessionId = ir.getSessionId();
long time = clock.currentTimeMillis(); long time = clock.currentTimeMillis();
@@ -1219,7 +1222,7 @@ public class IntroductionIntegrationTest
assertTrue( assertTrue(
latestEvent instanceof IntroductionRequestReceivedEvent); latestEvent instanceof IntroductionRequestReceivedEvent);
return ((IntroductionRequestReceivedEvent) latestEvent) return ((IntroductionRequestReceivedEvent) latestEvent)
.getIntroductionRequest(); .getMessageHeader();
} }
} }
@@ -1296,11 +1299,12 @@ public class IntroductionIntegrationTest
} else throw new AssertionError("Not implemented"); } else throw new AssertionError("Not implemented");
} }
private IntroductionRequest getIntroductionRequest( private IntroductionRequest getIntroductionRequest(DatabaseComponent db,
IntroductionManager manager, ContactId contactId) IntroductionManager manager, ContactId contactId)
throws DbException { throws DbException {
for (IntroductionMessage im : manager Collection<PrivateMessageHeader> messages = withinTransactionReturns(db,
.getIntroductionMessages(contactId)) { txn -> manager.getMessageHeaders(txn, contactId));
for (PrivateMessageHeader im : messages) {
if (im instanceof IntroductionRequest) { if (im instanceof IntroductionRequest) {
return (IntroductionRequest) im; return (IntroductionRequest) im;
} }

View File

@@ -2,7 +2,6 @@ package org.briarproject.briar.privategroup;
import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.test.TestDatabaseModule; import org.briarproject.bramble.test.TestDatabaseModule;
@@ -245,11 +244,8 @@ public class PrivateGroupManagerIntegrationTest
groupManager0.getPreviousMsgId(groupId0)); groupManager0.getPreviousMsgId(groupId0));
// share the group with 1 // share the group with 1
Transaction txn0 = db0.startTransaction(false); withinTransaction(db0, txn -> db0.setGroupVisibility(txn,
db0.setGroupVisibility(txn0, contactId1From0, privateGroup0.getId(), contactId1From0, privateGroup0.getId(), SHARED));
SHARED);
db0.commitTransaction(txn0);
db0.endTransaction(txn0);
// author1 joins privateGroup0 with wrong timestamp // author1 joins privateGroup0 with wrong timestamp
joinTime = clock.currentTimeMillis(); joinTime = clock.currentTimeMillis();
@@ -266,11 +262,8 @@ public class PrivateGroupManagerIntegrationTest
groupManager1.getPreviousMsgId(groupId0)); groupManager1.getPreviousMsgId(groupId0));
// share the group with 0 // share the group with 0
Transaction txn1 = db1.startTransaction(false); withinTransaction(db1, txn -> db1.setGroupVisibility(txn,
db1.setGroupVisibility(txn1, contactId0From1, privateGroup0.getId(), contactId0From1, privateGroup0.getId(), SHARED));
SHARED);
db1.commitTransaction(txn1);
db1.endTransaction(txn1);
// sync join messages // sync join messages
sync0To1(1, false); sync0To1(1, false);
@@ -303,11 +296,8 @@ public class PrivateGroupManagerIntegrationTest
groupManager0.getPreviousMsgId(groupId0)); groupManager0.getPreviousMsgId(groupId0));
// share the group with 1 // share the group with 1
Transaction txn0 = db0.startTransaction(false); withinTransaction(db0, txn -> db0.setGroupVisibility(txn,
db0.setGroupVisibility(txn0, contactId1From0, privateGroup0.getId(), contactId1From0, privateGroup0.getId(), SHARED));
SHARED);
db0.commitTransaction(txn0);
db0.endTransaction(txn0);
// author1 joins privateGroup0 with wrong signature in join message // author1 joins privateGroup0 with wrong signature in join message
joinTime = clock.currentTimeMillis(); joinTime = clock.currentTimeMillis();
@@ -325,11 +315,8 @@ public class PrivateGroupManagerIntegrationTest
groupManager1.getPreviousMsgId(groupId0)); groupManager1.getPreviousMsgId(groupId0));
// share the group with 0 // share the group with 0
Transaction txn1 = db1.startTransaction(false); withinTransaction(db1, txn -> db1.setGroupVisibility(txn,
db1.setGroupVisibility(txn1, contactId0From1, privateGroup0.getId(), contactId0From1, privateGroup0.getId(), SHARED));
SHARED);
db1.commitTransaction(txn1);
db1.endTransaction(txn1);
// sync join messages // sync join messages
sync0To1(1, false); sync0To1(1, false);
@@ -404,11 +391,8 @@ public class PrivateGroupManagerIntegrationTest
addGroup(); addGroup();
// share the group with 2 // share the group with 2
Transaction txn0 = db0.startTransaction(false); withinTransaction(db0, txn -> db0.setGroupVisibility(txn,
db0.setGroupVisibility(txn0, contactId2From0, privateGroup0.getId(), contactId2From0, privateGroup0.getId(), SHARED));
SHARED);
db0.commitTransaction(txn0);
db0.endTransaction(txn0);
// author2 joins privateGroup0 // author2 joins privateGroup0
long joinTime = clock.currentTimeMillis(); long joinTime = clock.currentTimeMillis();
@@ -420,14 +404,12 @@ public class PrivateGroupManagerIntegrationTest
GroupMessage joinMsg2 = groupMessageFactory GroupMessage joinMsg2 = groupMessageFactory
.createJoinMessage(privateGroup0.getId(), joinTime, author2, .createJoinMessage(privateGroup0.getId(), joinTime, author2,
inviteTime, creatorSignature); inviteTime, creatorSignature);
Transaction txn2 = db2.startTransaction(false); withinTransaction(db2, txn -> {
groupManager2.addPrivateGroup(txn2, privateGroup0, joinMsg2, false); groupManager2.addPrivateGroup(txn, privateGroup0, joinMsg2, false);
// share the group with 0
// share the group with 0 db2.setGroupVisibility(txn,
db2.setGroupVisibility(txn2, contactId0From1, privateGroup0.getId(), contactId0From2, privateGroup0.getId(), SHARED);
SHARED); });
db2.commitTransaction(txn2);
db2.endTransaction(txn2);
// sync join messages // sync join messages
sync2To0(1, true); sync2To0(1, true);
@@ -458,16 +440,10 @@ public class PrivateGroupManagerIntegrationTest
} }
// reveal contact relationship // reveal contact relationship
Transaction txn1 = db1.startTransaction(false); withinTransaction(db1, txn -> groupManager1.relationshipRevealed(txn,
groupManager1 groupId0, author2.getId(), false));
.relationshipRevealed(txn1, groupId0, author2.getId(), false); withinTransaction(db2, txn -> groupManager2.relationshipRevealed(txn,
db1.commitTransaction(txn1); groupId0, author1.getId(), true));
db1.endTransaction(txn1);
txn2 = db2.startTransaction(false);
groupManager2
.relationshipRevealed(txn2, groupId0, author1.getId(), true);
db2.commitTransaction(txn2);
db2.endTransaction(txn2);
// assert that contact relationship is now revealed properly // assert that contact relationship is now revealed properly
members1 = groupManager1.getMembers(groupId0); members1 = groupManager1.getMembers(groupId0);
@@ -520,10 +496,8 @@ public class PrivateGroupManagerIntegrationTest
assertFalse(groupManager1.isDissolved(groupId0)); assertFalse(groupManager1.isDissolved(groupId0));
// creator dissolves group // creator dissolves group
Transaction txn1 = db1.startTransaction(false); withinTransaction(db1,
groupManager1.markGroupDissolved(txn1, groupId0); txn -> groupManager1.markGroupDissolved(txn, groupId0));
db1.commitTransaction(txn1);
db1.endTransaction(txn1);
// group is dissolved now // group is dissolved now
assertTrue(groupManager1.isDissolved(groupId0)); assertTrue(groupManager1.isDissolved(groupId0));
@@ -539,11 +513,8 @@ public class PrivateGroupManagerIntegrationTest
groupManager0.getPreviousMsgId(groupId0)); groupManager0.getPreviousMsgId(groupId0));
// share the group with 1 // share the group with 1
Transaction txn0 = db0.startTransaction(false); withinTransaction(db0, txn -> db0.setGroupVisibility(txn,
db0.setGroupVisibility(txn0, contactId1From0, privateGroup0.getId(), contactId1From0, privateGroup0.getId(), SHARED));
SHARED);
db0.commitTransaction(txn0);
db0.endTransaction(txn0);
// author1 joins privateGroup0 // author1 joins privateGroup0
joinTime = clock.currentTimeMillis(); joinTime = clock.currentTimeMillis();
@@ -558,11 +529,8 @@ public class PrivateGroupManagerIntegrationTest
groupManager1.addPrivateGroup(privateGroup0, joinMsg1, false); groupManager1.addPrivateGroup(privateGroup0, joinMsg1, false);
// share the group with 0 // share the group with 0
Transaction txn1 = db1.startTransaction(false); withinTransaction(db1, txn -> db1.setGroupVisibility(txn,
db1.setGroupVisibility(txn1, contactId0From1, privateGroup0.getId(), contactId0From1, privateGroup0.getId(), SHARED));
SHARED);
db1.commitTransaction(txn1);
db1.endTransaction(txn1);
assertEquals(joinMsg1.getMessage().getId(), assertEquals(joinMsg1.getMessage().getId(),
groupManager1.getPreviousMsgId(groupId0)); groupManager1.getPreviousMsgId(groupId0));

View File

@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.test.TestDatabaseModule; import org.briarproject.bramble.test.TestDatabaseModule;
import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.privategroup.GroupMessage; import org.briarproject.briar.api.privategroup.GroupMessage;
import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroup;
import org.briarproject.briar.api.privategroup.PrivateGroupManager; import org.briarproject.briar.api.privategroup.PrivateGroupManager;
@@ -11,8 +12,6 @@ import org.briarproject.briar.api.privategroup.invitation.GroupInvitationItem;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import org.briarproject.briar.api.sharing.InvitationMessage;
import org.briarproject.briar.api.sharing.InvitationResponse;
import org.briarproject.briar.test.BriarIntegrationTest; import org.briarproject.briar.test.BriarIntegrationTest;
import org.briarproject.briar.test.BriarIntegrationTestComponent; import org.briarproject.briar.test.BriarIntegrationTestComponent;
import org.briarproject.briar.test.DaggerBriarIntegrationTestComponent; import org.briarproject.briar.test.DaggerBriarIntegrationTestComponent;
@@ -92,19 +91,20 @@ public class GroupInvitationIntegrationTest
assertEquals(privateGroup0.getName(), item.getName()); assertEquals(privateGroup0.getName(), item.getName());
assertFalse(item.isSubscribed()); assertFalse(item.isSubscribed());
Collection<InvitationMessage> messages = Collection<PrivateMessageHeader> messages =
groupInvitationManager1.getInvitationMessages(contactId0From1); withinTransactionReturns(db1, txn -> groupInvitationManager1
.getMessageHeaders(txn, contactId0From1));
assertEquals(1, messages.size()); assertEquals(1, messages.size());
GroupInvitationRequest request = GroupInvitationRequest request =
(GroupInvitationRequest) messages.iterator().next(); (GroupInvitationRequest) messages.iterator().next();
assertEquals(msg, request.getMessage()); assertEquals(msg, request.getMessage());
assertEquals(author0, request.getShareable().getCreator()); assertEquals(author0, request.getNameable().getCreator());
assertEquals(timestamp, request.getTimestamp()); assertEquals(timestamp, request.getTimestamp());
assertEquals(contactId0From1, request.getContactId()); assertEquals(privateGroup0.getName(), request.getNameable().getName());
assertEquals(privateGroup0.getName(), request.getShareable().getName());
assertFalse(request.isLocal()); assertFalse(request.isLocal());
assertFalse(request.isRead()); assertFalse(request.isRead());
assertFalse(request.canBeOpened()); assertFalse(request.canBeOpened());
assertFalse(request.wasAnswered());
} }
@Test @Test
@@ -118,15 +118,16 @@ public class GroupInvitationIntegrationTest
groupInvitationManager1 groupInvitationManager1
.respondToInvitation(contactId0From1, privateGroup0, false); .respondToInvitation(contactId0From1, privateGroup0, false);
Collection<InvitationMessage> messages = Collection<PrivateMessageHeader> messages =
groupInvitationManager1.getInvitationMessages(contactId0From1); withinTransactionReturns(db1, txn -> groupInvitationManager1
.getMessageHeaders(txn, contactId0From1));
assertEquals(2, messages.size()); assertEquals(2, messages.size());
boolean foundResponse = false; boolean foundResponse = false;
for (InvitationMessage m : messages) { for (PrivateMessageHeader m : messages) {
if (m instanceof GroupInvitationResponse) { if (m instanceof GroupInvitationResponse) {
foundResponse = true; foundResponse = true;
InvitationResponse response = (GroupInvitationResponse) m; GroupInvitationResponse response = (GroupInvitationResponse) m;
assertEquals(contactId0From1, response.getContactId()); assertEquals(privateGroup0.getId(), response.getShareableId());
assertTrue(response.isLocal()); assertTrue(response.isLocal());
assertFalse(response.wasAccepted()); assertFalse(response.wasAccepted());
} }
@@ -135,15 +136,15 @@ public class GroupInvitationIntegrationTest
sync1To0(1, true); sync1To0(1, true);
messages = messages = withinTransactionReturns(db0, txn -> groupInvitationManager0
groupInvitationManager0.getInvitationMessages(contactId1From0); .getMessageHeaders(txn, contactId1From0));
assertEquals(2, messages.size()); assertEquals(2, messages.size());
foundResponse = false; foundResponse = false;
for (InvitationMessage m : messages) { for (PrivateMessageHeader m : messages) {
if (m instanceof GroupInvitationResponse) { if (m instanceof GroupInvitationResponse) {
foundResponse = true; foundResponse = true;
InvitationResponse response = (GroupInvitationResponse) m; GroupInvitationResponse response = (GroupInvitationResponse) m;
assertEquals(contactId0From1, response.getContactId()); assertEquals(privateGroup0.getId(), response.getShareableId());
assertFalse(response.isLocal()); assertFalse(response.isLocal());
assertFalse(response.wasAccepted()); assertFalse(response.wasAccepted());
} }
@@ -167,31 +168,37 @@ public class GroupInvitationIntegrationTest
groupInvitationManager1 groupInvitationManager1
.respondToInvitation(contactId0From1, privateGroup0, true); .respondToInvitation(contactId0From1, privateGroup0, true);
Collection<InvitationMessage> messages = Collection<PrivateMessageHeader> messages =
groupInvitationManager1.getInvitationMessages(contactId0From1); withinTransactionReturns(db1, txn -> groupInvitationManager1
.getMessageHeaders(txn, contactId0From1));
assertEquals(2, messages.size()); assertEquals(2, messages.size());
boolean foundResponse = false; boolean foundResponse = false;
for (InvitationMessage m : messages) { for (PrivateMessageHeader m : messages) {
if (m instanceof GroupInvitationResponse) { if (m instanceof GroupInvitationResponse) {
foundResponse = true; foundResponse = true;
InvitationResponse response = (GroupInvitationResponse) m; GroupInvitationResponse response = (GroupInvitationResponse) m;
assertEquals(privateGroup0.getId(), response.getShareableId());
assertTrue(response.wasAccepted()); assertTrue(response.wasAccepted());
} else { } else {
assertTrue(((GroupInvitationRequest) m).canBeOpened()); GroupInvitationRequest request = (GroupInvitationRequest) m;
assertEquals(privateGroup0, request.getNameable());
assertTrue(request.wasAnswered());
assertTrue(request.canBeOpened());
} }
} }
assertTrue(foundResponse); assertTrue(foundResponse);
sync1To0(1, true); sync1To0(1, true);
messages = messages = withinTransactionReturns(db1, txn -> groupInvitationManager0
groupInvitationManager0.getInvitationMessages(contactId1From0); .getMessageHeaders(txn, contactId1From0));
assertEquals(2, messages.size()); assertEquals(2, messages.size());
foundResponse = false; foundResponse = false;
for (InvitationMessage m : messages) { for (PrivateMessageHeader m : messages) {
if (m instanceof GroupInvitationResponse) { if (m instanceof GroupInvitationResponse) {
foundResponse = true; foundResponse = true;
InvitationResponse response = (GroupInvitationResponse) m; GroupInvitationResponse response = (GroupInvitationResponse) m;
assertEquals(privateGroup0.getId(), response.getShareableId());
assertTrue(response.wasAccepted()); assertTrue(response.wasAccepted());
} }
} }
@@ -219,9 +226,9 @@ public class GroupInvitationIntegrationTest
// 1 has one unread message // 1 has one unread message
Group g0 = groupInvitationManager1.getContactGroup(contact0From1); Group g0 = groupInvitationManager1.getContactGroup(contact0From1);
assertGroupCount(messageTracker1, g0.getId(), 1, 1, timestamp); assertGroupCount(messageTracker1, g0.getId(), 1, 1, timestamp);
InvitationMessage m = PrivateMessageHeader m = withinTransactionReturns(db1,
groupInvitationManager1.getInvitationMessages(contactId0From1) txn -> groupInvitationManager1.getMessageHeaders(txn, contactId0From1)
.iterator().next(); .iterator().next());
groupInvitationManager1 groupInvitationManager1
.respondToInvitation(contactId0From1, privateGroup0, true); .respondToInvitation(contactId0From1, privateGroup0, true);

View File

@@ -24,13 +24,13 @@ import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.TestUtils; import org.briarproject.bramble.test.TestUtils;
import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroup;
import org.briarproject.briar.api.privategroup.PrivateGroupFactory; import org.briarproject.briar.api.privategroup.PrivateGroupFactory;
import org.briarproject.briar.api.privategroup.PrivateGroupManager; import org.briarproject.briar.api.privategroup.PrivateGroupManager;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationItem; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationItem;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import org.briarproject.briar.api.sharing.InvitationMessage;
import org.jmock.AbstractExpectations; import org.jmock.AbstractExpectations;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.jmock.lib.legacy.ClassImposteriser; import org.jmock.lib.legacy.ClassImposteriser;
@@ -669,8 +669,6 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
invite.getCreator(), invite.getSalt()); invite.getCreator(), invite.getSalt());
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getContact(txn, contactId); oneOf(db).getContact(txn, contactId);
will(returnValue(contact)); will(returnValue(contact));
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
@@ -696,23 +694,22 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
oneOf(messageParser).parseMetadata(meta2); oneOf(messageParser).parseMetadata(meta2);
will(returnValue(messageMetadata2)); will(returnValue(messageMetadata2));
oneOf(db).getMessageStatus(txn, contactId, messageId2); oneOf(db).getMessageStatus(txn, contactId, messageId2);
// end transaction
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}}); }});
Collection<InvitationMessage> messages = Collection<PrivateMessageHeader> messages =
groupInvitationManager.getInvitationMessages(contactId); groupInvitationManager.getMessageHeaders(txn, contactId);
assertEquals(2, messages.size()); assertEquals(2, messages.size());
for (InvitationMessage m : messages) { for (PrivateMessageHeader m : messages) {
assertEquals(contactGroup.getId(), m.getGroupId()); assertEquals(contactGroup.getId(), m.getGroupId());
assertEquals(contactId, m.getContactId());
if (m.getId().equals(message.getId())) { if (m.getId().equals(message.getId())) {
assertTrue(m instanceof GroupInvitationRequest); assertTrue(m instanceof GroupInvitationRequest);
assertEquals(time1, m.getTimestamp()); assertEquals(time1, m.getTimestamp());
assertEquals(pg, ((GroupInvitationRequest) m).getNameable());
} else if (m.getId().equals(messageId2)) { } else if (m.getId().equals(messageId2)) {
assertTrue(m instanceof GroupInvitationResponse); assertTrue(m instanceof GroupInvitationResponse);
assertEquals(time2, m.getTimestamp()); assertEquals(time2, m.getTimestamp());
assertEquals(pg.getId(),
((GroupInvitationResponse) m).getShareableId());
} else { } else {
throw new AssertionError(); throw new AssertionError();
} }

View File

@@ -18,7 +18,7 @@ import org.briarproject.briar.api.blog.BlogManager;
import org.briarproject.briar.api.blog.BlogSharingManager; import org.briarproject.briar.api.blog.BlogSharingManager;
import org.briarproject.briar.api.blog.event.BlogInvitationRequestReceivedEvent; import org.briarproject.briar.api.blog.event.BlogInvitationRequestReceivedEvent;
import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent; import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent;
import org.briarproject.briar.api.sharing.InvitationMessage; import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.test.BriarIntegrationTest; import org.briarproject.briar.test.BriarIntegrationTest;
import org.briarproject.briar.test.BriarIntegrationTestComponent; import org.briarproject.briar.test.BriarIntegrationTestComponent;
import org.briarproject.briar.test.DaggerBriarIntegrationTestComponent; import org.briarproject.briar.test.DaggerBriarIntegrationTestComponent;
@@ -27,9 +27,7 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import static org.briarproject.briar.api.blog.BlogSharingManager.CLIENT_ID; import static org.briarproject.briar.api.blog.BlogSharingManager.CLIENT_ID;
import static org.briarproject.briar.api.blog.BlogSharingManager.MAJOR_VERSION; import static org.briarproject.briar.api.blog.BlogSharingManager.MAJOR_VERSION;
@@ -147,32 +145,30 @@ public class BlogSharingIntegrationTest
assertTrue(blogManager1.getBlogs().contains(blog2)); assertTrue(blogManager1.getBlogs().contains(blog2));
// invitee has one invitation message from sharer // invitee has one invitation message from sharer
List<InvitationMessage> list = new ArrayList<>( Collection<PrivateMessageHeader> list = withinTransactionReturns(db1,
blogSharingManager1.getInvitationMessages(contactId0From1)); txn -> blogSharingManager1.getMessageHeaders(txn, contactId0From1));
assertEquals(2, list.size()); assertEquals(2, list.size());
// check other things are alright with the message // check other things are alright with the message
for (InvitationMessage m : list) { for (PrivateMessageHeader m : list) {
if (m instanceof BlogInvitationRequest) { if (m instanceof BlogInvitationRequest) {
BlogInvitationRequest invitation = BlogInvitationRequest invitation = (BlogInvitationRequest) m;
(BlogInvitationRequest) m; assertEquals(blog2, invitation.getNameable());
assertFalse(invitation.isAvailable()); assertTrue(invitation.wasAnswered());
assertEquals(blog2.getAuthor().getName(), assertEquals(blog2.getAuthor().getName(),
invitation.getBlogAuthorName()); invitation.getName());
assertFalse(invitation.getShareable().isRssFeed()); assertFalse(invitation.getNameable().isRssFeed());
assertEquals(contactId1From0, invitation.getContactId());
assertEquals("Hi!", invitation.getMessage()); assertEquals("Hi!", invitation.getMessage());
} else { } else {
BlogInvitationResponse response = BlogInvitationResponse response = (BlogInvitationResponse) m;
(BlogInvitationResponse) m; assertEquals(blog2.getId(), response.getShareableId());
assertEquals(contactId0From1, response.getContactId());
assertTrue(response.wasAccepted()); assertTrue(response.wasAccepted());
assertTrue(response.isLocal()); assertTrue(response.isLocal());
} }
} }
// sharer has own invitation message and response // sharer has own invitation message and response
assertEquals(2, assertEquals(2, withinTransactionReturns(db0,
blogSharingManager0.getInvitationMessages(contactId1From0) txn -> blogSharingManager0.getMessageHeaders(txn, contactId1From0))
.size()); .size());
// blog can not be shared again // blog can not be shared again
assertFalse(blogSharingManager0.canBeShared(blog2.getId(), assertFalse(blogSharingManager0.canBeShared(blog2.getId(),
contact1From0)); contact1From0));
@@ -222,31 +218,30 @@ public class BlogSharingIntegrationTest
assertTrue(blogManager1.getBlogs().contains(rssBlog)); assertTrue(blogManager1.getBlogs().contains(rssBlog));
// invitee has one invitation message from sharer // invitee has one invitation message from sharer
List<InvitationMessage> list = new ArrayList<>( Collection<PrivateMessageHeader> list = withinTransactionReturns(db1,
blogSharingManager1.getInvitationMessages(contactId0From1)); txn -> blogSharingManager1.getMessageHeaders(txn, contactId0From1));
assertEquals(2, list.size()); assertEquals(2, list.size());
// check other things are alright with the message // check other things are alright with the message
for (InvitationMessage m : list) { for (PrivateMessageHeader m : list) {
if (m instanceof BlogInvitationRequest) { if (m instanceof BlogInvitationRequest) {
BlogInvitationRequest invitation = BlogInvitationRequest invitation = (BlogInvitationRequest) m;
(BlogInvitationRequest) m; assertEquals(rssBlog, invitation.getNameable());
assertFalse(invitation.isAvailable()); assertTrue(invitation.wasAnswered());
assertEquals(rssBlog.getAuthor().getName(), assertEquals(rssBlog.getAuthor().getName(),
invitation.getBlogAuthorName()); invitation.getName());
assertTrue(invitation.getShareable().isRssFeed()); assertTrue(invitation.getNameable().isRssFeed());
assertEquals(contactId1From0, invitation.getContactId());
assertEquals("Hi!", invitation.getMessage()); assertEquals("Hi!", invitation.getMessage());
} else { } else {
BlogInvitationResponse response = BlogInvitationResponse response = (BlogInvitationResponse) m;
(BlogInvitationResponse) m; assertEquals(rssBlog.getId(), response.getShareableId());
assertEquals(contactId0From1, response.getContactId());
assertTrue(response.wasAccepted()); assertTrue(response.wasAccepted());
assertTrue(response.isLocal()); assertTrue(response.isLocal());
} }
} }
// sharer has own invitation message and response // sharer has own invitation message and response
assertEquals(2, blogSharingManager0.getInvitationMessages( assertEquals(2, withinTransactionReturns(db0,
contactId1From0).size()); txn -> blogSharingManager0.getMessageHeaders(txn, contactId1From0))
.size());
// blog can not be shared again // blog can not be shared again
assertFalse(blogSharingManager0.canBeShared(rssBlog.getId(), assertFalse(blogSharingManager0.canBeShared(rssBlog.getId(),
contact1From0)); contact1From0));
@@ -285,31 +280,29 @@ public class BlogSharingIntegrationTest
assertEquals(0, blogSharingManager1.getInvitations().size()); assertEquals(0, blogSharingManager1.getInvitations().size());
// invitee has one invitation message from sharer and one response // invitee has one invitation message from sharer and one response
List<InvitationMessage> list = new ArrayList<>( Collection<PrivateMessageHeader> list = withinTransactionReturns(db1,
blogSharingManager1.getInvitationMessages(contactId0From1)); txn -> blogSharingManager1.getMessageHeaders(txn, contactId0From1));
assertEquals(2, list.size()); assertEquals(2, list.size());
// check things are alright with the message // check things are alright with the message
for (InvitationMessage m : list) { for (PrivateMessageHeader m : list) {
if (m instanceof BlogInvitationRequest) { if (m instanceof BlogInvitationRequest) {
BlogInvitationRequest invitation = BlogInvitationRequest invitation = (BlogInvitationRequest) m;
(BlogInvitationRequest) m; assertEquals(blog2, invitation.getNameable());
assertFalse(invitation.isAvailable()); assertTrue(invitation.wasAnswered());
assertEquals(blog2.getAuthor().getName(), assertEquals(blog2.getAuthor().getName(),
invitation.getBlogAuthorName()); invitation.getName());
assertEquals(contactId1From0, invitation.getContactId());
assertEquals(null, invitation.getMessage()); assertEquals(null, invitation.getMessage());
} else { } else {
BlogInvitationResponse response = BlogInvitationResponse response = (BlogInvitationResponse) m;
(BlogInvitationResponse) m; assertEquals(blog2.getId(), response.getShareableId());
assertEquals(contactId0From1, response.getContactId());
assertFalse(response.wasAccepted()); assertFalse(response.wasAccepted());
assertTrue(response.isLocal()); assertTrue(response.isLocal());
} }
} }
// sharer has own invitation message and response // sharer has own invitation message and response
assertEquals(2, assertEquals(2, withinTransactionReturns(db0,
blogSharingManager0.getInvitationMessages(contactId1From0) txn -> blogSharingManager0.getMessageHeaders(txn, contactId1From0))
.size()); .size());
// blog can be shared again // blog can be shared again
assertTrue( assertTrue(
blogSharingManager0.canBeShared(blog2.getId(), contact1From0)); blogSharingManager0.canBeShared(blog2.getId(), contact1From0));
@@ -394,8 +387,9 @@ public class BlogSharingIntegrationTest
assertTrue(contacts.contains(contact0From1)); assertTrue(contacts.contains(contact0From1));
// make sure 1 knows that they have blog2 already // make sure 1 knows that they have blog2 already
Collection<InvitationMessage> messages = Collection<PrivateMessageHeader> messages =
blogSharingManager1.getInvitationMessages(contactId0From1); withinTransactionReturns(db1, txn -> blogSharingManager1
.getMessageHeaders(txn, contactId0From1));
assertEquals(2, messages.size()); assertEquals(2, messages.size());
assertEquals(blog2, blogManager1.getBlog(blog2.getId())); assertEquals(blog2, blogManager1.getBlog(blog2.getId()));
@@ -565,7 +559,7 @@ public class BlogSharingIntegrationTest
BlogInvitationRequestReceivedEvent event = BlogInvitationRequestReceivedEvent event =
(BlogInvitationRequestReceivedEvent) e; (BlogInvitationRequestReceivedEvent) e;
eventWaiter.assertEquals(contactId1From0, event.getContactId()); eventWaiter.assertEquals(contactId1From0, event.getContactId());
Blog b = event.getShareable(); Blog b = event.getMessageHeader().getNameable();
try { try {
Contact c = contactManager0.getContact(contactId1From0); Contact c = contactManager0.getContact(contactId1From0);
blogSharingManager0.respondToInvitation(b, c, true); blogSharingManager0.respondToInvitation(b, c, true);
@@ -601,7 +595,7 @@ public class BlogSharingIntegrationTest
(BlogInvitationRequestReceivedEvent) e; (BlogInvitationRequestReceivedEvent) e;
requestReceived = true; requestReceived = true;
if (!answer) return; if (!answer) return;
Blog b = event.getShareable(); Blog b = event.getMessageHeader().getNameable();
try { try {
eventWaiter.assertEquals(1, eventWaiter.assertEquals(1,
blogSharingManager1.getInvitations().size()); blogSharingManager1.getInvitations().size());
@@ -624,7 +618,7 @@ public class BlogSharingIntegrationTest
} }
} }
private void listenToEvents(boolean accept) throws DbException { private void listenToEvents(boolean accept) {
listener0 = new SharerListener(); listener0 = new SharerListener();
c0.getEventBus().addListener(listener0); c0.getEventBus().addListener(listener0);
listener1 = new InviteeListener(accept); listener1 = new InviteeListener(accept);

View File

@@ -5,7 +5,6 @@ import net.jodah.concurrentunit.Waiter;
import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -22,7 +21,7 @@ import org.briarproject.briar.api.forum.ForumPostHeader;
import org.briarproject.briar.api.forum.ForumSharingManager; import org.briarproject.briar.api.forum.ForumSharingManager;
import org.briarproject.briar.api.forum.event.ForumInvitationRequestReceivedEvent; import org.briarproject.briar.api.forum.event.ForumInvitationRequestReceivedEvent;
import org.briarproject.briar.api.forum.event.ForumInvitationResponseReceivedEvent; import org.briarproject.briar.api.forum.event.ForumInvitationResponseReceivedEvent;
import org.briarproject.briar.api.sharing.InvitationMessage; import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.sharing.SharingInvitationItem; import org.briarproject.briar.api.sharing.SharingInvitationItem;
import org.briarproject.briar.test.BriarIntegrationTest; import org.briarproject.briar.test.BriarIntegrationTest;
import org.briarproject.briar.test.BriarIntegrationTestComponent; import org.briarproject.briar.test.BriarIntegrationTestComponent;
@@ -32,9 +31,7 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNotNull;
import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.bramble.util.StringUtils.getRandomString;
@@ -131,31 +128,28 @@ public class ForumSharingIntegrationTest
assertEquals(1, forumManager1.getForums().size()); assertEquals(1, forumManager1.getForums().size());
// invitee has one invitation message from sharer // invitee has one invitation message from sharer
List<InvitationMessage> list = new ArrayList<>( Collection<PrivateMessageHeader> list = withinTransactionReturns(db1,
forumSharingManager1.getInvitationMessages(contactId0From1)); txn -> forumSharingManager1.getMessageHeaders(txn, contactId0From1));
assertEquals(2, list.size()); assertEquals(2, list.size());
// check other things are alright with the forum message // check other things are alright with the forum message
for (InvitationMessage m : list) { for (PrivateMessageHeader m : list) {
if (m instanceof ForumInvitationRequest) { if (m instanceof ForumInvitationRequest) {
ForumInvitationRequest invitation = ForumInvitationRequest invitation = (ForumInvitationRequest) m;
(ForumInvitationRequest) m; assertTrue(invitation.wasAnswered());
assertFalse(invitation.isAvailable()); assertEquals(forum0.getName(), invitation.getName());
assertEquals(forum0.getName(), invitation.getForumName()); assertEquals(forum0, invitation.getNameable());
assertEquals(contactId1From0, invitation.getContactId());
assertEquals("Hi!", invitation.getMessage()); assertEquals("Hi!", invitation.getMessage());
assertTrue(invitation.canBeOpened()); assertTrue(invitation.canBeOpened());
} else { } else {
ForumInvitationResponse response = ForumInvitationResponse response = (ForumInvitationResponse) m;
(ForumInvitationResponse) m; assertEquals(forum0.getId(), response.getShareableId());
assertEquals(contactId0From1, response.getContactId());
assertTrue(response.wasAccepted()); assertTrue(response.wasAccepted());
assertTrue(response.isLocal()); assertTrue(response.isLocal());
} }
} }
// sharer has own invitation message and response // sharer has own invitation message and response
assertEquals(2, assertEquals(2, withinTransactionReturns(db0, txn ->
forumSharingManager0.getInvitationMessages(contactId1From0) forumSharingManager0.getMessageHeaders(txn, contactId1From0)).size());
.size());
// forum can not be shared again // forum can not be shared again
Contact c1 = contactManager0.getContact(contactId1From0); Contact c1 = contactManager0.getContact(contactId1From0);
assertFalse(forumSharingManager0.canBeShared(forum0.getId(), c1)); assertFalse(forumSharingManager0.canBeShared(forum0.getId(), c1));
@@ -190,31 +184,28 @@ public class ForumSharingIntegrationTest
assertEquals(0, forumSharingManager1.getInvitations().size()); assertEquals(0, forumSharingManager1.getInvitations().size());
// invitee has one invitation message from sharer and one response // invitee has one invitation message from sharer and one response
List<InvitationMessage> list = new ArrayList<>( Collection<PrivateMessageHeader> list = withinTransactionReturns(db1,
forumSharingManager1.getInvitationMessages(contactId0From1)); txn -> forumSharingManager1.getMessageHeaders(txn, contactId0From1));
assertEquals(2, list.size()); assertEquals(2, list.size());
// check things are alright with the forum message // check things are alright with the forum message
for (InvitationMessage m : list) { for (PrivateMessageHeader m : list) {
if (m instanceof ForumInvitationRequest) { if (m instanceof ForumInvitationRequest) {
ForumInvitationRequest invitation = ForumInvitationRequest invitation = (ForumInvitationRequest) m;
(ForumInvitationRequest) m; assertEquals(forum0, invitation.getNameable());
assertFalse(invitation.isAvailable()); assertTrue(invitation.wasAnswered());
assertEquals(forum0.getName(), invitation.getForumName()); assertEquals(forum0.getName(), invitation.getName());
assertEquals(contactId1From0, invitation.getContactId());
assertEquals(null, invitation.getMessage()); assertEquals(null, invitation.getMessage());
assertFalse(invitation.canBeOpened()); assertFalse(invitation.canBeOpened());
} else { } else {
ForumInvitationResponse response = ForumInvitationResponse response = (ForumInvitationResponse) m;
(ForumInvitationResponse) m; assertEquals(forum0.getId(), response.getShareableId());
assertEquals(contactId0From1, response.getContactId());
assertFalse(response.wasAccepted()); assertFalse(response.wasAccepted());
assertTrue(response.isLocal()); assertTrue(response.isLocal());
} }
} }
// sharer has own invitation message and response // sharer has own invitation message and response
assertEquals(2, assertEquals(2, withinTransactionReturns(db0, txn ->
forumSharingManager0.getInvitationMessages(contactId1From0) forumSharingManager0.getMessageHeaders(txn, contactId1From0)).size());
.size());
// forum can be shared again // forum can be shared again
Contact c1 = contactManager0.getContact(contactId1From0); Contact c1 = contactManager0.getContact(contactId1From0);
assertTrue(forumSharingManager0.canBeShared(forum0.getId(), c1)); assertTrue(forumSharingManager0.canBeShared(forum0.getId(), c1));
@@ -455,10 +446,7 @@ public class ForumSharingIntegrationTest
listenToEvents(true); listenToEvents(true);
// invitee adds the same forum // invitee adds the same forum
Transaction txn = db1.startTransaction(false); withinTransaction(db1, txn -> forumManager1.addForum(txn, forum0));
forumManager1.addForum(txn, forum0);
db1.commitTransaction(txn);
db1.endTransaction(txn);
// send invitation // send invitation
forumSharingManager0 forumSharingManager0
@@ -490,10 +478,12 @@ public class ForumSharingIntegrationTest
.contains(contact0From1)); .contains(contact0From1));
// and both have each other's invitations (and no response) // and both have each other's invitations (and no response)
assertEquals(2, forumSharingManager0 assertEquals(2, withinTransactionReturns(db0, txn ->
.getInvitationMessages(contactId1From0).size()); forumSharingManager0.getMessageHeaders(txn, contactId1From0))
assertEquals(2, forumSharingManager1 .size());
.getInvitationMessages(contactId0From1).size()); assertEquals(2, withinTransactionReturns(db1, txn ->
forumSharingManager1.getMessageHeaders(txn, contactId0From1))
.size());
// there are no more open invitations // there are no more open invitations
assertTrue(forumSharingManager0.getInvitations().isEmpty()); assertTrue(forumSharingManager0.getInvitations().isEmpty());
@@ -568,17 +558,14 @@ public class ForumSharingIntegrationTest
@Test @Test
public void testTwoContactsShareSameForum() throws Exception { public void testTwoContactsShareSameForum() throws Exception {
// second sharer adds the same forum // second sharer adds the same forum
Transaction txn = db2.startTransaction(false); withinTransaction(db2, txn -> db2.addGroup(txn, forum0.getGroup()));
db2.addGroup(txn, forum0.getGroup());
db2.commitTransaction(txn);
db2.endTransaction(txn);
// add listeners // add listeners
listener0 = new SharerListener(); listener0 = new SharerListener(true);
c0.getEventBus().addListener(listener0); c0.getEventBus().addListener(listener0);
listener1 = new InviteeListener(true, false); listener1 = new InviteeListener(true, false);
c1.getEventBus().addListener(listener1); c1.getEventBus().addListener(listener1);
listener2 = new SharerListener(); listener2 = new SharerListener(true);
c2.getEventBus().addListener(listener2); c2.getEventBus().addListener(listener2);
// send invitation // send invitation
@@ -748,8 +735,9 @@ public class ForumSharingIntegrationTest
// get invitation MessageId for later // get invitation MessageId for later
MessageId invitationId = null; MessageId invitationId = null;
for (InvitationMessage m : forumSharingManager1 Collection<PrivateMessageHeader> list = withinTransactionReturns(db1,
.getInvitationMessages(contactId0From1)) { txn -> forumSharingManager1.getMessageHeaders(txn, contactId0From1));
for (PrivateMessageHeader m : list) {
if (m instanceof ForumInvitationRequest) { if (m instanceof ForumInvitationRequest) {
invitationId = m.getId(); invitationId = m.getId();
} }
@@ -802,13 +790,22 @@ public class ForumSharingIntegrationTest
@NotNullByDefault @NotNullByDefault
private class SharerListener implements EventListener { private class SharerListener implements EventListener {
private final boolean accept;
private volatile boolean requestReceived = false; private volatile boolean requestReceived = false;
private volatile boolean responseReceived = false; private volatile boolean responseReceived = false;
private SharerListener(boolean accept) {
this.accept = accept;
}
@Override @Override
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
if (e instanceof ForumInvitationResponseReceivedEvent) { if (e instanceof ForumInvitationResponseReceivedEvent) {
ForumInvitationResponseReceivedEvent event =
(ForumInvitationResponseReceivedEvent) e;
responseReceived = true; responseReceived = true;
eventWaiter.assertEquals(accept,
event.getMessageHeader().wasAccepted());
eventWaiter.resume(); eventWaiter.resume();
} }
// this is only needed for tests where a forum is re-shared // this is only needed for tests where a forum is re-shared
@@ -817,7 +814,7 @@ public class ForumSharingIntegrationTest
(ForumInvitationRequestReceivedEvent) e; (ForumInvitationRequestReceivedEvent) e;
eventWaiter.assertEquals(contactId1From0, event.getContactId()); eventWaiter.assertEquals(contactId1From0, event.getContactId());
requestReceived = true; requestReceived = true;
Forum f = event.getShareable(); Forum f = event.getMessageHeader().getNameable();
try { try {
if (respond) { if (respond) {
Contact c = contactManager0.getContact(contactId1From0); Contact c = contactManager0.getContact(contactId1From0);
@@ -855,7 +852,7 @@ public class ForumSharingIntegrationTest
(ForumInvitationRequestReceivedEvent) e; (ForumInvitationRequestReceivedEvent) e;
requestReceived = true; requestReceived = true;
if (!answer) return; if (!answer) return;
Forum f = event.getShareable(); Forum f = event.getMessageHeader().getNameable();
try { try {
if (respond) { if (respond) {
eventWaiter.assertEquals(1, eventWaiter.assertEquals(1,
@@ -880,17 +877,19 @@ public class ForumSharingIntegrationTest
ForumInvitationResponseReceivedEvent event = ForumInvitationResponseReceivedEvent event =
(ForumInvitationResponseReceivedEvent) e; (ForumInvitationResponseReceivedEvent) e;
eventWaiter.assertEquals(contactId0From1, event.getContactId()); eventWaiter.assertEquals(contactId0From1, event.getContactId());
eventWaiter.assertEquals(accept,
event.getMessageHeader().wasAccepted());
eventWaiter.resume(); eventWaiter.resume();
} }
} }
} }
private void listenToEvents(boolean accept) throws DbException { private void listenToEvents(boolean accept) {
listener0 = new SharerListener(); listener0 = new SharerListener(accept);
c0.getEventBus().addListener(listener0); c0.getEventBus().addListener(listener0);
listener1 = new InviteeListener(accept); listener1 = new InviteeListener(accept);
c1.getEventBus().addListener(listener1); c1.getEventBus().addListener(listener1);
listener2 = new SharerListener(); listener2 = new SharerListener(accept);
c2.getEventBus().addListener(listener2); c2.getEventBus().addListener(listener2);
} }

View File

@@ -2,6 +2,7 @@ package org.briarproject.briar.test;
import net.jodah.concurrentunit.Waiter; import net.jodah.concurrentunit.Waiter;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.client.ContactGroupFactory; import org.briarproject.bramble.api.client.ContactGroupFactory;
import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.Contact;
@@ -10,6 +11,7 @@ import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.identity.AuthorFactory; import org.briarproject.bramble.api.identity.AuthorFactory;
@@ -376,4 +378,41 @@ public abstract class BriarIntegrationTest<C extends BriarIntegrationTestCompone
assertNotNull(contactId1From2); assertNotNull(contactId1From2);
contactManager2.removeContact(contactId1From2); contactManager2.removeContact(contactId1From2);
} }
@FunctionalInterface
protected interface TransactionScope {
void execute(Transaction txn) throws DbException, FormatException;
}
protected void withinTransaction(DatabaseComponent db,
TransactionScope scope) throws DbException {
Transaction txn = db.startTransaction(false);
try {
scope.execute(txn);
db.commitTransaction(txn);
} catch (FormatException e) {
throw new DbException(e);
} finally {
db.endTransaction(txn);
}
}
@FunctionalInterface
protected interface TransactionResultScope<R> {
R execute(Transaction txn) throws DbException;
}
protected <R> R withinTransactionReturns(DatabaseComponent db,
TransactionResultScope<R> scope) throws DbException {
Transaction txn = db.startTransaction(false);
R r;
try {
r = scope.execute(txn);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return r;
}
} }