From 9f9a2163058b7714dcf46a164af4da9ee3b3c2b7 Mon Sep 17 00:00:00 2001
From: Torsten Grote <t@grobox.de>
Date: Tue, 26 Apr 2016 16:37:40 -0300
Subject: [PATCH] Prepare for new Forum Sharing Client

Methods for creating, adding and removing forums have been moved to the
`ForumManager`. In order to still handle removing forums properly, a
`RemoveForumHook` has been introduced.

Methods for sharing forums with all current and future contacts have
been removed along with the localGroup where this information was saved.

The `ShareForumActivity` now has the proper label.

The `SessionId` and the `ProtocolEngine` have been moved to the
`clients` package.

This addresses part of #322 and part of what has been discussed in #320.
---
 .../IntroductionIntegrationTest.java          |   2 +-
 briar-android/AndroidManifest.xml             |   6 +-
 .../res/menu/forum_share_actions.xml          |   2 +-
 briar-android/res/values/strings.xml          |   4 +-
 .../android/contact/ConversationActivity.java |   2 +-
 .../android/contact/ConversationAdapter.java  |   2 +-
 .../forum/AvailableForumsActivity.java        |   2 +-
 .../android/forum/CreateForumActivity.java    |   8 +-
 .../android/forum/ForumActivity.java          |   5 +-
 .../android/forum/ForumListFragment.java      |   2 +-
 .../android/forum/ShareForumActivity.java     |  12 +-
 .../api/{ => clients}/ProtocolEngine.java     |   2 +-
 .../{introduction => clients}/SessionId.java  |   6 +-
 .../api/event/IntroductionAbortedEvent.java   |   2 +-
 .../briarproject/api/forum/ForumManager.java  |  20 ++++
 .../api/forum/ForumSharingManager.java        |  11 --
 .../api/introduction/IntroductionManager.java |   6 +-
 .../api/introduction/IntroductionMessage.java |   1 +
 .../api/introduction/IntroductionRequest.java |   1 +
 .../introduction/IntroductionResponse.java    |   1 +
 .../briarproject/forum/ForumManagerImpl.java  |  68 ++++++++++-
 .../org/briarproject/forum/ForumModule.java   |  10 +-
 .../forum/ForumSharingManagerImpl.java        | 111 ++----------------
 .../introduction/IntroduceeEngine.java        |   4 +-
 .../introduction/IntroducerEngine.java        |   4 +-
 .../introduction/IntroductionManagerImpl.java |   2 +-
 .../introduction/IntroductionValidator.java   |   2 +-
 .../introduction/IntroduceeManagerTest.java   |   2 +-
 .../IntroductionManagerImplTest.java          |   2 +-
 .../IntroductionValidatorTest.java            |   2 +-
 .../introduction/MessageSenderTest.java       |   2 +-
 31 files changed, 144 insertions(+), 162 deletions(-)
 rename briar-api/src/org/briarproject/api/{ => clients}/ProtocolEngine.java (97%)
 rename briar-api/src/org/briarproject/api/{introduction => clients}/SessionId.java (65%)

diff --git a/briar-android-tests/src/test/java/org/briarproject/IntroductionIntegrationTest.java b/briar-android-tests/src/test/java/org/briarproject/IntroductionIntegrationTest.java
index 7e180253d7..56502a64b0 100644
--- a/briar-android-tests/src/test/java/org/briarproject/IntroductionIntegrationTest.java
+++ b/briar-android-tests/src/test/java/org/briarproject/IntroductionIntegrationTest.java
@@ -19,7 +19,7 @@ import org.briarproject.api.identity.IdentityManager;
 import org.briarproject.api.identity.LocalAuthor;
 import org.briarproject.api.introduction.IntroductionManager;
 import org.briarproject.api.introduction.IntroductionRequest;
-import org.briarproject.api.introduction.SessionId;
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.lifecycle.LifecycleManager;
 import org.briarproject.api.properties.TransportProperties;
 import org.briarproject.api.properties.TransportPropertyManager;
diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index c9784c094a..d5517f9046 100644
--- a/briar-android/AndroidManifest.xml
+++ b/briar-android/AndroidManifest.xml
@@ -140,11 +140,11 @@
 
 		<activity
 			android:name=".android.forum.ShareForumActivity"
-			android:label="@string/app_name"
-			android:parentActivityName=".android.NavDrawerActivity">
+			android:label="@string/forums_share_toolbar_header"
+			android:parentActivityName=".android.forum.ForumActivity">
 			<meta-data
 				android:name="android.support.PARENT_ACTIVITY"
-				android:value=".android.NavDrawerActivity"
+				android:value=".android.forum.ForumActivity"
 				/>
 		</activity>
 
diff --git a/briar-android/res/menu/forum_share_actions.xml b/briar-android/res/menu/forum_share_actions.xml
index f128fd17c5..a3d6c15477 100644
--- a/briar-android/res/menu/forum_share_actions.xml
+++ b/briar-android/res/menu/forum_share_actions.xml
@@ -6,7 +6,7 @@
 	<item
 		android:id="@+id/action_share_forum"
 		android:icon="@drawable/ic_check_white"
-		android:title="@string/forum_share_with_some"
+		android:title="@string/forum_share_action"
 		app:showAsAction="always"/>
 
 </menu>
\ No newline at end of file
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 9934c12dc0..4bbeca7689 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -85,8 +85,7 @@
 	<string name="choose_forum_name">Choose a name for your forum:</string>
 	<string name="create_forum_button">Create Forum</string>
 	<string name="forum_created_toast">Forum created</string>
-	<string name="forum_share_with_all">Share this forum with all contacts</string>
-	<string name="forum_share_with_some">Share this forum with chosen contacts</string>
+	<string name="forum_share_action">Share this forum with chosen contacts</string>
 	<string name="forum_share_button">Share Forum</string>
 	<string name="forum_compose_post">New Forum Post</string>
 	<string name="from">From:</string>
@@ -204,6 +203,7 @@
 	<string name="settings_toolbar_header">Settings</string>
 	<string name="contacts_toolbar_header">Contacts</string>
 	<string name="forums_toolbar_header">Forums</string>
+	<string name="forums_share_toolbar_header">Choose Contacts</string>
 	<!-- Progress titles -->
 	<string name="progress_title_logout">Signing out of Briar..</string>
 	<string name="progress_title_please_wait">Please wait..</string>
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
index c027bf4d63..213e412b52 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
@@ -51,7 +51,7 @@ import org.briarproject.api.introduction.IntroductionManager;
 import org.briarproject.api.introduction.IntroductionMessage;
 import org.briarproject.api.introduction.IntroductionRequest;
 import org.briarproject.api.introduction.IntroductionResponse;
-import org.briarproject.api.introduction.SessionId;
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.messaging.MessagingManager;
 import org.briarproject.api.messaging.PrivateMessage;
 import org.briarproject.api.messaging.PrivateMessageFactory;
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationAdapter.java b/briar-android/src/org/briarproject/android/contact/ConversationAdapter.java
index ea67900a41..91a006b9f5 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationAdapter.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationAdapter.java
@@ -14,7 +14,7 @@ import android.widget.TextView;
 
 import org.briarproject.R;
 import org.briarproject.api.introduction.IntroductionRequest;
-import org.briarproject.api.introduction.SessionId;
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.messaging.PrivateMessageHeader;
 import org.briarproject.util.StringUtils;
 
diff --git a/briar-android/src/org/briarproject/android/forum/AvailableForumsActivity.java b/briar-android/src/org/briarproject/android/forum/AvailableForumsActivity.java
index 6ce64a2a1b..67c6233b23 100644
--- a/briar-android/src/org/briarproject/android/forum/AvailableForumsActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/AvailableForumsActivity.java
@@ -171,7 +171,7 @@ implements EventListener, OnItemClickListener {
 		runOnDbThread(new Runnable() {
 			public void run() {
 				try {
-					forumSharingManager.addForum(f);
+					forumManager.addForum(f);
 					forumSharingManager.setSharedWith(f.getId(), shared);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
diff --git a/briar-android/src/org/briarproject/android/forum/CreateForumActivity.java b/briar-android/src/org/briarproject/android/forum/CreateForumActivity.java
index 19a555c98e..a35834c93a 100644
--- a/briar-android/src/org/briarproject/android/forum/CreateForumActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/CreateForumActivity.java
@@ -19,7 +19,7 @@ import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.api.db.DbException;
 import org.briarproject.api.forum.Forum;
-import org.briarproject.api.forum.ForumSharingManager;
+import org.briarproject.api.forum.ForumManager;
 import org.briarproject.util.StringUtils;
 
 import java.util.logging.Logger;
@@ -47,7 +47,7 @@ public class CreateForumActivity extends BriarActivity
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject
-	protected volatile ForumSharingManager forumSharingManager;
+	protected volatile ForumManager forumManager;
 
 	@Override
 	public void onCreate(Bundle state) {
@@ -126,8 +126,8 @@ public class CreateForumActivity extends BriarActivity
 			public void run() {
 				try {
 					long now = System.currentTimeMillis();
-					Forum f = forumSharingManager.createForum(name);
-					forumSharingManager.addForum(f);
+					Forum f = forumManager.createForum(name);
+					forumManager.addForum(f);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Storing forum took " + duration + " ms");
diff --git a/briar-android/src/org/briarproject/android/forum/ForumActivity.java b/briar-android/src/org/briarproject/android/forum/ForumActivity.java
index cd44592df4..6dd00d231e 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumActivity.java
@@ -68,7 +68,7 @@ public class ForumActivity extends BriarActivity implements EventListener,
 			Logger.getLogger(ForumActivity.class.getName());
 
 	@Inject protected AndroidNotificationManager notificationManager;
-	private Map<MessageId, byte[]> bodyCache = new HashMap<MessageId, byte[]>();
+	private Map<MessageId, byte[]> bodyCache = new HashMap<>();
 	private TextView empty = null;
 	private ForumAdapter adapter = null;
 	private ListView list = null;
@@ -158,7 +158,6 @@ public class ForumActivity extends BriarActivity implements EventListener,
 				Intent i2 = new Intent(this, ShareForumActivity.class);
 				i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
 				i2.putExtra(GROUP_ID, groupId.getBytes());
-				i2.putExtra(FORUM_NAME, forum.getName());
 				ActivityOptionsCompat options = ActivityOptionsCompat
 						.makeCustomAnimation(this, android.R.anim.slide_in_left,
 								android.R.anim.slide_out_right);
@@ -302,7 +301,7 @@ public class ForumActivity extends BriarActivity implements EventListener,
 	}
 
 	private void markPostsRead() {
-		List<MessageId> unread = new ArrayList<MessageId>();
+		List<MessageId> unread = new ArrayList<>();
 		int count = adapter.getCount();
 		for (int i = 0; i < count; i++) {
 			ForumPostHeader h = adapter.getItem(i).getHeader();
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
index c31fde4390..dea9d1fe47 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
@@ -401,7 +401,7 @@ public class ForumListFragment extends BaseEventFragment implements
 			public void run() {
 				try {
 					long now = System.currentTimeMillis();
-					forumSharingManager.removeForum(f);
+					forumManager.removeForum(f);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Removing forum took " + duration + " ms");
diff --git a/briar-android/src/org/briarproject/android/forum/ShareForumActivity.java b/briar-android/src/org/briarproject/android/forum/ShareForumActivity.java
index e2d4926b3b..cccecbc7ae 100644
--- a/briar-android/src/org/briarproject/android/forum/ShareForumActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/ShareForumActivity.java
@@ -33,7 +33,6 @@ import javax.inject.Inject;
 
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
-import static org.briarproject.android.forum.ForumActivity.FORUM_NAME;
 
 public class ShareForumActivity extends BriarActivity implements
 		BaseContactListAdapter.OnItemClickListener {
@@ -59,9 +58,6 @@ public class ShareForumActivity extends BriarActivity implements
 		byte[] b = i.getByteArrayExtra(GROUP_ID);
 		if (b == null) throw new IllegalStateException();
 		groupId = new GroupId(b);
-		String forumName = i.getStringExtra(FORUM_NAME);
-		if (forumName == null) throw new IllegalStateException();
-		setTitle(forumName);
 
 		adapter = new ContactSelectorAdapter(this, this);
 		BriarRecyclerView list =
@@ -112,11 +108,9 @@ public class ShareForumActivity extends BriarActivity implements
 			public void run() {
 				try {
 					long now = System.currentTimeMillis();
-					List<ContactListItem> contacts =
-							new ArrayList<ContactListItem>();
-					Collection<ContactId> selectedContacts =
-							new HashSet<ContactId>(
-									forumSharingManager.getSharedWith(groupId));
+					List<ContactListItem> contacts = new ArrayList<>();
+					Collection<ContactId> selectedContacts = new HashSet<>(
+							forumSharingManager.getSharedWith(groupId));
 
 					for (Contact c : contactManager.getActiveContacts()) {
 						LocalAuthor localAuthor = identityManager
diff --git a/briar-api/src/org/briarproject/api/ProtocolEngine.java b/briar-api/src/org/briarproject/api/clients/ProtocolEngine.java
similarity index 97%
rename from briar-api/src/org/briarproject/api/ProtocolEngine.java
rename to briar-api/src/org/briarproject/api/clients/ProtocolEngine.java
index 61833f6574..1958deaf0d 100644
--- a/briar-api/src/org/briarproject/api/ProtocolEngine.java
+++ b/briar-api/src/org/briarproject/api/clients/ProtocolEngine.java
@@ -1,4 +1,4 @@
-package org.briarproject.api;
+package org.briarproject.api.clients;
 
 import org.briarproject.api.event.Event;
 
diff --git a/briar-api/src/org/briarproject/api/introduction/SessionId.java b/briar-api/src/org/briarproject/api/clients/SessionId.java
similarity index 65%
rename from briar-api/src/org/briarproject/api/introduction/SessionId.java
rename to briar-api/src/org/briarproject/api/clients/SessionId.java
index d68bf9e030..c9730730bf 100644
--- a/briar-api/src/org/briarproject/api/introduction/SessionId.java
+++ b/briar-api/src/org/briarproject/api/clients/SessionId.java
@@ -1,10 +1,10 @@
-package org.briarproject.api.introduction;
+package org.briarproject.api.clients;
 
 import org.briarproject.api.sync.MessageId;
 
 /**
- * Type-safe wrapper for a byte array that uniquely identifies an
- * introduction session.
+ * Type-safe wrapper for a byte array
+ * that uniquely identifies a protocol session.
  */
 public class SessionId extends MessageId {
 
diff --git a/briar-api/src/org/briarproject/api/event/IntroductionAbortedEvent.java b/briar-api/src/org/briarproject/api/event/IntroductionAbortedEvent.java
index 258d588e28..b5d821655a 100644
--- a/briar-api/src/org/briarproject/api/event/IntroductionAbortedEvent.java
+++ b/briar-api/src/org/briarproject/api/event/IntroductionAbortedEvent.java
@@ -1,7 +1,7 @@
 package org.briarproject.api.event;
 
 import org.briarproject.api.contact.ContactId;
-import org.briarproject.api.introduction.SessionId;
+import org.briarproject.api.clients.SessionId;
 
 public class IntroductionAbortedEvent extends Event {
 
diff --git a/briar-api/src/org/briarproject/api/forum/ForumManager.java b/briar-api/src/org/briarproject/api/forum/ForumManager.java
index 1d32544654..bd5657b01b 100644
--- a/briar-api/src/org/briarproject/api/forum/ForumManager.java
+++ b/briar-api/src/org/briarproject/api/forum/ForumManager.java
@@ -1,6 +1,7 @@
 package org.briarproject.api.forum;
 
 import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.Transaction;
 import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
@@ -12,6 +13,18 @@ public interface ForumManager {
 	/** Returns the unique ID of the forum client. */
 	ClientId getClientId();
 
+	/** Creates a forum with the given name. */
+	Forum createForum(String name);
+
+	/** Creates a forum with the given name and salt. */
+	Forum createForum(String name, byte[] salt);
+
+	/** Subscribes to a forum. */
+	void addForum(Forum f) throws DbException;
+
+	/** Unsubscribes from a forum. */
+	void removeForum(Forum f) throws DbException;
+
 	/** Stores a local forum post. */
 	void addLocalPost(ForumPost p) throws DbException;
 
@@ -29,4 +42,11 @@ public interface ForumManager {
 
 	/** Marks a forum post as read or unread. */
 	void setReadFlag(MessageId m, boolean read) throws DbException;
+
+	/** Registers a hook to be called whenever a forum is removed. */
+	void registerRemoveForumHook(RemoveForumHook hook);
+
+	interface RemoveForumHook {
+		void removingForum(Transaction txn, Forum f) throws DbException;
+	}
 }
diff --git a/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java b/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java
index 91b806e0e8..e3e3b1191c 100644
--- a/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java
+++ b/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java
@@ -13,15 +13,6 @@ public interface ForumSharingManager {
 	/** Returns the unique ID of the forum sharing client. */
 	ClientId getClientId();
 
-	/** Creates a forum with the given name. */
-	Forum createForum(String name);
-
-	/** Subscribes to a forum. */
-	void addForum(Forum f) throws DbException;
-
-	/** Unsubscribes from a forum. */
-	void removeForum(Forum f) throws DbException;
-
 	/** Returns all forums to which the user could subscribe. */
 	Collection<Forum> getAvailableForums() throws DbException;
 
@@ -38,6 +29,4 @@ public interface ForumSharingManager {
 	void setSharedWith(GroupId g, Collection<ContactId> shared)
 			throws DbException;
 
-	/** Shares a forum with all current and future contacts. */
-	void setSharedWithAll(GroupId g) throws DbException;
 }
diff --git a/briar-api/src/org/briarproject/api/introduction/IntroductionManager.java b/briar-api/src/org/briarproject/api/introduction/IntroductionManager.java
index f02b9b635c..9819c87580 100644
--- a/briar-api/src/org/briarproject/api/introduction/IntroductionManager.java
+++ b/briar-api/src/org/briarproject/api/introduction/IntroductionManager.java
@@ -1,15 +1,11 @@
 package org.briarproject.api.introduction;
 
 import org.briarproject.api.FormatException;
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.contact.Contact;
 import org.briarproject.api.contact.ContactId;
-import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.db.DbException;
-import org.briarproject.api.db.Transaction;
 import org.briarproject.api.sync.ClientId;
-import org.briarproject.api.sync.Group;
-import org.briarproject.api.sync.GroupId;
-import org.briarproject.api.sync.MessageId;
 
 import java.util.Collection;
 
diff --git a/briar-api/src/org/briarproject/api/introduction/IntroductionMessage.java b/briar-api/src/org/briarproject/api/introduction/IntroductionMessage.java
index 8582f36c6d..8c9de76dfa 100644
--- a/briar-api/src/org/briarproject/api/introduction/IntroductionMessage.java
+++ b/briar-api/src/org/briarproject/api/introduction/IntroductionMessage.java
@@ -1,5 +1,6 @@
 package org.briarproject.api.introduction;
 
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.sync.MessageId;
 
 import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCEE;
diff --git a/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java b/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java
index dc674f77b9..912f8a3fba 100644
--- a/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java
+++ b/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java
@@ -1,5 +1,6 @@
 package org.briarproject.api.introduction;
 
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.identity.AuthorId;
 import org.briarproject.api.sync.MessageId;
 
diff --git a/briar-api/src/org/briarproject/api/introduction/IntroductionResponse.java b/briar-api/src/org/briarproject/api/introduction/IntroductionResponse.java
index 956131ccb5..be4cb57072 100644
--- a/briar-api/src/org/briarproject/api/introduction/IntroductionResponse.java
+++ b/briar-api/src/org/briarproject/api/introduction/IntroductionResponse.java
@@ -1,5 +1,6 @@
 package org.briarproject.api.introduction;
 
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.identity.AuthorId;
 import org.briarproject.api.sync.MessageId;
 
diff --git a/briar-core/src/org/briarproject/forum/ForumManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
index 8d319ca4ad..63d4a2db83 100644
--- a/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
+++ b/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
@@ -17,10 +17,12 @@ import org.briarproject.api.identity.AuthorId;
 import org.briarproject.api.identity.LocalAuthor;
 import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
+import org.briarproject.api.sync.GroupFactory;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.util.StringUtils;
 
+import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -29,9 +31,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.inject.Inject;
 
+import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH;
+import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH;
 import static org.briarproject.api.identity.Author.Status.ANONYMOUS;
 import static org.briarproject.api.identity.Author.Status.UNKNOWN;
 import static org.briarproject.api.identity.Author.Status.VERIFIED;
@@ -44,11 +49,19 @@ class ForumManagerImpl implements ForumManager {
 
 	private final DatabaseComponent db;
 	private final ClientHelper clientHelper;
+	private final GroupFactory groupFactory;
+	private final SecureRandom random;
+	private final List<RemoveForumHook> removeHooks;
 
 	@Inject
-	ForumManagerImpl(DatabaseComponent db, ClientHelper clientHelper) {
+	ForumManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
+			GroupFactory groupFactory, SecureRandom random) {
+
 		this.db = db;
 		this.clientHelper = clientHelper;
+		this.groupFactory = groupFactory;
+		this.random = random;
+		removeHooks = new CopyOnWriteArrayList<RemoveForumHook>();
 	}
 
 	@Override
@@ -56,6 +69,53 @@ class ForumManagerImpl implements ForumManager {
 		return CLIENT_ID;
 	}
 
+	@Override
+	public Forum createForum(String name) {
+		int length = StringUtils.toUtf8(name).length;
+		if (length == 0) throw new IllegalArgumentException();
+		if (length > MAX_FORUM_NAME_LENGTH)
+			throw new IllegalArgumentException();
+		byte[] salt = new byte[FORUM_SALT_LENGTH];
+		random.nextBytes(salt);
+		return createForum(name, salt);
+	}
+
+	@Override
+	public Forum createForum(String name, byte[] salt) {
+		try {
+			BdfList forum = BdfList.of(name, salt);
+			byte[] descriptor = clientHelper.toByteArray(forum);
+			Group g = groupFactory.createGroup(getClientId(), descriptor);
+			return new Forum(g, name, salt);
+		} catch (FormatException e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	@Override
+	public void addForum(Forum f) throws DbException {
+		Transaction txn = db.startTransaction(false);
+		try {
+			db.addGroup(txn, f.getGroup());
+			txn.setComplete();
+		} finally {
+			db.endTransaction(txn);
+		}
+	}
+
+	@Override
+	public void removeForum(Forum f) throws DbException {
+		Transaction txn = db.startTransaction(false);
+		try {
+			for (RemoveForumHook hook : removeHooks)
+				hook.removingForum(txn, f);
+			db.removeGroup(txn, f.getGroup());
+			txn.setComplete();
+		} finally {
+			db.endTransaction(txn);
+		}
+	}
+
 	@Override
 	public void addLocalPost(ForumPost p) throws DbException {
 		try {
@@ -190,10 +250,16 @@ class ForumManagerImpl implements ForumManager {
 		}
 	}
 
+	@Override
+	public void registerRemoveForumHook(RemoveForumHook hook) {
+		removeHooks.add(hook);
+	}
+
 	private Forum parseForum(Group g) throws FormatException {
 		byte[] descriptor = g.getDescriptor();
 		// Name, salt
 		BdfList forum = clientHelper.toList(descriptor, 0, descriptor.length);
 		return new Forum(g, forum.getString(0), forum.getRaw(1));
 	}
+
 }
diff --git a/briar-core/src/org/briarproject/forum/ForumModule.java b/briar-core/src/org/briarproject/forum/ForumModule.java
index f801e2770c..ac0ff20616 100644
--- a/briar-core/src/org/briarproject/forum/ForumModule.java
+++ b/briar-core/src/org/briarproject/forum/ForumModule.java
@@ -10,9 +10,12 @@ import org.briarproject.api.forum.ForumPostFactory;
 import org.briarproject.api.forum.ForumSharingManager;
 import org.briarproject.api.identity.AuthorFactory;
 import org.briarproject.api.lifecycle.LifecycleManager;
+import org.briarproject.api.sync.GroupFactory;
 import org.briarproject.api.sync.ValidationManager;
 import org.briarproject.api.system.Clock;
 
+import java.security.SecureRandom;
+
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
@@ -34,8 +37,9 @@ public class ForumModule {
 	@Provides
 	@Singleton
 	ForumManager provideForumManager(DatabaseComponent db,
-			ClientHelper clientHelper) {
-		return new ForumManagerImpl(db, clientHelper);
+			ClientHelper clientHelper,
+			GroupFactory groupFactory, SecureRandom random) {
+		return new ForumManagerImpl(db, clientHelper, groupFactory, random);
 	}
 
 	@Provides
@@ -75,12 +79,14 @@ public class ForumModule {
 			LifecycleManager lifecycleManager,
 			ContactManager contactManager,
 			ValidationManager validationManager,
+			ForumManager forumManager,
 			ForumSharingManagerImpl forumSharingManager) {
 		lifecycleManager.registerClient(forumSharingManager);
 		contactManager.registerAddContactHook(forumSharingManager);
 		contactManager.registerRemoveContactHook(forumSharingManager);
 		validationManager.registerIncomingMessageHook(
 				ForumSharingManagerImpl.CLIENT_ID, forumSharingManager);
+		forumManager.registerRemoveForumHook(forumSharingManager);
 		return forumSharingManager;
 	}
 }
diff --git a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java
index b975a45377..62501e8e50 100644
--- a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java
+++ b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java
@@ -19,7 +19,6 @@ import org.briarproject.api.forum.ForumManager;
 import org.briarproject.api.forum.ForumSharingManager;
 import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
-import org.briarproject.api.sync.GroupFactory;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
 import org.briarproject.api.sync.MessageId;
@@ -28,7 +27,6 @@ import org.briarproject.api.system.Clock;
 import org.briarproject.util.StringUtils;
 
 import java.io.IOException;
-import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -40,12 +38,12 @@ import java.util.Set;
 
 import javax.inject.Inject;
 
-import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH;
-import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH;
 import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
+import static org.briarproject.api.forum.ForumManager.RemoveForumHook;
 
 class ForumSharingManagerImpl implements ForumSharingManager, Client,
-		AddContactHook, RemoveContactHook, IncomingMessageHook {
+		AddContactHook, RemoveContactHook, IncomingMessageHook,
+		RemoveForumHook {
 
 	static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
 			"cd11a5d04dccd9e2931d6fc3df456313"
@@ -54,30 +52,23 @@ class ForumSharingManagerImpl implements ForumSharingManager, Client,
 	private final DatabaseComponent db;
 	private final ForumManager forumManager;
 	private final ClientHelper clientHelper;
-	private final GroupFactory groupFactory;
 	private final PrivateGroupFactory privateGroupFactory;
-	private final SecureRandom random;
 	private final Clock clock;
-	private final Group localGroup;
 
 	@Inject
 	ForumSharingManagerImpl(DatabaseComponent db, ForumManager forumManager,
-			ClientHelper clientHelper, GroupFactory groupFactory,
-			PrivateGroupFactory privateGroupFactory, SecureRandom random,
+			ClientHelper clientHelper, PrivateGroupFactory privateGroupFactory,
 			Clock clock) {
+
 		this.db = db;
 		this.forumManager = forumManager;
 		this.clientHelper = clientHelper;
-		this.groupFactory = groupFactory;
 		this.privateGroupFactory = privateGroupFactory;
-		this.random = random;
 		this.clock = clock;
-		localGroup = privateGroupFactory.createLocalGroup(CLIENT_ID);
 	}
 
 	@Override
 	public void createLocalState(Transaction txn) throws DbException {
-		db.addGroup(txn, localGroup);
 		// Ensure we've set things up for any pre-existing contacts
 		for (Contact c : db.getContacts(txn)) addingContact(txn, c);
 	}
@@ -96,9 +87,6 @@ class ForumSharingManagerImpl implements ForumSharingManager, Client,
 			BdfDictionary meta = new BdfDictionary();
 			meta.put("contactId", c.getId().getInt());
 			clientHelper.mergeGroupMetadata(txn, g.getId(), meta);
-			// Share any forums that are shared with all contacts
-			List<Forum> shared = getForumsSharedWithAllContacts(txn);
-			storeMessage(txn, g.getId(), shared, 0);
 		} catch (FormatException e) {
 			throw new DbException(e);
 		}
@@ -126,40 +114,10 @@ class ForumSharingManagerImpl implements ForumSharingManager, Client,
 	}
 
 	@Override
-	public Forum createForum(String name) {
-		int length = StringUtils.toUtf8(name).length;
-		if (length == 0) throw new IllegalArgumentException();
-		if (length > MAX_FORUM_NAME_LENGTH)
-			throw new IllegalArgumentException();
-		byte[] salt = new byte[FORUM_SALT_LENGTH];
-		random.nextBytes(salt);
-		return createForum(name, salt);
-	}
-
-	@Override
-	public void addForum(Forum f) throws DbException {
-		Transaction txn = db.startTransaction(false);
+	public void removingForum(Transaction txn, Forum f) throws DbException {
 		try {
-			db.addGroup(txn, f.getGroup());
-			txn.setComplete();
-		} finally {
-			db.endTransaction(txn);
-		}
-	}
-
-	@Override
-	public void removeForum(Forum f) throws DbException {
-		try {
-			// Update the list shared with each contact
-			Transaction txn = db.startTransaction(false);
-			try {
-				for (Contact c : db.getContacts(txn))
-					removeFromList(txn, getContactGroup(c).getId(), f);
-				db.removeGroup(txn, f.getGroup());
-				txn.setComplete();
-			} finally {
-				db.endTransaction(txn);
-			}
+			for (Contact c : db.getContacts(txn))
+				removeFromList(txn, getContactGroup(c).getId(), f);
 		} catch (IOException e) {
 			throw new DbException(e);
 		}
@@ -247,8 +205,6 @@ class ForumSharingManagerImpl implements ForumSharingManager, Client,
 			try {
 				// Retrieve the forum
 				Forum f = parseForum(db.getGroup(txn, g));
-				// Remove the forum from the list shared with all contacts
-				removeFromList(txn, localGroup.getId(), f);
 				// Update the list shared with each contact
 				shared = new HashSet<ContactId>(shared);
 				for (Contact c : db.getContacts(txn)) {
@@ -272,46 +228,10 @@ class ForumSharingManagerImpl implements ForumSharingManager, Client,
 		}
 	}
 
-	@Override
-	public void setSharedWithAll(GroupId g) throws DbException {
-		try {
-			Transaction txn = db.startTransaction(false);
-			try {
-				// Retrieve the forum
-				Forum f = parseForum(db.getGroup(txn, g));
-				// Add the forum to the list shared with all contacts
-				addToList(txn, localGroup.getId(), f);
-				// Add the forum to the list shared with each contact
-				for (Contact c : db.getContacts(txn)) {
-					Group cg = getContactGroup(c);
-					if (addToList(txn, cg.getId(), f)) {
-						if (listContains(txn, cg.getId(), g, false))
-							db.setVisibleToContact(txn, c.getId(), g, true);
-					}
-				}
-				txn.setComplete();
-			} finally {
-				db.endTransaction(txn);
-			}
-		} catch (FormatException e) {
-			throw new DbException(e);
-		}
-	}
-
 	private Group getContactGroup(Contact c) {
 		return privateGroupFactory.createPrivateGroup(CLIENT_ID, c);
 	}
 
-	private List<Forum> getForumsSharedWithAllContacts(Transaction txn)
-			throws DbException, FormatException {
-		// Find the latest update in the local group
-		LatestUpdate latest = findLatest(txn, localGroup.getId(), true);
-		if (latest == null) return Collections.emptyList();
-		// Retrieve and parse the latest update
-		BdfList message = clientHelper.getMessageAsList(txn, latest.messageId);
-		return parseForumList(message);
-	}
-
 	private LatestUpdate findLatest(Transaction txn, GroupId g, boolean local)
 			throws DbException, FormatException {
 		LatestUpdate latest = null;
@@ -334,7 +254,8 @@ class ForumSharingManagerImpl implements ForumSharingManager, Client,
 		for (int i = 0; i < forumList.size(); i++) {
 			// Name, salt
 			BdfList forum = forumList.getList(i);
-			forums.add(createForum(forum.getString(0), forum.getRaw(1)));
+			forums.add(forumManager
+					.createForum(forum.getString(0), forum.getRaw(1)));
 		}
 		return forums;
 	}
@@ -400,18 +321,6 @@ class ForumSharingManagerImpl implements ForumSharingManager, Client,
 		}
 	}
 
-	private Forum createForum(String name, byte[] salt) {
-		try {
-			BdfList forum = BdfList.of(name, salt);
-			byte[] descriptor = clientHelper.toByteArray(forum);
-			Group g = groupFactory.createGroup(forumManager.getClientId(),
-					descriptor);
-			return new Forum(g, name, salt);
-		} catch (FormatException e) {
-			throw new RuntimeException(e);
-		}
-	}
-
 	private Forum parseForum(Group g) throws FormatException {
 		byte[] descriptor = g.getDescriptor();
 		// Name, salt
diff --git a/briar-core/src/org/briarproject/introduction/IntroduceeEngine.java b/briar-core/src/org/briarproject/introduction/IntroduceeEngine.java
index 3f29b00b00..50af8e754a 100644
--- a/briar-core/src/org/briarproject/introduction/IntroduceeEngine.java
+++ b/briar-core/src/org/briarproject/introduction/IntroduceeEngine.java
@@ -1,7 +1,7 @@
 package org.briarproject.introduction;
 
 import org.briarproject.api.FormatException;
-import org.briarproject.api.ProtocolEngine;
+import org.briarproject.api.clients.ProtocolEngine;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.event.Event;
@@ -11,7 +11,7 @@ import org.briarproject.api.identity.AuthorId;
 import org.briarproject.api.introduction.IntroduceeAction;
 import org.briarproject.api.introduction.IntroduceeProtocolState;
 import org.briarproject.api.introduction.IntroductionRequest;
-import org.briarproject.api.introduction.SessionId;
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.sync.MessageId;
 
 import java.util.ArrayList;
diff --git a/briar-core/src/org/briarproject/introduction/IntroducerEngine.java b/briar-core/src/org/briarproject/introduction/IntroducerEngine.java
index e0e1449f65..a431fd7e46 100644
--- a/briar-core/src/org/briarproject/introduction/IntroducerEngine.java
+++ b/briar-core/src/org/briarproject/introduction/IntroducerEngine.java
@@ -1,7 +1,7 @@
 package org.briarproject.introduction;
 
 import org.briarproject.api.FormatException;
-import org.briarproject.api.ProtocolEngine;
+import org.briarproject.api.clients.ProtocolEngine;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.event.Event;
@@ -11,7 +11,7 @@ import org.briarproject.api.identity.AuthorId;
 import org.briarproject.api.introduction.IntroducerAction;
 import org.briarproject.api.introduction.IntroducerProtocolState;
 import org.briarproject.api.introduction.IntroductionResponse;
-import org.briarproject.api.introduction.SessionId;
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.sync.MessageId;
 
 import java.util.ArrayList;
diff --git a/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java b/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java
index 0d0c3102bd..97740b10ac 100644
--- a/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java
+++ b/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java
@@ -20,7 +20,7 @@ import org.briarproject.api.introduction.IntroductionManager;
 import org.briarproject.api.introduction.IntroductionMessage;
 import org.briarproject.api.introduction.IntroductionRequest;
 import org.briarproject.api.introduction.IntroductionResponse;
-import org.briarproject.api.introduction.SessionId;
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
diff --git a/briar-core/src/org/briarproject/introduction/IntroductionValidator.java b/briar-core/src/org/briarproject/introduction/IntroductionValidator.java
index 0307ccfd9f..3babe437b4 100644
--- a/briar-core/src/org/briarproject/introduction/IntroductionValidator.java
+++ b/briar-core/src/org/briarproject/introduction/IntroductionValidator.java
@@ -5,7 +5,7 @@ import org.briarproject.api.clients.ClientHelper;
 import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.data.BdfList;
 import org.briarproject.api.data.MetadataEncoder;
-import org.briarproject.api.introduction.SessionId;
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.Message;
 import org.briarproject.api.system.Clock;
diff --git a/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java b/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java
index a4d986d257..c6a0afa45c 100644
--- a/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java
+++ b/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java
@@ -19,7 +19,7 @@ import org.briarproject.api.identity.Author;
 import org.briarproject.api.identity.AuthorFactory;
 import org.briarproject.api.identity.AuthorId;
 import org.briarproject.api.introduction.IntroduceeProtocolState;
-import org.briarproject.api.introduction.SessionId;
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.properties.TransportPropertyManager;
 import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
diff --git a/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java b/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java
index f6b5e90e88..fac0b0b32d 100644
--- a/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java
+++ b/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java
@@ -18,7 +18,7 @@ import org.briarproject.api.db.DbException;
 import org.briarproject.api.db.Transaction;
 import org.briarproject.api.identity.Author;
 import org.briarproject.api.identity.AuthorId;
-import org.briarproject.api.introduction.SessionId;
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
diff --git a/briar-tests/src/org/briarproject/introduction/IntroductionValidatorTest.java b/briar-tests/src/org/briarproject/introduction/IntroductionValidatorTest.java
index dbacbc8f74..d7d4112946 100644
--- a/briar-tests/src/org/briarproject/introduction/IntroductionValidatorTest.java
+++ b/briar-tests/src/org/briarproject/introduction/IntroductionValidatorTest.java
@@ -9,7 +9,7 @@ import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.data.BdfEntry;
 import org.briarproject.api.data.BdfList;
 import org.briarproject.api.data.MetadataEncoder;
-import org.briarproject.api.introduction.SessionId;
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
diff --git a/briar-tests/src/org/briarproject/introduction/MessageSenderTest.java b/briar-tests/src/org/briarproject/introduction/MessageSenderTest.java
index 1c9d3b82c7..8809fd0a1a 100644
--- a/briar-tests/src/org/briarproject/introduction/MessageSenderTest.java
+++ b/briar-tests/src/org/briarproject/introduction/MessageSenderTest.java
@@ -14,7 +14,7 @@ import org.briarproject.api.db.DatabaseComponent;
 import org.briarproject.api.db.DbException;
 import org.briarproject.api.db.Metadata;
 import org.briarproject.api.db.Transaction;
-import org.briarproject.api.introduction.SessionId;
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
-- 
GitLab