[geary/mjog/invert-folder-class-hierarchy: 326/362] Geary.FolderPath, Geary.FolderRoot: Move into Folder namespace.




commit 365aa3c792d9a3c18d45a57e4003d31e1b75d6ee
Author: Michael Gratton <mike vee net>
Date:   Sat Feb 13 16:59:19 2021 +1100

    Geary.FolderPath, Geary.FolderRoot: Move into Folder namespace.
    
    Move FolderPath and FolderRoot classes into the Folder interface, and
    rename to avoid duplicating the `Folder` part.

 po/POTFILES.in                                     |   1 -
 .../application/application-account-context.vala   |   4 +-
 src/client/application/application-client.vala     |   2 +-
 .../application-folder-store-factory.vala          |   4 +-
 src/client/composer/composer-widget.vala           |   2 +-
 .../folder-list/folder-list-account-branch.vala    |   8 +-
 .../plugin/mail-merge/mail-merge-folder.vala       |   6 +-
 src/engine/api/geary-account-information.vala      |   8 +-
 src/engine/api/geary-account.vala                  |  26 +-
 src/engine/api/geary-folder-path.vala              | 397 ---------------------
 src/engine/api/geary-folder-supports-copy.vala     |   2 +-
 src/engine/api/geary-folder-supports-move.vala     |   2 +-
 src/engine/api/geary-folder.vala                   | 396 +++++++++++++++++++-
 src/engine/app/app-conversation-monitor.vala       |   8 +-
 src/engine/app/app-conversation.vala               |  38 +-
 src/engine/app/app-email-store.vala                |  24 +-
 src/engine/app/app-search-folder.vala              |  18 +-
 .../conversation-monitor/app-conversation-set.vala |  15 +-
 .../app-local-search-operation.vala                |   6 +-
 src/engine/app/email-store/app-copy-operation.vala |   4 +-
 src/engine/imap-db/imap-db-account.vala            |  84 ++---
 src/engine/imap-db/imap-db-folder.vala             |   6 +-
 .../gmail/imap-engine-gmail-account.vala           |   2 +-
 .../imap-engine/imap-engine-generic-account.vala   |  79 ++--
 .../imap-engine/imap-engine-minimal-folder.vala    |   8 +-
 .../imap-engine-revokable-committed-move.vala      |  11 +-
 .../other/imap-engine-other-account.vala           |   2 +-
 .../outlook/imap-engine-outlook-account.vala       |   2 +-
 .../replay-ops/imap-engine-copy-email.vala         |  10 +-
 .../replay-ops/imap-engine-move-email-commit.vala  |  10 +-
 .../yahoo/imap-engine-yahoo-account.vala           |   2 +-
 src/engine/imap/api/imap-account-session.vala      |  28 +-
 src/engine/imap/api/imap-folder-root.vala          |  14 +-
 src/engine/imap/api/imap-folder-session.vala       |   2 +-
 src/engine/imap/api/imap-folder.vala               |   4 +-
 .../imap/message/imap-mailbox-specifier.vala       |  16 +-
 src/engine/imap/transport/imap-client-session.vala |  10 +-
 src/engine/meson.build                             |   1 -
 src/engine/outbox/outbox-folder.vala               |   6 +-
 test/client/composer/composer-widget-test.vala     |   2 +-
 test/engine/api/geary-folder-path-test.vala        |  32 +-
 test/engine/app/app-conversation-monitor-test.vala |  50 +--
 test/engine/app/app-conversation-set-test.vala     |  38 +-
 test/engine/app/app-conversation-test.vala         |  16 +-
 test/engine/imap-db/imap-db-account-test.vala      |   4 +-
 test/mock/mock-account.vala                        |  22 +-
 test/mock/mock-folder.vala                         |   6 +-
 test/mock/mock-remote-folder.vala                  |   6 +-
 48 files changed, 718 insertions(+), 726 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9ac3950de..0aa7b8e1a 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -166,7 +166,6 @@ src/engine/api/geary-email.vala
 src/engine/api/geary-endpoint.vala
 src/engine/api/geary-engine-error.vala
 src/engine/api/geary-engine.vala
-src/engine/api/geary-folder-path.vala
 src/engine/api/geary-folder-properties.vala
 src/engine/api/geary-folder-supports-archive.vala
 src/engine/api/geary-folder-supports-copy.vala
diff --git a/src/client/application/application-account-context.vala 
b/src/client/application/application-account-context.vala
index 5b1b719a5..8c17471c4 100644
--- a/src/client/application/application-account-context.vala
+++ b/src/client/application/application-account-context.vala
@@ -66,8 +66,8 @@ public class Application.AccountContext : Geary.BaseObject {
         get; internal set; default = false;
     }
 
-    private Gee.Map<Geary.FolderPath,FolderContext> folders =
-        new Gee.HashMap<Geary.FolderPath,FolderContext>();
+    private Gee.Map<Geary.Folder.Path,FolderContext> folders =
+        new Gee.HashMap<Geary.Folder.Path,FolderContext>();
 
 
     /** Emitted when folders contexts become available. */
diff --git a/src/client/application/application-client.vala b/src/client/application/application-client.vala
index 19992eddf..f76e291b9 100644
--- a/src/client/application/application-client.vala
+++ b/src/client/application/application-client.vala
@@ -611,7 +611,7 @@ public class Application.Client : Gtk.Application {
                 email.get_email_identifier_for_variant(id);
             if (context != null && email_id != null) {
                 // Determine what folders the email is in
-                Gee.MultiMap<Geary.EmailIdentifier,Geary.FolderPath>? folders = null;
+                Gee.MultiMap<Geary.EmailIdentifier,Geary.Folder.Path>? folders = null;
                 try {
                     folders = yield context.account.get_containing_folders_async(
                         Geary.Collection.single(email_id),
diff --git a/src/client/application/application-folder-store-factory.vala 
b/src/client/application/application-folder-store-factory.vala
index e1eb4e6fb..c0bc1cbcb 100644
--- a/src/client/application/application-folder-store-factory.vala
+++ b/src/client/application/application-folder-store-factory.vala
@@ -43,7 +43,7 @@ internal class Application.FolderStoreFactory : Geary.BaseObject {
             var id = target as EmailStoreFactory.IdImpl;
             if (id != null) {
                 var context = id._account.backing;
-                Gee.MultiMap<Geary.EmailIdentifier,Geary.FolderPath>? multi_folders =
+                Gee.MultiMap<Geary.EmailIdentifier,Geary.Folder.Path>? multi_folders =
                     yield context.account.get_containing_folders_async(
                         Geary.Collection.single(id.backing),
                         cancellable
@@ -218,7 +218,7 @@ internal class Application.FolderStoreFactory : Geary.BaseObject {
         Geary.Folder? folder = null;
         if (context != null) {
             try {
-                Geary.FolderPath? path = context.account.to_folder_path(
+                Geary.Folder.Path? path = context.account.to_folder_path(
                     target.get_child_value(1).get_variant()
                 );
                 folder = context.account.get_folder(path);
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index 412c8a3b0..5e6616858 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -1061,7 +1061,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
 
         bool new_email = true;
         foreach (var mid in this.in_reply_to) {
-            Gee.MultiMap<Geary.Email, Geary.FolderPath?>? email_map = null;
+            Gee.MultiMap<Geary.Email, Geary.Folder.Path?>? email_map = null;
             try {
                 // TODO: Folder blacklist
                 email_map = yield this.sender_context.account
diff --git a/src/client/folder-list/folder-list-account-branch.vala 
b/src/client/folder-list/folder-list-account-branch.vala
index 7b541512a..ef6850bde 100644
--- a/src/client/folder-list/folder-list-account-branch.vala
+++ b/src/client/folder-list/folder-list-account-branch.vala
@@ -28,7 +28,7 @@ public class FolderList.AccountBranch : Sidebar.Branch {
 
     public Geary.Account account { get; private set; }
     public SpecialGrouping user_folder_group { get; private set; }
-    public Gee.HashMap<Geary.FolderPath, FolderEntry> folder_entries { get; private set; }
+    public Gee.HashMap<Geary.Folder.Path, FolderEntry> folder_entries { get; private set; }
 
     private string display_name = "";
 
@@ -41,7 +41,7 @@ public class FolderList.AccountBranch : Sidebar.Branch {
         // folders created by people (as opposed to special-use
         // folders)
         user_folder_group = new SpecialGrouping(2, _("Labels"), "tag-symbolic");
-        folder_entries = new Gee.HashMap<Geary.FolderPath, FolderEntry>();
+        folder_entries = new Gee.HashMap<Geary.Folder.Path, FolderEntry>();
 
         this.display_name = account.information.display_name;
         account.information.changed.connect(on_information_changed);
@@ -110,7 +110,7 @@ public class FolderList.AccountBranch : Sidebar.Branch {
         return a.get_sidebar_name().collate(b.get_sidebar_name());
     }
 
-    public FolderEntry? get_entry_for_path(Geary.FolderPath folder_path) {
+    public FolderEntry? get_entry_for_path(Geary.Folder.Path folder_path) {
         return folder_entries.get(folder_path);
     }
 
@@ -161,7 +161,7 @@ public class FolderList.AccountBranch : Sidebar.Branch {
         }
     }
 
-    public void remove_folder(Geary.FolderPath path) {
+    public void remove_folder(Geary.Folder.Path path) {
         Sidebar.Entry? entry = this.folder_entries.get(path);
         if (entry == null) {
             debug("Could not remove folder %s", path.to_string());
diff --git a/src/client/plugin/mail-merge/mail-merge-folder.vala 
b/src/client/plugin/mail-merge/mail-merge-folder.vala
index e75491d67..4be39dae4 100644
--- a/src/client/plugin/mail-merge/mail-merge-folder.vala
+++ b/src/client/plugin/mail-merge/mail-merge-folder.vala
@@ -105,10 +105,10 @@ public class MailMerge.Folder : Geary.BaseObject,
     private FolderProperties _properties = new FolderProperties();
 
     /** {@inheritDoc} */
-    public override Geary.FolderPath path {
+    public override Geary.Folder.Path path {
         get { return _path; }
     }
-    private Geary.FolderPath _path;
+    private Geary.Folder.Path _path;
 
     /** {@inheritDoc} */
     public override Geary.Folder.SpecialUse used_as {
@@ -153,7 +153,7 @@ public class MailMerge.Folder : Geary.BaseObject,
 
 
     public async Folder(Geary.Account account,
-                        Geary.FolderRoot root,
+                        Geary.Folder.Root root,
                         Geary.Email template,
                         GLib.File data_location,
                         Csv.Reader data)
diff --git a/src/engine/api/geary-account-information.vala b/src/engine/api/geary-account-information.vala
index 242a3561a..d01721f6b 100644
--- a/src/engine/api/geary-account-information.vala
+++ b/src/engine/api/geary-account-information.vala
@@ -382,9 +382,9 @@ public class Geary.AccountInformation : BaseObject {
     /**
      * Returns a folder path based on the configured steps for a use.
      */
-    public FolderPath? new_folder_path_for_use(FolderRoot root,
-                                               Folder.SpecialUse use) {
-        FolderPath? path = null;
+    public Folder.Path? new_folder_path_for_use(Folder.Root root,
+                                                Folder.SpecialUse use) {
+        Folder.Path? path = null;
         var steps = this.special_use_paths.get(use);
         if (steps != null) {
             path = root;
@@ -398,7 +398,7 @@ public class Geary.AccountInformation : BaseObject {
     /**
      * Returns the configured special folder use for a given path.
      */
-    public Folder.SpecialUse get_folder_use_for_path(FolderPath path) {
+    public Folder.SpecialUse get_folder_use_for_path(Folder.Path path) {
         var path_steps = path.as_array();
         var use = Folder.SpecialUse.NONE;
         foreach (var entry in this.special_use_paths.entries) {
diff --git a/src/engine/api/geary-account.vala b/src/engine/api/geary-account.vala
index 8f9b9339a..4a23f907a 100644
--- a/src/engine/api/geary-account.vala
+++ b/src/engine/api/geary-account.vala
@@ -72,7 +72,7 @@ public abstract class Geary.Account : BaseObject, Logging.Source {
 
     /**
      * A utility method to sort a Gee.Collection of {@link Folder}s by
-     * their {@link FolderPath}s to ensure they comport with {@link
+     * their {@link Folder.Path}s to ensure they comport with {@link
      * folders_available_unavailable}, {@link folders_created}, {@link
      * folders_deleted} signals' contracts.
      */
@@ -137,8 +137,8 @@ public abstract class Geary.Account : BaseObject, Logging.Source {
      * Any local folders create by the engine or clients must use this
      * as the root for local folders.
      */
-    public FolderRoot local_folder_root {
-        get; private set; default = new Geary.FolderRoot("$geary-local", true);
+    public Folder.Root local_folder_root {
+        get; private set; default = new Folder.Root("$geary-local", true);
     }
 
     public ProgressMonitor background_progress { get; protected set; }
@@ -359,12 +359,12 @@ public abstract class Geary.Account : BaseObject, Logging.Source {
      * not guarantee that the folder represented by the path will
      * exist.
      *
-     * @see FolderPath.to_variant
+     * @see Folder.Path.to_variant
      * @throws EngineError.BAD_PARAMETERS when the variant is not the
      * have the correct type or if no folder root with an appropriate
      * label exists.
      */
-    public abstract FolderPath to_folder_path(GLib.Variant serialised)
+    public abstract Folder.Path to_folder_path(GLib.Variant serialised)
         throws EngineError.BAD_PARAMETERS;
 
     /**
@@ -373,7 +373,7 @@ public abstract class Geary.Account : BaseObject, Logging.Source {
      * This method only considers currently known folders, it does not
      * check the remote to see if a previously folder exists.
      */
-    public virtual bool has_folder(FolderPath path) {
+    public virtual bool has_folder(Folder.Path path) {
         try {
             get_folder(path);
             return true;
@@ -390,7 +390,7 @@ public abstract class Geary.Account : BaseObject, Logging.Source {
      *
      * @throws EngineError.NOT_FOUND if the folder does not exist.
      */
-    public abstract Folder get_folder(FolderPath path)
+    public abstract Folder get_folder(Folder.Path path)
         throws EngineError.NOT_FOUND;
 
     /**
@@ -407,7 +407,7 @@ public abstract class Geary.Account : BaseObject, Logging.Source {
      * thrown. However, the caller should be prepared to deal with an
      * empty list being returned instead.
      */
-    public abstract Gee.Collection<Folder> list_matching_folders(FolderPath? parent)
+    public abstract Gee.Collection<Folder> list_matching_folders(Folder.Path? parent)
         throws EngineError.NOT_FOUND;
 
     /**
@@ -484,12 +484,12 @@ public abstract class Geary.Account : BaseObject, Logging.Source {
      * optionally ignoring emails that don't have the requested fields set.
      * Don't include emails that appear in any of the blacklisted folders in
      * the result.  If null is included in the blacklist, omit emails appearing
-     * in no folders.  Return a map of Email object to a list of FolderPaths
+     * in no folders.  Return a map of Email object to a list of Folder.Paths
      * it's in, which can be null if it's in no folders.
      */
-    public abstract async Gee.MultiMap<Geary.Email, Geary.FolderPath?>? local_search_message_id_async(
+    public abstract async Gee.MultiMap<Geary.Email, Folder.Path?>? local_search_message_id_async(
         Geary.RFC822.MessageID message_id, Geary.Email.Field requested_fields, bool partial_ok,
-        Gee.Collection<Geary.FolderPath?>? folder_blacklist, Geary.EmailFlags? flag_blacklist,
+        Gee.Collection<Folder.Path?>? folder_blacklist, Geary.EmailFlags? flag_blacklist,
         Cancellable? cancellable = null) throws Error;
 
     /**
@@ -535,7 +535,7 @@ public abstract class Geary.Account : BaseObject, Logging.Source {
      * offset must not be negative.
      */
     public abstract async Gee.Collection<Geary.EmailIdentifier>? local_search_async(Geary.SearchQuery query,
-        int limit = 100, int offset = 0, Gee.Collection<Geary.FolderPath?>? folder_blacklist = null,
+        int limit = 100, int offset = 0, Gee.Collection<Folder.Path?>? folder_blacklist = null,
         Gee.Collection<Geary.EmailIdentifier>? search_ids = null, Cancellable? cancellable = null) throws 
Error;
 
     /**
@@ -551,7 +551,7 @@ public abstract class Geary.Account : BaseObject, Logging.Source {
      * would be empty.  Only throw database errors et al., not errors due to
      * the email id not being found.
      */
-    public abstract async Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath>? 
get_containing_folders_async(
+    public abstract async Gee.MultiMap<Geary.EmailIdentifier,Folder.Path>? get_containing_folders_async(
         Gee.Collection<Geary.EmailIdentifier> ids, Cancellable? cancellable) throws Error;
 
     /** {@inheritDoc} */
diff --git a/src/engine/api/geary-folder-supports-copy.vala b/src/engine/api/geary-folder-supports-copy.vala
index 257e36248..37a7c936c 100644
--- a/src/engine/api/geary-folder-supports-copy.vala
+++ b/src/engine/api/geary-folder-supports-copy.vala
@@ -27,7 +27,7 @@ public interface Geary.FolderSupport.Copy : Folder {
      */
     public abstract async void
         copy_email_async(Gee.Collection<EmailIdentifier> to_copy,
-                         FolderPath destination,
+                         Folder.Path destination,
                          GLib.Cancellable? cancellable = null)
         throws GLib.Error;
 
diff --git a/src/engine/api/geary-folder-supports-move.vala b/src/engine/api/geary-folder-supports-move.vala
index d57a18d29..99d85f7e0 100644
--- a/src/engine/api/geary-folder-supports-move.vala
+++ b/src/engine/api/geary-folder-supports-move.vala
@@ -28,7 +28,7 @@ public interface Geary.FolderSupport.Move : Folder {
      */
     public abstract async Revokable?
         move_email_async(Gee.Collection<EmailIdentifier> to_move,
-                         FolderPath destination,
+                         Folder.Path destination,
                          GLib.Cancellable? cancellable = null)
         throws GLib.Error;
 
diff --git a/src/engine/api/geary-folder.vala b/src/engine/api/geary-folder.vala
index b3db09f48..6e2556929 100644
--- a/src/engine/api/geary-folder.vala
+++ b/src/engine/api/geary-folder.vala
@@ -37,6 +37,397 @@
 public interface Geary.Folder : GLib.Object, Logging.Source {
 
 
+    /**
+     * A generic structure for representing and maintaining folder paths.
+     *
+     * A Path may have one parent and one child.  A Path without a parent is called a
+     * root folder can be be created with {@link Root}, which is a Path.
+     *
+     * @see Root
+     */
+    public class Path :
+        BaseObject, Gee.Hashable<Path>, Gee.Comparable<Path> {
+
+
+        /** Type of the GLib.Variant used to represent folder paths */
+        public const string VARIANT_TYPE = "(sas)";
+
+
+        // Workaround for Vala issue #659. See children below.
+        private class PathWeakRef {
+
+            GLib.WeakRef weak_ref;
+
+            public PathWeakRef(Path path) {
+                this.weak_ref = GLib.WeakRef(path);
+            }
+
+            public Path? get() {
+                return this.weak_ref.get() as Path;
+            }
+
+        }
+
+
+        /** The base name of this folder, excluding parents. */
+        public string name { get; private set; }
+
+        /** The number of children under the root in this path. */
+        public uint length {
+            get {
+                uint length = 0;
+                Path parent = this.parent;
+                while (parent != null) {
+                    length++;
+                    parent = parent.parent;
+                }
+                return length;
+            }
+        }
+
+        /**
+         * Whether this path is lexiographically case-sensitive.
+         *
+         * This has implications, as {@link Path} is Comparable and Hashable.
+         */
+        public bool case_sensitive { get; private set; }
+
+        /** Determines if this path is a root folder path. */
+        public bool is_root {
+            get { return this.parent == null; }
+        }
+
+        /** Determines if this path is a child of the root folder. */
+        public bool is_top_level {
+            get {
+                Path? parent = parent;
+                return parent != null && parent.is_root;
+            }
+        }
+
+        /** Returns the parent of this path. */
+        public Path? parent { get; private set; }
+
+        private string[] path;
+
+        // Would use a `weak Path` value type for this map instead of
+        // the custom class, but we can't currently reassign built-in
+        // weak refs back to a strong ref at the moment, nor use a
+        // GLib.WeakRef as a generics param. See Vala issue #659.
+        private Gee.Map<string,PathWeakRef?> children =
+        new Gee.HashMap<string,PathWeakRef?>();
+
+        private uint? stored_hash = null;
+
+
+        /** Constructor only for use by {@link Root}. */
+        internal Path() {
+            this.name = "";
+            this.parent = null;
+            this.case_sensitive = false;
+            this.path = new string[0];
+        }
+
+        private Path.child(Path parent,
+                                 string name,
+                                 bool case_sensitive) {
+            this.parent = parent;
+            this.name = name;
+            this.case_sensitive = case_sensitive;
+            this.path = parent.path.copy();
+            this.path += name;
+        }
+
+        /**
+         * Returns the {@link Root} of this path.
+         */
+        public Root get_root() {
+            Path? path = this;
+            while (path.parent != null) {
+                path = path.parent;
+            }
+            return (Root) path;
+        }
+
+        /**
+         * Returns an array of the names of non-root elements in the path.
+         */
+        public string[] as_array() {
+            return this.path;
+        }
+
+        /**
+         * Creates a path that is a child of this folder.
+         *
+         * Specifying {@link Trillian.TRUE} or {@link Trillian.FALSE} for
+         * `is_case_sensitive` forces case-sensitivity either way. If
+         * {@link Trillian.UNKNOWN}, then {@link
+         * Root.default_case_sensitivity} is used.
+         */
+        public virtual Path
+        get_child(string name,
+                  Trillian is_case_sensitive = Trillian.UNKNOWN) {
+            Path? child = null;
+            PathWeakRef? child_ref = this.children.get(name);
+            if (child_ref != null) {
+                child = child_ref.get();
+            }
+            if (child == null) {
+                child = new Path.child(
+                    this,
+                    name,
+                    is_case_sensitive.to_boolean(
+                        get_root().default_case_sensitivity
+                    )
+                );
+                this.children.set(name, new PathWeakRef(child));
+            }
+            return child;
+        }
+
+        /**
+         * Determines if this path is a strict ancestor of another.
+         */
+        public bool is_descendant(Path target) {
+            bool is_descendent = false;
+            Path? path = target.parent;
+            while (path != null) {
+                if (path.equal_to(this)) {
+                    is_descendent = true;
+                    break;
+                }
+                path = path.parent;
+            }
+            return is_descendent;
+        }
+
+        /**
+         * Does a Unicode-normalized, case insensitive match.  Useful for
+         * getting a rough idea if a folder matches a name, but shouldn't
+         * be used to determine strict equality.
+         */
+        public int compare_normalized_ci(Path other) {
+            return compare_internal(other, false, true);
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * Comparisons for Path is defined as (a) empty paths
+         * are less-than non-empty paths and (b) each element is compared
+         * to the corresponding path element of the other Path
+         * following collation rules for casefolded (case-insensitive)
+         * compared, and (c) shorter paths are less-than longer paths,
+         * assuming the path elements are equal up to the shorter path's
+         * length.
+         *
+         * Note that {@link Path.case_sensitive} affects comparisons.
+         *
+         * Returns -1 if this path is lexiographically before the other, 1
+         * if its after, and 0 if they are equal.
+         */
+        public int compare_to(Path other) {
+            return compare_internal(other, true, false);
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * Note that {@link Path.case_sensitive} affects comparisons.
+         */
+        public uint hash() {
+            if (this.stored_hash == null) {
+                this.stored_hash = 0;
+                Path? path = this;
+                while (path != null) {
+                    this.stored_hash ^= (case_sensitive)
+                    ? str_hash(path.name) : str_hash(path.name.down());
+                    path = path.parent;
+                }
+            }
+            return this.stored_hash;
+        }
+
+        /** {@inheritDoc} */
+        public bool equal_to(Path other) {
+            return this.compare_internal(other, true, false) == 0;
+        }
+
+        /**
+         * Returns a representation useful for serialisation.
+         *
+         * This can be used to transmit folder paths as D-Bus method and
+         * GLib Action parameters, and so on.
+         *
+         * @return a serialised form of this path, that will match the
+         * GVariantType specified by {@link VARIANT_TYPE}.
+         * @see Root.from_variant
+         */
+        public GLib.Variant to_variant() {
+            return new GLib.Variant.tuple(new GLib.Variant[] {
+                    get_root().label,
+                    as_array()
+                });
+        }
+
+        /**
+         * Returns a representation useful for debugging.
+         *
+         * Do not use this for obtaining an IMAP mailbox name to send to a
+         * server, use {@link
+         * Geary.Imap.MailboxSpecifier.MailboxSpecifier.from_folder_path}
+         * instead. This method is useful for debugging and logging only.
+         */
+        public string to_string() {
+            const char SEP = '>';
+            StringBuilder builder = new StringBuilder();
+            if (this.is_root) {
+                builder.append_c(SEP);
+            } else {
+                foreach (string name in this.path) {
+                    builder.append_c(SEP);
+                    builder.append(name);
+                }
+            }
+            return builder.str;
+        }
+
+        private int compare_internal(Path other,
+                                     bool allow_case_sensitive,
+                                     bool normalize) {
+            if (this == other) {
+                return 0;
+            }
+
+            int a_len = (int) this.length;
+            int b_len = (int) other.length;
+            if (a_len != b_len) {
+                return a_len - b_len;
+            }
+
+            return compare_names(this, other, allow_case_sensitive, normalize);
+        }
+
+        private static int compare_names(Path a, Path b,
+                                         bool allow_case_sensitive,
+                                         bool normalize) {
+            int cmp = 0;
+            if (a.parent == null && b.parent == null) {
+                cmp = strcmp(((Root) a).label, ((Root) b).label);
+            } else {
+                cmp = compare_names(
+                    a.parent, b.parent, allow_case_sensitive, normalize
+                );
+            }
+
+            if (cmp == 0) {
+                string a_name = a.name;
+                string b_name = b.name;
+
+                if (normalize) {
+                    a_name = a_name.normalize();
+                    b_name = b_name.normalize();
+                }
+
+                if (!allow_case_sensitive
+                    // if either case-sensitive, then comparison is CS
+                    || (!a.case_sensitive && !b.case_sensitive)) {
+                    a_name = a_name.casefold();
+                    b_name = b_name.casefold();
+                }
+
+                return strcmp(a_name, b_name);
+            }
+            return cmp;
+        }
+
+    }
+
+
+    /**
+     * The root of a folder hierarchy.
+     *
+     * A {@link Path} can only be created by starting with a
+     * Root and adding children via {@link Path.get_child}.
+     * Because all Paths hold references to their parents, this
+     * element can be retrieved with {@link Path.get_root}.
+     */
+    public class Root : Path {
+
+
+        /**
+         * A label for a folder root.
+         *
+         * Since there may be multiple folder roots (for example, local
+         * and remote folders, or for different remote namespaces), the
+         * label can be used to look up a specific root.
+         */
+        public string label { get; private set; }
+
+        /**
+         * The default case sensitivity of descendant folders.
+         *
+         * @see Path.get_child
+         */
+        public bool default_case_sensitivity { get; private set; }
+
+
+        /**
+         * Constructs a new folder root with given default sensitivity.
+         */
+        public Root(string label, bool default_case_sensitivity) {
+            base();
+            this.label = label;
+            this.default_case_sensitivity = default_case_sensitivity;
+        }
+
+        /**
+         * Copies a folder path using this as the root.
+         *
+         * This method can be used to simply copy a path, or change the
+         * root that a path is attached to.
+         */
+        public Path copy(Path original) {
+            Path copy = this;
+            foreach (string step in original.as_array()) {
+                copy = copy.get_child(step);
+            }
+            return copy;
+        }
+
+        /**
+         * Reconstructs a path under this root from a GLib variant.
+         *
+         * @see Path.to_variant
+         * @throws EngineError.BAD_PARAMETERS when the variant is not the
+         * have the correct type or if the given root label does not match
+         * this root's label.
+         */
+        public Path from_variant(GLib.Variant serialised)
+        throws EngineError.BAD_PARAMETERS {
+            if (serialised.get_type_string() != VARIANT_TYPE) {
+                throw new EngineError.BAD_PARAMETERS(
+                    "Invalid serialised id type: %s", serialised.get_type_string()
+                );
+            }
+
+            string label = (string) serialised.get_child_value(0);
+            if (this.label != label) {
+                throw new EngineError.BAD_PARAMETERS(
+                    "Invalid serialised folder root label: %s", label
+                );
+            }
+
+            Path path = this;
+            foreach (string step in serialised.get_child_value(1).get_strv()) {
+                path = path.get_child(step);
+            }
+            return path;
+        }
+
+    }
+
+
     /**
      * Specifies the use of a specific folder.
      *
@@ -165,8 +556,8 @@ public interface Geary.Folder : GLib.Object, Logging.Source {
     /** Current properties for this folder. */
     public abstract Geary.FolderProperties properties { get; }
 
-    /** The folder path represented by this object. */
-    public abstract Geary.FolderPath path { get; }
+    /** The path to this folder in the account's folder hierarchy. */
+    public abstract Path path { get; }
 
     /**
      * Determines the special use of this folder.
@@ -180,6 +571,7 @@ public interface Geary.Folder : GLib.Object, Logging.Source {
     public abstract SpecialUse used_as { get; }
 
 
+
     /**
      * Fired when email has been appended to the folder.
      *
diff --git a/src/engine/app/app-conversation-monitor.vala b/src/engine/app/app-conversation-monitor.vala
index 796b95fd9..b3385d92d 100644
--- a/src/engine/app/app-conversation-monitor.vala
+++ b/src/engine/app/app-conversation-monitor.vala
@@ -423,14 +423,14 @@ public class Geary.App.ConversationMonitor : BaseObject, Logging.Source {
     /**
      * Returns the list of folders that disqualify emails from conversations.
      */
-    internal Gee.Collection<Geary.FolderPath> get_search_folder_blacklist() {
+    internal Gee.Collection<Folder.Path> get_search_folder_blacklist() {
         Folder.SpecialUse[] blacklisted_folder_types = {
             JUNK,
             TRASH,
             DRAFTS,
         };
 
-        var blacklist = new Gee.ArrayList<Geary.FolderPath?>();
+        var blacklist = new Gee.ArrayList<Folder.Path?>();
         foreach (var type in blacklisted_folder_types) {
             Geary.Folder? blacklist_folder = this.base_folder.account.get_special_folder(type);
             if (blacklist_folder != null) {
@@ -684,7 +684,7 @@ public class Geary.App.ConversationMonitor : BaseObject, Logging.Source {
         Gee.Collection<Conversation>? removed_due_to_merge = null;
         try {
             // Get known paths for all emails
-            Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath>? email_paths =
+            Gee.MultiMap<Geary.EmailIdentifier, Folder.Path>? email_paths =
                 yield this.base_folder.account.get_containing_folders_async(
                     job.emails.keys,
                     this.operation_cancellable
@@ -727,7 +727,7 @@ public class Geary.App.ConversationMonitor : BaseObject, Logging.Source {
 
         debug("expand_conversations: %d email ids", needed_message_ids.size);
 
-        Gee.Collection<Geary.FolderPath> folder_blacklist = get_search_folder_blacklist();
+        Gee.Collection<Folder.Path> folder_blacklist = get_search_folder_blacklist();
         Geary.EmailFlags flag_blacklist = get_search_flag_blacklist();
 
         // execute all the local search operations at once
diff --git a/src/engine/app/app-conversation.vala b/src/engine/app/app-conversation.vala
index 7eacb718a..9a4f26e21 100644
--- a/src/engine/app/app-conversation.vala
+++ b/src/engine/app/app-conversation.vala
@@ -44,10 +44,10 @@ public class Geary.App.Conversation : BaseObject {
     public Folder base_folder { get; private set; }
 
     /** Cache of paths associated with each email */
-    internal Gee.HashMultiMap<Geary.EmailIdentifier,Geary.FolderPath> path_map {
+    internal Gee.HashMultiMap<Geary.EmailIdentifier,Folder.Path> path_map {
         get;
         private set;
-        default = new Gee.HashMultiMap< Geary.EmailIdentifier,Geary.FolderPath>();
+        default = new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
     }
 
     private Gee.HashMultiSet<RFC822.MessageID> message_ids = new Gee.HashMultiSet<RFC822.MessageID>();
@@ -86,7 +86,7 @@ public class Geary.App.Conversation : BaseObject {
     /**
      * Constructs a conversation relative to the given base folder.
      */
-    internal Conversation(Geary.Folder base_folder) {
+    internal Conversation(Folder base_folder) {
         this.convnum = Conversation.next_convnum++;
         this.base_folder = base_folder;
     }
@@ -101,7 +101,7 @@ public class Geary.App.Conversation : BaseObject {
     /**
      * Returns the number of emails in the conversation in a particular folder.
      */
-    public uint get_count_in_folder(FolderPath path) {
+    public uint get_count_in_folder(Folder.Path path) {
         uint count = 0;
         foreach (Geary.EmailIdentifier id in this.path_map.get_keys()) {
             if (path in this.path_map.get(id)) {
@@ -147,7 +147,7 @@ public class Geary.App.Conversation : BaseObject {
      */
     public Email?
         get_earliest_sent_email(Location location,
-                                Gee.Collection<FolderPath>? blacklist = null) {
+                                Gee.Collection<Folder.Path>? blacklist = null) {
         return get_single_email(Ordering.SENT_DATE_ASCENDING, location, blacklist);
     }
 
@@ -159,7 +159,7 @@ public class Geary.App.Conversation : BaseObject {
      */
     public Email?
         get_latest_sent_email(Location location,
-                              Gee.Collection<FolderPath>? blacklist = null) {
+                              Gee.Collection<Folder.Path>? blacklist = null) {
         return get_single_email(Ordering.SENT_DATE_DESCENDING, location);
     }
 
@@ -168,7 +168,7 @@ public class Geary.App.Conversation : BaseObject {
      */
     public Email?
         get_earliest_recv_email(Location location,
-                                Gee.Collection<FolderPath>? blacklist = null) {
+                                Gee.Collection<Folder.Path>? blacklist = null) {
         return get_single_email(Ordering.RECV_DATE_ASCENDING, location);
     }
 
@@ -177,13 +177,13 @@ public class Geary.App.Conversation : BaseObject {
      */
     public Email?
         get_latest_recv_email(Location location,
-                              Gee.Collection<FolderPath>? blacklist = null) {
+                              Gee.Collection<Folder.Path>? blacklist = null) {
         return get_single_email(Ordering.RECV_DATE_DESCENDING, location);
     }
 
     public Gee.Collection<Email>
         get_emails_flagged_for_deletion(Location location,
-                                        Gee.Collection<FolderPath>? blacklist = null) {
+                                        Gee.Collection<Folder.Path>? blacklist = null) {
         Gee.Collection<Email> emails = get_emails(Ordering.NONE, location, blacklist, false);
         Iterable<Email> filtered = traverse<Email>(emails);
         return filtered.filter(
@@ -202,7 +202,7 @@ public class Geary.App.Conversation : BaseObject {
     public Gee.List<Email>
         get_emails(Ordering ordering,
                    Location location = Location.ANYWHERE,
-                   Gee.Collection<FolderPath>? blacklist = null,
+                   Gee.Collection<Folder.Path>? blacklist = null,
                    bool filter_deleted = true) {
         Gee.Collection<Email> email;
         switch (ordering) {
@@ -254,8 +254,8 @@ public class Geary.App.Conversation : BaseObject {
 
         if (blacklist != null && !blacklist.is_empty) {
             if (blacklist.size == 1) {
-                FolderPath blacklist_path =
-                    traverse<FolderPath>(blacklist).first();
+                Folder.Path blacklist_path =
+                    traverse<Folder.Path>(blacklist).first();
                 filtered = filtered.filter(
                     (e) => !this.path_map.get(e.id).contains(blacklist_path)
                 );
@@ -275,7 +275,7 @@ public class Geary.App.Conversation : BaseObject {
      * Determines if the given id is in the conversation's base folder.
      */
     public bool is_in_base_folder(Geary.EmailIdentifier id) {
-        Gee.Collection<Geary.FolderPath>? paths = this.path_map.get(id);
+        Gee.Collection<Folder.Path>? paths = this.path_map.get(id);
         return (paths != null && paths.contains(this.base_folder.path));
     }
 
@@ -283,7 +283,7 @@ public class Geary.App.Conversation : BaseObject {
      * Determines if the given id is in the conversation's base folder.
      */
     public uint get_folder_count(Geary.EmailIdentifier id) {
-        Gee.Collection<Geary.FolderPath>? paths = this.path_map.get(id);
+        Gee.Collection<Folder.Path>? paths = this.path_map.get(id);
         uint count = 0;
         if (paths != null) {
             count = paths.size;
@@ -333,16 +333,16 @@ public class Geary.App.Conversation : BaseObject {
      * Add the email to the conversation if not already present.
      *
      * The value of `known_paths` should contain all the known {@link
-     * FolderPath} instances this email is contained within.
+     * Folder.Path} instances this email is contained within.
      *
      * Returns if the email was added, else false if already present
      * and only `known_paths` were merged.
      */
-    internal bool add(Email email, Gee.Collection<Geary.FolderPath> known_paths) {
+    internal bool add(Email email, Gee.Collection<Folder.Path> known_paths) {
         // Add the known paths to the path map regardless of whether
         // the email is already in the conversation or not, so that it
         // remains complete
-        foreach (Geary.FolderPath path in known_paths)
+        foreach (Folder.Path path in known_paths)
             this.path_map.set(email.id, path);
 
         bool added = false;
@@ -406,13 +406,13 @@ public class Geary.App.Conversation : BaseObject {
     /**
      * Removes the target path from the known set for the given id.
      */
-    internal void remove_path(Geary.EmailIdentifier id, FolderPath path) {
+    internal void remove_path(Geary.EmailIdentifier id, Folder.Path path) {
         this.path_map.remove(id, path);
     }
 
     private Geary.Email?
         get_single_email(Ordering ordering, Location location,
-                         Gee.Collection<Geary.FolderPath>? blacklist = null) {
+                         Gee.Collection<Folder.Path>? blacklist = null) {
         // note that the location-ordering preferences are treated as
         // ANYWHERE by get_emails()
         Gee.Collection<Geary.Email> all = get_emails(
diff --git a/src/engine/app/app-email-store.vala b/src/engine/app/app-email-store.vala
index ad9f041e4..92338c873 100644
--- a/src/engine/app/app-email-store.vala
+++ b/src/engine/app/app-email-store.vala
@@ -20,7 +20,7 @@ public class Geary.App.EmailStore : BaseObject {
      */
     public async Gee.MultiMap<Geary.EmailIdentifier, Type>? get_supported_operations_async(
         Gee.Collection<Geary.EmailIdentifier> emails, Cancellable? cancellable = null) throws Error {
-        Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath>? folders
+        Gee.MultiMap<Geary.EmailIdentifier, Folder.Path>? folders
             = yield account.get_containing_folders_async(emails, cancellable);
         if (folders == null)
             return null;
@@ -38,7 +38,7 @@ public class Geary.App.EmailStore : BaseObject {
         foreach (Geary.EmailIdentifier email in folders.get_keys()) {
             Gee.HashSet<Type> support = new Gee.HashSet<Type>();
 
-            foreach (Geary.FolderPath path in folders.get(email)) {
+            foreach (Folder.Path path in folders.get(email)) {
                 Geary.Folder folder;
                 try {
                     folder = account.get_folder(path);
@@ -103,18 +103,18 @@ public class Geary.App.EmailStore : BaseObject {
      * Geary.FolderSupport.Copy folder.
      */
     public async void copy_email_async(Gee.Collection<Geary.EmailIdentifier> emails,
-        Geary.FolderPath destination, Cancellable? cancellable = null) throws Error {
+        Folder.Path destination, Cancellable? cancellable = null) throws Error {
         yield do_folder_operation_async(new Geary.App.CopyOperation(destination),
             emails, cancellable);
     }
 
-    private FolderPath?
+    private Folder.Path?
         next_folder_for_operation(AsyncFolderOperation operation,
-                                  Gee.MultiMap<FolderPath,EmailIdentifier> folders_to_ids)
+                                  Gee.MultiMap<Folder.Path,EmailIdentifier> folders_to_ids)
         throws GLib.Error {
-        Geary.FolderPath? best = null;
+        Folder.Path? best = null;
         int best_count = 0;
-        foreach (Geary.FolderPath path in folders_to_ids.get_keys()) {
+        foreach (Folder.Path path in folders_to_ids.get_keys()) {
             Folder folder = this.account.get_folder(path);
             if (folder.get_type().is_a(operation.folder_type)) {
                 int count = folders_to_ids.get(path).size;
@@ -135,14 +135,14 @@ public class Geary.App.EmailStore : BaseObject {
         debug("EmailStore %s running %s on %d emails", account.to_string(),
             operation.get_type().name(), emails.size);
 
-        Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath>? ids_to_folders
+        Gee.MultiMap<Geary.EmailIdentifier, Folder.Path>? ids_to_folders
             = yield account.get_containing_folders_async(emails, cancellable);
         if (ids_to_folders == null)
             return;
 
-        Gee.MultiMap<Geary.FolderPath, Geary.EmailIdentifier> folders_to_ids
-            = Geary.Collection.reverse_multi_map<Geary.EmailIdentifier, Geary.FolderPath>(ids_to_folders);
-        Geary.FolderPath? path;
+        Gee.MultiMap<Folder.Path, Geary.EmailIdentifier> folders_to_ids
+            = Geary.Collection.reverse_multi_map<Geary.EmailIdentifier, Folder.Path>(ids_to_folders);
+        Folder.Path? path;
         while ((path = next_folder_for_operation(operation, folders_to_ids)) != null) {
             Geary.Folder folder = this.account.get_folder(path);
             Gee.Collection<Geary.EmailIdentifier> ids = folders_to_ids.get(path);
@@ -154,7 +154,7 @@ public class Geary.App.EmailStore : BaseObject {
             // We don't want to operate on any mails twice.
             if (used_ids != null) {
                 foreach (Geary.EmailIdentifier id in used_ids.to_array()) {
-                    foreach (Geary.FolderPath p in ids_to_folders.get(id))
+                    foreach (Folder.Path p in ids_to_folders.get(id))
                         folders_to_ids.remove(p, id);
                 }
             }
diff --git a/src/engine/app/app-search-folder.vala b/src/engine/app/app-search-folder.vala
index 4dcdffe34..19496aa52 100644
--- a/src/engine/app/app-search-folder.vala
+++ b/src/engine/app/app-search-folder.vala
@@ -90,10 +90,10 @@ public class Geary.App.SearchFolder : BaseObject,
     private FolderPropertiesImpl _properties;
 
     /** {@inheritDoc} */
-    public FolderPath path {
+    public Folder.Path path {
         get { return _path; }
     }
-    private FolderPath? _path = null;
+    private Folder.Path? _path = null;
 
     /**
      * {@inheritDoc}
@@ -113,8 +113,8 @@ public class Geary.App.SearchFolder : BaseObject,
     }
 
     // Folders that should be excluded from search
-    private Gee.HashSet<FolderPath?> exclude_folders =
-        new Gee.HashSet<FolderPath?>();
+    private Gee.HashSet<Folder.Path?> exclude_folders =
+        new Gee.HashSet<Folder.Path?>();
 
     // The email present in the folder, sorted
     private Gee.SortedSet<EmailEntry> entries;
@@ -127,7 +127,7 @@ public class Geary.App.SearchFolder : BaseObject,
     private GLib.Cancellable executing = new GLib.Cancellable();
 
 
-    public SearchFolder(Account account, FolderRoot root) {
+    public SearchFolder(Account account, Folder.Root root) {
         this._account = account;
         this._properties = new FolderPropertiesImpl(0, 0);
         this._path = root.get_child(MAGIC_BASENAME, Trillian.TRUE);
@@ -352,17 +352,17 @@ public class Geary.App.SearchFolder : BaseObject,
         Gee.Collection<EmailIdentifier> remove,
         GLib.Cancellable? cancellable = null
     ) throws GLib.Error {
-        Gee.MultiMap<EmailIdentifier,FolderPath>? ids_to_folders =
+        Gee.MultiMap<EmailIdentifier,Folder.Path>? ids_to_folders =
             yield account.get_containing_folders_async(
                 check_ids(remove), cancellable
             );
         if (ids_to_folders != null) {
-            Gee.MultiMap<FolderPath,EmailIdentifier> folders_to_ids =
-                Collection.reverse_multi_map<EmailIdentifier,FolderPath>(
+            Gee.MultiMap<Folder.Path,EmailIdentifier> folders_to_ids =
+                Collection.reverse_multi_map<EmailIdentifier,Folder.Path>(
                     ids_to_folders
                 );
 
-            foreach (FolderPath path in folders_to_ids.get_keys()) {
+            foreach (Folder.Path path in folders_to_ids.get_keys()) {
                 Folder folder = account.get_folder(path);
                 FolderSupport.Remove? removable = folder as FolderSupport.Remove;
                 if (removable != null) {
diff --git a/src/engine/app/conversation-monitor/app-conversation-set.vala 
b/src/engine/app/conversation-monitor/app-conversation-set.vala
index 60653c09f..28c8b2fb2 100644
--- a/src/engine/app/conversation-monitor/app-conversation-set.vala
+++ b/src/engine/app/conversation-monitor/app-conversation-set.vala
@@ -92,7 +92,7 @@ private class Geary.App.ConversationSet : BaseObject, Logging.Source {
      * being merged into another.
      */
     public void add_all_emails(Gee.Collection<Email> emails,
-                               Gee.MultiMap<EmailIdentifier, FolderPath> id_to_paths,
+                               Gee.MultiMap<EmailIdentifier,Folder.Path> id_to_paths,
                                out Gee.Collection<Conversation> added,
                                out Gee.MultiMap<Conversation, Email> appended,
                                out Gee.Collection<Conversation> removed_due_to_merge) {
@@ -141,7 +141,7 @@ private class Geary.App.ConversationSet : BaseObject, Logging.Source {
 
             Conversation? conversation = null;
             bool added_conversation = false;
-            Gee.Collection<Geary.FolderPath>? known_paths = id_to_paths.get(email.id);
+            Gee.Collection<Folder.Path>? known_paths = id_to_paths.get(email.id);
             if (known_paths != null) {
                 // Don't add an email with no known paths - it may
                 // have been removed after being listed for adding.
@@ -177,7 +177,7 @@ private class Geary.App.ConversationSet : BaseObject, Logging.Source {
      * were trimmed and the emails that were trimmed from it,
      * respectively.
      */
-    public void remove_all_emails_by_identifier(FolderPath source_path,
+    public void remove_all_emails_by_identifier(Folder.Path source_path,
                                                 Gee.Collection<EmailIdentifier> ids,
                                                 Gee.Collection<Conversation> removed,
                                                 Gee.MultiMap<Conversation,Email> trimmed) {
@@ -298,7 +298,7 @@ private class Geary.App.ConversationSet : BaseObject, Logging.Source {
      * was created, else it is set to `false`.
      */
     private Conversation? add_email(Geary.Email email,
-                                    Gee.Collection<FolderPath>? known_paths,
+                                    Gee.Collection<Folder.Path>? known_paths,
                                     out bool added_conversation) {
         added_conversation = false;
 
@@ -333,7 +333,7 @@ private class Geary.App.ConversationSet : BaseObject, Logging.Source {
      * Unconditionally adds an email to a conversation.
      */
     private void add_email_to_conversation(Conversation conversation, Geary.Email email,
-        Gee.Collection<Geary.FolderPath>? known_paths) {
+        Gee.Collection<Folder.Path>? known_paths) {
         if (!conversation.add(email, known_paths)) {
             error("Couldn't add duplicate email %s to conversation %s",
                 email.id.to_string(), conversation.to_string());
@@ -368,12 +368,11 @@ private class Geary.App.ConversationSet : BaseObject, Logging.Source {
 
         // Collect all emails and their paths from all conversations
         // to be merged, then remove those conversations
-        Gee.MultiMap<Geary.EmailIdentifier,Geary.FolderPath>? id_to_paths =
-            new Gee.HashMultiMap<Geary.EmailIdentifier,Geary.FolderPath>();
+        var id_to_paths = new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         foreach (Conversation conversation in conversations) {
             foreach (EmailIdentifier id in conversation.path_map.get_keys()) {
                 moved_email.add(conversation.get_email_by_id(id));
-                foreach (FolderPath path in conversation.path_map.get(id)) {
+                foreach (var path in conversation.path_map.get(id)) {
                     id_to_paths.set(id, path);
                 }
             }
diff --git a/src/engine/app/conversation-monitor/app-local-search-operation.vala 
b/src/engine/app/conversation-monitor/app-local-search-operation.vala
index 7af514a75..9a9229ad1 100644
--- a/src/engine/app/conversation-monitor/app-local-search-operation.vala
+++ b/src/engine/app/conversation-monitor/app-local-search-operation.vala
@@ -9,14 +9,14 @@ private class Geary.App.LocalSearchOperation : Geary.Nonblocking.BatchOperation
     public Geary.Account account;
     public RFC822.MessageID message_id;
     public Geary.Email.Field required_fields;
-    public Gee.Collection<Geary.FolderPath>? blacklist;
+    public Gee.Collection<Folder.Path>? blacklist;
     public Geary.EmailFlags? flag_blacklist;
 
     // OUT
-    public Gee.MultiMap<Geary.Email, Geary.FolderPath?>? emails = null;
+    public Gee.MultiMap<Geary.Email, Folder.Path?>? emails = null;
 
     public LocalSearchOperation(Geary.Account account, RFC822.MessageID message_id,
-        Geary.Email.Field required_fields, Gee.Collection<Geary.FolderPath?> blacklist,
+        Geary.Email.Field required_fields, Gee.Collection<Folder.Path?> blacklist,
         Geary.EmailFlags? flag_blacklist) {
         this.account = account;
         this.message_id = message_id;
diff --git a/src/engine/app/email-store/app-copy-operation.vala 
b/src/engine/app/email-store/app-copy-operation.vala
index f6d370799..909df1b99 100644
--- a/src/engine/app/email-store/app-copy-operation.vala
+++ b/src/engine/app/email-store/app-copy-operation.vala
@@ -7,9 +7,9 @@
 private class Geary.App.CopyOperation : Geary.App.AsyncFolderOperation {
     public override Type folder_type { get { return typeof(Geary.FolderSupport.Copy); } }
 
-    public Geary.FolderPath destination;
+    public Folder.Path destination;
 
-    public CopyOperation(Geary.FolderPath destination) {
+    public CopyOperation(Folder.Path destination) {
         this.destination = destination;
     }
 
diff --git a/src/engine/imap-db/imap-db-account.vala b/src/engine/imap-db/imap-db-account.vala
index e9d3abc0d..577787f0b 100644
--- a/src/engine/imap-db/imap-db-account.vala
+++ b/src/engine/imap-db/imap-db-account.vala
@@ -14,9 +14,9 @@ private class Geary.ImapDB.Account : BaseObject {
 
 
     private class FolderReference : Geary.SmartReference {
-        public Geary.FolderPath path;
+        public Geary.Folder.Path path;
 
-        public FolderReference(ImapDB.Folder folder, Geary.FolderPath path) {
+        public FolderReference(ImapDB.Folder folder, Geary.Folder.Path path) {
             base (folder);
 
             this.path = path;
@@ -52,8 +52,8 @@ private class Geary.ImapDB.Account : BaseObject {
     private string name;
     private GLib.File db_file;
     private GLib.File attachments_dir;
-    private Gee.HashMap<Geary.FolderPath, FolderReference> folder_refs =
-        new Gee.HashMap<Geary.FolderPath, FolderReference>();
+    private Gee.HashMap<Geary.Folder.Path, FolderReference> folder_refs =
+        new Gee.HashMap<Geary.Folder.Path, FolderReference>();
     private Cancellable? background_cancellable = null;
 
     public Account(AccountInformation config,
@@ -166,7 +166,7 @@ private class Geary.ImapDB.Account : BaseObject {
         check_open();
 
         Geary.Imap.FolderProperties properties = imap_folder.properties;
-        Geary.FolderPath path = imap_folder.path;
+        Geary.Folder.Path path = imap_folder.path;
 
         // XXX this should really be a db table constraint
         Geary.ImapDB.Folder? folder = get_local_folder(path);
@@ -218,7 +218,7 @@ private class Geary.ImapDB.Account : BaseObject {
         return yield fetch_folder_async(path, cancellable);
     }
 
-    public async void delete_folder_async(Geary.FolderPath path,
+    public async void delete_folder_async(Geary.Folder.Path path,
                                           GLib.Cancellable? cancellable)
         throws GLib.Error {
         check_open();
@@ -251,17 +251,17 @@ private class Geary.ImapDB.Account : BaseObject {
      * as the parent.
      */
     public async Gee.Collection<Geary.ImapDB.Folder>
-        list_folders_async(Geary.FolderPath parent,
+        list_folders_async(Geary.Folder.Path parent,
                            GLib.Cancellable? cancellable)
         throws GLib.Error {
         check_open();
 
         // TODO: A better solution here would be to only pull the FolderProperties if the Folder
         // object itself doesn't already exist
-        Gee.HashMap<Geary.FolderPath, int64?> id_map = new Gee.HashMap<
-            Geary.FolderPath, int64?>();
-        Gee.HashMap<Geary.FolderPath, Geary.Imap.FolderProperties> prop_map = new Gee.HashMap<
-            Geary.FolderPath, Geary.Imap.FolderProperties>();
+        Gee.HashMap<Geary.Folder.Path, int64?> id_map = new Gee.HashMap<
+            Geary.Folder.Path, int64?>();
+        Gee.HashMap<Geary.Folder.Path, Geary.Imap.FolderProperties> prop_map = new Gee.HashMap<
+            Geary.Folder.Path, Geary.Imap.FolderProperties>();
         yield db.exec_transaction_async(Db.TransactionType.RO, (cx) => {
             int64 parent_id = Db.INVALID_ROWID;
             if (!parent.is_root &&
@@ -287,7 +287,7 @@ private class Geary.ImapDB.Account : BaseObject {
             Db.Result result = stmt.exec(cancellable);
             while (!result.finished) {
                 string basename = result.string_for("name");
-                Geary.FolderPath path = parent.get_child(basename);
+                Geary.Folder.Path path = parent.get_child(basename);
                 Geary.Imap.FolderProperties properties = new Geary.Imap.FolderProperties.from_imapdb(
                     Geary.Imap.MailboxAttributes.deserialize(result.string_for("attributes")),
                     result.int_for("last_seen_total"),
@@ -320,7 +320,7 @@ private class Geary.ImapDB.Account : BaseObject {
         }
 
         Gee.Collection<Geary.ImapDB.Folder> folders = new Gee.ArrayList<Geary.ImapDB.Folder>();
-        foreach (Geary.FolderPath path in id_map.keys) {
+        foreach (Geary.Folder.Path path in id_map.keys) {
             Geary.ImapDB.Folder? folder = get_local_folder(path);
             if (folder == null && id_map.has_key(path) && prop_map.has_key(path))
                 folder = create_local_folder(path, id_map.get(path), prop_map.get(path));
@@ -331,7 +331,7 @@ private class Geary.ImapDB.Account : BaseObject {
         return folders;
     }
 
-    public async Geary.ImapDB.Folder fetch_folder_async(Geary.FolderPath path, Cancellable? cancellable)
+    public async Geary.ImapDB.Folder fetch_folder_async(Geary.Folder.Path path, Cancellable? cancellable)
         throws Error {
         check_open();
 
@@ -433,7 +433,7 @@ private class Geary.ImapDB.Account : BaseObject {
         }, cancellable);
     }
 
-    private Geary.ImapDB.Folder? get_local_folder(Geary.FolderPath path) {
+    private Geary.ImapDB.Folder? get_local_folder(Geary.Folder.Path path) {
         FolderReference? folder_ref = folder_refs.get(path);
         if (folder_ref == null)
             return null;
@@ -445,7 +445,7 @@ private class Geary.ImapDB.Account : BaseObject {
         return folder;
     }
 
-    private Geary.ImapDB.Folder create_local_folder(Geary.FolderPath path, int64 folder_id,
+    private Geary.ImapDB.Folder create_local_folder(Geary.Folder.Path path, int64 folder_id,
         Imap.FolderProperties properties) throws Error {
         // return current if already created
         ImapDB.Folder? folder = get_local_folder(path);
@@ -480,14 +480,14 @@ private class Geary.ImapDB.Account : BaseObject {
         folder_refs.unset(folder_ref.path);
     }
 
-    public async Gee.MultiMap<Geary.Email, Geary.FolderPath?>? search_message_id_async(
+    public async Gee.MultiMap<Geary.Email, Geary.Folder.Path?>? search_message_id_async(
         Geary.RFC822.MessageID message_id, Geary.Email.Field requested_fields, bool partial_ok,
-        Gee.Collection<Geary.FolderPath?>? folder_blacklist, Geary.EmailFlags? flag_blacklist,
+        Gee.Collection<Geary.Folder.Path?>? folder_blacklist, Geary.EmailFlags? flag_blacklist,
         Cancellable? cancellable = null) throws Error {
         check_open();
 
-        Gee.HashMultiMap<Geary.Email, Geary.FolderPath?> messages
-            = new Gee.HashMultiMap<Geary.Email, Geary.FolderPath?>();
+        Gee.HashMultiMap<Geary.Email, Geary.Folder.Path?> messages
+            = new Gee.HashMultiMap<Geary.Email, Geary.Folder.Path?>();
 
         if (flag_blacklist != null)
             requested_fields = requested_fields | Geary.Email.Field.FLAGS;
@@ -511,12 +511,12 @@ private class Geary.ImapDB.Account : BaseObject {
                         cx, this.db.attachments_path, email, id, cancellable
                     );
 
-                    Gee.Set<Geary.FolderPath>? folders = do_find_email_folders(cx, id, true, cancellable);
+                    Gee.Set<Geary.Folder.Path>? folders = do_find_email_folders(cx, id, true, cancellable);
                     if (folders == null) {
                         if (folder_blacklist == null || !folder_blacklist.contains(null))
                             messages.set(email, null);
                     } else {
-                        foreach (Geary.FolderPath path in folders) {
+                        foreach (Geary.Folder.Path path in folders) {
                             // If it's in a blacklisted folder, we don't report
                             // it at all.
                             if (folder_blacklist != null && folder_blacklist.contains(path)) {
@@ -578,7 +578,7 @@ private class Geary.ImapDB.Account : BaseObject {
     }
 
     public async Gee.Collection<Geary.EmailIdentifier>? search_async(Geary.SearchQuery q,
-        int limit = 100, int offset = 0, Gee.Collection<Geary.FolderPath?>? excluded_folders = null,
+        int limit = 100, int offset = 0, Gee.Collection<Geary.Folder.Path?>? excluded_folders = null,
         Gee.Collection<Geary.EmailIdentifier>? search_ids = null, Cancellable? cancellable = null)
         throws Error {
 
@@ -747,7 +747,7 @@ private class Geary.ImapDB.Account : BaseObject {
      */
     public async void
         get_containing_folders_async(Gee.Collection<Geary.EmailIdentifier> ids,
-                                     Gee.MultiMap<Geary.EmailIdentifier,FolderPath>? map,
+                                     Gee.MultiMap<Geary.EmailIdentifier,Geary.Folder.Path>? map,
                                      GLib.Cancellable? cancellable)
         throws GLib.Error {
         check_open();
@@ -757,11 +757,11 @@ private class Geary.ImapDB.Account : BaseObject {
                 if (imap_db_id == null)
                     continue;
 
-                Gee.Set<Geary.FolderPath>? folders = do_find_email_folders(
+                Gee.Set<Geary.Folder.Path>? folders = do_find_email_folders(
                     cx, imap_db_id.message_id, false, cancellable);
                 if (folders != null) {
                     Geary.Collection.multi_map_set_all<Geary.EmailIdentifier,
-                        Geary.FolderPath>(map, id, folders);
+                        Geary.Folder.Path>(map, id, folders);
                 }
             }
 
@@ -941,12 +941,12 @@ private class Geary.ImapDB.Account : BaseObject {
         folder_stmt.exec(cancellable);
     }
 
-    // If the FolderPath has no parent, returns true and folder_id
+    // If the Folder.Path has no parent, returns true and folder_id
     // will be set to Db.INVALID_ROWID.  If cannot create path or
     // there is a logical problem traversing it, returns false with
     // folder_id set to Db.INVALID_ROWID.
     internal bool do_fetch_folder_id(Db.Connection cx,
-                                     Geary.FolderPath path,
+                                     Geary.Folder.Path path,
                                      bool create,
                                      out int64 folder_id,
                                      GLib.Cancellable? cancellable)
@@ -1008,7 +1008,7 @@ private class Geary.ImapDB.Account : BaseObject {
     }
 
     internal bool do_fetch_parent_id(Db.Connection cx,
-                                     FolderPath path,
+                                     Geary.Folder.Path path,
                                      bool create,
                                      out int64 parent_id,
                                      GLib.Cancellable? cancellable = null)
@@ -1037,7 +1037,7 @@ private class Geary.ImapDB.Account : BaseObject {
 
     // For a message row id, return a set of all folders it's in, or null if
     // it's not in any folders.
-    private Gee.Set<Geary.FolderPath>?
+    private Gee.Set<Geary.Folder.Path>?
         do_find_email_folders(Db.Connection cx,
                               int64 message_id,
                               bool include_removed,
@@ -1053,10 +1053,10 @@ private class Geary.ImapDB.Account : BaseObject {
         if (result.finished)
             return null;
 
-        Gee.HashSet<Geary.FolderPath> folder_paths = new Gee.HashSet<Geary.FolderPath>();
+        Gee.HashSet<Geary.Folder.Path> folder_paths = new Gee.HashSet<Geary.Folder.Path>();
         while (!result.finished) {
             int64 folder_id = result.int64_at(0);
-            Geary.FolderPath? path = do_find_folder_path(cx, folder_id, cancellable);
+            Geary.Folder.Path? path = do_find_folder_path(cx, folder_id, cancellable);
             if (path != null)
                 folder_paths.add(path);
 
@@ -1069,7 +1069,7 @@ private class Geary.ImapDB.Account : BaseObject {
     // For a folder row id, return the folder path (constructed with default
     // separator and case sensitivity) of that folder, or null in the event
     // it's not found.
-    private Geary.FolderPath? do_find_folder_path(Db.Connection cx,
+    private Geary.Folder.Path? do_find_folder_path(Db.Connection cx,
                                                   int64 folder_id,
                                                   GLib.Cancellable? cancellable)
         throws GLib.Error {
@@ -1092,11 +1092,11 @@ private class Geary.ImapDB.Account : BaseObject {
             return null;
         }
 
-        Geary.FolderPath? path = null;
+        Geary.Folder.Path? path = null;
         if (parent_id <= 0) {
             path = this.imap_folder_root.get_child(name);
         } else {
-            Geary.FolderPath? parent_path = do_find_folder_path(
+            Geary.Folder.Path? parent_path = do_find_folder_path(
                 cx, parent_id, cancellable
             );
             if (parent_path != null) {
@@ -1114,11 +1114,11 @@ private class Geary.ImapDB.Account : BaseObject {
     // Updates unread count on all folders.
     private async void update_unread_async(ImapDB.Folder source, Gee.Map<ImapDB.EmailIdentifier, bool>
         unread_status, Cancellable? cancellable) throws Error {
-        Gee.Map<Geary.FolderPath, int> unread_change = new Gee.HashMap<Geary.FolderPath, int>();
+        Gee.Map<Geary.Folder.Path, int> unread_change = new Gee.HashMap<Geary.Folder.Path, int>();
 
         yield db.exec_transaction_async(Db.TransactionType.RW, (cx) => {
             foreach (ImapDB.EmailIdentifier id in unread_status.keys) {
-                Gee.Set<Geary.FolderPath>? paths = do_find_email_folders(
+                Gee.Set<Geary.Folder.Path>? paths = do_find_email_folders(
                     cx, id.message_id, true, cancellable);
                 if (paths == null)
                     continue;
@@ -1128,7 +1128,7 @@ private class Geary.ImapDB.Account : BaseObject {
                 if (paths.size == 0)
                     continue;
 
-                foreach (Geary.FolderPath path in paths) {
+                foreach (Geary.Folder.Path path in paths) {
                     int current_unread = unread_change.has_key(path) ? unread_change.get(path) : 0;
                     current_unread += unread_status.get(id) ? 1 : -1;
                     unread_change.set(path, current_unread);
@@ -1136,7 +1136,7 @@ private class Geary.ImapDB.Account : BaseObject {
             }
 
             // Update each folder's unread count in the database.
-            foreach (Geary.FolderPath path in unread_change.keys) {
+            foreach (Geary.Folder.Path path in unread_change.keys) {
                 Geary.ImapDB.Folder? folder = get_local_folder(path);
                 if (folder == null)
                     continue;
@@ -1148,7 +1148,7 @@ private class Geary.ImapDB.Account : BaseObject {
         }, cancellable);
 
         // Update each folder's unread count property.
-        foreach (Geary.FolderPath path in unread_change.keys) {
+        foreach (Geary.Folder.Path path in unread_change.keys) {
             Geary.ImapDB.Folder? folder = get_local_folder(path);
             if (folder == null)
                 continue;
@@ -1232,7 +1232,7 @@ private class Geary.ImapDB.Account : BaseObject {
     // special case, if "folderless" or orphan emails are to be excluded,
     // set the out bool to true.
     private string do_get_excluded_folder_ids(
-        Gee.Collection<Geary.FolderPath?> excluded_folder,
+        Gee.Collection<Geary.Folder.Path?> excluded_folder,
         Db.Connection cx,
         out bool exclude_folderless,
         GLib.Cancellable? cancellable
@@ -1241,7 +1241,7 @@ private class Geary.ImapDB.Account : BaseObject {
 
         var ids = new GLib.StringBuilder();
         var is_first = true;
-        foreach (Geary.FolderPath? folder_path in excluded_folder) {
+        foreach (Geary.Folder.Path? folder_path in excluded_folder) {
             if (folder_path == null) {
                 exclude_folderless = true;
             } else {
diff --git a/src/engine/imap-db/imap-db-folder.vala b/src/engine/imap-db/imap-db-folder.vala
index 465508080..43eed2631 100644
--- a/src/engine/imap-db/imap-db-folder.vala
+++ b/src/engine/imap-db/imap-db-folder.vala
@@ -94,7 +94,7 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
     protected int manual_ref_count { get; protected set; }
 
     private Geary.Db.Database db;
-    private Geary.FolderPath path;
+    private Geary.Folder.Path path;
     private GLib.File attachments_path;
     private string account_owner_email;
     private int64 folder_id;
@@ -113,7 +113,7 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
     public signal void unread_updated(Gee.Map<ImapDB.EmailIdentifier, bool> unread_status);
 
     internal Folder(Geary.Db.Database db,
-                    Geary.FolderPath path,
+                    Geary.Folder.Path path,
                     GLib.File attachments_path,
                     string account_owner_email,
                     int64 folder_id,
@@ -127,7 +127,7 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
         this.properties = properties;
     }
 
-    public unowned Geary.FolderPath get_path() {
+    public unowned Geary.Folder.Path get_path() {
         return path;
     }
 
diff --git a/src/engine/imap-engine/gmail/imap-engine-gmail-account.vala 
b/src/engine/imap-engine/gmail/imap-engine-gmail-account.vala
index 9ff7eea78..c09986b11 100644
--- a/src/engine/imap-engine/gmail/imap-engine-gmail-account.vala
+++ b/src/engine/imap-engine/gmail/imap-engine-gmail-account.vala
@@ -50,7 +50,7 @@ private class Geary.ImapEngine.GmailAccount : Geary.ImapEngine.GenericAccount {
     }
 
     protected override MinimalFolder new_folder(ImapDB.Folder local_folder) {
-        FolderPath path = local_folder.get_path();
+        Folder.Path path = local_folder.get_path();
         Folder.SpecialUse use = NONE;
         if (Imap.MailboxSpecifier.folder_path_is_inbox(path)) {
             use = INBOX;
diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala 
b/src/engine/imap-engine/imap-engine-generic-account.vala
index 58b8c7d27..0a2eff987 100644
--- a/src/engine/imap-engine/imap-engine-generic-account.vala
+++ b/src/engine/imap-engine/imap-engine-generic-account.vala
@@ -49,10 +49,10 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
     private Cancellable? open_cancellable = null;
     private Nonblocking.Semaphore? remote_ready_lock = null;
 
-    private Gee.Map<FolderPath,MinimalFolder> remote_folders =
-        new Gee.HashMap<FolderPath,MinimalFolder>();
-    private Gee.Map<FolderPath,Folder> local_folders =
-        new Gee.HashMap<FolderPath,Folder>();
+    private Gee.Map<Folder.Path,MinimalFolder> remote_folders =
+        new Gee.HashMap<Folder.Path,MinimalFolder>();
+    private Gee.Map<Folder.Path,Folder> local_folders =
+        new Gee.HashMap<Folder.Path,Folder>();
 
     private AccountProcessor? processor;
     private TimeoutManager refresh_folder_timer;
@@ -320,7 +320,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
      *
      * The account must have been opened before calling this method.
      */
-    public async Imap.FolderSession claim_folder_session(Geary.FolderPath path,
+    public async Imap.FolderSession claim_folder_session(Folder.Path path,
                                                          GLib.Cancellable? cancellable)
         throws Error {
         check_open();
@@ -406,9 +406,9 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
     }
 
     /** {@inheritDoc} */
-    public override FolderPath to_folder_path(GLib.Variant serialised)
+    public override Folder.Path to_folder_path(GLib.Variant serialised)
         throws EngineError.BAD_PARAMETERS {
-        FolderPath? path = null;
+        Folder.Path? path = null;
         try {
             path = this.local.imap_folder_root.from_variant(serialised);
         } catch (EngineError.BAD_PARAMETERS err) {
@@ -418,7 +418,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
     }
 
     /** {@inheritDoc} */
-    public override Folder get_folder(FolderPath path)
+    public override Folder get_folder(Folder.Path path)
         throws EngineError.NOT_FOUND {
         Folder? folder = null;
         if (this.local.imap_folder_root.is_descendant(path)) {
@@ -443,9 +443,9 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
     }
 
     /** {@inheritDoc} */
-    public override Gee.Collection<Folder> list_matching_folders(FolderPath? parent)
+    public override Gee.Collection<Folder> list_matching_folders(Folder.Path? parent)
         throws EngineError.NOT_FOUND {
-        Gee.Map<FolderPath,Folder>? folders = null;
+        Gee.Map<Folder.Path,Folder>? folders = null;
         if (this.local.imap_folder_root.is_descendant(parent)) {
             folders = this.remote_folders;
         } else if (this.local_folder_root.is_descendant(parent)) {
@@ -460,9 +460,9 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
                 "Unknown parent: %s", parent.to_string()
             );
         }
-        return traverse<FolderPath>(folders.keys)
+        return traverse<Folder.Path>(folders.keys)
             .filter(p => {
-                FolderPath? path_parent = p.parent;
+                Folder.Path? path_parent = p.parent;
                 return ((parent == null && path_parent == null) ||
                     (parent != null && path_parent != null &&
                      path_parent.equal_to(parent)));
@@ -502,9 +502,9 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
     ) throws GLib.Error {
         check_open();
         var remote = yield claim_account_session(cancellable);
-        FolderPath root =
+        Folder.Path root =
             yield remote.get_default_personal_namespace(cancellable);
-        FolderPath path = root.get_child(name);
+        Folder.Path path = root.get_child(name);
         if (this.remote_folders.has_key(path)) {
             throw new EngineError.ALREADY_EXISTS(
                 "Folder already exists: %s", path.to_string()
@@ -590,9 +590,9 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
         return new FtsSearchQuery(expression, text, this.stemmer);
     }
 
-    public override async Gee.MultiMap<Geary.Email, Geary.FolderPath?>? local_search_message_id_async(
+    public override async Gee.MultiMap<Geary.Email, Folder.Path?>? local_search_message_id_async(
         Geary.RFC822.MessageID message_id, Geary.Email.Field requested_fields, bool partial_ok,
-        Gee.Collection<Geary.FolderPath?>? folder_blacklist, Geary.EmailFlags? flag_blacklist,
+        Gee.Collection<Folder.Path?>? folder_blacklist, Geary.EmailFlags? flag_blacklist,
         Cancellable? cancellable = null) throws Error {
         return yield local.search_message_id_async(
             message_id, requested_fields, partial_ok, folder_blacklist, flag_blacklist, cancellable);
@@ -615,7 +615,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
     }
 
     public override async Gee.Collection<Geary.EmailIdentifier>? local_search_async(Geary.SearchQuery query,
-        int limit = 100, int offset = 0, Gee.Collection<Geary.FolderPath?>? folder_blacklist = null,
+        int limit = 100, int offset = 0, Gee.Collection<Folder.Path?>? folder_blacklist = null,
         Gee.Collection<Geary.EmailIdentifier>? search_ids = null, Cancellable? cancellable = null) throws 
Error {
         if (offset < 0)
             throw new EngineError.BAD_PARAMETERS("Offset must not be negative");
@@ -628,12 +628,11 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
         return yield local.get_search_matches_async(query, check_ids(ids), cancellable);
     }
 
-    public override async Gee.MultiMap<EmailIdentifier,FolderPath>?
+    public override async Gee.MultiMap<EmailIdentifier,Folder.Path>?
         get_containing_folders_async(Gee.Collection<Geary.EmailIdentifier> ids,
                                      GLib.Cancellable? cancellable)
         throws GLib.Error {
-        Gee.MultiMap<EmailIdentifier,FolderPath> map =
-            new Gee.HashMultiMap<EmailIdentifier,FolderPath>();
+        var map = new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         yield this.local.get_containing_folders_async(ids, map, cancellable);
         foreach (var folder in this.local_folders.values) {
             var path = folder.path;
@@ -687,7 +686,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
             Account.folder_path_comparator
         );
         foreach(ImapDB.Folder db_folder in db_folders) {
-            FolderPath path = db_folder.get_path();
+            Folder.Path path = db_folder.get_path();
             if (!this.remote_folders.has_key(path)) {
                 MinimalFolder folder = new_folder(db_folder);
                 if (folder.used_as == NONE) {
@@ -803,7 +802,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
         throws GLib.Error {
         Folder? special = get_special_folder(use);
         if (special == null) {
-            FolderPath? path = information.new_folder_path_for_use(
+            Folder.Path? path = information.new_folder_path_for_use(
                 this.local.imap_folder_root, use
             );
             if (path != null && !remote.is_folder_path_valid(path)) {
@@ -816,12 +815,12 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
             }
 
             if (path == null) {
-                FolderPath root =
+                Folder.Path root =
                     yield remote.get_default_personal_namespace(cancellable);
                 Gee.List<string> search_names = special_search_names.get(use);
                 foreach (string search_name in search_names) {
-                    FolderPath search_path = root.get_child(search_name);
-                    foreach (FolderPath test_path in this.remote_folders.keys) {
+                    Folder.Path search_path = root.get_child(search_name);
+                    foreach (Folder.Path test_path in this.remote_folders.keys) {
                         if (test_path.compare_normalized_ci(search_path) == 0) {
                             path = search_path;
                             break;
@@ -1120,7 +1119,7 @@ internal class Geary.ImapEngine.LoadFolders : AccountOperation {
         generic.add_folders(this.folders, true);
     }
 
-    private async void enumerate_local_folders_async(FolderPath parent,
+    private async void enumerate_local_folders_async(Folder.Path parent,
                                                      GLib.Cancellable? cancellable)
         throws GLib.Error {
         Gee.Collection<ImapDB.Folder>? children = null;
@@ -1214,16 +1213,16 @@ internal class Geary.ImapEngine.UpdateRemoteFolders : AccountOperation {
     public override async void execute(GLib.Cancellable cancellable) throws Error {
         // Use sorted maps here to a) aid debugging, and b) ensure
         // that parent folders are processed before child folders
-        var existing_folders = new Gee.TreeMap<FolderPath,Folder>(
+        var existing_folders = new Gee.TreeMap<Folder.Path,Folder>(
             (a,b) => a.compare_to(b)
         );
-        var remote_folders = new Gee.TreeMap<FolderPath,Imap.Folder>(
+        var remote_folders = new Gee.TreeMap<Folder.Path,Imap.Folder>(
             (a,b) => a.compare_to(b)
         );
 
         Geary.traverse<Geary.Folder>(
             this.account.list_folders()
-        ).add_all_to_map<FolderPath>(
+        ).add_all_to_map<Folder.Path>(
             existing_folders, f => f.path
         );
 
@@ -1240,11 +1239,11 @@ internal class Geary.ImapEngine.UpdateRemoteFolders : AccountOperation {
             );
 
             debug("Existing folders:");
-            foreach (FolderPath path in existing_folders.keys) {
+            foreach (Folder.Path path in existing_folders.keys) {
                 debug(" - %s (%u)", path.to_string(), path.hash());
             }
             debug("Remote folders:");
-            foreach (FolderPath path in remote_folders.keys) {
+            foreach (Folder.Path path in remote_folders.keys) {
                 debug(" - %s (%u)", path.to_string(), path.hash());
             }
 
@@ -1259,8 +1258,8 @@ internal class Geary.ImapEngine.UpdateRemoteFolders : AccountOperation {
     }
 
     private async bool enumerate_remote_folders_async(Imap.AccountSession remote,
-                                                      Gee.Map<FolderPath,Imap.Folder> folders,
-                                                      Geary.FolderPath? parent,
+                                                      Gee.Map<Folder.Path,Imap.Folder> folders,
+                                                      Folder.Path? parent,
                                                       GLib.Cancellable? cancellable)
         throws Error {
         bool results_suspect = false;
@@ -1279,7 +1278,7 @@ internal class Geary.ImapEngine.UpdateRemoteFolders : AccountOperation {
 
         if (children != null) {
             foreach (Imap.Folder child in children) {
-                FolderPath path = child.path;
+                Folder.Path path = child.path;
                 folders.set(path, child);
                 if (child.properties.has_children.is_possible() &&
                     yield enumerate_remote_folders_async(
@@ -1293,13 +1292,13 @@ internal class Geary.ImapEngine.UpdateRemoteFolders : AccountOperation {
     }
 
     private async void update_folders_async(Imap.AccountSession remote,
-                                            Gee.Map<FolderPath,Geary.Folder> existing_folders,
-                                            Gee.Map<FolderPath,Imap.Folder> remote_folders,
+                                            Gee.Map<Folder.Path,Geary.Folder> existing_folders,
+                                            Gee.Map<Folder.Path,Imap.Folder> remote_folders,
                                             bool remote_folders_suspect,
                                             GLib.Cancellable? cancellable) {
         // update all remote folders properties in the local store and
         // active in the system
-        Gee.HashSet<Geary.FolderPath> altered_paths = new Gee.HashSet<Geary.FolderPath>();
+        Gee.HashSet<Folder.Path> altered_paths = new Gee.HashSet<Folder.Path>();
         foreach (Imap.Folder remote_folder in remote_folders.values) {
             MinimalFolder? minimal_folder = existing_folders.get(remote_folder.path)
                 as MinimalFolder;
@@ -1346,7 +1345,7 @@ internal class Geary.ImapEngine.UpdateRemoteFolders : AccountOperation {
 
         // Remove if path in local but not remote
         Gee.ArrayList<Geary.Folder> to_remove
-            = Geary.traverse<Gee.Map.Entry<FolderPath,Geary.Folder>>(existing_folders)
+            = Geary.traverse<Gee.Map.Entry<Folder.Path,Geary.Folder>>(existing_folders)
             .filter(e => !remote_folders.has_key(e.key))
             .map<Geary.Folder>(e => (Geary.Folder) e.value)
             .to_array_list();
@@ -1394,7 +1393,7 @@ internal class Geary.ImapEngine.UpdateRemoteFolders : AccountOperation {
             // Let the remote know as well
             remote.folders_removed(
                 Geary.traverse<Geary.Folder>(removed)
-                .map<FolderPath>(f => f.path).to_array_list()
+                .map<Folder.Path>(f => f.path).to_array_list()
             );
         }
 
@@ -1403,7 +1402,7 @@ internal class Geary.ImapEngine.UpdateRemoteFolders : AccountOperation {
             // connected. This will cause them to get refreshed.
             if (altered_paths.size > 0) {
                 Gee.ArrayList<Geary.Folder> altered = new Gee.ArrayList<Geary.Folder>();
-                foreach (Geary.FolderPath altered_path in altered_paths) {
+                foreach (Folder.Path altered_path in altered_paths) {
                     if (existing_folders.has_key(altered_path))
                         altered.add(existing_folders.get(altered_path));
                     else
diff --git a/src/engine/imap-engine/imap-engine-minimal-folder.vala 
b/src/engine/imap-engine/imap-engine-minimal-folder.vala
index 5c421357f..446ee162f 100644
--- a/src/engine/imap-engine/imap-engine-minimal-folder.vala
+++ b/src/engine/imap-engine/imap-engine-minimal-folder.vala
@@ -49,7 +49,7 @@ private class Geary.ImapEngine.MinimalFolder : BaseObject,
     private FolderProperties _properties;
 
     /** {@inheritDoc} */
-    public FolderPath path {
+    public Folder.Path path {
         get {
             return local_folder.get_path();
         }
@@ -975,7 +975,7 @@ private class Geary.ImapEngine.MinimalFolder : BaseObject,
 
     public virtual async void
         copy_email_async(Gee.Collection<Geary.EmailIdentifier> to_copy,
-                         Geary.FolderPath destination,
+                         Folder.Path destination,
                          GLib.Cancellable? cancellable = null)
         throws GLib.Error {
         Geary.Folder target = this._account.get_folder(destination);
@@ -988,7 +988,7 @@ private class Geary.ImapEngine.MinimalFolder : BaseObject,
      */
     protected async Gee.Set<Imap.UID>?
         copy_email_uids_async(Gee.Collection<Geary.EmailIdentifier> to_copy,
-                              Geary.FolderPath destination,
+                              Folder.Path destination,
                               GLib.Cancellable? cancellable = null)
         throws GLib.Error {
         check_ids("copy_email_uids_async", to_copy);
@@ -1012,7 +1012,7 @@ private class Geary.ImapEngine.MinimalFolder : BaseObject,
 
     public virtual async Geary.Revokable? move_email_async(
         Gee.Collection<Geary.EmailIdentifier> to_move,
-        Geary.FolderPath destination,
+        Folder.Path destination,
         Cancellable? cancellable = null)
     throws Error {
         check_ids("move_email_async", to_move);
diff --git a/src/engine/imap-engine/imap-engine-revokable-committed-move.vala 
b/src/engine/imap-engine/imap-engine-revokable-committed-move.vala
index 386186c0d..4f16106c9 100644
--- a/src/engine/imap-engine/imap-engine-revokable-committed-move.vala
+++ b/src/engine/imap-engine/imap-engine-revokable-committed-move.vala
@@ -10,12 +10,17 @@
  */
 
 private class Geary.ImapEngine.RevokableCommittedMove : Revokable {
+
+
     private GenericAccount account;
-    private FolderPath source;
-    private FolderPath destination;
+    private Folder.Path source;
+    private Folder.Path destination;
     private Gee.Set<Imap.UID> destination_uids;
 
-    public RevokableCommittedMove(GenericAccount account, FolderPath source, FolderPath destination,
+
+    public RevokableCommittedMove(GenericAccount account,
+                                  Folder.Path source,
+                                  Folder.Path destination,
         Gee.Set<Imap.UID> destination_uids) {
         this.account = account;
         this.source = source;
diff --git a/src/engine/imap-engine/other/imap-engine-other-account.vala 
b/src/engine/imap-engine/other/imap-engine-other-account.vala
index 65e194a90..42ff6a1ac 100644
--- a/src/engine/imap-engine/other/imap-engine-other-account.vala
+++ b/src/engine/imap-engine/other/imap-engine-other-account.vala
@@ -16,7 +16,7 @@ private class Geary.ImapEngine.OtherAccount : Geary.ImapEngine.GenericAccount {
     }
 
     protected override MinimalFolder new_folder(ImapDB.Folder local_folder) {
-        FolderPath path = local_folder.get_path();
+        Folder.Path path = local_folder.get_path();
         Folder.SpecialUse use = NONE;
         if (Imap.MailboxSpecifier.folder_path_is_inbox(path)) {
             use = INBOX;
diff --git a/src/engine/imap-engine/outlook/imap-engine-outlook-account.vala 
b/src/engine/imap-engine/outlook/imap-engine-outlook-account.vala
index df55b2279..e9c3edb56 100644
--- a/src/engine/imap-engine/outlook/imap-engine-outlook-account.vala
+++ b/src/engine/imap-engine/outlook/imap-engine-outlook-account.vala
@@ -38,7 +38,7 @@ private class Geary.ImapEngine.OutlookAccount : Geary.ImapEngine.GenericAccount
     }
 
     protected override MinimalFolder new_folder(ImapDB.Folder local_folder) {
-        FolderPath path = local_folder.get_path();
+        Folder.Path path = local_folder.get_path();
         Folder.SpecialUse use = NONE;
         if (Imap.MailboxSpecifier.folder_path_is_inbox(path)) {
             use = INBOX;
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-copy-email.vala 
b/src/engine/imap-engine/replay-ops/imap-engine-copy-email.vala
index de2c61b00..271d26738 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-copy-email.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-copy-email.vala
@@ -9,11 +9,13 @@ private class Geary.ImapEngine.CopyEmail : Geary.ImapEngine.SendReplayOperation
 
     private MinimalFolder engine;
     private Gee.HashSet<ImapDB.EmailIdentifier> to_copy = new Gee.HashSet<ImapDB.EmailIdentifier>();
-    private Geary.FolderPath destination;
-    private Cancellable? cancellable;
+    private Folder.Path destination;
+    private GLib.Cancellable? cancellable;
 
-    public CopyEmail(MinimalFolder engine, Gee.List<ImapDB.EmailIdentifier> to_copy,
-        Geary.FolderPath destination, Cancellable? cancellable = null) {
+    public CopyEmail(MinimalFolder engine,
+                     Gee.List<ImapDB.EmailIdentifier> to_copy,
+                     Folder.Path destination,
+                     GLib.Cancellable? cancellable = null) {
         base("CopyEmail", OnError.RETRY);
 
         this.engine = engine;
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-move-email-commit.vala 
b/src/engine/imap-engine/replay-ops/imap-engine-move-email-commit.vala
index b8941b5f1..2db597dfc 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-move-email-commit.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-move-email-commit.vala
@@ -13,12 +13,14 @@ private class Geary.ImapEngine.MoveEmailCommit : Geary.ImapEngine.SendReplayOper
 
     private MinimalFolder engine;
     private Gee.List<ImapDB.EmailIdentifier> to_move = new Gee.ArrayList<ImapDB.EmailIdentifier>();
-    private Geary.FolderPath destination;
-    private Cancellable? cancellable;
+    private Folder.Path destination;
+    private GLib.Cancellable? cancellable;
     private Gee.List<Imap.MessageSet>? remaining_msg_sets = null;
 
-    public MoveEmailCommit(MinimalFolder engine, Gee.Collection<ImapDB.EmailIdentifier> to_move,
-        Geary.FolderPath destination, Cancellable? cancellable) {
+    public MoveEmailCommit(MinimalFolder engine,
+                           Gee.Collection<ImapDB.EmailIdentifier> to_move,
+                           Folder.Path destination,
+                           GLib.Cancellable? cancellable) {
         base.only_remote("MoveEmailCommit", OnError.RETRY);
 
         this.engine = engine;
diff --git a/src/engine/imap-engine/yahoo/imap-engine-yahoo-account.vala 
b/src/engine/imap-engine/yahoo/imap-engine-yahoo-account.vala
index 6ee003238..bdcf7eeba 100644
--- a/src/engine/imap-engine/yahoo/imap-engine-yahoo-account.vala
+++ b/src/engine/imap-engine/yahoo/imap-engine-yahoo-account.vala
@@ -38,7 +38,7 @@ private class Geary.ImapEngine.YahooAccount : Geary.ImapEngine.GenericAccount {
     }
 
     protected override MinimalFolder new_folder(ImapDB.Folder local_folder) {
-        FolderPath path = local_folder.get_path();
+        Folder.Path path = local_folder.get_path();
         Folder.SpecialUse use = NONE;
         if (Imap.MailboxSpecifier.folder_path_is_inbox(path)) {
             use = INBOX;
diff --git a/src/engine/imap/api/imap-account-session.vala b/src/engine/imap/api/imap-account-session.vala
index 813d9e5e2..8157b1a8b 100644
--- a/src/engine/imap/api/imap-account-session.vala
+++ b/src/engine/imap/api/imap-account-session.vala
@@ -24,8 +24,8 @@
 internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
 
     private FolderRoot root;
-    private Gee.HashMap<FolderPath,Imap.Folder> folders =
-        new Gee.HashMap<FolderPath,Imap.Folder>();
+    private Gee.HashMap<Geary.Folder.Path,Imap.Folder> folders =
+        new Gee.HashMap<Geary.Folder.Path,Imap.Folder>();
 
     private Nonblocking.Mutex cmd_mutex = new Nonblocking.Mutex();
     private Gee.List<MailboxInformation>? list_collector = null;
@@ -43,7 +43,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
     /**
      * Returns the root path for the default personal namespace.
      */
-    public async FolderPath get_default_personal_namespace(Cancellable? cancellable)
+    public async Geary.Folder.Path get_default_personal_namespace(Cancellable? cancellable)
     throws Error {
         ClientSession session = get_session();
         Gee.List<Namespace> personal = session.get_personal_namespaces();
@@ -66,7 +66,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
     /**
      * Determines if the given folder path appears to a valid mailbox.
      */
-    public bool is_folder_path_valid(FolderPath? path) throws GLib.Error {
+    public bool is_folder_path_valid(Geary.Folder.Path? path) throws GLib.Error {
         bool is_valid = false;
         if (path != null) {
             ClientSession session = get_session();
@@ -90,7 +90,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
      * CREATE-SPECIAL-USE is supported by the connection, that will be
      * used to specify the type of the new folder.
      */
-    public async void create_folder_async(FolderPath path,
+    public async void create_folder_async(Geary.Folder.Path path,
                                           Geary.Folder.SpecialUse? use,
                                           Cancellable? cancellable)
     throws Error {
@@ -122,7 +122,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
      * instead of fetching it again. If not, it is fetched from the
      * server and cached for future use.
      */
-    public async Imap.Folder fetch_folder_async(FolderPath path,
+    public async Imap.Folder fetch_folder_async(Geary.Folder.Path path,
                                                 Cancellable? cancellable)
         throws Error {
         ClientSession session = get_session();
@@ -166,7 +166,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
      * folders found, and hence should be used with care.
      */
     public async Gee.List<Folder>
-        fetch_child_folders_async(FolderPath parent,
+        fetch_child_folders_async(Geary.Folder.Path parent,
                                   GLib.Cancellable? cancellable)
         throws GLib.Error {
         ClientSession session = get_session();
@@ -198,7 +198,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
                 // Mailbox is unselectable, so doesn't need a STATUS,
                 // so we can create it now if it does not already
                 // exist
-                FolderPath path = session.get_path_for_mailbox(
+                Geary.Folder.Path path = session.get_path_for_mailbox(
                     this.root, mailbox_info.mailbox
                 );
                 Folder? child = this.folders.get(path);
@@ -251,7 +251,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
                 }
                 status_results.remove(status);
 
-                FolderPath child_path = session.get_path_for_mailbox(
+                Geary.Folder.Path child_path = session.get_path_for_mailbox(
                     this.root, mailbox_info.mailbox
                 );
                 Imap.Folder? child = this.folders.get(child_path);
@@ -280,8 +280,8 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
         return children;
     }
 
-    internal void folders_removed(Gee.Collection<FolderPath> paths) {
-        foreach (FolderPath path in paths) {
+    internal void folders_removed(Gee.Collection<Geary.Folder.Path> paths) {
+        foreach (Geary.Folder.Path path in paths) {
             if (folders.has_key(path))
                 folders.unset(path);
         }
@@ -309,7 +309,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
 
     // Performs a LIST against the server, returning the results
     private async Gee.List<MailboxInformation> send_list_async(ClientSession session,
-                                                               FolderPath folder,
+                                                               Geary.Folder.Path folder,
                                                                bool list_children,
                                                                Cancellable? cancellable)
         throws Error {
@@ -363,7 +363,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
         if (folder != null && list_children) {
             Gee.Iterator<MailboxInformation> iter = list_results.iterator();
             while (iter.next()) {
-                FolderPath list_path = session.get_path_for_mailbox(
+                Geary.Folder.Path list_path = session.get_path_for_mailbox(
                     this.root, iter.get().mailbox
                 );
                 if (list_path.equal_to(folder)) {
@@ -465,7 +465,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
     }
 
     [NoReturn]
-    private void throw_not_found(Geary.FolderPath? path) throws EngineError {
+    private void throw_not_found(Geary.Folder.Path? path) throws EngineError {
         throw new EngineError.NOT_FOUND(
             "Folder not found: %s",
             (path != null) ? path.to_string() : "[root]"
diff --git a/src/engine/imap/api/imap-folder-root.vala b/src/engine/imap/api/imap-folder-root.vala
index 1a1f2e992..f2fd46dc8 100644
--- a/src/engine/imap/api/imap-folder-root.vala
+++ b/src/engine/imap/api/imap-folder-root.vala
@@ -15,7 +15,7 @@
  * this class ensure certain requirements are held throughout the
  * library.
  */
-public class Geary.Imap.FolderRoot : Geary.FolderRoot {
+public class Geary.Imap.FolderRoot : Geary.Folder.Root {
 
 
    /**
@@ -25,10 +25,11 @@ public class Geary.Imap.FolderRoot : Geary.FolderRoot {
      * with some case-insensitive version of the IMAP inbox mailbox is
      * obtained via {@link get_child} from this root folder. However
      * since multiple folder roots may be constructed, in general
-     * {@link FolderPath.equal_to} or {@link FolderPath.compare_to}
-     * should still be used for testing equality with this path.
+     * {@link Geary.Folder.Path.equal_to} or {@link
+     * Geary.Folder.Path.compare_to} should still be used for testing
+     * equality with this path.
      */
-    public FolderPath inbox { get; private set; }
+    public Geary.Folder.Path inbox { get; private set; }
 
 
     public FolderRoot(string label) {
@@ -45,9 +46,8 @@ public class Geary.Imap.FolderRoot : Geary.FolderRoot {
      * If the given basename is that of the IMAP inbox, then {@link
      * inbox} will be returned.
      */
-    public override
-        FolderPath get_child(string basename,
-                             Trillian is_case_sensitive = Trillian.UNKNOWN) {
+    public override Geary.Folder.Path get_child(string basename,
+                                                Trillian is_case_sensitive = UNKNOWN) {
         return (MailboxSpecifier.is_inbox_name(basename))
             ? this.inbox
             : base.get_child(basename, is_case_sensitive);
diff --git a/src/engine/imap/api/imap-folder-session.vala b/src/engine/imap/api/imap-folder-session.vala
index 3b777ee6a..24bbe3ada 100644
--- a/src/engine/imap/api/imap-folder-session.vala
+++ b/src/engine/imap/api/imap-folder-session.vala
@@ -718,7 +718,7 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
     // Returns a mapping of the source UID to the destination UID.  If the MessageSet is not for
     // UIDs, then null is returned.  If the server doesn't support COPYUID, null is returned.
     public async Gee.Map<UID, UID>? copy_email_async(MessageSet msg_set,
-                                                     FolderPath destination,
+                                                     Geary.Folder.Path destination,
                                                      GLib.Cancellable? cancellable)
         throws GLib.Error {
         ClientSession session = get_session();
diff --git a/src/engine/imap/api/imap-folder.vala b/src/engine/imap/api/imap-folder.vala
index 5e8028cea..afee82853 100644
--- a/src/engine/imap/api/imap-folder.vala
+++ b/src/engine/imap/api/imap-folder.vala
@@ -20,13 +20,13 @@
 internal class Geary.Imap.Folder : Geary.BaseObject {
 
     /** The full path to this folder. */
-    public FolderPath path { get; private set; }
+    public Geary.Folder.Path path { get; private set; }
 
     /** IMAP properties reported by the server. */
     public Imap.FolderProperties properties  { get; private set; }
 
 
-    internal Folder(FolderPath path, Imap.FolderProperties properties) {
+    internal Folder(Geary.Folder.Path path, Imap.FolderProperties properties) {
         this.path = path;
         this.properties = properties;
     }
diff --git a/src/engine/imap/message/imap-mailbox-specifier.vala 
b/src/engine/imap/message/imap-mailbox-specifier.vala
index da89bbbc6..27f3c0918 100644
--- a/src/engine/imap/message/imap-mailbox-specifier.vala
+++ b/src/engine/imap/message/imap-mailbox-specifier.vala
@@ -81,9 +81,9 @@ public class Geary.Imap.MailboxSpecifier : BaseObject, Gee.Hashable<MailboxSpeci
     }
 
     /**
-     * Returns true if the {@link Geary.FolderPath} points to the IMAP Inbox.
+     * Returns true if the given path points to the IMAP Inbox.
      */
-    public static bool folder_path_is_inbox(FolderPath path) {
+    public static bool folder_path_is_inbox(Geary.Folder.Path path) {
         return path.is_top_level && is_inbox_name(path.name);
     }
 
@@ -117,9 +117,9 @@ public class Geary.Imap.MailboxSpecifier : BaseObject, Gee.Hashable<MailboxSpeci
     }
 
     /**
-     * Converts a generic {@link FolderPath} into an IMAP mailbox specifier.
+     * Converts a generic folder path into an IMAP mailbox specifier.
      */
-    public MailboxSpecifier.from_folder_path(FolderPath path,
+    public MailboxSpecifier.from_folder_path(Geary.Folder.Path path,
                                              MailboxSpecifier inbox,
                                              string? delim)
         throws ImapError {
@@ -196,14 +196,14 @@ public class Geary.Imap.MailboxSpecifier : BaseObject, Gee.Hashable<MailboxSpeci
      * translated name but the standard IMAP name ("INBOX") must be
      * used in addressing its children.
      */
-    public FolderPath to_folder_path(FolderRoot root,
-                                     string? delim,
-                                     MailboxSpecifier? inbox_specifier) {
+    public Geary.Folder.Path to_folder_path(Geary.Folder.Root root,
+                                            string? delim,
+                                            MailboxSpecifier? inbox_specifier) {
         Gee.List<string> list = to_list(delim);
 
         // If the first element is same as supplied inbox specifier,
         // use canonical inbox name, otherwise keep
-        FolderPath? path = (
+        Geary.Folder.Path? path = (
             (inbox_specifier != null && list[0] == inbox_specifier.name)
             ? root.get_child(CANONICAL_INBOX_NAME)
             : root.get_child(list[0])
diff --git a/src/engine/imap/transport/imap-client-session.vala 
b/src/engine/imap/transport/imap-client-session.vala
index ba125616e..33dfa00b2 100644
--- a/src/engine/imap/transport/imap-client-session.vala
+++ b/src/engine/imap/transport/imap-client-session.vala
@@ -612,7 +612,7 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
     /**
      * Determines the SELECT-able mailbox name for a specific folder path.
      */
-    public MailboxSpecifier get_mailbox_for_path(FolderPath path)
+    public MailboxSpecifier get_mailbox_for_path(Geary.Folder.Path path)
         throws ImapError {
         string? delim = get_delimiter_for_path(path);
         return new MailboxSpecifier.from_folder_path(path, this.inbox.mailbox, delim);
@@ -621,8 +621,8 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
     /**
      * Determines the folder path for a mailbox name.
      */
-    public FolderPath get_path_for_mailbox(FolderRoot root,
-                                           MailboxSpecifier mailbox)
+    public Geary.Folder.Path get_path_for_mailbox(Geary.Folder.Root root,
+                                                  MailboxSpecifier mailbox)
         throws ImapError {
         string? delim = get_delimiter_for_mailbox(mailbox);
         return mailbox.to_folder_path(root, delim, this.inbox.mailbox);
@@ -634,7 +634,7 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
      * The returned delimiter be null if a namespace (INBOX, personal,
      * etc) for the path does not exist, or if the namespace is flat.
      */
-    public string? get_delimiter_for_path(FolderPath path)
+    public string? get_delimiter_for_path(Geary.Folder.Path path)
     throws ImapError {
         string? delim = null;
 
@@ -644,7 +644,7 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
             delim = this.inbox.delim;
         } else {
             Namespace? ns = null;
-            FolderPath? search = path;
+            var search = path;
             while (ns == null && search != null) {
                 ns = this.namespaces.get(search.name);
                 search = search.parent;
diff --git a/src/engine/meson.build b/src/engine/meson.build
index f539752ba..77f6ec9d3 100644
--- a/src/engine/meson.build
+++ b/src/engine/meson.build
@@ -20,7 +20,6 @@ engine_vala_sources = files(
   'api/geary-engine-error.vala',
   'api/geary-engine.vala',
   'api/geary-folder.vala',
-  'api/geary-folder-path.vala',
   'api/geary-folder-properties.vala',
   'api/geary-folder-supports-archive.vala',
   'api/geary-folder-supports-copy.vala',
diff --git a/src/engine/outbox/outbox-folder.vala b/src/engine/outbox/outbox-folder.vala
index 1724b9db9..f82c6ac32 100644
--- a/src/engine/outbox/outbox-folder.vala
+++ b/src/engine/outbox/outbox-folder.vala
@@ -57,12 +57,12 @@ public class Geary.Outbox.Folder : BaseObject,
      * This is always the child of the root given to the constructor,
      * with the name given by {@link MAGIC_BASENAME}.
      */
-    public override FolderPath path {
+    public override Geary.Folder.Path path {
         get {
             return _path;
         }
     }
-    private FolderPath _path;
+    private Geary.Folder.Path _path;
 
     /**
      * Returns the type of this folder.
@@ -86,7 +86,7 @@ public class Geary.Outbox.Folder : BaseObject,
     private int64 next_ordering = 0;
 
 
-    internal Folder(Account account, FolderRoot root, Db.Database db) {
+    internal Folder(Account account, Geary.Folder.Root root, Db.Database db) {
         this._account = account;
         this._path = root.get_child(MAGIC_BASENAME, Trillian.TRUE);
         this.db = db;
diff --git a/test/client/composer/composer-widget-test.vala b/test/client/composer/composer-widget-test.vala
index 6b31c9435..0b2af879a 100644
--- a/test/client/composer/composer-widget-test.vala
+++ b/test/client/composer/composer-widget-test.vala
@@ -120,7 +120,7 @@ public class Composer.WidgetTest : TestCase {
             mock_account,
             new Geary.App.SearchFolder(
                 mock_account,
-                new Geary.FolderRoot("", false)
+                new Geary.Folder.Root("", false)
             ),
             new Geary.App.EmailStore(mock_account),
             new Application.ContactStore(
diff --git a/test/engine/api/geary-folder-path-test.vala b/test/engine/api/geary-folder-path-test.vala
index c985a6bf5..03b84c852 100644
--- a/test/engine/api/geary-folder-path-test.vala
+++ b/test/engine/api/geary-folder-path-test.vala
@@ -10,7 +10,7 @@ public class Geary.FolderPathTest : TestCase {
 
     private const string TEST_LABEL = "#test";
 
-    private FolderRoot? root = null;
+    private Folder.Root? root = null;
 
 
     public FolderPathTest() {
@@ -33,7 +33,7 @@ public class Geary.FolderPathTest : TestCase {
     }
 
     public override void set_up() {
-        this.root = new FolderRoot(TEST_LABEL, false);
+        this.root = new Folder.Root(TEST_LABEL, false);
     }
 
     public override void tear_down() {
@@ -89,11 +89,11 @@ public class Geary.FolderPathTest : TestCase {
 
     public void distinct_roots_compare() throws GLib.Error {
         assert_true(
-            this.root.compare_to(new FolderRoot(TEST_LABEL, false)) == 0,
+            this.root.compare_to(new Folder.Root(TEST_LABEL, false)) == 0,
             "Root label equality"
         );
         assert_true(
-            this.root.compare_to(new FolderRoot("#other", false)) > 0,
+            this.root.compare_to(new Folder.Root("#other", false)) > 0,
             "Root label inequality"
         );
     }
@@ -270,64 +270,64 @@ public class Geary.FolderPathTest : TestCase {
 
     public void root_instances_compare() throws GLib.Error {
         assert_compare_eq(
-            this.root.compare_to(new FolderRoot(TEST_LABEL, false)),
+            this.root.compare_to(new Folder.Root(TEST_LABEL, false)),
             "Root equality"
         );
         assert_compare_eq(
-            this.root.get_child("a").compare_to(new FolderRoot(TEST_LABEL, false).get_child("a")),
+            this.root.get_child("a").compare_to(new Folder.Root(TEST_LABEL, false).get_child("a")),
             "Equal child comparison"
         );
 
         assert_compare_gt(
             this.root.get_child("a").compare_to(
-                new FolderRoot("#other", false).get_child("a")),
+                new Folder.Root("#other", false).get_child("a")),
             "Root label inequality with children"
         );
 
         assert_compare_lt(
-            this.root.get_child("a").compare_to(new FolderRoot(TEST_LABEL, false).get_child("b")),
+            this.root.get_child("a").compare_to(new Folder.Root(TEST_LABEL, false).get_child("b")),
             "Greater than child comparison"
         );
 
         assert_compare_gt(
-            this.root.get_child("b").compare_to(new FolderRoot(TEST_LABEL, false).get_child("a")),
+            this.root.get_child("b").compare_to(new Folder.Root(TEST_LABEL, false).get_child("a")),
             "Less than child comparison"
         );
 
         assert_compare_gt(
             this.root.get_child("a").get_child("test")
-            .compare_to(new FolderRoot(TEST_LABEL, false).get_child("a")),
+            .compare_to(new Folder.Root(TEST_LABEL, false).get_child("a")),
             "Greater than descendant"
         );
         assert_true(
             this.root.get_child("a")
-            .compare_to(new FolderRoot(TEST_LABEL, false).get_child("a").get_child("test")) < 0,
+            .compare_to(new Folder.Root(TEST_LABEL, false).get_child("a").get_child("test")) < 0,
             "Less than descendant"
         );
 
         assert_compare_eq(
             this.root.get_child("a").get_child("b")
-            .compare_to(new FolderRoot(TEST_LABEL, false).get_child("a").get_child("b")),
+            .compare_to(new Folder.Root(TEST_LABEL, false).get_child("a").get_child("b")),
             "N-path equality"
         );
 
         assert_compare_lt(
             this.root.get_child("a").get_child("a")
-            .compare_to(new FolderRoot(TEST_LABEL, false).get_child("b").get_child("b")),
+            .compare_to(new Folder.Root(TEST_LABEL, false).get_child("b").get_child("b")),
             "Less than double disjoint"
         );
         assert_compare_gt(
             this.root.get_child("b").get_child("a")
-            .compare_to(new FolderRoot(TEST_LABEL, false).get_child("a").get_child("a")),
+            .compare_to(new Folder.Root(TEST_LABEL, false).get_child("a").get_child("a")),
             "Greater than double disjoint"
         );
 
     }
 
     public void variant_representation() throws GLib.Error {
-        FolderPath orig = this.root.get_child("test");
+        Folder.Path orig = this.root.get_child("test");
         GLib.Variant variant = orig.to_variant();
-        FolderPath copy = this.root.from_variant(variant);
+        Folder.Path copy = this.root.from_variant(variant);
 
         assert_true(orig.equal_to(copy));
     }
diff --git a/test/engine/app/app-conversation-monitor-test.vala 
b/test/engine/app/app-conversation-monitor-test.vala
index f9c6b5a86..c54ecd47e 100644
--- a/test/engine/app/app-conversation-monitor-test.vala
+++ b/test/engine/app/app-conversation-monitor-test.vala
@@ -11,7 +11,7 @@ class Geary.App.ConversationMonitorTest : TestCase {
 
     AccountInformation? account_info = null;
     Mock.Account? account = null;
-    FolderRoot? folder_root = null;
+    Folder.Root? folder_root = null;
     Mock.RemoteFolder? base_folder = null;
     Mock.Folder? other_folder = null;
 
@@ -47,7 +47,7 @@ class Geary.App.ConversationMonitorTest : TestCase {
             new RFC822.MailboxAddress(null, "test1 example com")
         );
         this.account = new Mock.Account(this.account_info);
-        this.folder_root = new FolderRoot("#test", false);
+        this.folder_root = new Folder.Root("#test", false);
         this.base_folder = new Mock.RemoteFolder(
             this.account,
             null,
@@ -208,8 +208,8 @@ class Geary.App.ConversationMonitorTest : TestCase {
     public void load_single_message() throws Error {
         Email e1 = setup_email(1);
 
-        Gee.MultiMap<EmailIdentifier,FolderPath> paths =
-            new Gee.HashMultiMap<EmailIdentifier,FolderPath>();
+        Gee.MultiMap<EmailIdentifier,Folder.Path> paths =
+            new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         paths.set(e1.id, this.base_folder.path);
 
         ConversationMonitor monitor = setup_monitor({e1}, paths);
@@ -227,8 +227,8 @@ class Geary.App.ConversationMonitorTest : TestCase {
         Email e2 = setup_email(2, null);
         Email e3 = setup_email(3, null);
 
-        Gee.MultiMap<EmailIdentifier,FolderPath> paths =
-            new Gee.HashMultiMap<EmailIdentifier,FolderPath>();
+        Gee.MultiMap<EmailIdentifier,Folder.Path> paths =
+            new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         paths.set(e1.id, this.base_folder.path);
         paths.set(e2.id, this.base_folder.path);
         paths.set(e3.id, this.base_folder.path);
@@ -244,13 +244,13 @@ class Geary.App.ConversationMonitorTest : TestCase {
         Email e1 = setup_email(1);
         Email e2 = setup_email(2, e1);
 
-        Gee.MultiMap<EmailIdentifier,FolderPath> paths =
-            new Gee.HashMultiMap<EmailIdentifier,FolderPath>();
+        Gee.MultiMap<EmailIdentifier,Folder.Path> paths =
+            new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         paths.set(e1.id, this.other_folder.path);
         paths.set(e2.id, this.base_folder.path);
 
-        Gee.MultiMap<Email,FolderPath> related_paths =
-            new Gee.HashMultiMap<Email,FolderPath>();
+        Gee.MultiMap<Email,Folder.Path> related_paths =
+            new Gee.HashMultiMap<Email,Folder.Path>();
         related_paths.set(e1, this.other_folder.path);
         related_paths.set(e2, this.base_folder.path);
 
@@ -268,8 +268,8 @@ class Geary.App.ConversationMonitorTest : TestCase {
     public void base_folder_message_appended() throws Error {
         Email e1 = setup_email(1);
 
-        Gee.MultiMap<EmailIdentifier,FolderPath> paths =
-            new Gee.HashMultiMap<EmailIdentifier,FolderPath>();
+        Gee.MultiMap<EmailIdentifier,Folder.Path> paths =
+            new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         paths.set(e1.id, this.base_folder.path);
 
         ConversationMonitor monitor = setup_monitor();
@@ -300,14 +300,14 @@ class Geary.App.ConversationMonitorTest : TestCase {
         Email e2 = setup_email(2, e1);
         Email e3 = setup_email(3);
 
-        Gee.MultiMap<EmailIdentifier,FolderPath> paths =
-            new Gee.HashMultiMap<EmailIdentifier,FolderPath>();
+        Gee.MultiMap<EmailIdentifier,Folder.Path> paths =
+            new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         paths.set(e1.id, this.other_folder.path);
         paths.set(e2.id, this.base_folder.path);
         paths.set(e3.id, this.base_folder.path);
 
-        Gee.MultiMap<Email,FolderPath> e2_related_paths =
-            new Gee.HashMultiMap<Email,FolderPath>();
+        Gee.MultiMap<Email,Folder.Path> e2_related_paths =
+            new Gee.HashMultiMap<Email,Folder.Path>();
         e2_related_paths.set(e1, this.other_folder.path);
         e2_related_paths.set(e2, this.base_folder.path);
 
@@ -341,14 +341,14 @@ class Geary.App.ConversationMonitorTest : TestCase {
         Email e2 = setup_email(2, e1);
         Email e3 = setup_email(3, e1);
 
-        Gee.MultiMap<EmailIdentifier,FolderPath> paths =
-            new Gee.HashMultiMap<EmailIdentifier,FolderPath>();
+        Gee.MultiMap<EmailIdentifier,Folder.Path> paths =
+            new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         paths.set(e1.id, this.base_folder.path);
         paths.set(e2.id, this.base_folder.path);
         paths.set(e3.id, this.other_folder.path);
 
-        Gee.MultiMap<Email,FolderPath> related_paths =
-            new Gee.HashMultiMap<Email,FolderPath>();
+        Gee.MultiMap<Email,Folder.Path> related_paths =
+            new Gee.HashMultiMap<Email,Folder.Path>();
         related_paths.set(e1, this.base_folder.path);
         related_paths.set(e3, this.other_folder.path);
 
@@ -421,8 +421,8 @@ class Geary.App.ConversationMonitorTest : TestCase {
     public void conversation_marked_as_deleted() throws Error {
         Email e1 = setup_email(1);
 
-        Gee.MultiMap<EmailIdentifier,FolderPath> paths =
-            new Gee.HashMultiMap<EmailIdentifier,FolderPath>();
+        Gee.MultiMap<EmailIdentifier,Folder.Path> paths =
+            new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         paths.set(e1.id, this.base_folder.path);
 
         ConversationMonitor monitor = setup_monitor({e1}, paths);
@@ -466,8 +466,8 @@ class Geary.App.ConversationMonitorTest : TestCase {
 
     private ConversationMonitor
         setup_monitor(Email[] base_folder_email = {},
-                      Gee.MultiMap<EmailIdentifier,FolderPath>? paths = null,
-                      Gee.MultiMap<Email,FolderPath>[] related_paths = {})
+                      Gee.MultiMap<EmailIdentifier,Folder.Path>? paths = null,
+                      Gee.MultiMap<Email,Folder.Path>[] related_paths = {})
         throws Error {
         ConversationMonitor monitor = new ConversationMonitor(
             this.base_folder, Email.Field.NONE, 10
@@ -539,7 +539,7 @@ class Geary.App.ConversationMonitorTest : TestCase {
                 this.account.expect_call("get_special_folder");
 
                 seen_ids.clear();
-                foreach (Gee.MultiMap<Email,FolderPath> related in related_paths) {
+                foreach (Gee.MultiMap<Email,Folder.Path> related in related_paths) {
                     if (related != null) {
                         foreach (Email email in related.get_keys()) {
                             if (!base_email_ids.contains(email.message_id)) {
diff --git a/test/engine/app/app-conversation-set-test.vala b/test/engine/app/app-conversation-set-test.vala
index 30149bc17..ef84c81d3 100644
--- a/test/engine/app/app-conversation-set-test.vala
+++ b/test/engine/app/app-conversation-set-test.vala
@@ -9,7 +9,7 @@ class Geary.App.ConversationSetTest : TestCase {
 
 
     ConversationSet? test = null;
-    FolderRoot? folder_root = null;
+    Folder.Root? folder_root = null;
     Folder? base_folder = null;
 
     public ConversationSetTest() {
@@ -28,7 +28,7 @@ class Geary.App.ConversationSetTest : TestCase {
     }
 
     public override void set_up() {
-        this.folder_root = new FolderRoot("#test", false);
+        this.folder_root = new Folder.Root("#test", false);
         this.base_folder = new Mock.Folder(
             null,
             null,
@@ -53,8 +53,7 @@ class Geary.App.ConversationSetTest : TestCase {
         emails.add(e1);
         emails.add(e2);
 
-        Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath> email_paths =
-            new Gee.HashMultiMap<Geary.EmailIdentifier, Geary.FolderPath>();
+        var email_paths = new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         email_paths.set(e1.id, this.base_folder.path);
         email_paths.set(e2.id, this.base_folder.path);
 
@@ -99,8 +98,7 @@ class Geary.App.ConversationSetTest : TestCase {
         emails.add(e1);
         emails.add(e1);
 
-        Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath> email_paths =
-            new Gee.HashMultiMap<Geary.EmailIdentifier, Geary.FolderPath>();
+        var email_paths = new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         email_paths.set(e1.id, this.base_folder.path);
 
         // Pass 1: Duplicate in same input collection
@@ -148,8 +146,7 @@ class Geary.App.ConversationSetTest : TestCase {
         emails.add(e1);
         emails.add(e2);
 
-        Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath> email_paths =
-            new Gee.HashMultiMap<Geary.EmailIdentifier, Geary.FolderPath>();
+        var email_paths = new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         email_paths.set(e1.id, this.base_folder.path);
         email_paths.set(e2.id, this.folder_root.get_child("other"));
 
@@ -217,8 +214,7 @@ class Geary.App.ConversationSetTest : TestCase {
         Gee.LinkedList<Email> emails = new Gee.LinkedList<Email>();
         emails.add(e1);
 
-        Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath> email_paths =
-            new Gee.HashMultiMap<Geary.EmailIdentifier, Geary.FolderPath>();
+        var email_paths = new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         email_paths.set(e1.id, this.base_folder.path);
 
         Gee.Collection<Conversation>? added = null;
@@ -266,8 +262,7 @@ class Geary.App.ConversationSetTest : TestCase {
         Gee.LinkedList<Email> emails = new Gee.LinkedList<Email>();
         emails.add(e2);
 
-        Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath> email_paths =
-            new Gee.HashMultiMap<Geary.EmailIdentifier, Geary.FolderPath>();
+        var email_paths = new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         email_paths.set(e2.id, this.base_folder.path);
 
         Gee.Collection<Conversation>? added = null;
@@ -313,13 +308,12 @@ class Geary.App.ConversationSetTest : TestCase {
 
     public void add_all_multi_path() throws Error {
         Email e1 = setup_email(1);
-        FolderPath other_path = this.folder_root.get_child("other");
+        Folder.Path other_path = this.folder_root.get_child("other");
 
         Gee.LinkedList<Email> emails = new Gee.LinkedList<Email>();
         emails.add(e1);
 
-        Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath> email_paths =
-            new Gee.HashMultiMap<Geary.EmailIdentifier, Geary.FolderPath>();
+        var email_paths = new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         email_paths.set(e1.id, this.base_folder.path);
         email_paths.set(e1.id, other_path);
 
@@ -342,13 +336,12 @@ class Geary.App.ConversationSetTest : TestCase {
         Email e1 = setup_email(1);
         add_email_to_test_set(e1);
 
-        FolderPath other_path = this.folder_root.get_child("other");
+        Folder.Path other_path = this.folder_root.get_child("other");
 
         Gee.LinkedList<Email> emails = new Gee.LinkedList<Email>();
         emails.add(e1);
 
-        Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath> email_paths =
-            new Gee.HashMultiMap<Geary.EmailIdentifier, Geary.FolderPath>();
+        var email_paths = new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         email_paths.set(e1.id, other_path);
 
         Gee.Collection<Conversation>? added = null;
@@ -426,7 +419,7 @@ class Geary.App.ConversationSetTest : TestCase {
     }
 
     public void remove_all_remove_path() throws Error {
-        FolderPath other_path = this.folder_root.get_child("other");
+        Folder.Path other_path = this.folder_root.get_child("other");
         Email e1 = setup_email(1);
         add_email_to_test_set(e1, other_path);
 
@@ -454,7 +447,7 @@ class Geary.App.ConversationSetTest : TestCase {
     }
 
     public void remove_all_base_folder() throws Error {
-        FolderPath other_path = this.folder_root.get_child("other");
+        Folder.Path other_path = this.folder_root.get_child("other");
         Email e1 = setup_email(1);
         add_email_to_test_set(e1, other_path);
 
@@ -496,12 +489,11 @@ class Geary.App.ConversationSetTest : TestCase {
     }
 
     private void add_email_to_test_set(Email to_add,
-                                       FolderPath? other_path=null) {
+                                       Folder.Path? other_path=null) {
         Gee.LinkedList<Email> emails = new Gee.LinkedList<Email>();
         emails.add(to_add);
 
-        Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath> email_paths =
-            new Gee.HashMultiMap<Geary.EmailIdentifier, Geary.FolderPath>();
+        var email_paths = new Gee.HashMultiMap<EmailIdentifier,Folder.Path>();
         email_paths.set(to_add.id, this.base_folder.path);
         if (other_path != null) {
             email_paths.set(to_add.id, other_path);
diff --git a/test/engine/app/app-conversation-test.vala b/test/engine/app/app-conversation-test.vala
index 014aa4d22..194f11c65 100644
--- a/test/engine/app/app-conversation-test.vala
+++ b/test/engine/app/app-conversation-test.vala
@@ -10,7 +10,7 @@ class Geary.App.ConversationTest : TestCase {
 
     Conversation? test = null;
     Folder? base_folder = null;
-    FolderRoot? folder_root = null;
+    Folder.Root? folder_root = null;
 
 
     public ConversationTest() {
@@ -28,7 +28,7 @@ class Geary.App.ConversationTest : TestCase {
     }
 
     public override void set_up() {
-        this.folder_root = new FolderRoot("#test", false);
+        this.folder_root = new Folder.Root("#test", false);
         this.base_folder = new Mock.Folder(
             null,
             null,
@@ -89,8 +89,8 @@ class Geary.App.ConversationTest : TestCase {
         Geary.Email e2 = setup_email(2);
         this.test.add(e2, singleton(this.base_folder.path));
 
-        FolderPath other_path = this.folder_root.get_child("other");
-        Gee.LinkedList<FolderPath> other_paths = new Gee.LinkedList<FolderPath>();
+        Folder.Path other_path = this.folder_root.get_child("other");
+        Gee.LinkedList<Folder.Path> other_paths = new Gee.LinkedList<Folder.Path>();
         other_paths.add(other_path);
 
         assert(this.test.add(e1, other_paths) == false);
@@ -156,7 +156,7 @@ class Geary.App.ConversationTest : TestCase {
         Geary.Email e1 = setup_email(1);
         this.test.add(e1, singleton(this.base_folder.path));
 
-        FolderPath other_path = this.folder_root.get_child("other");
+        Folder.Path other_path = this.folder_root.get_child("other");
         Geary.Email e2 = setup_email(2);
         this.test.add(e2, singleton(other_path));
 
@@ -169,7 +169,7 @@ class Geary.App.ConversationTest : TestCase {
         Geary.Email e1 = setup_email(1);
         this.test.add(e1, singleton(this.base_folder.path));
 
-        FolderPath other_path = this.folder_root.get_child("other");
+        Folder.Path other_path = this.folder_root.get_child("other");
         Geary.Email e2 = setup_email(2);
         this.test.add(e2, singleton(other_path));
 
@@ -188,11 +188,11 @@ class Geary.App.ConversationTest : TestCase {
         Geary.Email e1 = setup_email(1);
         this.test.add(e1, singleton(this.base_folder.path));
 
-        FolderPath other_path = this.folder_root.get_child("other");
+        Folder.Path other_path = this.folder_root.get_child("other");
         Geary.Email e2 = setup_email(2);
         this.test.add(e2, singleton(other_path));
 
-        Gee.Collection<FolderPath> blacklist = new Gee.ArrayList<FolderPath>();
+        Gee.Collection<Folder.Path> blacklist = new Gee.ArrayList<Folder.Path>();
 
         blacklist.add(other_path);
         assert_collection(
diff --git a/test/engine/imap-db/imap-db-account-test.vala b/test/engine/imap-db/imap-db-account-test.vala
index 9d699fc31..15613ff68 100644
--- a/test/engine/imap-db/imap-db-account-test.vala
+++ b/test/engine/imap-db/imap-db-account-test.vala
@@ -12,7 +12,7 @@ class Geary.ImapDB.AccountTest : TestCase {
     private GLib.File? tmp_dir = null;
     private Geary.AccountInformation? config = null;
     private Account? account = null;
-    private FolderRoot? root = null;
+    private Geary.Folder.Root? root = null;
 
 
     public AccountTest() {
@@ -52,7 +52,7 @@ class Geary.ImapDB.AccountTest : TestCase {
         );
         this.account.open_async.end(async_result());
 
-        this.root = new FolderRoot("#test", false);
+        this.root = new Geary.Folder.Root("#test", false);
     }
 
     public override void tear_down() throws GLib.Error {
diff --git a/test/mock/mock-account.vala b/test/mock/mock-account.vala
index f617f9693..192508922 100644
--- a/test/mock/mock-account.vala
+++ b/test/mock/mock-account.vala
@@ -64,7 +64,7 @@ public class Mock.Account : Geary.Account,
     }
 
     public override Gee.Collection<Geary.Folder>
-        list_matching_folders(Geary.FolderPath? parent) {
+        list_matching_folders(Geary.Folder.Path? parent) {
         try {
             return object_call<Gee.Collection<Geary.Folder>>(
                 "get_containing_folders_async",
@@ -115,10 +115,10 @@ public class Mock.Account : Geary.Account,
         }
     }
 
-    public override Geary.FolderPath to_folder_path(GLib.Variant serialised)
+    public override Geary.Folder.Path to_folder_path(GLib.Variant serialised)
         throws Geary.EngineError.BAD_PARAMETERS {
         try {
-            return object_or_throw_call<Geary.FolderPath>(
+            return object_or_throw_call<Geary.Folder.Path>(
                 "to_folder_path",
                 { box_arg(serialised) },
                 new Geary.EngineError.BAD_PARAMETERS("Mock error")
@@ -126,11 +126,11 @@ public class Mock.Account : Geary.Account,
         } catch (Geary.EngineError.BAD_PARAMETERS err) {
             throw err;
         } catch (GLib.Error err) {
-            return new Geary.FolderRoot("#mock", false);
+            return new Geary.Folder.Root("#mock", false);
         }
     }
 
-    public override Geary.Folder get_folder(Geary.FolderPath path)
+    public override Geary.Folder get_folder(Geary.Folder.Path path)
         throws Geary.EngineError.NOT_FOUND {
         try {
             return object_or_throw_call<Folder>(
@@ -176,15 +176,15 @@ public class Mock.Account : Geary.Account,
         );
     }
 
-    public override async Gee.MultiMap<Geary.Email,Geary.FolderPath?>?
+    public override async Gee.MultiMap<Geary.Email,Geary.Folder.Path?>?
         local_search_message_id_async(Geary.RFC822.MessageID message_id,
                                       Geary.Email.Field requested_fields,
                                       bool partial_ok,
-                                      Gee.Collection<Geary.FolderPath?>? folder_blacklist,
+                                      Gee.Collection<Geary.Folder.Path?>? folder_blacklist,
                                       Geary.EmailFlags? flag_blacklist,
                                       GLib.Cancellable? cancellable = null)
         throws GLib.Error {
-        return object_call<Gee.MultiMap<Geary.Email,Geary.FolderPath?>?>(
+        return object_call<Gee.MultiMap<Geary.Email,Geary.Folder.Path?>?>(
             "local_search_message_id_async",
             {
                 message_id,
@@ -233,7 +233,7 @@ public class Mock.Account : Geary.Account,
         local_search_async(Geary.SearchQuery query,
                            int limit = 100,
                            int offset = 0,
-                           Gee.Collection<Geary.FolderPath?>? folder_blacklist = null,
+                           Gee.Collection<Geary.Folder.Path?>? folder_blacklist = null,
                            Gee.Collection<Geary.EmailIdentifier>? search_ids = null,
                            GLib.Cancellable? cancellable = null)
         throws GLib.Error {
@@ -261,11 +261,11 @@ public class Mock.Account : Geary.Account,
         );
     }
 
-    public override async Gee.MultiMap<Geary.EmailIdentifier,Geary.FolderPath>?
+    public override async Gee.MultiMap<Geary.EmailIdentifier,Geary.Folder.Path>?
         get_containing_folders_async(Gee.Collection<Geary.EmailIdentifier> ids,
                                      GLib.Cancellable? cancellable)
         throws GLib.Error {
-        return object_call<Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath>?>(
+        return object_call<Gee.MultiMap<Geary.EmailIdentifier, Geary.Folder.Path>?>(
             "get_containing_folders_async", {ids, cancellable}, null
         );
     }
diff --git a/test/mock/mock-folder.vala b/test/mock/mock-folder.vala
index 951d32aba..ee274b24f 100644
--- a/test/mock/mock-folder.vala
+++ b/test/mock/mock-folder.vala
@@ -20,7 +20,7 @@ public class Mock.Folder : GLib.Object,
         get { return this._properties; }
     }
 
-    public override Geary.FolderPath path {
+    public override Geary.Folder.Path path {
         get { return this._path; }
     }
 
@@ -39,14 +39,14 @@ public class Mock.Folder : GLib.Object,
 
     private Geary.Account _account;
     private Geary.FolderProperties _properties;
-    private Geary.FolderPath _path;
+    private Geary.Folder.Path _path;
     private Geary.Folder.SpecialUse _used_as;
     private Geary.ProgressMonitor _opening_monitor;
 
 
     public Folder(Geary.Account? account,
                   Geary.FolderProperties? properties,
-                  Geary.FolderPath? path,
+                  Geary.Folder.Path? path,
                   Geary.Folder.SpecialUse used_as,
                   Geary.ProgressMonitor? monitor) {
         this._account = account;
diff --git a/test/mock/mock-remote-folder.vala b/test/mock/mock-remote-folder.vala
index 3a5902937..8b9b1fc92 100644
--- a/test/mock/mock-remote-folder.vala
+++ b/test/mock/mock-remote-folder.vala
@@ -21,7 +21,7 @@ public class Mock.RemoteFolder : GLib.Object,
         get { return this._properties; }
     }
 
-    public Geary.FolderPath path {
+    public Geary.Folder.Path path {
         get { return this._path; }
     }
 
@@ -50,14 +50,14 @@ public class Mock.RemoteFolder : GLib.Object,
 
     private Geary.Account _account;
     private Geary.FolderProperties _properties;
-    private Geary.FolderPath _path;
+    private Geary.Folder.Path _path;
     private Geary.Folder.SpecialUse _used_as;
     private Geary.ProgressMonitor _opening_monitor;
 
 
     public RemoteFolder(Geary.Account? account,
                         Geary.FolderProperties? properties,
-                        Geary.FolderPath? path,
+                        Geary.Folder.Path? path,
                         Geary.Folder.SpecialUse used_as,
                         Geary.ProgressMonitor? monitor,
                         bool is_monitoring,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]