diff --git a/briar-api/src/org/briarproject/api/clients/MessageTree.java b/briar-api/src/org/briarproject/api/clients/MessageTree.java
new file mode 100644
index 0000000000000000000000000000000000000000..500db6a583435f5371ff4e403b7b37778a7f3098
--- /dev/null
+++ b/briar-api/src/org/briarproject/api/clients/MessageTree.java
@@ -0,0 +1,21 @@
+package org.briarproject.api.clients;
+
+import org.briarproject.api.sync.MessageId;
+
+import java.util.Collection;
+import java.util.Comparator;
+
+public interface MessageTree<T extends MessageTree.MessageNode> {
+
+	void add(Collection<T> nodes);
+	void clear();
+	Collection<T> depthFirstOrder();
+	void setComparator(Comparator<T> comparator);
+
+	interface MessageNode {
+		MessageId getId();
+		MessageId getParentId();
+		long getTimestamp();
+	}
+
+}
diff --git a/briar-api/src/org/briarproject/api/forum/ForumPostHeader.java b/briar-api/src/org/briarproject/api/forum/ForumPostHeader.java
index 00924f98ab0834de48700d4f855128f1de6dcb02..40779390539cd3dff457cc70470d1443780f1755 100644
--- a/briar-api/src/org/briarproject/api/forum/ForumPostHeader.java
+++ b/briar-api/src/org/briarproject/api/forum/ForumPostHeader.java
@@ -1,9 +1,10 @@
 package org.briarproject.api.forum;
 
+import org.briarproject.api.clients.MessageTree;
 import org.briarproject.api.identity.Author;
 import org.briarproject.api.sync.MessageId;
 
-public class ForumPostHeader {
+public class ForumPostHeader implements MessageTree.MessageNode {
 
 	private final MessageId id;
 	private final MessageId parentId;
diff --git a/briar-core/src/org/briarproject/clients/MessageTreeImpl.java b/briar-core/src/org/briarproject/clients/MessageTreeImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..55f69cf54008adbcb57e57788a24afe25f0284d7
--- /dev/null
+++ b/briar-core/src/org/briarproject/clients/MessageTreeImpl.java
@@ -0,0 +1,89 @@
+package org.briarproject.clients;
+
+import org.briarproject.api.clients.MessageTree;
+import org.briarproject.api.sync.MessageId;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+
+public class MessageTreeImpl<T extends MessageTree.MessageNode>
+		implements MessageTree<T> {
+
+	Map<MessageId, List<T>> nodeMap = new HashMap<MessageId, List<T>>();
+	List<T> roots = new ArrayList<T>();
+
+	private Comparator<T> comparator = new Comparator<T>() {
+		@Override
+		public int compare(T o1, T o2) {
+			return Long.valueOf(o1.getTimestamp()).compareTo(o2.getTimestamp());
+		}
+	};
+
+	@Inject
+	public MessageTreeImpl() {
+
+	}
+
+	@Override
+	public void clear() {
+		roots.clear();
+		nodeMap.clear();
+	}
+
+	@Override
+	public void add(Collection<T> nodes) {
+		// add all nodes to the node map
+		for (T node : nodes) {
+			nodeMap.put(node.getId(), new ArrayList<T>());
+		}
+		// parse the nodes for dependencies
+		for (T node : nodes) {
+			if (node.getParentId() == null) {
+				roots.add(node);
+			}
+			else {
+				// retrieve the parent's children
+				List<T> pChildren = nodeMap.get(node.getParentId());
+				pChildren.add(node);
+			}
+		}
+		sortAll();
+	}
+
+	private void sortAll() {
+		Collections.sort(roots, comparator);
+		// Sort all the sub-lists
+		for (Map.Entry<MessageId, List<T>> entry: nodeMap.entrySet()) {
+			Collections.sort(entry.getValue(), comparator);
+		}
+	}
+
+	private void traverse(List<T> list, T node) {
+		list.add(node);
+		for (T child : nodeMap.get(node.getId())) {
+			traverse(list, child);
+		}
+	}
+
+	@Override
+	public Collection<T> depthFirstOrder() {
+		List<T> orderedList = new ArrayList<T>();
+		for (T root : roots) {
+			traverse(orderedList, root);
+		}
+		return Collections.unmodifiableList(orderedList);
+	}
+
+	@Override
+	public void setComparator(Comparator<T> comparator) {
+		this.comparator = comparator;
+	}
+
+}
diff --git a/briar-core/src/org/briarproject/forum/ForumModule.java b/briar-core/src/org/briarproject/forum/ForumModule.java
index bde6a057df777386641fc75c4656c4e9272175b7..04d934a21ccccaabdae511448eee6d6fa55d5d4d 100644
--- a/briar-core/src/org/briarproject/forum/ForumModule.java
+++ b/briar-core/src/org/briarproject/forum/ForumModule.java
@@ -2,6 +2,7 @@ package org.briarproject.forum;
 
 import org.briarproject.api.clients.ClientHelper;
 import org.briarproject.api.clients.MessageQueueManager;
+import org.briarproject.api.clients.MessageTree;
 import org.briarproject.api.contact.ContactManager;
 import org.briarproject.api.crypto.CryptoComponent;
 import org.briarproject.api.data.MetadataEncoder;
@@ -9,12 +10,14 @@ import org.briarproject.api.db.DatabaseComponent;
 import org.briarproject.api.forum.ForumFactory;
 import org.briarproject.api.forum.ForumManager;
 import org.briarproject.api.forum.ForumPostFactory;
+import org.briarproject.api.forum.ForumPostHeader;
 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 org.briarproject.clients.MessageTreeImpl;
 
 import java.security.SecureRandom;
 
@@ -100,4 +103,11 @@ public class ForumModule {
 
 		return forumSharingManager;
 	}
+
+	@Provides
+	@Singleton
+	MessageTree<ForumPostHeader> provideForumMessageTree(
+			MessageTreeImpl<ForumPostHeader> messageTree) {
+		return messageTree;
+	}
 }
diff --git a/briar-tests/src/org/briarproject/clients/MessageTreeTest.java b/briar-tests/src/org/briarproject/clients/MessageTreeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c6e165311ea13955c7124704dd568bf7732e499
--- /dev/null
+++ b/briar-tests/src/org/briarproject/clients/MessageTreeTest.java
@@ -0,0 +1,102 @@
+package org.briarproject.clients;
+
+import org.briarproject.TestUtils;
+import org.briarproject.api.clients.MessageTree;
+import org.briarproject.api.sync.MessageId;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.logging.Logger;
+
+import static org.junit.Assert.assertEquals;
+
+public class MessageTreeTest {
+
+	private static final Logger LOG =
+			Logger.getLogger(MessageTreeTest.class.getName());
+
+	private MessageTree<TestNode> tree;
+
+	@Test
+	public void testMessageTree() {
+		tree = new MessageTreeImpl<>();
+		testSimpleTree();
+		tree.clear();
+		testSimpleTree();
+	}
+
+	private void testSimpleTree() {
+		TestNode[] nodes = new TestNode[5];
+		for (int i = 0; i < nodes.length; i++) {
+			nodes[i] = new TestNode();
+		}
+		/*
+		Construct the following tree:
+		4
+		1 ->
+		   0  ->
+		       2
+		   3
+		 */
+		nodes[0].setParentId(nodes[1].getId());
+		nodes[2].setParentId(nodes[0].getId());
+		nodes[3].setParentId(nodes[1].getId());
+		long timestamp = System.currentTimeMillis();
+		nodes[4].setTimestamp(timestamp - 5);
+		nodes[1].setTimestamp(timestamp - 4);
+		nodes[0].setTimestamp(timestamp - 3);
+		nodes[3].setTimestamp(timestamp - 2);
+		nodes[2].setTimestamp(timestamp - 1);
+		// add all nodes except the last one
+		tree.add(Arrays.asList(Arrays.copyOf(nodes, nodes.length-1)));
+		tree.add(Collections.singletonList(nodes[nodes.length-1]));
+		TestNode[] sortedNodes = tree.depthFirstOrder().toArray(new TestNode[5]);
+		assertEquals(nodes[4], sortedNodes[0]);
+		assertEquals(nodes[1], sortedNodes[1]);
+		assertEquals(nodes[0], sortedNodes[2]);
+		assertEquals(nodes[2], sortedNodes[3]);
+		assertEquals(nodes[3], sortedNodes[4]);
+	}
+
+	private void printNodes(TestNode[] nodes, TestNode[] sortedNodes) {
+		for (int i = 0; i < sortedNodes.length; i++) {
+			for (int j = 0; j < nodes.length; j++) {
+				if (sortedNodes[i] == nodes[j]) {
+					LOG.info("index: " + j);
+					break;
+				}
+			}
+		}
+	}
+
+	class TestNode implements MessageTree.MessageNode {
+
+		private final MessageId id = new MessageId(TestUtils.getRandomId());
+		private MessageId parentId;
+		private long timestamp;
+
+		@Override
+		public MessageId getId() {
+			return id;
+		}
+
+		@Override
+		public MessageId getParentId() {
+			return parentId;
+		}
+
+		@Override
+		public long getTimestamp() {
+			return timestamp;
+		}
+
+		public void setParentId(MessageId parentId) {
+			this.parentId = parentId;
+		}
+
+		public void setTimestamp(long timestamp) {
+			this.timestamp = timestamp;
+		}
+	}
+}