public void FinishFetcher ()
        {
            this.watcher.EnableRaisingEvents = false;

            this.fetcher.Complete ();
            string canonical_name = Path.GetFileName (this.fetcher.RemoteUrl.AbsolutePath);
            
            if (canonical_name.EndsWith (".git"))
                canonical_name = canonical_name.Replace (".git", "");

            canonical_name = canonical_name.Replace ("-crypto", "");
            canonical_name = canonical_name.Replace ("_", " ");
            canonical_name = canonical_name.Replace ("%20", " ");

            bool target_folder_exists = Directory.Exists (
                Path.Combine (this.config.FoldersPath, canonical_name));

            // Add a numbered suffix to the name if a folder with the same name
            // already exists. Example: "Folder (2)"
            int suffix = 1;
            while (target_folder_exists) {
                suffix++;
                target_folder_exists = Directory.Exists (
                    Path.Combine (this.config.FoldersPath, canonical_name + " (" + suffix + ")"));
            }

            string target_folder_name = canonical_name;

            if (suffix > 1)
                target_folder_name += " (" + suffix + ")";

            string target_folder_path = Path.Combine (this.config.FoldersPath, target_folder_name);

            try {
                Directory.Move (this.fetcher.TargetFolder, target_folder_path);

            } catch (Exception e) {
                SparkleLogger.LogInfo ("Controller", "Error moving directory: \"" + e.Message + "\", trying again...");

                try {
                    ClearDirectoryAttributes (this.fetcher.TargetFolder);
                    Directory.Move (this.fetcher.TargetFolder, target_folder_path);

                } catch (Exception x) {
                    SparkleLogger.LogInfo ("Controller", "Error moving directory: " + x.Message);
                    this.watcher.EnableRaisingEvents = true;
                    return;
                }
            }

            string backend = SparkleFetcherBase.GetBackend (this.fetcher.RemoteUrl.ToString ());

            this.config.AddFolder (target_folder_name, this.fetcher.Identifier,
                this.fetcher.RemoteUrl.ToString (), backend);

            if (this.fetcher.OriginalFetcherInfo.AnnouncementsUrl != null) {
                this.config.SetFolderOptionalAttribute (target_folder_name, "announcements_url",
                    this.fetcher.OriginalFetcherInfo.AnnouncementsUrl);
            }

            RepositoriesLoaded = true;
            FolderFetched (this.fetcher.RemoteUrl.ToString (), this.fetcher.Warnings.ToArray ());

            AddRepository (target_folder_path);
            FolderListChanged ();

            this.fetcher.Dispose ();
            this.fetcher = null;

            this.watcher.EnableRaisingEvents = true;
        }
        public void StartFetcher (SparkleFetcherInfo info)
        {
            string tmp_path = this.config.TmpPath;

            if (!Directory.Exists (tmp_path)) {
                Directory.CreateDirectory (tmp_path);
                File.SetAttributes (tmp_path, File.GetAttributes (tmp_path) | FileAttributes.Hidden);
            }

            string canonical_name = Path.GetFileName (info.RemotePath);
            string backend        = SparkleFetcherBase.GetBackend (info.Address);
            info.TargetDirectory  = Path.Combine (tmp_path, canonical_name);

            try {
                this.fetcher = (SparkleFetcherBase) Activator.CreateInstance (
                    Type.GetType ("SparkleLib." + backend + ".SparkleFetcher, SparkleLib." + backend), info);

            } catch (Exception e) {
                SparkleLogger.LogInfo ("Controller",
                    "Failed to load '" + backend + "' backend for '" + canonical_name + "' " + e.Message);

                FolderFetchError (Path.Combine (info.Address, info.RemotePath).Replace (@"\", "/"),
                    new string [] {"Failed to load \"" + backend + "\" backend for \"" + canonical_name + "\""});

                return;
            }

            this.fetcher.Finished += delegate (bool repo_is_encrypted, bool repo_is_empty, string [] warnings) {
                if (repo_is_encrypted && repo_is_empty) {
                    ShowSetupWindowEvent (PageType.CryptoSetup);

                } else if (repo_is_encrypted) {
                    ShowSetupWindowEvent (PageType.CryptoPassword);

                } else {
                    FinishFetcher ();
                }
            };

            this.fetcher.Failed += delegate {
                FolderFetchError (this.fetcher.RemoteUrl.ToString (), this.fetcher.Errors);
                StopFetcher ();
            };
            
            this.fetcher.ProgressChanged += delegate (double percentage) {
                FolderFetching (percentage);
            };

            this.fetcher.Start ();
        }
        public void StopFetcher ()
        {
            this.fetcher.Stop ();

            if (Directory.Exists (this.fetcher.TargetFolder)) {
                try {
                    Directory.Delete (this.fetcher.TargetFolder, true);
                    SparkleLogger.LogInfo ("Controller", "Deleted " + this.fetcher.TargetFolder);

                } catch (Exception e) {
                    SparkleLogger.LogInfo ("Controller",
                        "Failed to delete '" + this.fetcher.TargetFolder + "': " + e.Message);
                }
            }

            this.fetcher.Dispose ();
            this.fetcher = null;

            this.watcher.EnableRaisingEvents = true;
        }
        public void StopFetcher ()
        {
            this.fetcher.Stop ();

            if (Directory.Exists (this.fetcher.TargetFolder)) {
                try {
                    Directory.Delete (this.fetcher.TargetFolder, true);
                    SparkleHelpers.DebugInfo ("Controller", "Deleted " + this.fetcher.TargetFolder);

                } catch (Exception e) {
                    SparkleHelpers.DebugInfo ("Controller",
                        "Failed to delete " + this.fetcher.TargetFolder + ": " + e.Message);
                }
            }

            this.fetcher.Dispose ();
            this.fetcher = null;
        }
        public void FinishFetcher ()
        {
            this.fetcher.Complete ();
            string canonical_name = Path.GetFileNameWithoutExtension (this.fetcher.RemoteUrl.AbsolutePath);

            bool target_folder_exists = Directory.Exists (
                Path.Combine (this.config.FoldersPath, canonical_name));

            // Add a numbered suffix to the name if a folder with the same name
            // already exists. Example: "Folder (2)"
            int suffix = 1;
            while (target_folder_exists) {
                suffix++;
                target_folder_exists = Directory.Exists (
                    Path.Combine (
                        this.config.FoldersPath,
                        canonical_name + " (" + suffix + ")"
                    )
                );
            }

            string target_folder_name = canonical_name;

            if (suffix > 1)
                target_folder_name += " (" + suffix + ")";

            string target_folder_path = Path.Combine (this.config.FoldersPath, target_folder_name);

            try {
                SparkleHelpers.ClearAttributes (this.fetcher.TargetFolder);
                Directory.Move (this.fetcher.TargetFolder, target_folder_path);

            } catch (Exception e) {
                SparkleHelpers.DebugInfo ("Controller", "Error moving directory: " + e.Message);
                return;
            }

            string backend = SparkleFetcherBase.GetBackend (this.fetcher.RemoteUrl.AbsolutePath);

            this.config.AddFolder (target_folder_name, this.fetcher.Identifier,
                this.fetcher.RemoteUrl.ToString (), backend);

            FolderFetched (this.fetcher.RemoteUrl.ToString (), this.fetcher.Warnings.ToArray ());

            /* TODO
            if (!string.IsNullOrEmpty (announcements_url)) {
                this.config.SetFolderOptionalAttribute (
                    target_folder_name, "announcements_url", announcements_url);
            */

            AddRepository (target_folder_path);
            FolderListChanged ();

            this.fetcher.Dispose ();
            this.fetcher = null;
        }
        public void StartFetcher (string address, string required_fingerprint,
            string remote_path, string announcements_url, bool fetch_prior_history)
        {
            if (announcements_url != null)
                announcements_url = announcements_url.Trim ();

            string tmp_path = this.config.TmpPath;

			if (!Directory.Exists (tmp_path)) {
                Directory.CreateDirectory (tmp_path);
                File.SetAttributes (tmp_path, File.GetAttributes (tmp_path) | FileAttributes.Hidden);
            }

            string canonical_name = Path.GetFileNameWithoutExtension (remote_path);
            string tmp_folder     = Path.Combine (tmp_path, canonical_name);
            string backend        = SparkleFetcherBase.GetBackend (remote_path);

            try {
                this.fetcher = (SparkleFetcherBase) Activator.CreateInstance (
                    Type.GetType ("SparkleLib." + backend + ".SparkleFetcher, SparkleLib." + backend),
                        address, required_fingerprint, remote_path, tmp_folder, fetch_prior_history
                );

            } catch (Exception e) {
                SparkleHelpers.DebugInfo ("Controller",
                    "Failed to load '" + backend + "' backend for '" + canonical_name + "' " + e.Message);

                FolderFetchError (Path.Combine (address, remote_path).Replace (@"\", "/"),
                    new string [] {"Failed to load \"" + backend + "\" backend for \"" + canonical_name + "\""});

                return;
            }


            this.fetcher.Finished += delegate (bool repo_is_encrypted, bool repo_is_empty, string [] warnings) {
                if (repo_is_encrypted && repo_is_empty) {
                    ShowSetupWindowEvent (PageType.CryptoSetup);

                } else if (repo_is_encrypted) {
                    ShowSetupWindowEvent (PageType.CryptoPassword);

                } else {
                    FinishFetcher ();
                }
            };

            this.fetcher.Failed += delegate {
                FolderFetchError (this.fetcher.RemoteUrl.ToString (), this.fetcher.Errors);
                StopFetcher ();
            };
            
            this.fetcher.ProgressChanged += delegate (double percentage) {
                FolderFetching (percentage);
            };

            this.fetcher.Start ();
        }
        public void StopFetcher ()
        {
            this.fetcher.Stop ();
            this.fetcher.Dispose ();

            this.fetcher = null;
            this.watcher.EnableRaisingEvents = true;
        }
        public void FinishFetcher ()
        {
            this.watcher.EnableRaisingEvents = false;

            this.fetcher.Complete ();
            string canonical_name = Path.GetFileNameWithoutExtension (this.fetcher.RemoteUrl.AbsolutePath);
            canonical_name = canonical_name.Replace ("-crypto", "");

            bool target_folder_exists = Directory.Exists (
                Path.Combine (this.config.FoldersPath, canonical_name));

            // Add a numbered suffix to the name if a folder with the same name
            // already exists. Example: "Folder (2)"
            int suffix = 1;
            while (target_folder_exists) {
                suffix++;
                target_folder_exists = Directory.Exists (
                    Path.Combine (this.config.FoldersPath, canonical_name + " (" + suffix + ")"));
            }

            string target_folder_name = canonical_name;

            if (suffix > 1)
                target_folder_name += " (" + suffix + ")";

            string target_folder_path = Path.Combine (this.config.FoldersPath, target_folder_name);

            try {
                ClearFolderAttributes (this.fetcher.TargetFolder);
                Directory.Move (this.fetcher.TargetFolder, target_folder_path);

            } catch (Exception e) {
                SparkleLogger.LogInfo ("Controller", "Error moving directory: " + e.Message);
                this.watcher.EnableRaisingEvents = true;
                return;
            }

            string backend = SparkleFetcherBase.GetBackend (this.fetcher.RemoteUrl.AbsolutePath);

            this.config.AddFolder (target_folder_name, this.fetcher.Identifier,
                this.fetcher.RemoteUrl.ToString (), backend);

            FolderFetched (this.fetcher.RemoteUrl.ToString (), this.fetcher.Warnings.ToArray ());

            AddRepository (target_folder_path);
            FolderListChanged ();

            this.fetcher.Dispose ();
            this.fetcher = null;

            this.watcher.EnableRaisingEvents = true;
        }
        public void FinishFetcher ()
        {
            this.fetcher.Complete ();
            string canonical_name = Path.GetFileName (this.fetcher.RemoteFolder);

            bool target_folder_exists = Directory.Exists (
                Path.Combine (this.config.FoldersPath, canonical_name));

            // Add a numbered suffix to the name if a folder with the same name
            // already exists. Example: "Folder (2)"
            /*int suffix = 1;
            while (target_folder_exists) {
                suffix++;
                target_folder_exists = Directory.Exists (
                    Path.Combine (this.config.FoldersPath, canonical_name + " (" + suffix + ")"));
            }*/

            string target_folder_name = canonical_name;

            /*if (suffix > 1)   TODO make this work by first creating checkout in temp directory (also paragraph just above)
                target_folder_name += " (" + suffix + ")";*/

            string target_folder_path = Path.Combine (this.config.FoldersPath, target_folder_name);

            //try {
            //    ClearFolderAttributes (this.fetcher.TargetFolder);
            //    Directory.Move (this.fetcher.TargetFolder, target_folder_path);
            //
            //} catch (Exception e) {
            //    SparkleLogger.LogInfo ("Controller", "Error moving directory: " + e.Message);
            //    return;
            //}

            string backend = SparkleFetcherBase.GetBackend (this.fetcher.RemoteUrl.AbsolutePath);

            this.config.AddFolder (target_folder_name, this.fetcher.Identifier,
                this.fetcher.RemoteUrl.ToString (), backend,
                this.fetcher.Repository, this.fetcher.RemoteFolder, this.fetcher.User, this.fetcher.Password);

            FolderFetched (this.fetcher.RemoteUrl.ToString (), this.fetcher.Warnings.ToArray ());

            /* TODO
            if (!string.IsNullOrEmpty (announcements_url)) {
                this.config.SetFolderOptionalAttribute (
                    target_folder_name, "announcements_url", announcements_url);
            */

            //AddRepository (target_folder_path);
            AddRepository(Path.Combine(SparkleFolder.ROOT_FOLDER, canonical_name));

            FolderListChanged ();

            this.fetcher.Dispose ();
            this.fetcher = null;
        }
        public void StartFetcher (string address, string required_fingerprint,
            string remote_path, string announcements_url, bool fetch_prior_history,
            string repository, string path, string user, string password)
        {
            if (announcements_url != null)
                announcements_url = announcements_url.Trim ();

            string tmp_path = this.config.TmpPath;

			//if (!Directory.Exists (tmp_path)) {
            //    Directory.CreateDirectory (tmp_path);
            //    File.SetAttributes (tmp_path, File.GetAttributes (tmp_path) | FileAttributes.Hidden);
            //}

            string canonical_name = Path.GetFileName(remote_path);
            //string tmp_folder     = Path.Combine (tmp_path, canonical_name);
            //string backend        = SparkleFetcherBase.GetBackend (remote_path);

            fetcher = new SparkleLib.Cmis.SparkleFetcher(address, required_fingerprint, remote_path, "dummy_tmp_folder",
                fetch_prior_history, canonical_name, repository, path, user, password, activityListenerAggregator);
            //try {
            //    SparkleLogger.LogInfo("Controller", "Getting type " + "SparkleLib." + backend + ".SparkleFetcher, SparkleLib." + backend);
            //    this.fetcher = (SparkleFetcherBase) Activator.CreateInstance (
            //        Type.GetType("SparkleLib." + backend + ".SparkleFetcher, SparkleLib." + backend),
            //            address, required_fingerprint, remote_path, tmp_folder, fetch_prior_history
            //    );
            //
            //} catch (Exception e) {
            //    SparkleLogger.LogInfo ("Controller",
            //        "Failed to load '" + backend + "' backend for '" + canonical_name + "' " + e.Message);
            //
            //    FolderFetchError (Path.Combine (address, remote_path).Replace (@"\", "/"),
            //        new string [] {"Failed to load \"" + backend + "\" backend for \"" + canonical_name + "\""});
            //
            //    return;
            //}


            this.fetcher.Finished += delegate (bool repo_is_encrypted, bool repo_is_empty, string [] warnings) {
                if (repo_is_encrypted && repo_is_empty) {
                    ShowSetupWindowEvent (PageType.CryptoSetup);

                } else if (repo_is_encrypted) {
                    ShowSetupWindowEvent (PageType.CryptoPassword);

                } else {
                    FinishFetcher ();
                }
            };

            this.fetcher.Failed += delegate {
                FolderFetchError (this.fetcher.RemoteUrl.ToString (), this.fetcher.Errors);
                StopFetcher ();
            };
            
            this.fetcher.ProgressChanged += delegate (double percentage) {
                FolderFetching (percentage);
            };

            this.fetcher.Start ();
        }