/SparkleLib/SparkleFetcherBase.cs

http://github.com/hbons/SparkleShare · C# · 272 lines · 188 code · 66 blank · 18 comment · 18 complexity · a609b76642d90d11d7c1d769b3a2fe27 MD5 · raw file

  1. // SparkleShare, a collaboration and sharing tool.
  2. // Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as
  6. // published by the Free Software Foundation, either version 3 of the
  7. // License, or (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.IO;
  20. using System.Security.Cryptography;
  21. using System.Threading;
  22. namespace SparkleLib {
  23. public class SparkleFetcherInfo {
  24. public string Address;
  25. public string RemotePath;
  26. public string Backend;
  27. public string Fingerprint;
  28. public string TargetDirectory;
  29. public string AnnouncementsUrl;
  30. public bool FetchPriorHistory;
  31. }
  32. public abstract class SparkleFetcherBase {
  33. public event Action Started = delegate { };
  34. public event Action Failed = delegate { };
  35. public event FinishedEventHandler Finished = delegate { };
  36. public delegate void FinishedEventHandler (bool repo_is_encrypted, bool repo_is_empty, string [] warnings);
  37. public event ProgressChangedEventHandler ProgressChanged = delegate { };
  38. public delegate void ProgressChangedEventHandler (double percentage, double speed);
  39. public abstract bool Fetch ();
  40. public abstract void Stop ();
  41. public abstract bool IsFetchedRepoEmpty { get; }
  42. public abstract bool IsFetchedRepoPasswordCorrect (string password);
  43. public abstract void EnableFetchedRepoCrypto (string password);
  44. public double ProgressPercentage { get; private set; }
  45. public double ProgressSpeed { get; private set; }
  46. public Uri RemoteUrl { get; protected set; }
  47. public string RequiredFingerprint { get; protected set; }
  48. public readonly bool FetchPriorHistory = false;
  49. public string TargetFolder { get; protected set; }
  50. public bool IsActive { get; protected set; }
  51. public string Identifier;
  52. public SparkleFetcherInfo OriginalFetcherInfo;
  53. public string [] Warnings {
  54. get {
  55. return this.warnings.ToArray ();
  56. }
  57. }
  58. public string [] Errors {
  59. get {
  60. return this.errors.ToArray ();
  61. }
  62. }
  63. protected List<string> warnings = new List<string> ();
  64. protected List<string> errors = new List<string> ();
  65. protected string [] ExcludeRules = new string [] {
  66. "*.autosave", // Various autosaving apps
  67. "*~", // gedit and emacs
  68. ".~lock.*", // LibreOffice
  69. "*.part", "*.crdownload", // Firefox and Chromium temporary download files
  70. ".*.sw[a-z]", "*.un~", "*.swp", "*.swo", // vi(m)
  71. ".directory", // KDE
  72. "*.kate-swp", // Kate
  73. ".DS_Store", "Icon\r", "._*", ".Spotlight-V100", ".Trashes", // Mac OS X
  74. "*(Autosaved).graffle", // Omnigraffle
  75. "Thumbs.db", "Desktop.ini", // Windows
  76. "~*.tmp", "~*.TMP", "*~*.tmp", "*~*.TMP", // MS Office
  77. "~*.ppt", "~*.PPT", "~*.pptx", "~*.PPTX",
  78. "~*.xls", "~*.XLS", "~*.xlsx", "~*.XLSX",
  79. "~*.doc", "~*.DOC", "~*.docx", "~*.DOCX",
  80. "~$*",
  81. "*.a$v", // QuarkXPress
  82. "*/CVS/*", ".cvsignore", "*/.cvsignore", // CVS
  83. "/.svn/*", "*/.svn/*", // Subversion
  84. "/.hg/*", "*/.hg/*", "*/.hgignore", // Mercurial
  85. "/.bzr/*", "*/.bzr/*", "*/.bzrignore", // Bazaar
  86. "*<*", "*>*", "*:*", "*\"*", "*|*", "*\\?*", "*\\**", "*\\\\*" // Not allowed on Windows systems,
  87. // see (http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx)
  88. };
  89. private Thread thread;
  90. public SparkleFetcherBase (SparkleFetcherInfo info)
  91. {
  92. OriginalFetcherInfo = info;
  93. RequiredFingerprint = info.Fingerprint;
  94. FetchPriorHistory = info.FetchPriorHistory;
  95. string remote_path = info.RemotePath.Trim ("/".ToCharArray ());
  96. string address = info.Address;
  97. if (address.EndsWith ("/"))
  98. address = address.Substring (0, address.Length - 1);
  99. if (!remote_path.StartsWith ("/"))
  100. remote_path = "/" + remote_path;
  101. if (!address.Contains ("://"))
  102. address = "ssh://" + address;
  103. TargetFolder = info.TargetDirectory;
  104. RemoteUrl = new Uri (address + remote_path);
  105. IsActive = false;
  106. }
  107. public void Start ()
  108. {
  109. IsActive = true;
  110. Started ();
  111. SparkleLogger.LogInfo ("Fetcher", TargetFolder + " | Fetching folder: " + RemoteUrl);
  112. try {
  113. if (Directory.Exists (TargetFolder))
  114. Directory.Delete (TargetFolder, true);
  115. } catch (IOException) {
  116. this.errors.Add ("\"" + TargetFolder + "\" is read-only.");
  117. Failed ();
  118. return;
  119. }
  120. this.thread = new Thread (() => {
  121. if (Fetch ()) {
  122. Thread.Sleep (500);
  123. SparkleLogger.LogInfo ("Fetcher", "Finished");
  124. IsActive = false;
  125. bool repo_is_encrypted = (RemoteUrl.AbsolutePath.Contains ("-crypto") ||
  126. RemoteUrl.Host.Equals ("sparkleshare.net"));
  127. Finished (repo_is_encrypted, IsFetchedRepoEmpty, Warnings);
  128. } else {
  129. Thread.Sleep (500);
  130. if (IsActive) {
  131. SparkleLogger.LogInfo ("Fetcher", "Failed");
  132. Failed ();
  133. } else {
  134. SparkleLogger.LogInfo ("Fetcher", "Failed: cancelled by user");
  135. }
  136. IsActive = false;
  137. }
  138. });
  139. this.thread.Start ();
  140. }
  141. public virtual void Complete ()
  142. {
  143. string identifier_path = Path.Combine (TargetFolder, ".sparkleshare");
  144. if (File.Exists (identifier_path)) {
  145. Identifier = File.ReadAllText (identifier_path).Trim ();
  146. } else {
  147. Identifier = CreateIdentifier ();
  148. File.WriteAllText (identifier_path, Identifier);
  149. if (IsFetchedRepoEmpty)
  150. CreateInitialChangeSet ();
  151. }
  152. File.SetAttributes (identifier_path, FileAttributes.Hidden);
  153. }
  154. // Create an initial change set when the
  155. // user has fetched an empty remote folder
  156. private void CreateInitialChangeSet ()
  157. {
  158. string file_path = Path.Combine (TargetFolder, "SparkleShare.txt");
  159. string n = Environment.NewLine;
  160. UriBuilder uri_builder = new UriBuilder (RemoteUrl);
  161. if (RemoteUrl.Scheme.Contains ("http")) {
  162. uri_builder.UserName = "";
  163. uri_builder.Password = "";
  164. }
  165. string text = "Congratulations, you've successfully created a SparkleShare repository!" + n +
  166. n +
  167. "Any files you add or change in this folder will be automatically synced to " + n +
  168. uri_builder.ToString () + " and everyone connected to it." + n +
  169. n +
  170. "SparkleShare is an Open Source software program that helps people collaborate and " + n +
  171. "share files. If you like what we do, consider buying us a beer: http://www.sparkleshare.org/" + n +
  172. n +
  173. "Have fun! :)" + n;
  174. if (RemoteUrl.AbsolutePath.Contains ("-crypto") || RemoteUrl.Host.Equals ("sparkleshare.net"))
  175. text = text.Replace ("a SparkleShare repository", "an encrypted SparkleShare repository");
  176. File.WriteAllText (file_path, text);
  177. }
  178. public static string CreateIdentifier ()
  179. {
  180. return Path.GetRandomFileName ().SHA1 ();
  181. }
  182. public void Dispose ()
  183. {
  184. if (this.thread != null)
  185. this.thread.Abort ();
  186. }
  187. protected void OnProgressChanged (double percentage, double speed) {
  188. ProgressChanged (percentage, speed);
  189. }
  190. protected string GenerateCryptoSalt ()
  191. {
  192. string salt = Path.GetRandomFileName ().SHA1 ();
  193. return salt.Substring (0, 16);
  194. }
  195. public static string GetBackend (string address)
  196. {
  197. if (address.StartsWith ("ssh+")) {
  198. string backend = address.Substring (0, address.IndexOf ("://"));
  199. backend = backend.Substring (4);
  200. return char.ToUpper (backend [0]) + backend.Substring (1);
  201. } else {
  202. return "Git";
  203. }
  204. }
  205. }
  206. }