282 lines
9.6 KiB
C#
282 lines
9.6 KiB
C#
// SparkleShare, a collaboration and sharing tool.
|
|
// Copyright (C) 2010 Hylke Bons <hi@planetpeanut.uk>
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// 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.IO;
|
|
using System.Threading;
|
|
|
|
namespace Sparkles {
|
|
|
|
public class SparkleFetcherInfo {
|
|
public string Address; // TODO: Uri object
|
|
public string RemotePath;
|
|
|
|
public string Fingerprint;
|
|
|
|
public string Backend;
|
|
public string TargetDirectory;
|
|
public bool FetchPriorHistory;
|
|
|
|
public string AnnouncementsUrl; // TODO: Uri object
|
|
}
|
|
|
|
|
|
public abstract class BaseFetcher {
|
|
|
|
public event Action Started = delegate { };
|
|
public event Action Failed = delegate { };
|
|
|
|
public event FinishedEventHandler Finished = delegate { };
|
|
public delegate void FinishedEventHandler (StorageType storage_type, string [] warnings);
|
|
|
|
public event ProgressChangedEventHandler ProgressChanged = delegate { };
|
|
public delegate void ProgressChangedEventHandler (double percentage, double speed, string information);
|
|
|
|
|
|
public abstract bool Fetch ();
|
|
public abstract void Stop ();
|
|
public bool IsActive { get; protected set; }
|
|
public double ProgressPercentage { get; private set; }
|
|
public double ProgressSpeed { get; private set; }
|
|
|
|
|
|
protected abstract bool IsFetchedRepoEmpty { get; }
|
|
public StorageType FetchedRepoStorageType { get; protected set; }
|
|
public abstract bool IsFetchedRepoPasswordCorrect (string password);
|
|
public abstract void EnableFetchedRepoCrypto (string password);
|
|
|
|
public readonly List<StorageTypeInfo> AvailableStorageTypes = new List<StorageTypeInfo> ();
|
|
|
|
|
|
public Uri RemoteUrl { get; protected set; }
|
|
public string RequiredFingerprint { get; protected set; }
|
|
public readonly bool FetchPriorHistory;
|
|
public string TargetFolder { get; protected set; }
|
|
public SparkleFetcherInfo OriginalFetcherInfo;
|
|
|
|
|
|
protected List<string> warnings = new List<string> ();
|
|
protected List<string> errors = new List<string> ();
|
|
|
|
public string [] Warnings {
|
|
get {
|
|
return warnings.ToArray ();
|
|
}
|
|
}
|
|
|
|
public string [] Errors {
|
|
get {
|
|
return errors.ToArray ();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
protected BaseFetcher (SparkleFetcherInfo info)
|
|
{
|
|
FetchedRepoStorageType = StorageType.Unknown;
|
|
|
|
AvailableStorageTypes.Add (
|
|
new StorageTypeInfo (StorageType.Plain, "Plain Storage", "Nothing fancy;\nmaximum compatibility"));
|
|
|
|
OriginalFetcherInfo = info;
|
|
RequiredFingerprint = info.Fingerprint;
|
|
FetchPriorHistory = info.FetchPriorHistory;
|
|
string remote_path = info.RemotePath.Trim ("/".ToCharArray ());
|
|
string address = info.Address;
|
|
|
|
if (address.EndsWith ("/", StringComparison.InvariantCulture))
|
|
address = address.Substring (0, address.Length - 1);
|
|
|
|
if (!remote_path.StartsWith ("/", StringComparison.InvariantCulture))
|
|
remote_path = "/" + remote_path;
|
|
|
|
if (!address.Contains ("://"))
|
|
address = "ssh://" + address;
|
|
|
|
TargetFolder = info.TargetDirectory;
|
|
|
|
RemoteUrl = new Uri (address + remote_path);
|
|
IsActive = false;
|
|
}
|
|
|
|
|
|
Thread thread;
|
|
|
|
public void Start ()
|
|
{
|
|
IsActive = true;
|
|
Started ();
|
|
|
|
Logger.LogInfo ("Fetcher", TargetFolder + " | Fetching folder: " + RemoteUrl);
|
|
|
|
try {
|
|
if (Directory.Exists (TargetFolder))
|
|
Directory.Delete (TargetFolder, recursive: true);
|
|
|
|
} catch (IOException) {
|
|
errors.Add ("\"" + TargetFolder + "\" is read-only.");
|
|
Failed ();
|
|
|
|
return;
|
|
}
|
|
|
|
thread = new Thread (() => {
|
|
if (Fetch ()) {
|
|
Thread.Sleep (500);
|
|
Logger.LogInfo ("Fetcher", "Finished");
|
|
|
|
IsActive = false;
|
|
Finished (FetchedRepoStorageType, Warnings);
|
|
|
|
} else {
|
|
Thread.Sleep (500);
|
|
|
|
if (IsActive) {
|
|
Logger.LogInfo ("Fetcher", "Failed");
|
|
Failed ();
|
|
|
|
} else {
|
|
Logger.LogInfo ("Fetcher", "Failed: cancelled by user");
|
|
}
|
|
|
|
IsActive = false;
|
|
}
|
|
});
|
|
|
|
thread.Start ();
|
|
}
|
|
|
|
|
|
public void Complete ()
|
|
{
|
|
if (FetchedRepoStorageType == StorageType.Unknown) {
|
|
Complete (StorageType.Plain);
|
|
return;
|
|
}
|
|
|
|
this.Complete (FetchedRepoStorageType);
|
|
}
|
|
|
|
|
|
public virtual string Complete (StorageType storage_type)
|
|
{
|
|
FetchedRepoStorageType = storage_type;
|
|
|
|
if (IsFetchedRepoEmpty)
|
|
CreateInitialChangeSet ();
|
|
|
|
return Path.GetRandomFileName ().SHA256 ();
|
|
}
|
|
|
|
|
|
// Create an initial change set when the
|
|
// user has fetched an empty remote folder
|
|
void CreateInitialChangeSet ()
|
|
{
|
|
string n = Environment.NewLine;
|
|
string file_path = Path.Combine (TargetFolder, "SparkleShare.txt");
|
|
|
|
var uri_builder = new UriBuilder (RemoteUrl);
|
|
|
|
// Don't expose possible username or password
|
|
if (RemoteUrl.Scheme.StartsWith ("http", StringComparison.InvariantCultureIgnoreCase)) {
|
|
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.Uri + " 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 (FetchedRepoStorageType == StorageType.Encrypted)
|
|
text = text.Replace ("a SparkleShare repository", "an encrypted SparkleShare repository");
|
|
|
|
File.WriteAllText (file_path, text);
|
|
}
|
|
|
|
|
|
DateTime progress_last_change = DateTime.Now;
|
|
|
|
protected void OnProgressChanged (double percentage, double speed, string information) {
|
|
// Only trigger the ProgressChanged event once per second
|
|
if (DateTime.Compare (this.progress_last_change, DateTime.Now.Subtract (new TimeSpan (0, 0, 0, 1))) >= 0)
|
|
return;
|
|
|
|
ProgressChanged (percentage, speed, information);
|
|
}
|
|
|
|
|
|
public static string GetBackend (string address)
|
|
{
|
|
if (address.StartsWith ("ssh+", StringComparison.InvariantCultureIgnoreCase)) {
|
|
string backend = address.Substring (0, address.IndexOf ("://", StringComparison.InvariantCulture));
|
|
backend = backend.Substring (4);
|
|
|
|
return char.ToUpper (backend [0]) + backend.Substring (1);
|
|
}
|
|
|
|
return "Git";
|
|
}
|
|
|
|
|
|
public virtual string FormatName ()
|
|
{
|
|
return Path.GetFileName (RemoteUrl.AbsolutePath);
|
|
}
|
|
|
|
|
|
public void Dispose ()
|
|
{
|
|
if (thread != null)
|
|
thread.Abort ();
|
|
}
|
|
|
|
|
|
protected string [] ExcludeRules = {
|
|
"*.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
|
|
"*(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
|
|
"*/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)
|
|
};
|
|
}
|
|
}
|