diff --git a/briar-api/src/net/sf/briar/api/db/DatabaseComponent.java b/briar-api/src/net/sf/briar/api/db/DatabaseComponent.java
index c8a8b3a02fc8944a7a78008043804084b76555f6..0932c53595947a76de7d3f89d0014370b04ea1f6 100644
--- a/briar-api/src/net/sf/briar/api/db/DatabaseComponent.java
+++ b/briar-api/src/net/sf/briar/api/db/DatabaseComponent.java
@@ -174,6 +174,9 @@ public interface DatabaseComponent {
 	/** Returns the contacts to which the given group is visible. */
 	Collection<ContactId> getVisibility(GroupId g) throws DbException;
 
+	/** Returns the subscriptions that are visible to the given contact. */
+	Collection<GroupId> getVisibleSubscriptions(ContactId c) throws DbException;
+
 	/** Returns true if any messages are sendable to the given contact. */
 	boolean hasSendableMessages(ContactId c) throws DbException;
 
diff --git a/briar-core/src/net/sf/briar/db/Database.java b/briar-core/src/net/sf/briar/db/Database.java
index eaf7b6a143199af17e8d37e05272ef9f51340377..9fa585ff380f004daa4bb661c3bb6c2fd64daafa 100644
--- a/briar-core/src/net/sf/briar/db/Database.java
+++ b/briar-core/src/net/sf/briar/db/Database.java
@@ -441,6 +441,14 @@ interface Database<T> {
 	 */
 	Collection<ContactId> getVisibility(T txn, GroupId g) throws DbException;
 
+	/**
+	 * Returns the subscriptions that are visible to the given contact.
+	 * <p>
+	 * Locking: contact read, subscription read.
+	 */
+	Collection<GroupId> getVisibleSubscriptions(T txn, ContactId c)
+			throws DbException;
+
 	/**
 	 * Returns true if any messages are sendable to the given contact.
 	 * <p>
diff --git a/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java b/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
index 0c96b0fa87fd52bdb7ef4020d9cf5e8429eb8fb4..87777852ed103512434501aa3e28a7b89f7b6435 100644
--- a/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
+++ b/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
@@ -982,6 +982,32 @@ DatabaseCleaner.Callback {
 		}
 	}
 
+	public Collection<GroupId> getVisibleSubscriptions(ContactId c)
+			throws DbException {
+		contactLock.readLock().lock();
+		try {
+			subscriptionLock.readLock().lock();
+			try {
+				T txn = db.startTransaction();
+				try {
+					if(!db.containsContact(txn, c))
+						throw new NoSuchContactException();
+					Collection<GroupId> visible =
+							db.getVisibleSubscriptions(txn, c);
+					db.commitTransaction(txn);
+					return visible;
+				} catch(DbException e) {
+					db.abortTransaction(txn);
+					throw e;
+				}
+			} finally {
+				subscriptionLock.readLock().unlock();
+			}
+		} finally {
+			contactLock.readLock().unlock();
+		}
+	}
+
 	public boolean hasSendableMessages(ContactId c) throws DbException {
 		contactLock.readLock().lock();
 		try {
diff --git a/briar-core/src/net/sf/briar/db/JdbcDatabase.java b/briar-core/src/net/sf/briar/db/JdbcDatabase.java
index c6ba2bb27d9bf463f181ffb1d26bd8ac6c369007..e3a8637e42d15c39bedb6e6dba0d7979014f9402 100644
--- a/briar-core/src/net/sf/briar/db/JdbcDatabase.java
+++ b/briar-core/src/net/sf/briar/db/JdbcDatabase.java
@@ -1854,7 +1854,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
 		try {
-			String sql = "SELECT transportId, key, value, localVersion"
+			String sql = "SELECT tp.transportId, key, value, localVersion"
 					+ " FROM transportProperties AS tp"
 					+ " JOIN transportVersions AS tv"
 					+ " ON tp.transportId = tv.transportId"
@@ -1937,6 +1937,28 @@ abstract class JdbcDatabase implements Database<Connection> {
 		}
 	}
 
+	public Collection<GroupId> getVisibleSubscriptions(Connection txn,
+			ContactId c) throws DbException {
+		PreparedStatement ps = null;
+		ResultSet rs = null;
+		try {
+			String sql = "SELECT groupId FROM groupVisibilities"
+					+ " WHERE contactId = ?";
+			ps = txn.prepareStatement(sql);
+			ps.setInt(1, c.getInt());
+			rs = ps.executeQuery();
+			List<GroupId> visible = new ArrayList<GroupId>();
+			while(rs.next()) visible.add(new GroupId(rs.getBytes(1)));
+			rs.close();
+			ps.close();
+			return Collections.unmodifiableList(visible);
+		} catch(SQLException e) {
+			tryToClose(rs);
+			tryToClose(ps);
+			throw new DbException(e);
+		}
+	}
+
 	public boolean hasSendableMessages(Connection txn, ContactId c)
 			throws DbException {
 		PreparedStatement ps = null;