diff --git a/briar-core/src/org/briarproject/forum/ForumManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
index 174f23147b6ab1c2e5a3ef287a2ead6a7a51392e..899b3de541d8382300d440122dc180e21e0a54a1 100644
--- a/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
+++ b/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
@@ -3,15 +3,12 @@ package org.briarproject.forum;
 import com.google.inject.Inject;
 
 import org.briarproject.api.FormatException;
+import org.briarproject.api.clients.ClientHelper;
 import org.briarproject.api.contact.Contact;
 import org.briarproject.api.data.BdfDictionary;
-import org.briarproject.api.data.BdfReader;
-import org.briarproject.api.data.BdfReaderFactory;
-import org.briarproject.api.data.MetadataEncoder;
-import org.briarproject.api.data.MetadataParser;
+import org.briarproject.api.data.BdfList;
 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.forum.Forum;
 import org.briarproject.api.forum.ForumManager;
@@ -26,8 +23,6 @@ import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.util.StringUtils;
 
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -36,16 +31,10 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-import java.util.logging.Logger;
 
-import static java.util.logging.Level.WARNING;
-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.forum.ForumConstants.MAX_FORUM_POST_BODY_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;
-import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
 
 class ForumManagerImpl implements ForumManager {
 
@@ -53,21 +42,13 @@ class ForumManagerImpl implements ForumManager {
 			"859a7be50dca035b64bd6902fb797097"
 					+ "795af837abbf8c16d750b3c2ccc186ea"));
 
-	private static final Logger LOG =
-			Logger.getLogger(ForumManagerImpl.class.getName());
-
 	private final DatabaseComponent db;
-	private final BdfReaderFactory bdfReaderFactory;
-	private final MetadataEncoder metadataEncoder;
-	private final MetadataParser metadataParser;
+	private final ClientHelper clientHelper;
 
 	@Inject
-	ForumManagerImpl(DatabaseComponent db, BdfReaderFactory bdfReaderFactory,
-			MetadataEncoder metadataEncoder, MetadataParser metadataParser) {
+	ForumManagerImpl(DatabaseComponent db, ClientHelper clientHelper) {
 		this.db = db;
-		this.bdfReaderFactory = bdfReaderFactory;
-		this.metadataEncoder = metadataEncoder;
-		this.metadataParser = metadataParser;
+		this.clientHelper = clientHelper;
 	}
 
 	@Override
@@ -78,29 +59,22 @@ class ForumManagerImpl implements ForumManager {
 	@Override
 	public void addLocalPost(ForumPost p) throws DbException {
 		try {
-			BdfDictionary d = new BdfDictionary();
-			d.put("timestamp", p.getMessage().getTimestamp());
+			BdfDictionary meta = new BdfDictionary();
+			meta.put("timestamp", p.getMessage().getTimestamp());
 			if (p.getParent() != null)
-				d.put("parent", p.getParent().getBytes());
+				meta.put("parent", p.getParent().getBytes());
 			if (p.getAuthor() != null) {
 				Author a = p.getAuthor();
-				BdfDictionary d1 = new BdfDictionary();
-				d1.put("id", a.getId().getBytes());
-				d1.put("name", a.getName());
-				d1.put("publicKey", a.getPublicKey());
-				d.put("author", d1);
-			}
-			d.put("contentType", p.getContentType());
-			d.put("local", true);
-			d.put("read", true);
-			Metadata meta = metadataEncoder.encode(d);
-			Transaction txn = db.startTransaction();
-			try {
-				db.addLocalMessage(txn, p.getMessage(), CLIENT_ID, meta, true);
-				txn.setComplete();
-			} finally {
-				db.endTransaction(txn);
+				BdfDictionary author = new BdfDictionary();
+				author.put("id", a.getId().getBytes());
+				author.put("name", a.getName());
+				author.put("publicKey", a.getPublicKey());
+				meta.put("author", author);
 			}
+			meta.put("contentType", p.getContentType());
+			meta.put("local", true);
+			meta.put("read", true);
+			clientHelper.addLocalMessage(p.getMessage(), CLIENT_ID, meta, true);
 		} catch (FormatException e) {
 			throw new RuntimeException(e);
 		}
@@ -145,34 +119,11 @@ class ForumManagerImpl implements ForumManager {
 	@Override
 	public byte[] getPostBody(MessageId m) throws DbException {
 		try {
-			byte[] raw;
-			Transaction txn = db.startTransaction();
-			try {
-				raw = db.getRawMessage(txn, m);
-				txn.setComplete();
-			} finally {
-				db.endTransaction(txn);
-			}
-			ByteArrayInputStream in = new ByteArrayInputStream(raw,
-					MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH);
-			BdfReader r = bdfReaderFactory.createReader(in);
-			r.readListStart();
-			if (r.hasRaw()) r.skipRaw(); // Parent ID
-			else r.skipNull(); // No parent
-			if (r.hasList()) r.skipList(); // Author
-			else r.skipNull(); // No author
-			r.skipString(); // Content type
-			byte[] postBody = r.readRaw(MAX_FORUM_POST_BODY_LENGTH);
-			if (r.hasRaw()) r.skipRaw(); // Signature
-			else r.skipNull();
-			r.readListEnd();
-			if (!r.eof()) throw new FormatException();
-			return postBody;
+			// Parent ID, author, content type, forum post body, signature
+			BdfList message = clientHelper.getMessageAsList(m);
+			return message.getRaw(3);
 		} catch (FormatException e) {
 			throw new DbException(e);
-		} catch (IOException e) {
-			// Shouldn't happen with ByteArrayInputStream
-			throw new RuntimeException(e);
 		}
 	}
 
@@ -181,7 +132,7 @@ class ForumManagerImpl implements ForumManager {
 			throws DbException {
 		Set<AuthorId> localAuthorIds = new HashSet<AuthorId>();
 		Set<AuthorId> contactAuthorIds = new HashSet<AuthorId>();
-		Map<MessageId, Metadata> metadata;
+		Map<MessageId, BdfDictionary> metadata;
 		Transaction txn = db.startTransaction();
 		try {
 			// Load the IDs of the user's identities
@@ -191,20 +142,22 @@ class ForumManagerImpl implements ForumManager {
 			for (Contact c : db.getContacts(txn))
 				contactAuthorIds.add(c.getAuthor().getId());
 			// Load the metadata
-			metadata = db.getMessageMetadata(txn, g);
+			metadata = clientHelper.getMessageMetadataAsDictionary(txn, g);
 			txn.setComplete();
+		} catch (FormatException e) {
+			throw new DbException(e);
 		} finally {
 			db.endTransaction(txn);
 		}
 		// Parse the metadata
 		Collection<ForumPostHeader> headers = new ArrayList<ForumPostHeader>();
-		for (Entry<MessageId, Metadata> e : metadata.entrySet()) {
+		for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
 			try {
-				BdfDictionary d = metadataParser.parse(e.getValue());
-				long timestamp = d.getLong("timestamp");
+				BdfDictionary meta = entry.getValue();
+				long timestamp = meta.getLong("timestamp");
 				Author author = null;
 				Author.Status authorStatus = ANONYMOUS;
-				BdfDictionary d1 = d.getDictionary("author", null);
+				BdfDictionary d1 = meta.getDictionary("author", null);
 				if (d1 != null) {
 					AuthorId authorId = new AuthorId(d1.getRaw("id"));
 					String name = d1.getString("name");
@@ -216,13 +169,12 @@ class ForumManagerImpl implements ForumManager {
 						authorStatus = VERIFIED;
 					else authorStatus = UNKNOWN;
 				}
-				String contentType = d.getString("contentType");
-				boolean read = d.getBoolean("read");
-				headers.add(new ForumPostHeader(e.getKey(), timestamp, author,
-						authorStatus, contentType, read));
-			} catch (FormatException ex) {
-				if (LOG.isLoggable(WARNING))
-					LOG.log(WARNING, ex.toString(), ex);
+				String contentType = meta.getString("contentType");
+				boolean read = meta.getBoolean("read");
+				headers.add(new ForumPostHeader(entry.getKey(), timestamp,
+						author, authorStatus, contentType, read));
+			} catch (FormatException e) {
+				throw new DbException(e);
 			}
 		}
 		return headers;
@@ -231,36 +183,18 @@ class ForumManagerImpl implements ForumManager {
 	@Override
 	public void setReadFlag(MessageId m, boolean read) throws DbException {
 		try {
-			BdfDictionary d = new BdfDictionary();
-			d.put("read", read);
-			Metadata meta = metadataEncoder.encode(d);
-			Transaction txn = db.startTransaction();
-			try {
-				db.mergeMessageMetadata(txn, m, meta);
-				txn.setComplete();
-			} finally {
-				db.endTransaction(txn);
-			}
+			BdfDictionary meta = new BdfDictionary();
+			meta.put("read", read);
+			clientHelper.mergeMessageMetadata(m, meta);
 		} catch (FormatException e) {
 			throw new RuntimeException(e);
 		}
 	}
 
 	private Forum parseForum(Group g) throws FormatException {
-		ByteArrayInputStream in = new ByteArrayInputStream(g.getDescriptor());
-		BdfReader r = bdfReaderFactory.createReader(in);
-		try {
-			r.readListStart();
-			String name = r.readString(MAX_FORUM_NAME_LENGTH);
-			byte[] salt = r.readRaw(FORUM_SALT_LENGTH);
-			r.readListEnd();
-			if (!r.eof()) throw new FormatException();
-			return new Forum(g, name, salt);
-		} catch (FormatException e) {
-			throw e;
-		} catch (IOException e) {
-			// Shouldn't happen with ByteArrayInputStream
-			throw new RuntimeException(e);
-		}
+		byte[] descriptor = g.getDescriptor();
+		// Name, salt
+		BdfList forum = clientHelper.toList(descriptor, 0, descriptor.length);
+		return new Forum(g, forum.getString(0), forum.getRaw(1));
 	}
 }