SparkleShare/Sparkles/BaseFetcher.cs

264 lines
9 KiB
C#
Raw Normal View History

// SparkleShare, a collaboration and sharing tool.
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
2013-10-11 15:13:46 +00:00
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Threading;
2016-03-31 08:35:26 +00:00
namespace Sparkles {
public class SparkleFetcherInfo {
public string Address;
public string RemotePath;
public string Backend;
public string Fingerprint;
public string TargetDirectory;
public string AnnouncementsUrl;
public bool FetchPriorHistory;
}
2016-03-30 23:36:31 +00:00
public abstract class BaseFetcher {
public event Action Started = delegate { };
public event Action Failed = delegate { };
public event FinishedEventHandler Finished = delegate { };
public delegate void FinishedEventHandler (bool repo_is_encrypted, bool repo_is_empty, string [] warnings);
public event ProgressChangedEventHandler ProgressChanged = delegate { };
public delegate void ProgressChangedEventHandler (double percentage, double speed);
2012-02-09 01:46:25 +00:00
public abstract bool Fetch ();
public abstract void Stop ();
public abstract bool IsFetchedRepoEmpty { get; }
public abstract bool IsFetchedRepoPasswordCorrect (string password);
public abstract void EnableFetchedRepoCrypto (string password);
public double ProgressPercentage { get; private set; }
public double ProgressSpeed { get; private set; }
public Uri RemoteUrl { get; protected set; }
public string RequiredFingerprint { get; protected set; }
public readonly bool FetchPriorHistory = false;
public string TargetFolder { get; protected set; }
public bool IsActive { get; protected set; }
2012-07-06 09:26:02 +00:00
public string Identifier;
public SparkleFetcherInfo OriginalFetcherInfo;
public string [] Warnings {
get {
return this.warnings.ToArray ();
}
}
2012-06-17 20:56:27 +00:00
public string [] Errors {
get {
return this.errors.ToArray ();
}
}
2012-06-19 09:43:18 +00:00
protected List<string> warnings = new List<string> ();
2012-07-06 09:26:02 +00:00
protected List<string> errors = new List<string> ();
2016-03-31 14:46:17 +00:00
protected string [] ExcludeRules = {
2012-07-06 09:26:02 +00:00
"*.autosave", // Various autosaving apps
"*~", // gedit and emacs
".~lock.*", // LibreOffice
"*.part", "*.crdownload", // Firefox and Chromium temporary download files
".*.sw[a-z]", "*.un~", "*.swp", "*.swo", // vi(m)
".directory", // KDE
"*.kate-swp", // Kate
".DS_Store", "Icon\r", "._*", ".Spotlight-V100", ".Trashes", // Mac OS X
2012-07-06 09:26:02 +00:00
"*(Autosaved).graffle", // Omnigraffle
"Thumbs.db", "Desktop.ini", // Windows
"~*.tmp", "~*.TMP", "*~*.tmp", "*~*.TMP", // MS Office
"~*.ppt", "~*.PPT", "~*.pptx", "~*.PPTX",
"~*.xls", "~*.XLS", "~*.xlsx", "~*.XLSX",
"~*.doc", "~*.DOC", "~*.docx", "~*.DOCX",
"~$*",
"*.a$v", // QuarkXPress
2012-07-06 09:26:02 +00:00
"*/CVS/*", ".cvsignore", "*/.cvsignore", // CVS
"/.svn/*", "*/.svn/*", // Subversion
"/.hg/*", "*/.hg/*", "*/.hgignore", // Mercurial
"/.bzr/*", "*/.bzr/*", "*/.bzrignore", // Bazaar
"*<*", "*>*", "*:*", "*\"*", "*|*", "*\\?*", "*\\**", "*\\\\*" // Not allowed on Windows systems,
// see (http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx)
2012-07-06 09:26:02 +00:00
};
2012-06-17 20:56:27 +00:00
2011-08-27 18:57:34 +00:00
private Thread thread;
2016-03-30 23:36:31 +00:00
public BaseFetcher (SparkleFetcherInfo info)
{
OriginalFetcherInfo = info;
RequiredFingerprint = info.Fingerprint;
FetchPriorHistory = info.FetchPriorHistory;
string remote_path = info.RemotePath.Trim ("/".ToCharArray ());
string address = info.Address;
2012-04-11 21:10:02 +00:00
if (address.EndsWith ("/"))
address = address.Substring (0, address.Length - 1);
2012-04-11 21:10:02 +00:00
if (!remote_path.StartsWith ("/"))
remote_path = "/" + remote_path;
if (!address.Contains ("://"))
address = "ssh://" + address;
2012-04-11 21:10:02 +00:00
TargetFolder = info.TargetDirectory;
RemoteUrl = new Uri (address + remote_path);
2012-12-19 20:58:22 +00:00
IsActive = false;
}
public void Start ()
{
IsActive = true;
Started ();
2016-03-30 23:36:31 +00:00
Logger.LogInfo ("Fetcher", TargetFolder + " | Fetching folder: " + RemoteUrl);
try {
if (Directory.Exists (TargetFolder))
Directory.Delete (TargetFolder, true);
} catch (IOException) {
this.errors.Add ("\"" + TargetFolder + "\" is read-only.");
Failed ();
return;
}
2012-07-22 09:51:56 +00:00
this.thread = new Thread (() => {
if (Fetch ()) {
Thread.Sleep (500);
2016-03-30 23:36:31 +00:00
Logger.LogInfo ("Fetcher", "Finished");
2011-05-31 01:26:57 +00:00
2012-07-22 09:51:56 +00:00
IsActive = false;
bool repo_is_encrypted = RemoteUrl.AbsolutePath.Contains ("-crypto");
2012-07-22 09:51:56 +00:00
Finished (repo_is_encrypted, IsFetchedRepoEmpty, Warnings);
2011-05-31 01:26:57 +00:00
2012-07-22 09:51:56 +00:00
} else {
Thread.Sleep (500);
if (IsActive) {
2016-03-30 23:36:31 +00:00
Logger.LogInfo ("Fetcher", "Failed");
Failed ();
} else {
2016-03-30 23:36:31 +00:00
Logger.LogInfo ("Fetcher", "Failed: cancelled by user");
}
2011-05-31 01:26:57 +00:00
2012-07-22 09:51:56 +00:00
IsActive = false;
}
});
this.thread.Start ();
}
public virtual void Complete ()
{
string identifier_path = Path.Combine (TargetFolder, ".sparkleshare");
2012-07-06 09:26:02 +00:00
if (File.Exists (identifier_path)) {
Identifier = File.ReadAllText (identifier_path).Trim ();
2012-10-20 22:25:36 +00:00
2012-07-06 09:26:02 +00:00
} else {
Identifier = CreateIdentifier ();
File.WriteAllText (identifier_path, Identifier);
if (IsFetchedRepoEmpty)
CreateInitialChangeSet ();
2012-10-04 16:51:47 +00:00
}
2012-10-20 22:25:36 +00:00
File.SetAttributes (identifier_path, FileAttributes.Hidden);
}
// Create an initial change set when the
// user has fetched an empty remote folder
2012-10-04 16:51:47 +00:00
private void CreateInitialChangeSet ()
{
string file_path = Path.Combine (TargetFolder, "SparkleShare.txt");
string n = Environment.NewLine;
UriBuilder uri_builder = new UriBuilder (RemoteUrl);
if (RemoteUrl.Scheme.Contains ("http")) {
uri_builder.UserName = "";
uri_builder.Password = "";
}
string text = "Congratulations, you've successfully created a SparkleShare repository!" + n +
n +
"Any files you add or change in this folder will be automatically synced to " + n +
uri_builder.ToString () + " and everyone connected to it." + n +
n +
"SparkleShare is an Open Source software program that helps people collaborate and " + n +
"share files. If you like what we do, consider buying us a beer: http://www.sparkleshare.org/" + n +
n +
"Have fun! :)" + n;
if (RemoteUrl.AbsolutePath.Contains ("-crypto") || RemoteUrl.Host.Equals ("sparkleshare.net"))
text = text.Replace ("a SparkleShare repository", "an encrypted SparkleShare repository");
File.WriteAllText (file_path, text);
}
2012-07-06 09:26:02 +00:00
public static string CreateIdentifier ()
{
return Path.GetRandomFileName ().SHA1 ();
2012-07-06 09:26:02 +00:00
}
public void Dispose ()
{
2012-08-27 12:24:23 +00:00
if (this.thread != null)
this.thread.Abort ();
}
protected void OnProgressChanged (double percentage, double speed) {
ProgressChanged (percentage, speed);
2011-08-27 15:53:17 +00:00
}
2011-05-31 01:26:57 +00:00
public static string GetBackend (string address)
2012-10-04 16:51:47 +00:00
{
if (address.StartsWith ("ssh+")) {
string backend = address.Substring (0, address.IndexOf ("://"));
backend = backend.Substring (4);
return char.ToUpper (backend [0]) + backend.Substring (1);
2012-10-04 16:51:47 +00:00
} else {
return "Git";
}
}
}
}