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.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 (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 (Config.FoldersPath, canonical_name + " (" + suffix + ")"));
            }

            string target_folder_name = canonical_name;

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

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

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

            } catch (Exception e) {
                PryanetLogger.LogInfo ("Controller", "Error moving directory, trying again...", e);

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

                } catch (Exception x) {
                    PryanetLogger.LogInfo ("Controller", "Error moving directory", x);
                    
                    this.fetcher.Dispose ();
                    this.fetcher = null;
                    this.watcher.EnableRaisingEvents = true;
                    return;
                }
            }

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

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

            if (this.fetcher.OriginalFetcherInfo.AnnouncementsUrl != null) {
                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 (PryanetFetcherInfo info)
        {
            string tmp_path = 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        = info.Backend; 

            if (string.IsNullOrEmpty (backend))
                backend = PryanetFetcherBase.GetBackend (info.Address); 
 
            info.TargetDirectory  = Path.Combine (tmp_path, canonical_name);

            try {
                this.fetcher = (PryanetFetcherBase) Activator.CreateInstance (
                    Type.GetType ("PryanetLib." + backend + ".PryanetFetcher, PryanetLib." + backend), info);

            } catch (Exception e) {
                PryanetLogger.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 ();
        }