diff --git a/SparkleLib/Git/SparkleRepoGit.cs b/SparkleLib/Git/SparkleRepoGit.cs index afbf8548..2ae1ee65 100644 --- a/SparkleLib/Git/SparkleRepoGit.cs +++ b/SparkleLib/Git/SparkleRepoGit.cs @@ -33,6 +33,8 @@ namespace SparkleLib.Git { public SparkleRepo (string path, SparkleConfig config) : base (path, config) { + // TODO: Set git locale to en-US + SparkleGit git = new SparkleGit (LocalPath, "config --get filter.bin.clean"); git.StartAndWaitForExit (); @@ -157,6 +159,7 @@ namespace SparkleLib.Git { SparkleLogger.LogInfo ("Git", Name + " | Remote changes found, local: " + current_revision + ", remote: " + remote_revision); + Error = ErrorStatus.None; return true; } else { @@ -212,11 +215,6 @@ namespace SparkleLib.Git { number = (number / 100 * 20); } else { - if (line.StartsWith ("ERROR: QUOTA EXCEEDED")) { - int quota_limit = int.Parse (line.Substring (21).Trim ()); - throw new QuotaExceededException ("Quota exceeded", quota_limit); - } - // "Writing objects" stage number = (number / 100 * 80 + 20); @@ -231,6 +229,9 @@ namespace SparkleLib.Git { } else { SparkleLogger.LogInfo ("Git", Name + " | " + line); + + if (FindError (line)) + return false; } if (number >= percentage) { @@ -247,6 +248,7 @@ namespace SparkleLib.Git { return true; } else { + Error = ErrorStatus.HostUnreachable; return false; } } @@ -293,6 +295,9 @@ namespace SparkleLib.Git { } else { SparkleLogger.LogInfo ("Git", Name + " | " + line); + + if (FindError (line)) + return false; } @@ -316,6 +321,7 @@ namespace SparkleLib.Git { return true; } else { + Error = ErrorStatus.HostUnreachable; return false; } } @@ -548,6 +554,31 @@ namespace SparkleLib.Git { } + private bool FindError (string line) + { + Error = ErrorStatus.None; + + if (line.StartsWith ("WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!") || + line.StartsWith ("WARNING: POSSIBLE DNS SPOOFING DETECTED!")) { + + Error = ErrorStatus.HostIdentityChanged; + + } else if (line.StartsWith ("Permission denied")) { + Error = ErrorStatus.AuthenticationFailed; + + } else if (line.StartsWith ("error: Disk space exceeded")) { + Error = ErrorStatus.DiskSpaceExcedeed; + } + + if (Error != ErrorStatus.None) { + SparkleLogger.LogInfo ("Git", Name + " | Error status changed to " + Error); + return true; + } else { + return false; + } + } + + private List GetChangeSetsInternal (string path, int count) { if (count < 1) diff --git a/SparkleLib/SparkleRepoBase.cs b/SparkleLib/SparkleRepoBase.cs index 7eee1268..dfbcbee0 100755 --- a/SparkleLib/SparkleRepoBase.cs +++ b/SparkleLib/SparkleRepoBase.cs @@ -32,6 +32,15 @@ namespace SparkleLib { } + public enum ErrorStatus { + None, + HostUnreachable, + HostIdentityChanged, + AuthenticationFailed, + DiskSpaceExcedeed + } + + public abstract class SparkleRepoBase { public static bool UseCustomWatcher = false; @@ -67,7 +76,7 @@ namespace SparkleLib { public readonly Uri RemoteUrl; public List ChangeSets { get; protected set; } public SyncStatus Status { get; private set; } - public bool ServerOnline { get; private set; } + public ErrorStatus Error { get; protected set; } public bool IsBuffering { get; private set; } public double ProgressPercentage { get; private set; } public string ProgressSpeed { get; private set; } @@ -136,12 +145,13 @@ namespace SparkleLib { public SparkleRepoBase (string path, SparkleConfig config) { + Status = SyncStatus.Idle; + Error = ErrorStatus.None; this.local_config = config; LocalPath = path; Name = Path.GetFileName (LocalPath); RemoteUrl = new Uri (this.local_config.GetUrlForFolder (Name)); IsBuffering = false; - ServerOnline = true; this.identifier = Identifier; ChangeSets = GetChangeSets (); @@ -170,7 +180,7 @@ namespace SparkleLib { // In the unlikely case that we haven't synced up our // changes or the server was down, sync up again - if (HasUnsyncedChanges && !is_syncing && ServerOnline) + if (HasUnsyncedChanges && !is_syncing && Error == ErrorStatus.None) SyncUpBase (); }; } @@ -309,14 +319,13 @@ namespace SparkleLib { if (!UseCustomWatcher) this.watcher.Disable (); - if (ServerOnline && SyncUp ()) { + if (Error == ErrorStatus.None && SyncUp ()) { HasUnsyncedChanges = false; SyncStatusChanged (SyncStatus.Idle); this.listener.Announce (new SparkleAnnouncement (Identifier, CurrentRevision)); } else { - ServerOnline = false; SyncStatusChanged (SyncStatus.Error); } } @@ -341,7 +350,7 @@ namespace SparkleLib { if (SyncDown ()) { SparkleLogger.LogInfo ("SyncDown", Name + " | Done"); - ServerOnline = true; + Error = ErrorStatus.None; ChangeSets = GetChangeSets (); @@ -373,10 +382,8 @@ namespace SparkleLib { } else { SparkleLogger.LogInfo ("SyncDown", Name + " | Error"); - ServerOnline = false; ChangeSets = GetChangeSets (); - SyncStatusChanged (SyncStatus.Error); } diff --git a/SparkleShare/Linux/SparkleStatusIcon.cs b/SparkleShare/Linux/SparkleStatusIcon.cs index 354cb9d8..e6faa4a0 100644 --- a/SparkleShare/Linux/SparkleStatusIcon.cs +++ b/SparkleShare/Linux/SparkleStatusIcon.cs @@ -130,7 +130,7 @@ namespace SparkleShare { }); }; - Controller.UpdateOpenRecentEventsItemEvent += delegate (bool item_enabled) { + Controller.UpdateRecentEventsItemEvent += delegate (bool item_enabled) { Application.Invoke (delegate { this.recent_events_item.Sensitive = item_enabled; this.recent_events_item.ShowAll (); @@ -167,46 +167,66 @@ namespace SparkleShare { this.menu.Add (folder_item); if (Program.Controller.Folders.Count > 0) { + int i = 0; foreach (string folder_name in Controller.Folders) { + ImageMenuItem item = new SparkleMenuItem (folder_name); Gdk.Pixbuf folder_icon; - if (Program.Controller.UnsyncedFolders.Contains (folder_name)) { - folder_icon = IconTheme.Default.LoadIcon ("dialog-error", 16, + if (!string.IsNullOrEmpty (Controller.FolderErrors [i])) { + folder_icon = IconTheme.Default.LoadIcon ("dialog-warning", 16, IconLookupFlags.GenericFallback); + item.Submenu = new Menu (); + + MenuItem error_item = new MenuItem (Controller.FolderErrors [i]) { + Sensitive = false + }; + + item.Submenu.Add (error_item); + } else { folder_icon = IconTheme.Default.LoadIcon ("folder", 16, IconLookupFlags.GenericFallback); } - ImageMenuItem subfolder_item = new SparkleMenuItem (folder_name) { - Image = new Image (folder_icon) - }; + item.Image = new Image (folder_icon); - subfolder_item.Activated += OpenFolderDelegate (folder_name); - this.menu.Add (subfolder_item); + item.Activated += OpenFolderDelegate (folder_name); + this.menu.Add (item); + + i++; } Menu submenu = new Menu (); + i = 0; foreach (string folder_name in Controller.OverflowFolders) { + ImageMenuItem item = new SparkleMenuItem (folder_name); Gdk.Pixbuf folder_icon; - if (Program.Controller.UnsyncedFolders.Contains (folder_name)) { - folder_icon = IconTheme.Default.LoadIcon ("dialog-error", 16, + if (!string.IsNullOrEmpty (Controller.OverflowFolderErrors [i])) { + folder_icon = IconTheme.Default.LoadIcon ("dialog-warning", 16, IconLookupFlags.GenericFallback); + item.Submenu = new Menu (); + + MenuItem error_item = new MenuItem (Controller.OverflowFolderErrors [i]) { + Sensitive = false + }; + + item.Submenu.Add (error_item); + } else { folder_icon = IconTheme.Default.LoadIcon ("folder", 16, IconLookupFlags.GenericFallback); } - ImageMenuItem subfolder_item = new SparkleMenuItem (folder_name) { - Image = new Image (folder_icon) - }; + item.Image = new Image (folder_icon); + + item.Activated += OpenFolderDelegate (folder_name); + submenu.Add (item); - subfolder_item.Activated += OpenFolderDelegate (folder_name); - submenu.Add (subfolder_item); + i++; } if (submenu.Children.Length > 0) { @@ -232,10 +252,10 @@ namespace SparkleShare { this.recent_events_item = new MenuItem ("Recent Changes…"); - this.recent_events_item.Sensitive = Controller.OpenRecentEventsItemEnabled; + this.recent_events_item.Sensitive = Controller.RecentEventsItemEnabled; this.recent_events_item.Activated += delegate { - Controller.OpenRecentEventsClicked (); + Controller.RecentEventsClicked (); }; this.menu.Add (this.recent_events_item); diff --git a/SparkleShare/Mac/SparkleStatusIcon.cs b/SparkleShare/Mac/SparkleStatusIcon.cs index 618e02d6..194713d4 100755 --- a/SparkleShare/Mac/SparkleStatusIcon.cs +++ b/SparkleShare/Mac/SparkleStatusIcon.cs @@ -162,7 +162,7 @@ namespace SparkleShare { } }; - Controller.UpdateOpenRecentEventsItemEvent += delegate (bool events_item_enabled) { + Controller.UpdateRecentEventsItemEvent += delegate (bool events_item_enabled) { using (var a = new NSAutoreleasePool ()) { InvokeOnMainThread (delegate { @@ -208,12 +208,12 @@ namespace SparkleShare { this.recent_events_item = new NSMenuItem () { Title = "Recent Changes…", - Enabled = Controller.OpenRecentEventsItemEnabled + Enabled = Controller.RecentEventsItemEnabled }; if (Controller.Folders.Length > 0) { this.recent_events_item.Activated += delegate { - Controller.OpenRecentEventsClicked (); + Controller.RecentEventsClicked (); }; } @@ -272,10 +272,19 @@ namespace SparkleShare { NSMenuItem item = new NSMenuItem (); item.Title = folder_name; - if (Program.Controller.UnsyncedFolders.Contains (folder_name)) - item.Image = this.caution_image; - else + if (!string.IsNullOrEmpty (Controller.FolderErrors [i])) { + item.Image = this.caution_image; + item.Submenu = new NSMenu (); + + NSMenuItem error_item = new NSMenuItem () { + Title = Controller.FolderErrors [i] + }; + + item.Submenu.AddItem (error_item); + + } else { item.Image = this.folder_image; + } item.Image.Size = new SizeF (16, 16); this.folder_tasks [i] = OpenFolderDelegate (folder_name); @@ -291,10 +300,19 @@ namespace SparkleShare { NSMenuItem item = new NSMenuItem (); item.Title = folder_name; - if (Program.Controller.UnsyncedFolders.Contains (folder_name)) - item.Image = this.caution_image; - else + if (!string.IsNullOrEmpty (Controller.OverflowFolderErrors [i])) { + item.Image = this.caution_image; + item.Submenu = new NSMenu (); + + NSMenuItem error_item = new NSMenuItem () { + Title = Controller.OverflowFolderErrors [i] + }; + + item.Submenu.AddItem (error_item); + + } else { item.Image = this.folder_image; + } item.Image.Size = new SizeF (16, 16); this.overflow_tasks [i] = OpenFolderDelegate (folder_name); diff --git a/SparkleShare/SparkleStatusIconController.cs b/SparkleShare/SparkleStatusIconController.cs index 17652504..4948435b 100755 --- a/SparkleShare/SparkleStatusIconController.cs +++ b/SparkleShare/SparkleStatusIconController.cs @@ -16,9 +16,7 @@ using System; -using System.Timers; - -using Threading = System.Threading; +using System.Threading; using SparkleLib; @@ -47,38 +45,21 @@ namespace SparkleShare { public event UpdateQuitItemEventHandler UpdateQuitItemEvent = delegate { }; public delegate void UpdateQuitItemEventHandler (bool quit_item_enabled); - public event UpdateOpenRecentEventsItemEventHandler UpdateOpenRecentEventsItemEvent = delegate { }; - public delegate void UpdateOpenRecentEventsItemEventHandler (bool open_recent_events_item_enabled); + public event UpdateRecentEventsItemEventHandler UpdateRecentEventsItemEvent = delegate { }; + public delegate void UpdateRecentEventsItemEventHandler (bool recent_events_item_enabled); public IconState CurrentState = IconState.Idle; public string StateText = "Welcome to SparkleShare!"; - public readonly int MenuOverflowThreshold = 9; public readonly int MinSubmenuOverflowCount = 3; - - public string [] Folders { - get { - int overflow_count = (Program.Controller.Folders.Count - MenuOverflowThreshold); - - if (overflow_count >= MinSubmenuOverflowCount) - return Program.Controller.Folders.GetRange (0, MenuOverflowThreshold).ToArray (); - else - return Program.Controller.Folders.ToArray (); - } - } - - public string [] OverflowFolders { - get { - int overflow_count = (Program.Controller.Folders.Count - MenuOverflowThreshold); - - if (overflow_count >= MinSubmenuOverflowCount) - return Program.Controller.Folders.GetRange (MenuOverflowThreshold, overflow_count).ToArray (); - else - return new string [0]; - } - } + public string [] Folders; + public string [] FolderErrors; + + public string [] OverflowFolders; + public string [] OverflowFolderErrors; + public string FolderSize { get { @@ -112,7 +93,7 @@ namespace SparkleShare { } } - public bool OpenRecentEventsItemEnabled { + public bool RecentEventsItemEnabled { get { return (Program.Controller.RepositoriesLoaded && Program.Controller.Folders.Count > 0); } @@ -121,6 +102,8 @@ namespace SparkleShare { public SparkleStatusIconController () { + UpdateFolders (); + Program.Controller.FolderListChanged += delegate { if (CurrentState != IconState.Error) { CurrentState = IconState.Idle; @@ -131,12 +114,16 @@ namespace SparkleShare { StateText = "Files up to date " + FolderSize; } + UpdateFolders (); + UpdateStatusItemEvent (StateText); - UpdateOpenRecentEventsItemEvent (OpenRecentEventsItemEnabled); + UpdateRecentEventsItemEvent (RecentEventsItemEnabled); UpdateMenuEvent (CurrentState); }; Program.Controller.OnIdle += delegate { + UpdateFolders (); + if (CurrentState != IconState.Error) { CurrentState = IconState.Idle; @@ -148,7 +135,6 @@ namespace SparkleShare { UpdateQuitItemEvent (QuitItemEnabled); UpdateStatusItemEvent (StateText); - UpdateIconEvent (CurrentState); UpdateMenuEvent (CurrentState); }; @@ -191,10 +177,12 @@ namespace SparkleShare { CurrentState = IconState.Error; StateText = "Failed to send some changes"; + UpdateFolders (); + UpdateQuitItemEvent (QuitItemEnabled); UpdateStatusItemEvent (StateText); - UpdateIconEvent (CurrentState); + UpdateMenuEvent (CurrentState); }; } @@ -217,9 +205,9 @@ namespace SparkleShare { } - public void OpenRecentEventsClicked () + public void RecentEventsClicked () { - new Threading.Thread (() => Program.Controller.ShowEventLogWindow ()).Start (); + new Thread (() => Program.Controller.ShowEventLogWindow ()).Start (); } @@ -233,5 +221,53 @@ namespace SparkleShare { { Program.Controller.Quit (); } + + + private void UpdateFolders () + { + int overflow_count = (Program.Controller.Folders.Count - MenuOverflowThreshold); + + if (overflow_count >= MinSubmenuOverflowCount) { + Folders = Program.Controller.Folders.GetRange (0, MenuOverflowThreshold).ToArray (); + OverflowFolders = Program.Controller.Folders.GetRange (MenuOverflowThreshold, overflow_count).ToArray (); + } else { + Folders = Program.Controller.Folders.ToArray (); + OverflowFolders = new string [0]; + } + + string [] errors = new string [Folders.Length]; + string [] overflow_errors = new string [OverflowFolders.Length]; + + int i = 0; + foreach (SparkleRepoBase repo in Program.Controller.Repositories) { + string error_message; + + if (repo.Error == ErrorStatus.HostUnreachable) { + error_message = "Host unreachable"; + + } else if (repo.Error == ErrorStatus.HostIdentityChanged) { + error_message = "Host identity changed"; + + } else if (repo.Error == ErrorStatus.AuthenticationFailed) { + error_message = "Authentication failed"; + + } else if (repo.Error == ErrorStatus.DiskSpaceExcedeed) { + error_message = "Host identity changed"; + + } else { + error_message = ""; + } + + if (i > Folders.Length - 1) + overflow_errors [i] = error_message; + else + errors [i] = error_message; + + i++; + } + + FolderErrors = errors; + OverflowFolderErrors = overflow_errors; + } } } diff --git a/SparkleShare/Windows/SparkleSetupWindow.cs b/SparkleShare/Windows/SparkleSetupWindow.cs index 809fdca4..2a9f23bf 100644 --- a/SparkleShare/Windows/SparkleSetupWindow.cs +++ b/SparkleShare/Windows/SparkleSetupWindow.cs @@ -47,7 +47,7 @@ namespace SparkleShare { Height = 440; ResizeMode = ResizeMode.NoResize; Background = new SolidColorBrush (Colors.WhiteSmoke); - Icon = SparkleUIHelpers.GetImageSource("sparkleshare-app", "ico"); + Icon = SparkleUIHelpers.GetImageSource ("sparkleshare-app", "ico"); TaskbarItemInfo = new TaskbarItemInfo () { Description = "SparkleShare" diff --git a/SparkleShare/Windows/SparkleStatusIcon.cs b/SparkleShare/Windows/SparkleStatusIcon.cs index a52b77da..3a849b57 100644 --- a/SparkleShare/Windows/SparkleStatusIcon.cs +++ b/SparkleShare/Windows/SparkleStatusIcon.cs @@ -110,7 +110,7 @@ namespace SparkleShare { }); }; - Controller.UpdateOpenRecentEventsItemEvent += delegate (bool item_enabled) { + Controller.UpdateRecentEventsItemEvent += delegate (bool item_enabled) { Dispatcher.BeginInvoke ((Action) delegate { this.log_item.IsEnabled = item_enabled; this.log_item.UpdateLayout (); @@ -155,11 +155,11 @@ namespace SparkleShare { this.log_item = new SparkleMenuItem () { Header = "Recent changes…", - IsEnabled = Controller.OpenRecentEventsItemEnabled + IsEnabled = Controller.RecentEventsItemEnabled }; this.log_item.Click += delegate { - Controller.OpenRecentEventsClicked (); + Controller.RecentEventsClicked (); }; SparkleMenuItem notify_item = new SparkleMenuItem () { @@ -207,6 +207,7 @@ namespace SparkleShare { this.context_menu.Items.Add (folder_item); if (Controller.Folders.Length > 0) { + int i = 0; foreach (string folder_name in Controller.Folders) { SparkleMenuItem subfolder_item = new SparkleMenuItem () { Header = folder_name @@ -220,26 +221,35 @@ namespace SparkleShare { Height = 16 }; - if (Program.Controller.UnsyncedFolders.Contains (folder_name)) { - subfolder_item.Icon = new Image () { - Source = (BitmapSource) Imaging.CreateBitmapSourceFromHIcon ( - System.Drawing.SystemIcons.Exclamation.Handle, - Int32Rect.Empty, - BitmapSizeOptions.FromWidthAndHeight (16,16) - ) - }; - + if (!string.IsNullOrEmpty (Controller.FolderErrors [i])) { + subfolder_item.Icon = new Image () { + Source = (BitmapSource) Imaging.CreateBitmapSourceFromHIcon ( + System.Drawing.SystemIcons.Exclamation.Handle, Int32Rect.Empty, + BitmapSizeOptions.FromWidthAndHeight (16,16) + ) + }; + + SparkleMenuItem error_item = new SparkleMenuItem () { + Header = Controller.FolderErrors [i], + IsEnabled = false + }; + + subfolder_item.Items.Add (error_item); + } else { subfolder_item.Icon = subfolder_image; } this.context_menu.Items.Add (subfolder_item); + + i++; } SparkleMenuItem more_item = new SparkleMenuItem () { Header = "More projects" }; + i = 0; foreach (string folder_name in Controller.OverflowFolders) { SparkleMenuItem subfolder_item = new SparkleMenuItem () { Header = folder_name @@ -253,20 +263,28 @@ namespace SparkleShare { Height = 16 }; - if (Program.Controller.UnsyncedFolders.Contains (folder_name)) { - subfolder_item.Icon = new Image () { - Source = (BitmapSource) Imaging.CreateBitmapSourceFromHIcon ( - System.Drawing.SystemIcons.Exclamation.Handle, - Int32Rect.Empty, - BitmapSizeOptions.FromWidthAndHeight (16,16) - ) - }; - + if (!string.IsNullOrEmpty (Controller.OverflowFolderErrors [i])) { + subfolder_item.Icon = new Image () { + Source = (BitmapSource) Imaging.CreateBitmapSourceFromHIcon ( + System.Drawing.SystemIcons.Exclamation.Handle, Int32Rect.Empty, + BitmapSizeOptions.FromWidthAndHeight (16,16) + ) + }; + + SparkleMenuItem error_item = new SparkleMenuItem () { + Header = Controller.OverflowFolderErrors [i], + IsEnabled = false + }; + + subfolder_item.Items.Add (error_item); + } else { subfolder_item.Icon = subfolder_image; } more_item.Items.Add (subfolder_item); + + i++; } if (more_item.Items.Count > 0) {