diff --git a/SparkleLib/Git/SparkleRepoGit.cs b/SparkleLib/Git/SparkleRepoGit.cs index 0adff153..d37f2450 100644 --- a/SparkleLib/Git/SparkleRepoGit.cs +++ b/SparkleLib/Git/SparkleRepoGit.cs @@ -32,7 +32,7 @@ namespace SparkleLib.Git { private bool use_git_bin; - public SparkleRepo (string path) : base (path) + public SparkleRepo (string path, SparkleConfig config) : base (path, config) { SparkleGit git = new SparkleGit (LocalPath, "config --get filter.bin.clean"); git.Start (); @@ -199,7 +199,7 @@ namespace SparkleLib.Git { this.remote_url_is_set = true; } - + Console.WriteLine (this.use_git_bin); SparkleGitBin git_bin = new SparkleGitBin (LocalPath, "push"); git_bin.Start (); git_bin.WaitForExit (); @@ -407,13 +407,13 @@ namespace SparkleLib.Git { if (!this.user_is_set) { git = new SparkleGit (LocalPath, - "config user.name \"" + SparkleConfig.DefaultConfig.User.Name + "\""); + "config user.name \"" + base.local_config.User.Name + "\""); git.Start (); git.WaitForExit (); git = new SparkleGit (LocalPath, - "config user.email \"" + SparkleConfig.DefaultConfig.User.Email + "\""); + "config user.email \"" + base.local_config.User.Email + "\""); git.Start (); git.WaitForExit (); @@ -423,8 +423,8 @@ namespace SparkleLib.Git { git = new SparkleGit (LocalPath, "commit --all --message=\"" + message + "\" " + - "--author=\"" + SparkleConfig.DefaultConfig.User.Name + - " <" + SparkleConfig.DefaultConfig.User.Email + ">\""); + "--author=\"" + base.local_config.User.Name + + " <" + base.local_config.User.Email + ">\""); git.Start (); git.StandardOutput.ReadToEnd (); @@ -537,7 +537,7 @@ namespace SparkleLib.Git { // we use "h" between the hours and minutes instead. string timestamp = DateTime.Now.ToString ("MMM d H\\hmm"); string their_path = Path.GetFileNameWithoutExtension (conflicting_path) + - " (" + SparkleConfig.DefaultConfig.User.Name + ", " + timestamp + ")" + + " (" + base.local_config.User.Name + ", " + timestamp + ")" + Path.GetExtension (conflicting_path); string abs_conflicting_path = Path.Combine (LocalPath, conflicting_path); @@ -684,6 +684,8 @@ namespace SparkleLib.Git { if (file_path.Equals (".sparkleshare")) continue; + file_path = file_path.Replace ("\\\"", "\""); + if (change_type.Equals ("A")) { change_set.Changes.Add ( new SparkleChange () { @@ -719,6 +721,9 @@ namespace SparkleLib.Git { file_path = EnsureSpecialCharacters (file_path); to_file_path = EnsureSpecialCharacters (to_file_path); + file_path = file_path.Replace ("\\\"", "\""); + to_file_path = to_file_path.Replace ("\\\"", "\""); + if (file_path.EndsWith (".empty")) file_path = file_path.Substring (0, file_path.Length - 6); @@ -915,7 +920,7 @@ namespace SparkleLib.Git { } git_status.WaitForExit (); - return message.Replace ("\"", "\\\""); + return message; } diff --git a/SparkleLib/SparkleConfig.cs b/SparkleLib/SparkleConfig.cs index 0365a8c5..bfcca4e8 100755 --- a/SparkleLib/SparkleConfig.cs +++ b/SparkleLib/SparkleConfig.cs @@ -25,11 +25,7 @@ namespace SparkleLib { public class SparkleConfig : XmlDocument { - private static string default_config_path = Path.Combine ( - Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), - "sparkleshare"); - - public static SparkleConfig DefaultConfig = new SparkleConfig (default_config_path, "config.xml"); + public static SparkleConfig DefaultConfig; public static bool DebugMode = true; public string FullPath; diff --git a/SparkleLib/SparkleHelpers.cs b/SparkleLib/SparkleHelpers.cs index d58f5c51..b9fb68d1 100755 --- a/SparkleLib/SparkleHelpers.cs +++ b/SparkleLib/SparkleHelpers.cs @@ -105,8 +105,18 @@ namespace SparkleLib { public static string SHA1 (string s) { SHA1 sha1 = new SHA1CryptoServiceProvider (); - Byte [] bytes = ASCIIEncoding.Default.GetBytes (s); - Byte [] enc_bytes = sha1.ComputeHash (bytes); + byte [] bytes = ASCIIEncoding.Default.GetBytes (s); + byte [] enc_bytes = sha1.ComputeHash (bytes); + + return BitConverter.ToString (enc_bytes).ToLower ().Replace ("-", ""); + } + + + public static string MD5 (string s) + { + MD5 md5 = new MD5CryptoServiceProvider (); + byte [] bytes = ASCIIEncoding.Default.GetBytes (s); + byte [] enc_bytes = md5.ComputeHash (bytes); return BitConverter.ToString (enc_bytes).ToLower ().Replace ("-", ""); } diff --git a/SparkleLib/SparkleRepoBase.cs b/SparkleLib/SparkleRepoBase.cs index 0024590f..2e4007d0 100755 --- a/SparkleLib/SparkleRepoBase.cs +++ b/SparkleLib/SparkleRepoBase.cs @@ -87,7 +87,7 @@ namespace SparkleLib { return this.identifier; } else { - string config_identifier = SparkleConfig.DefaultConfig.GetIdentifierForFolder (Name); + string config_identifier = this.local_config.GetIdentifierForFolder (Name); if (!string.IsNullOrEmpty (config_identifier)) this.identifier = config_identifier; @@ -137,11 +137,16 @@ namespace SparkleLib { } - public SparkleRepoBase (string path) // TODO: pass a config object + protected SparkleConfig local_config; + + + public SparkleRepoBase (string path, SparkleConfig config) { + this.local_config = config; + LocalPath = path; Name = Path.GetFileName (LocalPath); - RemoteUrl = new Uri (SparkleConfig.DefaultConfig.GetUrlForFolder (Name)); + RemoteUrl = new Uri (this.local_config.GetUrlForFolder (Name)); IsBuffering = false; ServerOnline = true; diff --git a/SparkleShare/Mac/SparkleController.cs b/SparkleShare/Mac/SparkleController.cs index ad8a5bf4..45847ce2 100755 --- a/SparkleShare/Mac/SparkleController.cs +++ b/SparkleShare/Mac/SparkleController.cs @@ -166,15 +166,19 @@ namespace SparkleShare { NSUserDefaults.StandardUserDefaults.SetPersistentDomain (sidebar_plist, "com.apple.sidebarlists");*/ } - - // Creates the SparkleShare folder in the user's home folder + public override bool CreateSparkleShareFolder () { - this.watcher = new SparkleMacWatcher (SparkleConfig.DefaultConfig.FoldersPath); + this.watcher = new SparkleMacWatcher (Program.Controller.FoldersPath); + + if (!Directory.Exists (Program.Controller.FoldersPath)) { + Directory.CreateDirectory (Program.Controller.FoldersPath); + + NSWorkspace.SharedWorkspace.SetIconforFile ( + NSImage.ImageNamed ("sparkleshare-folder.icns"), FoldersPath, + NSWorkspaceIconCreationOptions.NSExclude10_4Elements); - if (!Directory.Exists (SparkleConfig.DefaultConfig.FoldersPath)) { - Directory.CreateDirectory (SparkleConfig.DefaultConfig.FoldersPath); return true; } else { @@ -188,7 +192,14 @@ namespace SparkleShare { NSWorkspace.SharedWorkspace.OpenFile (path); } - + + public override void OpenFile (string path) + { + path = Uri.UnescapeDataString (path); + NSWorkspace.SharedWorkspace.OpenFile (path); + } + + public override string EventLogHTML { get { @@ -242,12 +253,5 @@ namespace SparkleShare { } } } - - - public override void OpenFile (string url) - { - url = url.Replace ("%20", " "); - NSWorkspace.SharedWorkspace.OpenFile (url); - } } } diff --git a/SparkleShare/Mac/SparkleUI.cs b/SparkleShare/Mac/SparkleUI.cs index 5339cef9..b059d549 100755 --- a/SparkleShare/Mac/SparkleUI.cs +++ b/SparkleShare/Mac/SparkleUI.cs @@ -78,7 +78,7 @@ namespace SparkleShare { NSImage folder_icon = new NSImage (folder_icon_path); NSWorkspace.SharedWorkspace.SetIconforFile (folder_icon, - Program.Controller.SparklePath, 0); + Program.Controller.FoldersPath, 0); } } diff --git a/SparkleShare/Program.cs b/SparkleShare/Program.cs index b339512c..39b17bb2 100644 --- a/SparkleShare/Program.cs +++ b/SparkleShare/Program.cs @@ -73,15 +73,11 @@ namespace SparkleShare { Environment.Exit (-1); } - // Initialize the controller this way so that - // there aren't any exceptions in the OS specific UI's Controller = new SparkleController (); Controller.Initialize (); - - if (Controller != null) { - UI = new SparkleUI (); - UI.Run (); - } + + UI = new SparkleUI (); + UI.Run (); #if !__MonoCS__ // Suppress assertion messages in debug mode diff --git a/SparkleShare/SparkleControllerBase.cs b/SparkleShare/SparkleControllerBase.cs index 43d2bf52..18ac7ffc 100644 --- a/SparkleShare/SparkleControllerBase.cs +++ b/SparkleShare/SparkleControllerBase.cs @@ -17,12 +17,9 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Net; -using System.Security.Cryptography; -using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -41,8 +38,8 @@ namespace SparkleShare { public bool RepositoriesLoaded { get; private set;} - public List repositories = new List (); - public readonly string SparklePath = SparkleConfig.DefaultConfig.FoldersPath; + private List repositories = new List (); + public string FoldersPath { get; private set; } public double ProgressPercentage = 0.0; public string ProgressSpeed = ""; @@ -70,6 +67,7 @@ namespace SparkleShare { public event FolderListChangedHandler FolderListChanged; public delegate void FolderListChangedHandler (); + public event OnIdleHandler OnIdle; public delegate void OnIdleHandler (); @@ -79,6 +77,7 @@ namespace SparkleShare { public event OnErrorHandler OnError; public delegate void OnErrorHandler (); + public event InviteReceivedHandler InviteReceived; public delegate void InviteReceivedHandler (SparkleInvite invite); @@ -91,13 +90,13 @@ namespace SparkleShare { public bool FirstRun { get { - return SparkleConfig.DefaultConfig.User.Email.Equals ("Unknown"); + return this.config.User.Email.Equals ("Unknown"); } } public List Folders { get { - List folders = SparkleConfig.DefaultConfig.Folders; + List folders = this.config.Folders; folders.Sort (); return folders; @@ -119,20 +118,20 @@ namespace SparkleShare { public SparkleUser CurrentUser { get { - return SparkleConfig.DefaultConfig.User; + return this.config.User; } set { - SparkleConfig.DefaultConfig.User = value; + this.config.User = value; } } public bool NotificationsEnabled { get { - string notifications_enabled = SparkleConfig.DefaultConfig.GetConfigOption ("notifications"); + string notifications_enabled = this.config.GetConfigOption ("notifications"); if (string.IsNullOrEmpty (notifications_enabled)) { - SparkleConfig.DefaultConfig.SetConfigOption ("notifications", bool.TrueString); + this.config.SetConfigOption ("notifications", bool.TrueString); return true; } else { @@ -142,6 +141,10 @@ namespace SparkleShare { } + public abstract string EventLogHTML { get; } + public abstract string DayEntryHTML { get; } + public abstract string EventEntryHTML { get; } + // Path where the plugins are kept public abstract string PluginsPath { get; } @@ -165,138 +168,27 @@ namespace SparkleShare { public abstract void OpenFile (string path); + private SparkleConfig config; private SparkleFetcherBase fetcher; private Object repo_lock = new Object (); private Object check_repos_lock = new Object (); - // Short alias for the translations - public static string _ (string s) - { - return Program._(s); - } - - public SparkleControllerBase () { } - public void HandleInvite (FileSystemEventArgs args) - { - if (this.fetcher != null && - this.fetcher.IsActive) { - - if (AlertNotificationRaised != null) - AlertNotificationRaised ("SparkleShare Setup seems busy", - "Please wait for it to finish"); - - } else { - if (InviteReceived != null) { - SparkleInvite invite = new SparkleInvite (args.FullPath); - - // It may be that the invite we received a path to isn't - // fully downloaded yet, so we try to read it several times - int tries = 0; - while (!invite.IsValid) { - Thread.Sleep (1 * 250); - invite = new SparkleInvite (args.FullPath); - tries++; - if (tries > 20) - break; - } - - if (invite.IsValid) { - InviteReceived (invite); - - } else { - if (AlertNotificationRaised != null) - AlertNotificationRaised ("Oh noes!", - "This invite seems screwed up..."); - } - - File.Delete (args.FullPath); - } - } - } - - - public void CheckRepositories () - { - lock (this.check_repos_lock) { - string path = SparkleConfig.DefaultConfig.FoldersPath; - - foreach (string folder_path in Directory.GetDirectories (path)) { - string folder_name = Path.GetFileName (folder_path); - - if (folder_name.Equals (".tmp")) - continue; - - if (SparkleConfig.DefaultConfig.GetIdentifierForFolder (folder_name) == null) { - string identifier_file_path = Path.Combine (folder_path, ".sparkleshare"); - - if (!File.Exists (identifier_file_path)) - continue; - - string identifier = File.ReadAllText (identifier_file_path).Trim (); - - if (SparkleConfig.DefaultConfig.IdentifierExists (identifier)) { - RemoveRepository (folder_path); - SparkleConfig.DefaultConfig.RenameFolder (identifier, folder_name); - - string new_folder_path = Path.Combine (path, folder_name); - AddRepository (new_folder_path); - - SparkleHelpers.DebugInfo ("Controller", - "Renamed folder with identifier " + identifier + " to '" + folder_name + "'"); - } - } - } - - foreach (string folder_name in SparkleConfig.DefaultConfig.Folders) { - string folder_path = new SparkleFolder (folder_name).FullPath; - - if (!Directory.Exists (folder_path)) { - SparkleConfig.DefaultConfig.RemoveFolder (folder_name); - RemoveRepository (folder_path); - - SparkleHelpers.DebugInfo ("Controller", - "Removed folder '" + folder_name + "' from config"); - - } else { - AddRepository (folder_path); - } - } - - if (FolderListChanged != null) - FolderListChanged (); - } - } - - - public void OnFolderActivity (object o, FileSystemEventArgs args) - { - if (args != null && - args.ChangeType == WatcherChangeTypes.Created && - args.FullPath.EndsWith (".xml")) { - - HandleInvite (args); - return; - - } else { - if (Directory.Exists (args.FullPath) && - args.ChangeType == WatcherChangeTypes.Created) { - - return; - } - - CheckRepositories (); - } - } - - public virtual void Initialize () { + string app_data_path = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData); + string config_path = Path.Combine (app_data_path, "sparkleshare"); + + this.config = new SparkleConfig (config_path, "config.xml"); + SparkleConfig.DefaultConfig = this.config; + + FoldersPath = this.config.FoldersPath; + SparklePlugin.PluginsPath = PluginsPath; InstallProtocolHandler (); @@ -305,10 +197,10 @@ namespace SparkleShare { AddToBookmarks (); if (FirstRun) { - SparkleConfig.DefaultConfig.SetConfigOption ("notifications", bool.TrueString); + this.config.SetConfigOption ("notifications", bool.TrueString); } else { - string keys_path = Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath); + string keys_path = Path.GetDirectoryName (this.config.FullPath); string key_file_name = "sparkleshare." + CurrentUser.Email + ".key"; string key_file_path = Path.Combine (keys_path, key_file_name); @@ -325,7 +217,7 @@ namespace SparkleShare { } string pubkey_file_path = key_file_path + ".pub"; - string link_code_file_path = Path.Combine (SparklePath, CurrentUser.Name + "'s link code.txt"); + string link_code_file_path = Path.Combine (FoldersPath, CurrentUser.Name + "'s link code.txt"); // Create an easily accessible copy of the public // key in the user's SparkleShare folder @@ -340,7 +232,7 @@ namespace SparkleShare { FileSystemWatcher watcher = new FileSystemWatcher () { Filter = "*", IncludeSubdirectories = false, - Path = SparkleConfig.DefaultConfig.FoldersPath + Path = FoldersPath }; watcher.Deleted += OnFolderActivity; @@ -360,234 +252,13 @@ namespace SparkleShare { } - public void ShowSetupWindow (PageType page_type) + private void PopulateRepositories () { - if (ShowSetupWindowEvent != null) - ShowSetupWindowEvent (page_type); - } + CheckRepositories (); + RepositoriesLoaded = true; - - public void ShowAboutWindow () - { - if (ShowAboutWindowEvent != null) - ShowAboutWindowEvent (); - } - - - public void ShowEventLogWindow () - { - if (ShowEventLogWindowEvent != null) - ShowEventLogWindowEvent (); - } - - - public List GetLog () - { - List list = new List (); - - foreach (SparkleRepoBase repo in Repositories) { - List change_sets = repo.ChangeSets; - - if (change_sets != null) - list.AddRange (change_sets); - else - SparkleHelpers.DebugInfo ("Log", "Could not create log for " + repo.Name); - } - - list.Sort ((x, y) => (x.Timestamp.CompareTo (y.Timestamp))); - list.Reverse (); - - if (list.Count > 100) - return list.GetRange (0, 100); - else - return list.GetRange (0, list.Count); - } - - - public List GetLog (string name) - { - if (name == null) - return GetLog (); - - foreach (SparkleRepoBase repo in Repositories) { - if (repo.Name.Equals (name)) - return repo.ChangeSets; - } - - return null; - } - - - public abstract string EventLogHTML { get; } - public abstract string DayEntryHTML { get; } - public abstract string EventEntryHTML { get; } - - public string GetHTMLLog (List change_sets) - { - List activity_days = new List (); - - change_sets.Sort ((x, y) => (x.Timestamp.CompareTo (y.Timestamp))); - change_sets.Reverse (); - - if (change_sets.Count == 0) - return null; - - foreach (SparkleChangeSet change_set in change_sets) { - bool change_set_inserted = false; - foreach (ActivityDay stored_activity_day in activity_days) { - if (stored_activity_day.Date.Year == change_set.Timestamp.Year && - stored_activity_day.Date.Month == change_set.Timestamp.Month && - stored_activity_day.Date.Day == change_set.Timestamp.Day) { - - stored_activity_day.Add (change_set); - - change_set_inserted = true; - break; - } - } - - if (!change_set_inserted) { - ActivityDay activity_day = new ActivityDay (change_set.Timestamp); - activity_day.Add (change_set); - activity_days.Add (activity_day); - } - } - - string event_log_html = EventLogHTML; - string day_entry_html = DayEntryHTML; - string event_entry_html = EventEntryHTML; - string event_log = ""; - - foreach (ActivityDay activity_day in activity_days) { - string event_entries = ""; - - foreach (SparkleChangeSet change_set in activity_day) { - string event_entry = "
"; - - foreach (SparkleChange change in change_set.Changes) { - if (change.Type != SparkleChangeType.Moved) { - - event_entry += "
"; - event_entry += "" + change.Timestamp.ToString ("HH:mm") +"  "; - event_entry += FormatBreadCrumbs (change_set.Folder.FullPath, change.Path); - event_entry += "
"; - - } else { - - event_entry += "
"; - event_entry += FormatBreadCrumbs (change_set.Folder.FullPath, change.Path); - event_entry += "
"; - event_entry += "" + change.Timestamp.ToString ("HH:mm") +"  "; - event_entry += FormatBreadCrumbs (change_set.Folder.FullPath, change.MovedToPath); - event_entry += "
"; - - } - } - - string change_set_avatar = GetAvatar (change_set.User.Email, 48); - - if (change_set_avatar != null) { - change_set_avatar = "file://" + change_set_avatar.Replace ("\\", "/"); - - } else { - change_set_avatar = "file:///" + - AssignAvatar (change_set.User.Email); - } - - event_entry += "
"; - - string timestamp = change_set.Timestamp.ToString ("H:mm"); - - if (!change_set.FirstTimestamp.Equals (new DateTime ()) && - !change_set.Timestamp.ToString ("H:mm").Equals (change_set.FirstTimestamp.ToString ("H:mm"))) - timestamp = change_set.FirstTimestamp.ToString ("H:mm") + " – " + timestamp; - - event_entries += event_entry_html.Replace ("", event_entry) - .Replace ("", change_set.User.Name) - .Replace ("", change_set_avatar) - .Replace ("", change_set.Folder.Name) - .Replace ("", change_set.RemoteUrl.ToString ()) - .Replace ("", change_set.Revision); - } - - string day_entry = ""; - DateTime today = DateTime.Now; - DateTime yesterday = DateTime.Now.AddDays (-1); - - if (today.Day == activity_day.Date.Day && - today.Month == activity_day.Date.Month && - today.Year == activity_day.Date.Year) { - - day_entry = day_entry_html.Replace ("", - "" - + _("Today") + ""); - - } else if (yesterday.Day == activity_day.Date.Day && - yesterday.Month == activity_day.Date.Month && - yesterday.Year == activity_day.Date.Year) { - - day_entry = day_entry_html.Replace ("", - "" - + _("Yesterday") + ""); - - } else { - if (activity_day.Date.Year != DateTime.Now.Year) { - - // TRANSLATORS: This is the date in the event logs - day_entry = day_entry_html.Replace ("", - activity_day.Date.ToString (_("dddd, MMMM d, yyyy"))); - - } else { - - // TRANSLATORS: This is the date in the event logs, without the year - day_entry = day_entry_html.Replace ("", - activity_day.Date.ToString (_("dddd, MMMM d"))); - } - } - - event_log += day_entry.Replace ("", event_entries); - } - - - int midnight = (int) (DateTime.Today.AddDays (1) - new DateTime (1970, 1, 1)).TotalSeconds; - - string html = event_log_html.Replace ("", event_log) - .Replace ("", midnight.ToString ()); - - return html; - } - - - // Fires events for the current syncing state - public void UpdateState () - { - bool has_syncing_repos = false; - bool has_unsynced_repos = false; - - foreach (SparkleRepoBase repo in Repositories) { - if (repo.Status == SyncStatus.SyncDown || - repo.Status == SyncStatus.SyncUp || - repo.IsBuffering) { - - has_syncing_repos = true; - - } else if (repo.HasUnsyncedChanges) { - has_unsynced_repos = true; - } - } - - if (has_syncing_repos) { - if (OnSyncing != null) - OnSyncing (); - - } else if (has_unsynced_repos) { - if (OnError != null) - OnError (); - - } else { - if (OnIdle != null) - OnIdle (); - } + if (FolderListChanged != null) + FolderListChanged (); } @@ -595,12 +266,12 @@ namespace SparkleShare { { SparkleRepoBase repo = null; string folder_name = Path.GetFileName (folder_path); - string backend = SparkleConfig.DefaultConfig.GetBackendForFolder (folder_name); + string backend = this.config.GetBackendForFolder (folder_name); try { repo = (SparkleRepoBase) Activator.CreateInstance ( Type.GetType ("SparkleLib." + backend + ".SparkleRepo, SparkleLib." + backend), - new object [] {folder_path, SparkleConfig.DefaultConfig} + new object [] {folder_path, this.config} ); } catch { @@ -668,54 +339,148 @@ namespace SparkleShare { } - private void PopulateRepositories () + private void CheckRepositories () { - CheckRepositories (); - RepositoriesLoaded = true; + lock (this.check_repos_lock) { + string path = this.config.FoldersPath; - if (FolderListChanged != null) - FolderListChanged (); + foreach (string folder_path in Directory.GetDirectories (path)) { + string folder_name = Path.GetFileName (folder_path); + + if (folder_name.Equals (".tmp")) + continue; + + if (this.config.GetIdentifierForFolder (folder_name) == null) { + string identifier_file_path = Path.Combine (folder_path, ".sparkleshare"); + + if (!File.Exists (identifier_file_path)) + continue; + + string identifier = File.ReadAllText (identifier_file_path).Trim (); + + if (this.config.IdentifierExists (identifier)) { + RemoveRepository (folder_path); + this.config.RenameFolder (identifier, folder_name); + + string new_folder_path = Path.Combine (path, folder_name); + AddRepository (new_folder_path); + + SparkleHelpers.DebugInfo ("Controller", + "Renamed folder with identifier " + identifier + " to '" + folder_name + "'"); + } + } + } + + foreach (string folder_name in this.config.Folders) { + string folder_path = new SparkleFolder (folder_name).FullPath; + + if (!Directory.Exists (folder_path)) { + this.config.RemoveFolder (folder_name); + RemoveRepository (folder_path); + + SparkleHelpers.DebugInfo ("Controller", + "Removed folder '" + folder_name + "' from config"); + + } else { + AddRepository (folder_path); + } + } + + if (FolderListChanged != null) + FolderListChanged (); + } } - public void ToggleNotifications () { - bool notifications_enabled = - SparkleConfig.DefaultConfig.GetConfigOption ("notifications") - .Equals (bool.TrueString); + // Fires events for the current syncing state + private void UpdateState () + { + bool has_syncing_repos = false; + bool has_unsynced_repos = false; - if (notifications_enabled) - SparkleConfig.DefaultConfig.SetConfigOption ("notifications", bool.FalseString); - else - SparkleConfig.DefaultConfig.SetConfigOption ("notifications", bool.TrueString); + foreach (SparkleRepoBase repo in Repositories) { + if (repo.Status == SyncStatus.SyncDown || + repo.Status == SyncStatus.SyncUp || + repo.IsBuffering) { + + has_syncing_repos = true; + + } else if (repo.HasUnsyncedChanges) { + has_unsynced_repos = true; + } + } + + if (has_syncing_repos) { + if (OnSyncing != null) + OnSyncing (); + + } else if (has_unsynced_repos) { + if (OnError != null) + OnError (); + + } else { + if (OnIdle != null) + OnIdle (); + } } - // Format a file size nicely with small caps. - // Example: 1048576 becomes "1 ᴍʙ" - public string FormatSize (double byte_count) + public void OnFolderActivity (object o, FileSystemEventArgs args) { - if (byte_count >= 1099511627776) - return String.Format ("{0:##.##} ᴛʙ", Math.Round (byte_count / 1099511627776, 1)); - else if (byte_count >= 1073741824) - return String.Format ("{0:##.##} ɢʙ", Math.Round (byte_count / 1073741824, 1)); - else if (byte_count >= 1048576) - return String.Format ("{0:##.##} ᴍʙ", Math.Round (byte_count / 1048576, 0)); - else if (byte_count >= 1024) - return String.Format ("{0:##.##} ᴋʙ", Math.Round (byte_count / 1024, 0)); - else - return byte_count.ToString () + " bytes"; + if (args != null && + args.ChangeType == WatcherChangeTypes.Created && + args.FullPath.EndsWith (".xml")) { + + HandleInvite (args); + return; + + } else { + if (Directory.Exists (args.FullPath) && + args.ChangeType == WatcherChangeTypes.Created) { + + return; + } + + CheckRepositories (); + } } - - public void OpenSparkleShareFolder () + public void HandleInvite (FileSystemEventArgs args) { - OpenFolder (SparkleConfig.DefaultConfig.FoldersPath); - } + if (this.fetcher != null && + this.fetcher.IsActive) { + if (AlertNotificationRaised != null) + AlertNotificationRaised ("SparkleShare Setup seems busy", + "Please wait for it to finish"); - public void OpenSparkleShareFolder (string name) - { - OpenFolder (new SparkleFolder (name).FullPath); + } else { + if (InviteReceived != null) { + SparkleInvite invite = new SparkleInvite (args.FullPath); + + // It may be that the invite we received a path to isn't + // fully downloaded yet, so we try to read it several times + int tries = 0; + while (!invite.IsValid) { + Thread.Sleep (1 * 250); + invite = new SparkleInvite (args.FullPath); + tries++; + if (tries > 20) + break; + } + + if (invite.IsValid) { + InviteReceived (invite); + + } else { + if (AlertNotificationRaised != null) + AlertNotificationRaised ("Oh noes!", + "This invite seems screwed up..."); + } + + File.Delete (args.FullPath); + } + } } @@ -725,7 +490,7 @@ namespace SparkleShare { if (announcements_url != null) announcements_url = announcements_url.Trim (); - string tmp_path = SparkleConfig.DefaultConfig.TmpPath; + string tmp_path = this.config.TmpPath; if (!Directory.Exists (tmp_path)) { Directory.CreateDirectory (tmp_path); @@ -824,7 +589,7 @@ namespace SparkleShare { string canonical_name = Path.GetFileNameWithoutExtension (this.fetcher.RemoteUrl.AbsolutePath); bool target_folder_exists = Directory.Exists ( - Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, canonical_name)); + 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)" @@ -833,7 +598,7 @@ namespace SparkleShare { suffix++; target_folder_exists = Directory.Exists ( Path.Combine ( - SparkleConfig.DefaultConfig.FoldersPath, + this.config.FoldersPath, canonical_name + " (" + suffix + ")" ) ); @@ -844,14 +609,14 @@ namespace SparkleShare { if (suffix > 1) target_folder_name += " (" + suffix + ")"; - string target_folder_path = Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, target_folder_name); + 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); string backend = SparkleFetcherBase.GetBackend (this.fetcher.RemoteUrl.AbsolutePath); - SparkleConfig.DefaultConfig.AddFolder (target_folder_name, this.fetcher.Identifier, + this.config.AddFolder (target_folder_name, this.fetcher.Identifier, this.fetcher.RemoteUrl.ToString (), backend); if (FolderFetched != null) @@ -859,7 +624,7 @@ namespace SparkleShare { /* TODO if (!string.IsNullOrEmpty (announcements_url)) { - SparkleConfig.DefaultConfig.SetFolderOptionalAttribute ( + this.config.SetFolderOptionalAttribute ( target_folder_name, "announcements_url", announcements_url); */ @@ -883,9 +648,52 @@ namespace SparkleShare { } + public void ShowSetupWindow (PageType page_type) + { + if (ShowSetupWindowEvent != null) + ShowSetupWindowEvent (page_type); + } + + + public void ShowAboutWindow () + { + if (ShowAboutWindowEvent != null) + ShowAboutWindowEvent (); + } + + + public void ShowEventLogWindow () + { + if (ShowEventLogWindowEvent != null) + ShowEventLogWindowEvent (); + } + + + public void OpenSparkleShareFolder () + { + OpenFolder (this.config.FoldersPath); + } + + + public void OpenSparkleShareFolder (string name) + { + OpenFolder (new SparkleFolder (name).FullPath); + } + + + public void ToggleNotifications () { + bool notifications_enabled = this.config.GetConfigOption ("notifications").Equals (bool.TrueString); + + if (notifications_enabled) + this.config.SetConfigOption ("notifications", bool.FalseString); + else + this.config.SetConfigOption ("notifications", bool.TrueString); + } + + public string GetAvatar (string email, int size) { - string fetch_gravatars_option = SparkleConfig.DefaultConfig.GetConfigOption ("fetch_gravatars"); + string fetch_gravatars_option = this.config.GetConfigOption ("fetch_gravatars"); if (fetch_gravatars_option != null && fetch_gravatars_option.Equals (bool.FalseString)) { @@ -895,7 +703,7 @@ namespace SparkleShare { email = email.ToLower (); - string avatars_path = new string [] { Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath), + string avatars_path = new string [] { Path.GetDirectoryName (this.config.FullPath), "icons", size + "x" + size, "status" }.Combine (); string avatar_file_path = Path.Combine (avatars_path, "avatar-" + email); @@ -908,7 +716,7 @@ namespace SparkleShare { } WebClient client = new WebClient (); - string url = "http://gravatar.com/avatar/" + GetMD5 (email) + ".jpg?s=" + size + "&d=404"; + string url = "http://gravatar.com/avatar/" + SparkleHelpers.MD5 (email) + ".jpg?s=" + size + "&d=404"; try { byte [] buffer = client.DownloadData (url); @@ -934,18 +742,9 @@ namespace SparkleShare { } - public virtual void Quit () + public string AssignAvatar (string s) { - foreach (SparkleRepoBase repo in Repositories) - repo.Dispose (); - - Environment.Exit (0); - } - - - private string AssignAvatar (string s) - { - string hash = "0" + GetMD5 (s).Substring (0, 8); + string hash = "0" + SparkleHelpers.MD5 (s).Substring (0, 8); string numbers = Regex.Replace (hash, "[a-z]", ""); int number = int.Parse (numbers); string letters = "abcdefghijklmnopqrstuvwxyz"; @@ -954,67 +753,29 @@ namespace SparkleShare { } - // Creates an MD5 hash of input - private string GetMD5 (string s) + // Format a file size nicely with small caps. + // Example: 1048576 becomes "1 ᴍʙ" + public string FormatSize (double byte_count) { - MD5 md5 = new MD5CryptoServiceProvider (); - Byte[] bytes = ASCIIEncoding.Default.GetBytes (s); - Byte[] encoded_bytes = md5.ComputeHash (bytes); - return BitConverter.ToString (encoded_bytes).ToLower ().Replace ("-", ""); + if (byte_count >= 1099511627776) + return String.Format ("{0:##.##} ᴛʙ", Math.Round (byte_count / 1099511627776, 1)); + else if (byte_count >= 1073741824) + return String.Format ("{0:##.##} ɢʙ", Math.Round (byte_count / 1073741824, 1)); + else if (byte_count >= 1048576) + return String.Format ("{0:##.##} ᴍʙ", Math.Round (byte_count / 1048576, 0)); + else if (byte_count >= 1024) + return String.Format ("{0:##.##} ᴋʙ", Math.Round (byte_count / 1024, 0)); + else + return byte_count.ToString () + " bytes"; } - private string FormatBreadCrumbs (string path_root, string path) + public virtual void Quit () { - path_root = path_root.Replace ("/", Path.DirectorySeparatorChar.ToString ()); - path = path.Replace ("/", Path.DirectorySeparatorChar.ToString ()); - - string link = ""; - string [] crumbs = path.Split (Path.DirectorySeparatorChar); + foreach (SparkleRepoBase repo in Repositories) + repo.Dispose (); - int i = 0; - string new_path_root = path_root; - bool previous_was_folder = false; - - foreach (string crumb in crumbs) { - if (string.IsNullOrEmpty (crumb)) - continue; - - string crumb_path = Path.Combine (new_path_root, crumb); - - if (Directory.Exists (crumb_path)) { - link += "" + crumb + Path.DirectorySeparatorChar + ""; - previous_was_folder = true; - - } else if (File.Exists (crumb_path)) { - link += "" + crumb + ""; - previous_was_folder = false; - - } else { - if (i > 0 && !previous_was_folder) - link += Path.DirectorySeparatorChar; - - link += crumb; - previous_was_folder = false; - } - - new_path_root = Path.Combine (new_path_root, crumb); - i++; - } - - return link; - } - - - // All change sets that happened on a day - private class ActivityDay : List - { - public DateTime Date; - - public ActivityDay (DateTime date_time) - { - Date = new DateTime (date_time.Year, date_time.Month, date_time.Day); - } + Environment.Exit (0); } } } diff --git a/SparkleShare/SparkleEventLogController.cs b/SparkleShare/SparkleEventLogController.cs index bba4f5fb..157023f8 100755 --- a/SparkleShare/SparkleEventLogController.cs +++ b/SparkleShare/SparkleEventLogController.cs @@ -90,9 +90,9 @@ namespace SparkleShare { public string HTML { get { - List change_sets = Program.Controller.GetLog (this.selected_folder); + List change_sets = GetLog (this.selected_folder); - string html = Program.Controller.GetHTMLLog (change_sets); + string html = GetHTMLLog (change_sets); if (UpdateSizeInfoEvent != null) UpdateSizeInfoEvent (Size, HistorySize); @@ -214,5 +214,232 @@ namespace SparkleShare { Program.Controller.OpenFile (url); } } + + + private List GetLog () + { + List list = new List (); + + foreach (SparkleRepoBase repo in Program.Controller.Repositories) { + List change_sets = repo.ChangeSets; + + if (change_sets != null) + list.AddRange (change_sets); + else + SparkleHelpers.DebugInfo ("Log", "Could not create log for " + repo.Name); + } + + list.Sort ((x, y) => (x.Timestamp.CompareTo (y.Timestamp))); + list.Reverse (); + + if (list.Count > 100) + return list.GetRange (0, 100); + else + return list.GetRange (0, list.Count); + } + + + private List GetLog (string name) + { + if (name == null) + return GetLog (); + + foreach (SparkleRepoBase repo in Program.Controller.Repositories) { + if (repo.Name.Equals (name)) + return repo.ChangeSets; + } + + return null; + } + + + public string GetHTMLLog (List change_sets) + { + List activity_days = new List (); + + change_sets.Sort ((x, y) => (x.Timestamp.CompareTo (y.Timestamp))); + change_sets.Reverse (); + + if (change_sets.Count == 0) + return null; + + foreach (SparkleChangeSet change_set in change_sets) { + bool change_set_inserted = false; + foreach (ActivityDay stored_activity_day in activity_days) { + if (stored_activity_day.Date.Year == change_set.Timestamp.Year && + stored_activity_day.Date.Month == change_set.Timestamp.Month && + stored_activity_day.Date.Day == change_set.Timestamp.Day) { + + stored_activity_day.Add (change_set); + + change_set_inserted = true; + break; + } + } + + if (!change_set_inserted) { + ActivityDay activity_day = new ActivityDay (change_set.Timestamp); + activity_day.Add (change_set); + activity_days.Add (activity_day); + } + } + + string event_log_html = Program.Controller.EventLogHTML; + string day_entry_html = Program.Controller.DayEntryHTML; + string event_entry_html = Program.Controller.EventEntryHTML; + string event_log = ""; + + foreach (ActivityDay activity_day in activity_days) { + string event_entries = ""; + + foreach (SparkleChangeSet change_set in activity_day) { + string event_entry = "
"; + + foreach (SparkleChange change in change_set.Changes) { + if (change.Type != SparkleChangeType.Moved) { + + event_entry += "
"; + event_entry += "" + change.Timestamp.ToString ("HH:mm") +"  "; + event_entry += FormatBreadCrumbs (change_set.Folder.FullPath, change.Path); + event_entry += "
"; + + } else { + + event_entry += "
"; + event_entry += FormatBreadCrumbs (change_set.Folder.FullPath, change.Path); + event_entry += "
"; + event_entry += "" + change.Timestamp.ToString ("HH:mm") +"  "; + event_entry += FormatBreadCrumbs (change_set.Folder.FullPath, change.MovedToPath); + event_entry += "
"; + + } + } + + string change_set_avatar = Program.Controller.GetAvatar (change_set.User.Email, 48); + + if (change_set_avatar != null) { + change_set_avatar = "file://" + change_set_avatar.Replace ("\\", "/"); + + } else { + change_set_avatar = "file:///" + + Program.Controller.AssignAvatar (change_set.User.Email); + } + + event_entry += "
"; + + string timestamp = change_set.Timestamp.ToString ("H:mm"); + + if (!change_set.FirstTimestamp.Equals (new DateTime ()) && + !change_set.Timestamp.ToString ("H:mm").Equals (change_set.FirstTimestamp.ToString ("H:mm"))) + timestamp = change_set.FirstTimestamp.ToString ("H:mm") + " – " + timestamp; + + event_entries += event_entry_html.Replace ("", event_entry) + .Replace ("", change_set.User.Name) + .Replace ("", change_set_avatar) + .Replace ("", change_set.Folder.Name) + .Replace ("", change_set.RemoteUrl.ToString ()) + .Replace ("", change_set.Revision); + } + + string day_entry = ""; + DateTime today = DateTime.Now; + DateTime yesterday = DateTime.Now.AddDays (-1); + + if (today.Day == activity_day.Date.Day && + today.Month == activity_day.Date.Month && + today.Year == activity_day.Date.Year) { + + day_entry = day_entry_html.Replace ("", + "" + + "Today" + ""); + + } else if (yesterday.Day == activity_day.Date.Day && + yesterday.Month == activity_day.Date.Month && + yesterday.Year == activity_day.Date.Year) { + + day_entry = day_entry_html.Replace ("", + "" + + "Yesterday" + ""); + + } else { + if (activity_day.Date.Year != DateTime.Now.Year) { + + // TRANSLATORS: This is the date in the event logs + day_entry = day_entry_html.Replace ("", + activity_day.Date.ToString ("dddd, MMMM d, yyyy")); + + } else { + + // TRANSLATORS: This is the date in the event logs, without the year + day_entry = day_entry_html.Replace ("", + activity_day.Date.ToString ("dddd, MMMM d")); + } + } + + event_log += day_entry.Replace ("", event_entries); + } + + + int midnight = (int) (DateTime.Today.AddDays (1) - new DateTime (1970, 1, 1)).TotalSeconds; + + string html = event_log_html.Replace ("", event_log) + .Replace ("", midnight.ToString ()); + + return html; + } + + + private string FormatBreadCrumbs (string path_root, string path) + { + path_root = path_root.Replace ("/", Path.DirectorySeparatorChar.ToString ()); + path = path.Replace ("/", Path.DirectorySeparatorChar.ToString ()); + + string link = ""; + string [] crumbs = path.Split (Path.DirectorySeparatorChar); + + int i = 0; + string new_path_root = path_root; + bool previous_was_folder = false; + + foreach (string crumb in crumbs) { + if (string.IsNullOrEmpty (crumb)) + continue; + + string crumb_path = Path.Combine (new_path_root, crumb); + + if (Directory.Exists (crumb_path)) { + link += "" + crumb + Path.DirectorySeparatorChar + ""; + previous_was_folder = true; + + } else if (File.Exists (crumb_path)) { + link += "" + crumb + ""; + previous_was_folder = false; + + } else { + if (i > 0 && !previous_was_folder) + link += Path.DirectorySeparatorChar; + + link += crumb; + previous_was_folder = false; + } + + new_path_root = Path.Combine (new_path_root, crumb); + i++; + } + + return link; + } + + + // All change sets that happened on a day + private class ActivityDay : List + { + public DateTime Date; + + public ActivityDay (DateTime date_time) + { + Date = new DateTime (date_time.Year, date_time.Month, date_time.Day); + } + } } } diff --git a/SparkleShare/SparkleSetupController.cs b/SparkleShare/SparkleSetupController.cs index b9909968..9da39f8e 100755 --- a/SparkleShare/SparkleSetupController.cs +++ b/SparkleShare/SparkleSetupController.cs @@ -289,7 +289,7 @@ namespace SparkleShare { string private_key_file_path = SparkleKeys.GenerateKeyPair (keys_path, key_file_name); SparkleKeys.ImportPrivateKey (private_key_file_path); - string link_code_file_path = Path.Combine (Program.Controller.SparklePath, + string link_code_file_path = Path.Combine (Program.Controller.FoldersPath, Program.Controller.CurrentUser.Name + "'s link code.txt"); // Create an easily accessible copy of the public @@ -633,7 +633,7 @@ namespace SparkleShare { if (HideWindowEvent != null) HideWindowEvent (); - Program.Controller.UpdateState (); + //Program.Controller.UpdateState (); TODO: still relevant? }