diff --git a/SparkleLib/SparkleListenerBase.cs b/SparkleLib/SparkleListenerBase.cs
index b9293841..56758ecd 100755
--- a/SparkleLib/SparkleListenerBase.cs
+++ b/SparkleLib/SparkleListenerBase.cs
@@ -50,7 +50,7 @@ namespace SparkleLib {
// don't have your own. All data needed to connect is hashed and
// we don't store any personal information ever
- uri = "irc://204.62.14.135/";
+ uri = "tcp://204.62.14.135:1986";
}
Uri announce_uri = new Uri (uri);
@@ -77,7 +77,7 @@ namespace SparkleLib {
listeners.Add (new SparkleListenerIrc (announce_uri, folder_identifier));
break;
default:
- listeners.Add (new SparkleListenerIrc (announce_uri, folder_identifier));
+ listeners.Add (new SparkleListenerTcp (announce_uri, folder_identifier));
break;
}
diff --git a/SparkleLib/SparkleRepoBase.cs b/SparkleLib/SparkleRepoBase.cs
index 6d724859..9be8e97a 100755
--- a/SparkleLib/SparkleRepoBase.cs
+++ b/SparkleLib/SparkleRepoBase.cs
@@ -256,6 +256,8 @@ namespace SparkleLib {
this.listener.Announcement += delegate (SparkleAnnouncement announcement) {
string identifier = Identifier;
+ Console.WriteLine (announcement.Message + " ! " + CurrentRevision);
+
if (announcement.FolderIdentifier == identifier &&
!announcement.Message.Equals (CurrentRevision)) {
if ((Status != SyncStatus.SyncUp) &&
diff --git a/SparkleShare/Mac/SparkleMacController.cs b/SparkleShare/Mac/SparkleController.cs
similarity index 97%
rename from SparkleShare/Mac/SparkleMacController.cs
rename to SparkleShare/Mac/SparkleController.cs
index 761c7953..15fa3da1 100755
--- a/SparkleShare/Mac/SparkleMacController.cs
+++ b/SparkleShare/Mac/SparkleController.cs
@@ -26,13 +26,17 @@ using SparkleLib;
namespace SparkleShare {
- public class SparkleMacController : SparkleController {
+ public class SparkleController : SparkleControllerBase {
// We have to use our own custom made folder watcher, as
// System.IO.FileSystemWatcher fails watching subfolders on Mac
private SparkleMacWatcher watcher;
- public SparkleMacController () : base () { }
+
+ public SparkleController () : base ()
+ {
+ }
+
public override void Initialize ()
{
diff --git a/SparkleShare/Mac/SparkleShare.csproj b/SparkleShare/Mac/SparkleShare.csproj
index 5f99df54..078dfbf0 100755
--- a/SparkleShare/Mac/SparkleShare.csproj
+++ b/SparkleShare/Mac/SparkleShare.csproj
@@ -74,10 +74,9 @@
MainMenu.xib
-
- SparkleController.cs
+
+ SparkleControllerBase.cs
-
@@ -109,6 +108,7 @@
SparkleExtensions.cs
+
diff --git a/SparkleShare/Makefile.am b/SparkleShare/Makefile.am
index 96350ab7..802cbdbd 100755
--- a/SparkleShare/Makefile.am
+++ b/SparkleShare/Makefile.am
@@ -18,11 +18,11 @@ SOURCES = \
SparkleBubbles.cs \
SparkleBubblesController.cs \
SparkleController.cs \
+ SparkleControllerBase.cs \
SparkleEntry.cs \
SparkleEventLog.cs \
SparkleEventLogController.cs \
SparkleExtensions.cs \
- SparkleLinController.cs \
SparkleSetup.cs \
SparkleSetupController.cs \
SparkleSetupWindow.cs \
diff --git a/SparkleShare/Program.cs b/SparkleShare/Program.cs
index 4291d3bb..8d5f7697 100755
--- a/SparkleShare/Program.cs
+++ b/SparkleShare/Program.cs
@@ -64,23 +64,10 @@ namespace SparkleShare {
if (show_help)
ShowHelp (option_set);
- // Load the right controller for the OS
- string controller_name = "Lin";
- switch (SparkleBackend.Platform) {
- case PlatformID.Unix:
- SetProcessName ("sparkleshare");
- break;
- case PlatformID.MacOSX:
- controller_name = "Mac";
- break;
- case PlatformID.Win32NT:
- controller_name = "Win";
- break;
- }
// Initialize the controller this way so that
// there aren't any exceptions in the OS specific UI's
- Controller = new SparkleMacController ();
+ Controller = new SparkleController ();
Controller.Initialize ();
if (Controller != null) {
diff --git a/SparkleShare/SparkleController.cs b/SparkleShare/SparkleController.cs
index d003fac1..d4ceda9e 100755
--- a/SparkleShare/SparkleController.cs
+++ b/SparkleShare/SparkleController.cs
@@ -19,1148 +19,195 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
-using System.Linq;
-using System.Net;
-using System.Security.Cryptography;
+using System.Runtime.InteropServices;
using System.Text;
-using System.Text.RegularExpressions;
using System.Threading;
-using System.Xml;
using Mono.Unix;
using SparkleLib;
namespace SparkleShare {
- public abstract class SparkleController {
+ public class SparkleController : SparkleControllerBase {
- public List Repositories;
- public string FolderSize;
- public readonly string SparklePath = SparkleConfig.DefaultConfig.FoldersPath;
-
- public event OnQuitWhileSyncingEventHandler OnQuitWhileSyncing;
- public delegate void OnQuitWhileSyncingEventHandler ();
-
- public event FolderFetchedEventHandler FolderFetched;
- public delegate void FolderFetchedEventHandler ();
-
- public event FolderFetchErrorEventHandler FolderFetchError;
- public delegate void FolderFetchErrorEventHandler (string remote_url);
-
- public event FolderFetchingEventHandler FolderFetching;
- public delegate void FolderFetchingEventHandler (double percentage);
-
- public event FolderListChangedEventHandler FolderListChanged;
- public delegate void FolderListChangedEventHandler ();
-
- public event FolderSizeChangedEventHandler FolderSizeChanged;
- public delegate void FolderSizeChangedEventHandler (string folder_size);
-
- public event AvatarFetchedEventHandler AvatarFetched;
- public delegate void AvatarFetchedEventHandler ();
-
- public event OnIdleEventHandler OnIdle;
- public delegate void OnIdleEventHandler ();
-
- public event OnSyncingEventHandler OnSyncing;
- public delegate void OnSyncingEventHandler ();
-
- public event OnErrorEventHandler OnError;
- public delegate void OnErrorEventHandler ();
-
- public event OnInvitationEventHandler OnInvitation;
- public delegate void OnInvitationEventHandler (string server, string folder, string token);
-
- public event ConflictNotificationRaisedEventHandler ConflictNotificationRaised;
- public delegate void ConflictNotificationRaisedEventHandler ();
-
- public event NotificationRaisedEventHandler NotificationRaised;
- public delegate void NotificationRaisedEventHandler (string user_name, string user_email,
- string message, string repository_path);
-
- private SparkleFetcherBase fetcher;
-
-
- // Short alias for the translations
- public static string _ (string s)
+ public SparkleController () : base ()
{
- return Catalog.GetString (s);
- }
-
-
- public SparkleController () { }
-
- public virtual void Initialize ()
- {
- InstallLauncher ();
- EnableSystemAutostart ();
-
- // Create the SparkleShare folder and add it to the bookmarks
- if (CreateSparkleShareFolder ())
- AddToBookmarks ();
-
- FolderSize = GetFolderSize ();
-
- if (FirstRun)
- SparkleConfig.DefaultConfig.SetConfigOption ("notifications", bool.TrueString);
- else
- AddKey ();
-
- // Watch the SparkleShare folder
- FileSystemWatcher watcher = new FileSystemWatcher (SparkleConfig.DefaultConfig.FoldersPath) {
- IncludeSubdirectories = false,
- EnableRaisingEvents = true,
- Filter = "*"
- };
-
- // Remove the repository when a delete event occurs
- watcher.Deleted += delegate (object o, FileSystemEventArgs args) {
- RemoveRepository (args.FullPath);
- SparkleConfig.DefaultConfig.RemoveFolder (Path.GetFileName (args.Name));
-
- if (FolderListChanged != null)
- FolderListChanged ();
-
- FolderSize = GetFolderSize ();
-
- if (FolderSizeChanged != null)
- FolderSizeChanged (FolderSize);
- };
-
-
- watcher.Created += delegate (object o, FileSystemEventArgs args) {
-
- // Handle invitations when the user saves an
- // invitation into the SparkleShare folder
- if (args.Name.EndsWith (".sparkle") && !FirstRun) {
- XmlDocument xml_doc = new XmlDocument ();
- xml_doc.Load (args.Name);
-
- string server = xml_doc.GetElementsByTagName ("server") [0].InnerText;
- string folder = xml_doc.GetElementsByTagName ("folder") [0].InnerText;
- string token = xml_doc.GetElementsByTagName ("token") [0].InnerText;
-
- // FIXME: this is broken :\
- if (OnInvitation != null)
- OnInvitation (server, folder, token);
- }
- };
-
- new Thread (new ThreadStart (PopulateRepositories)).Start ();
- }
-
-
- public bool FirstRun {
- get {
- return SparkleConfig.DefaultConfig.User.Email.Equals ("Unknown");
- }
- }
-
-
- // Uploads the user's public key to the server
- public bool AcceptInvitation (string server, string folder, string token)
- {
- // The location of the user's public key for SparkleShare
- string public_key_file_path = SparkleHelpers.CombineMore (SparkleConfig.DefaultConfig.HomePath, ".ssh",
- "sparkleshare." + UserEmail + ".key.pub");
-
- if (!File.Exists (public_key_file_path))
- return false;
-
- StreamReader reader = new StreamReader (public_key_file_path);
- string public_key = reader.ReadToEnd ();
- reader.Close ();
-
- string url = "https://" + server + "/?folder=" + folder +
- "&token=" + token + "&pubkey=" + public_key;
-
- SparkleHelpers.DebugInfo ("WebRequest", url);
-
- HttpWebRequest request = (HttpWebRequest) WebRequest.Create (url);
- HttpWebResponse response = (HttpWebResponse) request.GetResponse();
-
- if (response.StatusCode == HttpStatusCode.OK) {
- response.Close ();
- return true;
-
- } else {
- response.Close ();
- return false;
- }
- }
-
-
- public List Folders {
- get {
- List folders = SparkleConfig.DefaultConfig.Folders;
- folders.Sort ();
- return folders;
- }
- }
-
-
- public List PreviousHosts {
- get {
- List hosts = SparkleConfig.DefaultConfig.HostsWithUsername;
- hosts.AddRange(SparkleConfig.DefaultConfig.Hosts);
- hosts.Sort ();
- return hosts;
- }
- }
-
-
- public List UnsyncedFolders {
- get {
- List unsynced_folders = new List ();
-
- foreach (SparkleRepoBase repo in Repositories) {
- if (repo.HasUnsyncedChanges)
- unsynced_folders.Add (repo.Name);
- }
-
- return unsynced_folders;
- }
- }
-
-
- public List GetLog ()
- {
- List list = new List ();
-
- foreach (SparkleRepoBase repo in Repositories) {
- List change_sets = repo.GetChangeSets (50);
-
- 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 ();
-
- string path = new string [] {SparkleConfig.DefaultConfig.FoldersPath, name}.Combine ();
- int log_size = 50;
-
- foreach (SparkleRepoBase repo in Repositories) {
- if (repo.LocalPath.Equals (path))
- return repo.GetChangeSets (log_size);
- }
-
- 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 ();
- List emails = 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) {
- if (!emails.Contains (change_set.User.Email))
- emails.Add (change_set.User.Email);
-
- bool change_set_inserted = false;
- foreach (ActivityDay stored_activity_day in activity_days) {
- if (stored_activity_day.DateTime.Year == change_set.Timestamp.Year &&
- stored_activity_day.DateTime.Month == change_set.Timestamp.Month &&
- stored_activity_day.DateTime.Day == change_set.Timestamp.Day) {
-
- bool squash = false;
- foreach (SparkleChangeSet existing_set in stored_activity_day) {
- if (change_set.User.Name.Equals (existing_set.User.Name) &&
- change_set.User.Email.Equals (existing_set.User.Email) &&
- change_set.Folder.Equals (existing_set.Folder)) {
-
- existing_set.Added.AddRange (change_set.Added);
- existing_set.Edited.AddRange (change_set.Edited);
- existing_set.Deleted.AddRange (change_set.Deleted);
- existing_set.MovedFrom.AddRange (change_set.MovedFrom);
- existing_set.MovedTo.AddRange (change_set.MovedTo);
- existing_set.Notes.AddRange (change_set.Notes);
-
- existing_set.Added = existing_set.Added.Distinct ().ToList ();
- existing_set.Edited = existing_set.Edited.Distinct ().ToList ();
- existing_set.Deleted = existing_set.Deleted.Distinct ().ToList ();
-
- if (DateTime.Compare (existing_set.Timestamp, change_set.Timestamp) < 1) {
- existing_set.FirstTimestamp = existing_set.Timestamp;
- existing_set.Timestamp = change_set.Timestamp;
- existing_set.Revision = change_set.Revision;
-
- } else {
- existing_set.FirstTimestamp = change_set.Timestamp;
- }
-
- squash = true;
- }
- }
-
- if (!squash)
- 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);
- }
- }
-
- new Thread (new ThreadStart (delegate {
- FetchAvatars (emails, 48);
- })).Start ();
-
- 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 = "";
-
- if (change_set.IsMagical) {
- event_entry += "- Did something magical
";
-
- } else {
- if (change_set.Edited.Count > 0) {
- foreach (string file_path in change_set.Edited) {
- string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
- change_set.Folder, file_path}.Combine ();
-
- if (File.Exists (absolute_file_path))
- event_entry += "- " + file_path + "
";
- else
- event_entry += "- " + file_path + "
";
- }
- }
-
- if (change_set.Added.Count > 0) {
- foreach (string file_path in change_set.Added) {
- string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
- change_set.Folder, file_path}.Combine ();
-
- if (File.Exists (absolute_file_path))
- event_entry += "- " + file_path + "
";
- else
- event_entry += "- " + file_path + "
";
- }
- }
-
- if (change_set.Deleted.Count > 0) {
- foreach (string file_path in change_set.Deleted) {
- string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
- change_set.Folder, file_path}.Combine ();
-
- if (File.Exists (absolute_file_path))
- event_entry += "- " + file_path + "
";
- else
- event_entry += "- " + file_path + "
";
- }
- }
-
- if (change_set.MovedFrom.Count > 0) {
- int i = 0;
- foreach (string file_path in change_set.MovedFrom) {
- string to_file_path = change_set.MovedTo [i];
-
- string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
- change_set.Folder, file_path}.Combine ();
-
- string absolute_to_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
- change_set.Folder, to_file_path}.Combine ();
-
- if (File.Exists (absolute_file_path))
- event_entry += "- " + file_path + "
";
- else
- event_entry += "- " + file_path + "
";
-
- if (File.Exists (absolute_to_file_path))
- event_entry += "" + to_file_path + " ";
- else
- event_entry += to_file_path + " ";
-
- i++;
- }
- }
- }
-
- string comments = "";
- comments = "";
-
- string change_set_avatar = GetAvatar (change_set.User.Email, 48);
- if (File.Exists (change_set_avatar))
- change_set_avatar = "file://" + change_set_avatar;
- else
- change_set_avatar = "";
-
- event_entry += "
";
-
- string timestamp = change_set.Timestamp.ToString ("H:mm");
-
- if (!change_set.FirstTimestamp.Equals (new DateTime ()))
- 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 ("", timestamp)
- .Replace ("", change_set.Folder)
- .Replace ("", change_set.Revision)
- .Replace ("", AssignColor (change_set.Folder))
- .Replace ("", comments);
- }
-
- string day_entry = "";
- DateTime today = DateTime.Now;
- DateTime yesterday = DateTime.Now.AddDays (-1);
-
- if (today.Day == activity_day.DateTime.Day &&
- today.Month == activity_day.DateTime.Month &&
- today.Year == activity_day.DateTime.Year) {
-
- day_entry = day_entry_html.Replace ("", "Today");
-
- } else if (yesterday.Day == activity_day.DateTime.Day &&
- yesterday.Month == activity_day.DateTime.Month &&
- yesterday.Year == activity_day.DateTime.Year) {
-
- day_entry = day_entry_html.Replace ("", "Yesterday");
-
- } else {
- if (activity_day.DateTime.Year != DateTime.Now.Year) {
-
- // TRANSLATORS: This is the date in the event logs
- day_entry = day_entry_html.Replace ("",
- activity_day.DateTime.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.DateTime.ToString (_("dddd, MMMM d")));
- }
- }
-
- event_log += day_entry.Replace ("", event_entries);
- }
-
- string html = event_log_html.Replace ("", event_log)
- .Replace ("", UserName)
- .Replace ("", "file://" + GetAvatar (UserEmail, 48));
-
- return html;
}
// Creates a .desktop entry in autostart folder to
// start SparkleShare automatically at login
- public abstract void EnableSystemAutostart ();
+ public override void EnableSystemAutostart ()
+ {
+ string autostart_path = Path.Combine (Environment.GetFolderPath (
+ Environment.SpecialFolder.ApplicationData), "autostart");
+
+ string desktopfile_path = Path.Combine (autostart_path, "sparkleshare.desktop");
+
+ if (!Directory.Exists (autostart_path))
+ Directory.CreateDirectory (autostart_path);
+
+ if (!File.Exists (desktopfile_path)) {
+ TextWriter writer = new StreamWriter (desktopfile_path);
+ writer.WriteLine ("[Desktop Entry]\n" +
+ "Type=Application\n" +
+ "Name=SparkleShare\n" +
+ "Exec=sparkleshare start\n" +
+ "Icon=folder-sparkleshare\n" +
+ "Terminal=false\n" +
+ "X-GNOME-Autostart-enabled=true\n" +
+ "Categories=Network");
+ writer.Close ();
+
+ // Give the launcher the right permissions so it can be launched by the user
+ UnixFileInfo file_info = new UnixFileInfo (desktopfile_path);
+ file_info.Create (FileAccessPermissions.UserReadWriteExecute);
+
+ SparkleHelpers.DebugInfo ("Controller", "Enabled autostart on login");
+ }
+ }
+
// Installs a launcher so the user can launch SparkleShare
// from the Internet category if needed
- public abstract void InstallLauncher ();
+ public override void InstallLauncher ()
+ {
+ string apps_path =
+ new string [] {SparkleConfig.DefaultConfig.HomePath,
+ ".local", "share", "applications"}.Combine ();
+
+ string desktopfile_path = Path.Combine (apps_path, "sparkleshare.desktop");
+
+ if (!File.Exists (desktopfile_path)) {
+ if (!Directory.Exists (apps_path))
+ Directory.CreateDirectory (apps_path);
+
+ TextWriter writer = new StreamWriter (desktopfile_path);
+ writer.WriteLine ("[Desktop Entry]\n" +
+ "Type=Application\n" +
+ "Name=SparkleShare\n" +
+ "Comment=Share documents\n" +
+ "Exec=sparkleshare start\n" +
+ "Icon=folder-sparkleshare\n" +
+ "Terminal=false\n" +
+ "Categories=Network;");
+ writer.Close ();
+
+ // Give the launcher the right permissions so it can be launched by the user
+ UnixFileInfo file_info = new UnixFileInfo (desktopfile_path);
+ file_info.FileAccessPermissions = FileAccessPermissions.UserReadWriteExecute;
+
+ SparkleHelpers.DebugInfo ("Controller", "Created '" + desktopfile_path + "'");
+ }
+ }
+
// Adds the SparkleShare folder to the user's
// list of bookmarked places
- public abstract void AddToBookmarks ();
+ public override void AddToBookmarks ()
+ {
+ string bookmarks_file_path = Path.Combine (SparkleConfig.DefaultConfig.HomePath, ".gtk-bookmarks");
+ string sparkleshare_bookmark = "file://" + SparkleConfig.DefaultConfig.FoldersPath + " SparkleShare";
+
+ if (File.Exists (bookmarks_file_path)) {
+ StreamReader reader = new StreamReader (bookmarks_file_path);
+ string bookmarks = reader.ReadToEnd ();
+ reader.Close ();
+
+ if (!bookmarks.Contains (sparkleshare_bookmark)) {
+ TextWriter writer = File.AppendText (bookmarks_file_path);
+ writer.WriteLine ("file://" + SparkleConfig.DefaultConfig.FoldersPath + " SparkleShare");
+ writer.Close ();
+ }
+ } else {
+ StreamWriter writer = new StreamWriter (bookmarks_file_path);
+ writer.WriteLine ("file://" + SparkleConfig.DefaultConfig.FoldersPath + " SparkleShare");
+ writer.Close ();
+ }
+ }
+
// Creates the SparkleShare folder in the user's home folder
- public abstract bool CreateSparkleShareFolder ();
-
- // Opens the SparkleShare folder or an (optional) subfolder
- public abstract void OpenSparkleShareFolder (string subfolder);
-
-
- // Fires events for the current syncing state
- public void UpdateState ()
+ public override bool CreateSparkleShareFolder ()
{
- foreach (SparkleRepoBase repo in Repositories) {
- if (repo.Status == SyncStatus.SyncDown ||
- repo.Status == SyncStatus.SyncUp ||
- repo.IsBuffering) {
+ if (!Directory.Exists (SparkleConfig.DefaultConfig.FoldersPath)) {
+
+ Directory.CreateDirectory (SparkleConfig.DefaultConfig.FoldersPath);
+ SparkleHelpers.DebugInfo ("Controller", "Created '" + SparkleConfig.DefaultConfig.FoldersPath + "'");
- if (OnSyncing != null)
- OnSyncing ();
+ string gvfs_command_path =
+ new string [] {Path.VolumeSeparatorChar.ToString (),
+ "usr", "bin", "gvfs-set-attribute"}.Combine ();
- return;
+ // Add a special icon to the SparkleShare folder
+ if (File.Exists (gvfs_command_path)) {
+ Process process = new Process ();
- } else if (repo.HasUnsyncedChanges) {
- if (OnError != null)
- OnError ();
+ process.StartInfo.RedirectStandardOutput = true;
+ process.StartInfo.UseShellExecute = false;
+ process.StartInfo.FileName = "gvfs-set-attribute";
- return;
+ // Clear the custom (legacy) icon path
+ process.StartInfo.Arguments = "-t unset " + SparkleConfig.DefaultConfig.FoldersPath + " metadata::custom-icon";
+ process.Start ();
+ process.WaitForExit ();
+
+ // Give the SparkleShare folder an icon name, so that it scales
+ process.StartInfo.Arguments = SparkleConfig.DefaultConfig.FoldersPath + " metadata::custom-icon-name 'folder-sparkleshare'";
+ process.Start ();
+ process.WaitForExit ();
}
+
+ return true;
}
- if (OnIdle != null)
- OnIdle ();
-
- FolderSize = GetFolderSize ();
-
- if (FolderSizeChanged != null)
- FolderSizeChanged (FolderSize);
+ return false;
}
+
-
- // Adds a repository to the list of repositories
- private void AddRepository (string folder_path)
- {
- if (folder_path.Equals (SparkleConfig.DefaultConfig.TmpPath))
- return;
-
- string folder_name = Path.GetFileName (folder_path);
- string backend = SparkleConfig.DefaultConfig.GetBackendForFolder (folder_name);
-
- if (backend == null)
- return;
-
- SparkleRepoBase repo = new SparkleRepoGit (folder_path, SparkleBackend.DefaultBackend);
-
- repo.NewChangeSet += delegate (SparkleChangeSet change_set) {
- string message = FormatMessage (change_set);
-
- if (NotificationRaised != null)
- NotificationRaised (change_set.User.Name, change_set.User.Email, message, repo.LocalPath);
- };
-
- repo.NewNote += delegate (string user_name, string user_email) {
- if (NotificationRaised != null)
- NotificationRaised (user_name, user_email,
- "added a note to " + Path.GetFileName (repo.LocalPath), repo.LocalPath);
- };
-
- repo.ConflictResolved += delegate {
- if (ConflictNotificationRaised != null)
- ConflictNotificationRaised ();
- };
-
- repo.SyncStatusChanged += delegate (SyncStatus status) {
-/* if (status == SyncStatus.SyncUp) {
- foreach (string path in repo.UnsyncedFilePaths)
- Console.WriteLine (path);
- }
-*/
- if (status == SyncStatus.Idle ||
- status == SyncStatus.SyncUp ||
- status == SyncStatus.SyncDown ||
- status == SyncStatus.Error) {
-
- UpdateState ();
- }
- };
-
- repo.ChangesDetected += delegate {
- UpdateState ();
- };
-
- Repositories.Add (repo);
- }
-
-
- // Removes a repository from the list of repositories and
- // updates the statusicon menu
- private void RemoveRepository (string folder_path)
- {
- string folder_name = Path.GetFileName (folder_path);
-
- for (int i = 0; i < Repositories.Count; i++) {
- SparkleRepoBase repo = Repositories [i];
-
- if (repo.Name.Equals (folder_name)) {
- repo.Dispose ();
- Repositories.Remove (repo);
- repo = null;
- break;
- }
- }
- }
-
-
- // Updates the list of repositories with all the
- // folders in the SparkleShare folder
- private void PopulateRepositories ()
- {
- Repositories = new List ();
-
- foreach (string folder_name in SparkleConfig.DefaultConfig.Folders) {
- string folder_path = new SparkleFolder (folder_name).FullPath;
-
- if (Directory.Exists (folder_path))
- AddRepository (folder_path);
- else
- SparkleConfig.DefaultConfig.RemoveFolder (folder_name);
- }
-
- if (FolderListChanged != null)
- FolderListChanged ();
-
- FolderSize = GetFolderSize ();
-
- if (FolderSizeChanged != null)
- FolderSizeChanged (FolderSize);
- }
-
-
- public bool NotificationsEnabled {
+ public override string EventLogHTML {
get {
- string notifications_enabled =
- SparkleConfig.DefaultConfig.GetConfigOption ("notifications");
+ string path = new string [] {Defines.PREFIX,
+ "share", "sparkleshare", "html", "event-log.html"}.Combine ();
- if (String.IsNullOrEmpty (notifications_enabled)) {
- SparkleConfig.DefaultConfig.SetConfigOption ("notifications", bool.TrueString);
- return true;
+ string html = String.Join (Environment.NewLine, File.ReadAllLines (path));
- } else {
- return notifications_enabled.Equals (bool.TrueString);
- }
+ html = html.Replace ("", "file://" +
+ new string [] {Defines.PREFIX, "share", "sparkleshare", "html", "jquery.js"}.Combine ());
+
+ return html;
}
- }
-
-
- public void ToggleNotifications () {
- bool notifications_enabled =
- SparkleConfig.DefaultConfig.GetConfigOption ("notifications")
- .Equals (bool.TrueString);
-
- if (notifications_enabled)
- SparkleConfig.DefaultConfig.SetConfigOption ("notifications", bool.FalseString);
- else
- SparkleConfig.DefaultConfig.SetConfigOption ("notifications", bool.TrueString);
- }
-
-
- private string GetFolderSize ()
- {
- double folder_size = CalculateFolderSize (
- new DirectoryInfo (SparkleConfig.DefaultConfig.FoldersPath));
-
- return FormatFolderSize (folder_size);
- }
-
-
- private string FormatMessage (SparkleChangeSet change_set)
- {
- string file_name = "";
- string message = "";
-
- if (change_set.Added.Count > 0) {
- file_name = change_set.Added [0];
- message = String.Format (_("added ‘{0}’"), file_name);
- }
-
- if (change_set.MovedFrom.Count > 0) {
- file_name = change_set.MovedFrom [0];
- message = String.Format (_("moved ‘{0}’"), file_name);
- }
-
- if (change_set.Edited.Count > 0) {
- file_name = change_set.Edited [0];
- message = String.Format (_("edited ‘{0}’"), file_name);
- }
-
- if (change_set.Deleted.Count > 0) {
- file_name = change_set.Deleted [0];
- message = String.Format (_("deleted ‘{0}’"), file_name);
- }
-
- int changes_count = (change_set.Added.Count +
- change_set.Edited.Count +
- change_set.Deleted.Count +
- change_set.MovedFrom.Count) - 1;
-
- if (changes_count > 0) {
- string msg = Catalog.GetPluralString ("and {0} more", "and {0} more", changes_count);
- message += " " + String.Format (msg, changes_count);
-
- } else if (changes_count < 0) {
- message += _("did something magical");
- }
-
- return message;
- } // TODO: move to bubbles controller
-
-
- // Recursively gets a folder's size in bytes
- private double CalculateFolderSize (DirectoryInfo parent)
- {
- if (!Directory.Exists (parent.ToString ()))
- return 0;
-
- double size = 0;
-
- // Ignore the temporary 'rebase-apply' and '.tmp' directories. This prevents potential
- // crashes when files are being queried whilst the files have already been deleted.
- if (parent.Name.Equals ("rebase-apply") ||
- parent.Name.Equals (".tmp"))
- return 0;
-
- try {
- foreach (FileInfo file in parent.GetFiles()) {
- if (!file.Exists)
- return 0;
-
- size += file.Length;
- }
-
- foreach (DirectoryInfo directory in parent.GetDirectories())
- size += CalculateFolderSize (directory);
-
- } catch (Exception) {
- return 0;
- }
-
- return size;
- }
-
-
- // Format a file size nicely with small caps.
- // Example: 1048576 becomes "1 ᴍʙ"
- private string FormatFolderSize (double byte_count)
- {
- 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, 1));
- else if (byte_count >= 1024)
- return String.Format ("{0:##.##} ᴋʙ", Math.Round (byte_count / 1024, 1));
- else
- return byte_count.ToString () + " bytes";
- }
-
-
- public void OpenSparkleShareFolder ()
- {
- OpenSparkleShareFolder ("");
}
- // Adds the user's SparkleShare key to the ssh-agent,
- // so all activity is done with this key
- public void AddKey ()
+ public override string DayEntryHTML {
+ get {
+ string path = new string [] {Defines.PREFIX,
+ "share", "sparkleshare", "html", "day-entry.html"}.Combine ();
+
+ return String.Join (Environment.NewLine, File.ReadAllLines (path));
+ }
+ }
+
+
+ public override string EventEntryHTML {
+ get {
+ string path = new string [] {Defines.PREFIX,
+ "share", "sparkleshare", "html", "event-entry.html"}.Combine ();
+
+ return String.Join (Environment.NewLine, File.ReadAllLines (path));
+ }
+ }
+
+
+ public override void OpenSparkleShareFolder (string subfolder)
{
- string keys_path = Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath);
- string key_file_name = "sparkleshare." + UserEmail + ".key";
+ string folder = Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, subfolder);
Process process = new Process ();
- process.StartInfo.RedirectStandardOutput = true;
- process.StartInfo.UseShellExecute = false;
- process.StartInfo.FileName = "ssh-add";
- process.StartInfo.Arguments = "\"" + Path.Combine (keys_path, key_file_name) + "\"";
+ process.StartInfo.FileName = "xdg-open";
+ process.StartInfo.Arguments = "\"" + folder + "\"";
process.Start ();
- process.WaitForExit ();
- }
-
-
- public bool BackendIsPresent {
- get {
- return SparkleBackend.DefaultBackend.IsPresent;
- }
- }
-
-
- // Looks up the user's name from the global configuration
- public string UserName
- {
- get {
- return SparkleConfig.DefaultConfig.User.Name;
- }
-
- set {
- SparkleConfig.DefaultConfig.User = new SparkleUser (value, UserEmail);
- }
- }
-
-
- // Looks up the user's email from the global configuration
- public string UserEmail
- {
- get {
- return SparkleConfig.DefaultConfig.User.Email;
- }
-
- set {
- SparkleConfig.DefaultConfig.User = new SparkleUser (UserName, value);
- }
- }
-
-
- // Generates and installs an RSA keypair to identify this system
- public void GenerateKeyPair ()
- {
- string keys_path = Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath);
- string key_file_name = "sparkleshare." + UserEmail + ".key";
- string key_file_path = Path.Combine (keys_path, key_file_name);
-
- if (File.Exists (key_file_path)) {
- SparkleHelpers.DebugInfo ("Config", "Key already exists ('" + key_file_name + "'), " +
- "leaving it untouched");
- return;
- }
-
- if (!Directory.Exists (keys_path))
- Directory.CreateDirectory (keys_path);
-
- if (!File.Exists (key_file_name)) {
- Process process = new Process () {
- EnableRaisingEvents = true
- };
-
- process.StartInfo.WorkingDirectory = keys_path;
- process.StartInfo.UseShellExecute = false;
- process.StartInfo.RedirectStandardOutput = true;
- process.StartInfo.FileName = "ssh-keygen";
-
- // -t is the crypto type
- // -P is the password (none)
- // -f is the file name to store the private key in
- process.StartInfo.Arguments = "-t rsa -P \"\" -f " + key_file_name;
-
- process.Exited += delegate {
- SparkleHelpers.DebugInfo ("Config", "Created private key '" + key_file_name + "'");
- SparkleHelpers.DebugInfo ("Config", "Created public key '" + key_file_name + ".pub'");
-
- // Create an easily accessible copy of the public
- // key in the user's SparkleShare folder
- File.Copy (key_file_path + ".pub",
- Path.Combine (SparklePath, UserName + "'s key.txt"));
- };
-
- process.Start ();
- process.WaitForExit ();
- }
- }
-
-
- // Gets the avatar for a specific email address and size
- public void FetchAvatars (List emails, int size)
- {
- List old_avatars = new List ();
- bool avatar_fetched = false;
- string avatar_path = new string [] {
- Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath),
- "icons", size + "x" + size, "status"}.Combine ();
-
- if (!Directory.Exists (avatar_path)) {
- Directory.CreateDirectory (avatar_path);
- SparkleHelpers.DebugInfo ("Config", "Created '" + avatar_path + "'");
- }
-
- foreach (string raw_email in emails) {
-
- // Gravatar wants lowercase emails
- string email = raw_email.ToLower ();
- string avatar_file_path = Path.Combine (avatar_path, "avatar-" + email);
-
- if (File.Exists (avatar_file_path)) {
- FileInfo avatar_info = new FileInfo (avatar_file_path);
-
- // Delete avatars older than a month
- if (avatar_info.CreationTime < DateTime.Now.AddMonths (-1)) {
- avatar_info.Delete ();
- old_avatars.Add (email);
- }
-
- } else {
- WebClient client = new WebClient ();
- string url = "http://gravatar.com/avatar/" + GetMD5 (email) +
- ".jpg?s=" + size + "&d=404";
-
- try {
- // Fetch the avatar
- byte [] buffer = client.DownloadData (url);
-
- // Write the avatar data to a
- // if not empty
- if (buffer.Length > 255) {
- avatar_fetched = true;
- File.WriteAllBytes (avatar_file_path, buffer);
- SparkleHelpers.DebugInfo ("Controller", "Fetched gravatar for " + email);
- }
-
- } catch (WebException e) {
- SparkleHelpers.DebugInfo ("Controller", "Failed fetching gravatar for " + email);
-
- // Stop downloading further avatars if we have no internet access
- if (e.Status == WebExceptionStatus.Timeout)
- break;
- }
- }
- }
-
- // Fetch new versions of the avatars that we
- // deleted because they were too old
- if (old_avatars.Count > 0)
- FetchAvatars (old_avatars, size);
-
- if (AvatarFetched != null && avatar_fetched)
- AvatarFetched ();
- }
-
-
- public string GetAvatar (string email, int size)
- {
- string avatar_file_path = SparkleHelpers.CombineMore (
- Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath), "icons",
- size + "x" + size, "status", "avatar-" + email);
-
- return avatar_file_path;
- }
-
-
- public void FetchFolder (string server, string remote_folder)
- {
- server = server.Trim ();
- remote_folder = remote_folder.Trim ();
-
- string tmp_path = SparkleConfig.DefaultConfig.TmpPath;
- if (!Directory.Exists (tmp_path))
- Directory.CreateDirectory (tmp_path);
-
- // Strip the '.git' from the name
- string canonical_name = Path.GetFileNameWithoutExtension (remote_folder);
- string tmp_folder = Path.Combine (tmp_path, canonical_name);
-
- string backend = null;
-
-/* if (remote_folder.EndsWith (".hg")) {
- remote_folder = remote_folder.Substring (0, (remote_folder.Length - 3));
- fetcher = new SparkleFetcherHg (server, remote_folder, tmp_folder);
- backend = "Hg";
-
- } else if (remote_folder.EndsWith (".scp")) {
- remote_folder = remote_folder.Substring (0, (remote_folder.Length - 4));
- fetcher = new SparkleFetcherScp (server, remote_folder, tmp_folder);
- backend = "Scp";
-
- } else {*/
- this.fetcher = new SparkleFetcherGit (server, remote_folder, tmp_folder);
- backend = "Git";
- //}
-
- bool target_folder_exists = Directory.Exists (
- Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, canonical_name));
-
- // Add a numbered suffix to the nameif a folder with the same name
- // already exists. Example: "Folder (2)"
- int i = 1;
- while (target_folder_exists) {
- i++;
- target_folder_exists = Directory.Exists (
- Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, canonical_name + " (" + i + ")"));
- }
-
- string target_folder_name = canonical_name;
- if (i > 1)
- target_folder_name += " (" + i + ")";
-
- this.fetcher.Finished += delegate {
-
- // Needed to do the moving
- SparkleHelpers.ClearAttributes (tmp_folder);
- string target_folder_path = Path.Combine (
- SparkleConfig.DefaultConfig.FoldersPath, target_folder_name);
-
- try {
- Directory.Move (tmp_folder, target_folder_path);
- } catch (Exception e) {
- SparkleHelpers.DebugInfo ("Controller", "Error moving folder: " + e.Message);
- }
-
- SparkleConfig.DefaultConfig.AddFolder (target_folder_name, this.fetcher.RemoteUrl, backend);
- AddRepository (target_folder_path);
-
- if (FolderFetched != null)
- FolderFetched ();
-
- FolderSize = GetFolderSize ();
-
- if (FolderSizeChanged != null)
- FolderSizeChanged (FolderSize);
-
- if (FolderListChanged != null)
- FolderListChanged ();
-
- this.fetcher.Dispose ();
-
- if (Directory.Exists (tmp_path))
- Directory.Delete (tmp_path, true);
- };
-
-
- this.fetcher.Failed += delegate {
- if (FolderFetchError != null)
- FolderFetchError (this.fetcher.RemoteUrl);
-
- this.fetcher.Dispose ();
-
- if (Directory.Exists (tmp_path))
- Directory.Delete (tmp_path, true);
- };
-
-
- this.fetcher.ProgressChanged += delegate (double percentage) {
- if (FolderFetching != null)
- FolderFetching (percentage);
- };
-
-
- this.fetcher.Start ();
- }
-
-
- public void StopFetcher ()
- {
- if (fetcher != null)
- fetcher.Stop ();
- }
-
-
- // Creates an MD5 hash of input
- private string GetMD5 (string s)
- {
- MD5 md5 = new MD5CryptoServiceProvider ();
- Byte[] bytes = ASCIIEncoding.Default.GetBytes (s);
- Byte[] encoded_bytes = md5.ComputeHash (bytes);
- return BitConverter.ToString (encoded_bytes).ToLower ().Replace ("-", "");
- }
-
-
- // Checks whether there are any folders syncing and
- // quits if safe
- public void TryQuit ()
- {
- foreach (SparkleRepoBase repo in Repositories) {
- if (repo.Status == SyncStatus.SyncUp ||
- repo.Status == SyncStatus.SyncDown ||
- repo.IsBuffering) {
-
- if (OnQuitWhileSyncing != null)
- OnQuitWhileSyncing ();
-
- return;
- }
- }
-
- Quit ();
- }
-
-
- public void Quit ()
- {
- foreach (SparkleRepoBase repo in Repositories)
- repo.Dispose ();
-
- Environment.Exit (0);
- }
-
-
- // Checks to see if an email address is valid
- public bool IsValidEmail (string email)
- {
- Regex regex = new Regex (@"^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$", RegexOptions.IgnoreCase);
- return regex.IsMatch (email);
- }
-
-
-
-
- public void AddNoteToFolder (string folder_name, string revision, string note)
- {
- folder_name = folder_name.Replace ("%20", " ");
- note = note.Replace ("%20", " ");
-
- foreach (SparkleRepoBase repo in Repositories) {
- if (repo.Name.Equals (folder_name))
- repo.AddNote (revision, note);
- }
- }
-
-
-
-
- private string [] tango_palette = new string [] {"#eaab00", "#e37222",
- "#3892ab", "#33c2cb", "#19b271", "#9eab05", "#8599a8", "#9ca696",
- "#b88454", "#cc0033", "#8f6678", "#8c6cd0", "#796cbf", "#4060af",
- "#aa9c8f", "#818a8f"};
-
- private string AssignColor (string s)
- {
- string hash = GetMD5 (s).Substring (0, 8);
- string numbers = Regex.Replace (hash, "[a-z]", "");
- int number = 3 + int.Parse (numbers);
- return this.tango_palette [number % this.tango_palette.Length];
- }
- }
-
-
- public class ChangeSet : SparkleChangeSet { }
-
-
- // All change sets that happened on a day
- public class ActivityDay : List
- {
- public DateTime DateTime;
-
- public ActivityDay (DateTime date_time)
- {
- DateTime = date_time;
- DateTime = new DateTime (DateTime.Year, DateTime.Month, DateTime.Day);
}
}
}
diff --git a/SparkleShare/SparkleControllerBase.cs b/SparkleShare/SparkleControllerBase.cs
new file mode 100755
index 00000000..79d38140
--- /dev/null
+++ b/SparkleShare/SparkleControllerBase.cs
@@ -0,0 +1,1169 @@
+// SparkleShare, a collaboration and sharing tool.
+// Copyright (C) 2010 Hylke Bons
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU 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 .
+
+
+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;
+using System.Xml;
+
+using Mono.Unix;
+using SparkleLib;
+
+namespace SparkleShare {
+
+ public abstract class SparkleControllerBase {
+
+ public List Repositories;
+ public string FolderSize;
+ public readonly string SparklePath = SparkleConfig.DefaultConfig.FoldersPath;
+
+ public event OnQuitWhileSyncingEventHandler OnQuitWhileSyncing;
+ public delegate void OnQuitWhileSyncingEventHandler ();
+
+ public event FolderFetchedEventHandler FolderFetched;
+ public delegate void FolderFetchedEventHandler ();
+
+ public event FolderFetchErrorEventHandler FolderFetchError;
+ public delegate void FolderFetchErrorEventHandler (string remote_url);
+
+ public event FolderFetchingEventHandler FolderFetching;
+ public delegate void FolderFetchingEventHandler (double percentage);
+
+ public event FolderListChangedEventHandler FolderListChanged;
+ public delegate void FolderListChangedEventHandler ();
+
+ public event FolderSizeChangedEventHandler FolderSizeChanged;
+ public delegate void FolderSizeChangedEventHandler (string folder_size);
+
+ public event AvatarFetchedEventHandler AvatarFetched;
+ public delegate void AvatarFetchedEventHandler ();
+
+ public event OnIdleEventHandler OnIdle;
+ public delegate void OnIdleEventHandler ();
+
+ public event OnSyncingEventHandler OnSyncing;
+ public delegate void OnSyncingEventHandler ();
+
+ public event OnErrorEventHandler OnError;
+ public delegate void OnErrorEventHandler ();
+
+ public event OnInvitationEventHandler OnInvitation;
+ public delegate void OnInvitationEventHandler (string server, string folder, string token);
+
+ public event ConflictNotificationRaisedEventHandler ConflictNotificationRaised;
+ public delegate void ConflictNotificationRaisedEventHandler ();
+
+ public event NotificationRaisedEventHandler NotificationRaised;
+ public delegate void NotificationRaisedEventHandler (string user_name, string user_email,
+ string message, string repository_path);
+
+ private SparkleFetcherBase fetcher;
+
+
+ // Short alias for the translations
+ public static string _ (string s)
+ {
+ return Catalog.GetString (s);
+ }
+
+
+ public SparkleControllerBase ()
+ {
+ }
+
+
+ public virtual void Initialize ()
+ {
+ InstallLauncher ();
+ EnableSystemAutostart ();
+
+ // Create the SparkleShare folder and add it to the bookmarks
+ if (CreateSparkleShareFolder ())
+ AddToBookmarks ();
+
+ FolderSize = GetFolderSize ();
+
+ if (FirstRun)
+ SparkleConfig.DefaultConfig.SetConfigOption ("notifications", bool.TrueString);
+ else
+ AddKey ();
+
+ // Watch the SparkleShare folder
+ FileSystemWatcher watcher = new FileSystemWatcher (SparkleConfig.DefaultConfig.FoldersPath) {
+ IncludeSubdirectories = false,
+ EnableRaisingEvents = true,
+ Filter = "*"
+ };
+
+ // Remove the repository when a delete event occurs
+ watcher.Deleted += delegate (object o, FileSystemEventArgs args) {
+ RemoveRepository (args.FullPath);
+ SparkleConfig.DefaultConfig.RemoveFolder (Path.GetFileName (args.Name));
+
+ if (FolderListChanged != null)
+ FolderListChanged ();
+
+ FolderSize = GetFolderSize ();
+
+ if (FolderSizeChanged != null)
+ FolderSizeChanged (FolderSize);
+ };
+
+
+ watcher.Created += delegate (object o, FileSystemEventArgs args) {
+
+ // Handle invitations when the user saves an
+ // invitation into the SparkleShare folder
+ if (args.Name.EndsWith (".sparkle") && !FirstRun) {
+ XmlDocument xml_doc = new XmlDocument ();
+ xml_doc.Load (args.Name);
+
+ string server = xml_doc.GetElementsByTagName ("server") [0].InnerText;
+ string folder = xml_doc.GetElementsByTagName ("folder") [0].InnerText;
+ string token = xml_doc.GetElementsByTagName ("token") [0].InnerText;
+
+ // FIXME: this is broken :\
+ if (OnInvitation != null)
+ OnInvitation (server, folder, token);
+ }
+ };
+
+ new Thread (new ThreadStart (PopulateRepositories)).Start ();
+ }
+
+
+ public bool FirstRun {
+ get {
+ return SparkleConfig.DefaultConfig.User.Email.Equals ("Unknown");
+ }
+ }
+
+
+ // Uploads the user's public key to the server
+ public bool AcceptInvitation (string server, string folder, string token)
+ {
+ // The location of the user's public key for SparkleShare
+ string public_key_file_path = SparkleHelpers.CombineMore (SparkleConfig.DefaultConfig.HomePath, ".ssh",
+ "sparkleshare." + UserEmail + ".key.pub");
+
+ if (!File.Exists (public_key_file_path))
+ return false;
+
+ StreamReader reader = new StreamReader (public_key_file_path);
+ string public_key = reader.ReadToEnd ();
+ reader.Close ();
+
+ string url = "https://" + server + "/?folder=" + folder +
+ "&token=" + token + "&pubkey=" + public_key;
+
+ SparkleHelpers.DebugInfo ("WebRequest", url);
+
+ HttpWebRequest request = (HttpWebRequest) WebRequest.Create (url);
+ HttpWebResponse response = (HttpWebResponse) request.GetResponse();
+
+ if (response.StatusCode == HttpStatusCode.OK) {
+ response.Close ();
+ return true;
+
+ } else {
+ response.Close ();
+ return false;
+ }
+ }
+
+
+ public List Folders {
+ get {
+ List folders = SparkleConfig.DefaultConfig.Folders;
+ folders.Sort ();
+ return folders;
+ }
+ }
+
+
+ public List PreviousHosts {
+ get {
+ List hosts = SparkleConfig.DefaultConfig.HostsWithUsername;
+ hosts.AddRange(SparkleConfig.DefaultConfig.Hosts);
+ hosts.Sort ();
+ return hosts;
+ }
+ }
+
+
+ public List UnsyncedFolders {
+ get {
+ List unsynced_folders = new List ();
+
+ foreach (SparkleRepoBase repo in Repositories) {
+ if (repo.HasUnsyncedChanges)
+ unsynced_folders.Add (repo.Name);
+ }
+
+ return unsynced_folders;
+ }
+ }
+
+
+ public List GetLog ()
+ {
+ List list = new List ();
+
+ foreach (SparkleRepoBase repo in Repositories) {
+ List change_sets = repo.GetChangeSets (50);
+
+ 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 ();
+
+ string path = new string [] {SparkleConfig.DefaultConfig.FoldersPath, name}.Combine ();
+ int log_size = 50;
+
+ foreach (SparkleRepoBase repo in Repositories) {
+ if (repo.LocalPath.Equals (path))
+ return repo.GetChangeSets (log_size);
+ }
+
+ 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 ();
+ List emails = 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) {
+ if (!emails.Contains (change_set.User.Email))
+ emails.Add (change_set.User.Email);
+
+ bool change_set_inserted = false;
+ foreach (ActivityDay stored_activity_day in activity_days) {
+ if (stored_activity_day.DateTime.Year == change_set.Timestamp.Year &&
+ stored_activity_day.DateTime.Month == change_set.Timestamp.Month &&
+ stored_activity_day.DateTime.Day == change_set.Timestamp.Day) {
+
+ bool squash = false;
+ foreach (SparkleChangeSet existing_set in stored_activity_day) {
+ if (change_set.User.Name.Equals (existing_set.User.Name) &&
+ change_set.User.Email.Equals (existing_set.User.Email) &&
+ change_set.Folder.Equals (existing_set.Folder)) {
+
+ existing_set.Added.AddRange (change_set.Added);
+ existing_set.Edited.AddRange (change_set.Edited);
+ existing_set.Deleted.AddRange (change_set.Deleted);
+ existing_set.MovedFrom.AddRange (change_set.MovedFrom);
+ existing_set.MovedTo.AddRange (change_set.MovedTo);
+ existing_set.Notes.AddRange (change_set.Notes);
+
+ existing_set.Added = existing_set.Added.Distinct ().ToList ();
+ existing_set.Edited = existing_set.Edited.Distinct ().ToList ();
+ existing_set.Deleted = existing_set.Deleted.Distinct ().ToList ();
+
+ if (DateTime.Compare (existing_set.Timestamp, change_set.Timestamp) < 1) {
+ existing_set.FirstTimestamp = existing_set.Timestamp;
+ existing_set.Timestamp = change_set.Timestamp;
+ existing_set.Revision = change_set.Revision;
+
+ } else {
+ existing_set.FirstTimestamp = change_set.Timestamp;
+ }
+
+ squash = true;
+ }
+ }
+
+ if (!squash)
+ 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);
+ }
+ }
+
+ new Thread (new ThreadStart (delegate {
+ FetchAvatars (emails, 48);
+ })).Start ();
+
+ 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 = "";
+
+ if (change_set.IsMagical) {
+ event_entry += "- Did something magical
";
+
+ } else {
+ if (change_set.Edited.Count > 0) {
+ foreach (string file_path in change_set.Edited) {
+ string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
+ change_set.Folder, file_path}.Combine ();
+
+ if (File.Exists (absolute_file_path))
+ event_entry += "- " + file_path + "
";
+ else
+ event_entry += "- " + file_path + "
";
+ }
+ }
+
+ if (change_set.Added.Count > 0) {
+ foreach (string file_path in change_set.Added) {
+ string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
+ change_set.Folder, file_path}.Combine ();
+
+ if (File.Exists (absolute_file_path))
+ event_entry += "- " + file_path + "
";
+ else
+ event_entry += "- " + file_path + "
";
+ }
+ }
+
+ if (change_set.Deleted.Count > 0) {
+ foreach (string file_path in change_set.Deleted) {
+ string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
+ change_set.Folder, file_path}.Combine ();
+
+ if (File.Exists (absolute_file_path))
+ event_entry += "- " + file_path + "
";
+ else
+ event_entry += "- " + file_path + "
";
+ }
+ }
+
+ if (change_set.MovedFrom.Count > 0) {
+ int i = 0;
+ foreach (string file_path in change_set.MovedFrom) {
+ string to_file_path = change_set.MovedTo [i];
+
+ string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
+ change_set.Folder, file_path}.Combine ();
+
+ string absolute_to_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
+ change_set.Folder, to_file_path}.Combine ();
+
+ if (File.Exists (absolute_file_path))
+ event_entry += "- " + file_path + "
";
+ else
+ event_entry += "- " + file_path + "
";
+
+ if (File.Exists (absolute_to_file_path))
+ event_entry += "" + to_file_path + " ";
+ else
+ event_entry += to_file_path + " ";
+
+ i++;
+ }
+ }
+ }
+
+ string comments = "";
+ comments = "";
+
+ string change_set_avatar = GetAvatar (change_set.User.Email, 48);
+ if (File.Exists (change_set_avatar))
+ change_set_avatar = "file://" + change_set_avatar;
+ else
+ change_set_avatar = "";
+
+ event_entry += "
";
+
+ string timestamp = change_set.Timestamp.ToString ("H:mm");
+
+ if (!change_set.FirstTimestamp.Equals (new DateTime ()))
+ 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 ("", timestamp)
+ .Replace ("", change_set.Folder)
+ .Replace ("", change_set.Revision)
+ .Replace ("", AssignColor (change_set.Folder))
+ .Replace ("", comments);
+ }
+
+ string day_entry = "";
+ DateTime today = DateTime.Now;
+ DateTime yesterday = DateTime.Now.AddDays (-1);
+
+ if (today.Day == activity_day.DateTime.Day &&
+ today.Month == activity_day.DateTime.Month &&
+ today.Year == activity_day.DateTime.Year) {
+
+ day_entry = day_entry_html.Replace ("", "Today");
+
+ } else if (yesterday.Day == activity_day.DateTime.Day &&
+ yesterday.Month == activity_day.DateTime.Month &&
+ yesterday.Year == activity_day.DateTime.Year) {
+
+ day_entry = day_entry_html.Replace ("", "Yesterday");
+
+ } else {
+ if (activity_day.DateTime.Year != DateTime.Now.Year) {
+
+ // TRANSLATORS: This is the date in the event logs
+ day_entry = day_entry_html.Replace ("",
+ activity_day.DateTime.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.DateTime.ToString (_("dddd, MMMM d")));
+ }
+ }
+
+ event_log += day_entry.Replace ("", event_entries);
+ }
+
+ string html = event_log_html.Replace ("", event_log)
+ .Replace ("", UserName)
+ .Replace ("", "file://" + GetAvatar (UserEmail, 48));
+
+ return html;
+ }
+
+
+ // Creates a .desktop entry in autostart folder to
+ // start SparkleShare automatically at login
+ public abstract void EnableSystemAutostart ();
+
+ // Installs a launcher so the user can launch SparkleShare
+ // from the Internet category if needed
+ public abstract void InstallLauncher ();
+
+ // Adds the SparkleShare folder to the user's
+ // list of bookmarked places
+ public abstract void AddToBookmarks ();
+
+ // Creates the SparkleShare folder in the user's home folder
+ public abstract bool CreateSparkleShareFolder ();
+
+ // Opens the SparkleShare folder or an (optional) subfolder
+ public abstract void OpenSparkleShareFolder (string subfolder);
+
+
+ // Fires events for the current syncing state
+ public void UpdateState ()
+ {
+ foreach (SparkleRepoBase repo in Repositories) {
+ if (repo.Status == SyncStatus.SyncDown ||
+ repo.Status == SyncStatus.SyncUp ||
+ repo.IsBuffering) {
+
+ if (OnSyncing != null)
+ OnSyncing ();
+
+ return;
+
+ } else if (repo.HasUnsyncedChanges) {
+ if (OnError != null)
+ OnError ();
+
+ return;
+ }
+ }
+
+ if (OnIdle != null)
+ OnIdle ();
+
+ FolderSize = GetFolderSize ();
+
+ if (FolderSizeChanged != null)
+ FolderSizeChanged (FolderSize);
+ }
+
+
+ // Adds a repository to the list of repositories
+ private void AddRepository (string folder_path)
+ {
+ if (folder_path.Equals (SparkleConfig.DefaultConfig.TmpPath))
+ return;
+
+ string folder_name = Path.GetFileName (folder_path);
+ string backend = SparkleConfig.DefaultConfig.GetBackendForFolder (folder_name);
+
+ if (backend == null)
+ return;
+
+ SparkleRepoBase repo = new SparkleRepoGit (folder_path, SparkleBackend.DefaultBackend);
+
+ repo.NewChangeSet += delegate (SparkleChangeSet change_set) {
+ string message = FormatMessage (change_set);
+
+ if (NotificationRaised != null)
+ NotificationRaised (change_set.User.Name, change_set.User.Email, message, repo.LocalPath);
+ };
+
+ repo.NewNote += delegate (string user_name, string user_email) {
+ if (NotificationRaised != null)
+ NotificationRaised (user_name, user_email,
+ "added a note to " + Path.GetFileName (repo.LocalPath), repo.LocalPath);
+ };
+
+ repo.ConflictResolved += delegate {
+ if (ConflictNotificationRaised != null)
+ ConflictNotificationRaised ();
+ };
+
+ repo.SyncStatusChanged += delegate (SyncStatus status) {
+/* if (status == SyncStatus.SyncUp) {
+ foreach (string path in repo.UnsyncedFilePaths)
+ Console.WriteLine (path);
+ }
+*/
+ if (status == SyncStatus.Idle ||
+ status == SyncStatus.SyncUp ||
+ status == SyncStatus.SyncDown ||
+ status == SyncStatus.Error) {
+
+ UpdateState ();
+ }
+ };
+
+ repo.ChangesDetected += delegate {
+ UpdateState ();
+ };
+
+ Repositories.Add (repo);
+ }
+
+
+ // Removes a repository from the list of repositories and
+ // updates the statusicon menu
+ private void RemoveRepository (string folder_path)
+ {
+ string folder_name = Path.GetFileName (folder_path);
+
+ for (int i = 0; i < Repositories.Count; i++) {
+ SparkleRepoBase repo = Repositories [i];
+
+ if (repo.Name.Equals (folder_name)) {
+ repo.Dispose ();
+ Repositories.Remove (repo);
+ repo = null;
+ break;
+ }
+ }
+ }
+
+
+ // Updates the list of repositories with all the
+ // folders in the SparkleShare folder
+ private void PopulateRepositories ()
+ {
+ Repositories = new List ();
+
+ foreach (string folder_name in SparkleConfig.DefaultConfig.Folders) {
+ string folder_path = new SparkleFolder (folder_name).FullPath;
+
+ if (Directory.Exists (folder_path))
+ AddRepository (folder_path);
+ else
+ SparkleConfig.DefaultConfig.RemoveFolder (folder_name);
+ }
+
+ if (FolderListChanged != null)
+ FolderListChanged ();
+
+ FolderSize = GetFolderSize ();
+
+ if (FolderSizeChanged != null)
+ FolderSizeChanged (FolderSize);
+ }
+
+
+ public bool NotificationsEnabled {
+ get {
+ string notifications_enabled =
+ SparkleConfig.DefaultConfig.GetConfigOption ("notifications");
+
+ if (String.IsNullOrEmpty (notifications_enabled)) {
+ SparkleConfig.DefaultConfig.SetConfigOption ("notifications", bool.TrueString);
+ return true;
+
+ } else {
+ return notifications_enabled.Equals (bool.TrueString);
+ }
+ }
+ }
+
+
+ public void ToggleNotifications () {
+ bool notifications_enabled =
+ SparkleConfig.DefaultConfig.GetConfigOption ("notifications")
+ .Equals (bool.TrueString);
+
+ if (notifications_enabled)
+ SparkleConfig.DefaultConfig.SetConfigOption ("notifications", bool.FalseString);
+ else
+ SparkleConfig.DefaultConfig.SetConfigOption ("notifications", bool.TrueString);
+ }
+
+
+ private string GetFolderSize ()
+ {
+ double folder_size = CalculateFolderSize (
+ new DirectoryInfo (SparkleConfig.DefaultConfig.FoldersPath));
+
+ return FormatFolderSize (folder_size);
+ }
+
+
+ private string FormatMessage (SparkleChangeSet change_set)
+ {
+ string file_name = "";
+ string message = "";
+
+ if (change_set.Added.Count > 0) {
+ file_name = change_set.Added [0];
+ message = String.Format (_("added ‘{0}’"), file_name);
+ }
+
+ if (change_set.MovedFrom.Count > 0) {
+ file_name = change_set.MovedFrom [0];
+ message = String.Format (_("moved ‘{0}’"), file_name);
+ }
+
+ if (change_set.Edited.Count > 0) {
+ file_name = change_set.Edited [0];
+ message = String.Format (_("edited ‘{0}’"), file_name);
+ }
+
+ if (change_set.Deleted.Count > 0) {
+ file_name = change_set.Deleted [0];
+ message = String.Format (_("deleted ‘{0}’"), file_name);
+ }
+
+ int changes_count = (change_set.Added.Count +
+ change_set.Edited.Count +
+ change_set.Deleted.Count +
+ change_set.MovedFrom.Count) - 1;
+
+ if (changes_count > 0) {
+ string msg = Catalog.GetPluralString ("and {0} more", "and {0} more", changes_count);
+ message += " " + String.Format (msg, changes_count);
+
+ } else if (changes_count < 0) {
+ message += _("did something magical");
+ }
+
+ return message;
+ } // TODO: move to bubbles controller
+
+
+ // Recursively gets a folder's size in bytes
+ private double CalculateFolderSize (DirectoryInfo parent)
+ {
+ if (!Directory.Exists (parent.ToString ()))
+ return 0;
+
+ double size = 0;
+
+ // Ignore the temporary 'rebase-apply' and '.tmp' directories. This prevents potential
+ // crashes when files are being queried whilst the files have already been deleted.
+ if (parent.Name.Equals ("rebase-apply") ||
+ parent.Name.Equals (".tmp"))
+ return 0;
+
+ try {
+ foreach (FileInfo file in parent.GetFiles()) {
+ if (!file.Exists)
+ return 0;
+
+ size += file.Length;
+ }
+
+ foreach (DirectoryInfo directory in parent.GetDirectories())
+ size += CalculateFolderSize (directory);
+
+ } catch (Exception) {
+ return 0;
+ }
+
+ return size;
+ }
+
+
+ // Format a file size nicely with small caps.
+ // Example: 1048576 becomes "1 ᴍʙ"
+ private string FormatFolderSize (double byte_count)
+ {
+ 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, 1));
+ else if (byte_count >= 1024)
+ return String.Format ("{0:##.##} ᴋʙ", Math.Round (byte_count / 1024, 1));
+ else
+ return byte_count.ToString () + " bytes";
+ }
+
+
+ public void OpenSparkleShareFolder ()
+ {
+ OpenSparkleShareFolder ("");
+ }
+
+
+ // Adds the user's SparkleShare key to the ssh-agent,
+ // so all activity is done with this key
+ public void AddKey ()
+ {
+ string keys_path = Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath);
+ string key_file_name = "sparkleshare." + UserEmail + ".key";
+
+ Process process = new Process ();
+ process.StartInfo.RedirectStandardOutput = true;
+ process.StartInfo.UseShellExecute = false;
+ process.StartInfo.FileName = "ssh-add";
+ process.StartInfo.Arguments = "\"" + Path.Combine (keys_path, key_file_name) + "\"";
+ process.Start ();
+ process.WaitForExit ();
+ }
+
+
+ public bool BackendIsPresent {
+ get {
+ return SparkleBackend.DefaultBackend.IsPresent;
+ }
+ }
+
+
+ // Looks up the user's name from the global configuration
+ public string UserName
+ {
+ get {
+ return SparkleConfig.DefaultConfig.User.Name;
+ }
+
+ set {
+ SparkleConfig.DefaultConfig.User = new SparkleUser (value, UserEmail);
+ }
+ }
+
+
+ // Looks up the user's email from the global configuration
+ public string UserEmail
+ {
+ get {
+ return SparkleConfig.DefaultConfig.User.Email;
+ }
+
+ set {
+ SparkleConfig.DefaultConfig.User = new SparkleUser (UserName, value);
+ }
+ }
+
+
+ // Generates and installs an RSA keypair to identify this system
+ public void GenerateKeyPair ()
+ {
+ string keys_path = Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath);
+ string key_file_name = "sparkleshare." + UserEmail + ".key";
+ string key_file_path = Path.Combine (keys_path, key_file_name);
+
+ if (File.Exists (key_file_path)) {
+ SparkleHelpers.DebugInfo ("Config", "Key already exists ('" + key_file_name + "'), " +
+ "leaving it untouched");
+ return;
+ }
+
+ if (!Directory.Exists (keys_path))
+ Directory.CreateDirectory (keys_path);
+
+ if (!File.Exists (key_file_name)) {
+ Process process = new Process () {
+ EnableRaisingEvents = true
+ };
+
+ process.StartInfo.WorkingDirectory = keys_path;
+ process.StartInfo.UseShellExecute = false;
+ process.StartInfo.RedirectStandardOutput = true;
+ process.StartInfo.FileName = "ssh-keygen";
+
+ // -t is the crypto type
+ // -P is the password (none)
+ // -f is the file name to store the private key in
+ process.StartInfo.Arguments = "-t rsa -P \"\" -f " + key_file_name;
+
+ process.Exited += delegate {
+ SparkleHelpers.DebugInfo ("Config", "Created private key '" + key_file_name + "'");
+ SparkleHelpers.DebugInfo ("Config", "Created public key '" + key_file_name + ".pub'");
+
+ // Create an easily accessible copy of the public
+ // key in the user's SparkleShare folder
+ File.Copy (key_file_path + ".pub",
+ Path.Combine (SparklePath, UserName + "'s key.txt"));
+ };
+
+ process.Start ();
+ process.WaitForExit ();
+ }
+ }
+
+
+ // Gets the avatar for a specific email address and size
+ public void FetchAvatars (List emails, int size)
+ {
+ List old_avatars = new List ();
+ bool avatar_fetched = false;
+ string avatar_path = new string [] {
+ Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath),
+ "icons", size + "x" + size, "status"}.Combine ();
+
+ if (!Directory.Exists (avatar_path)) {
+ Directory.CreateDirectory (avatar_path);
+ SparkleHelpers.DebugInfo ("Config", "Created '" + avatar_path + "'");
+ }
+
+ foreach (string raw_email in emails) {
+
+ // Gravatar wants lowercase emails
+ string email = raw_email.ToLower ();
+ string avatar_file_path = Path.Combine (avatar_path, "avatar-" + email);
+
+ if (File.Exists (avatar_file_path)) {
+ FileInfo avatar_info = new FileInfo (avatar_file_path);
+
+ // Delete avatars older than a month
+ if (avatar_info.CreationTime < DateTime.Now.AddMonths (-1)) {
+ avatar_info.Delete ();
+ old_avatars.Add (email);
+ }
+
+ } else {
+ WebClient client = new WebClient ();
+ string url = "http://gravatar.com/avatar/" + GetMD5 (email) +
+ ".jpg?s=" + size + "&d=404";
+
+ try {
+ // Fetch the avatar
+ byte [] buffer = client.DownloadData (url);
+
+ // Write the avatar data to a
+ // if not empty
+ if (buffer.Length > 255) {
+ avatar_fetched = true;
+ File.WriteAllBytes (avatar_file_path, buffer);
+ SparkleHelpers.DebugInfo ("Controller", "Fetched gravatar for " + email);
+ }
+
+ } catch (WebException e) {
+ SparkleHelpers.DebugInfo ("Controller", "Failed fetching gravatar for " + email);
+
+ // Stop downloading further avatars if we have no internet access
+ if (e.Status == WebExceptionStatus.Timeout)
+ break;
+ }
+ }
+ }
+
+ // Fetch new versions of the avatars that we
+ // deleted because they were too old
+ if (old_avatars.Count > 0)
+ FetchAvatars (old_avatars, size);
+
+ if (AvatarFetched != null && avatar_fetched)
+ AvatarFetched ();
+ }
+
+
+ public string GetAvatar (string email, int size)
+ {
+ string avatar_file_path = SparkleHelpers.CombineMore (
+ Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath), "icons",
+ size + "x" + size, "status", "avatar-" + email);
+
+ return avatar_file_path;
+ }
+
+
+ public void FetchFolder (string server, string remote_folder)
+ {
+ server = server.Trim ();
+ remote_folder = remote_folder.Trim ();
+
+ string tmp_path = SparkleConfig.DefaultConfig.TmpPath;
+ if (!Directory.Exists (tmp_path))
+ Directory.CreateDirectory (tmp_path);
+
+ // Strip the '.git' from the name
+ string canonical_name = Path.GetFileNameWithoutExtension (remote_folder);
+ string tmp_folder = Path.Combine (tmp_path, canonical_name);
+
+ string backend = null;
+
+/* if (remote_folder.EndsWith (".hg")) {
+ remote_folder = remote_folder.Substring (0, (remote_folder.Length - 3));
+ fetcher = new SparkleFetcherHg (server, remote_folder, tmp_folder);
+ backend = "Hg";
+
+ } else if (remote_folder.EndsWith (".scp")) {
+ remote_folder = remote_folder.Substring (0, (remote_folder.Length - 4));
+ fetcher = new SparkleFetcherScp (server, remote_folder, tmp_folder);
+ backend = "Scp";
+
+ } else {*/
+ this.fetcher = new SparkleFetcherGit (server, remote_folder, tmp_folder);
+ backend = "Git";
+ //}
+
+ bool target_folder_exists = Directory.Exists (
+ Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, canonical_name));
+
+ // Add a numbered suffix to the nameif a folder with the same name
+ // already exists. Example: "Folder (2)"
+ int i = 1;
+ while (target_folder_exists) {
+ i++;
+ target_folder_exists = Directory.Exists (
+ Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, canonical_name + " (" + i + ")"));
+ }
+
+ string target_folder_name = canonical_name;
+ if (i > 1)
+ target_folder_name += " (" + i + ")";
+
+ this.fetcher.Finished += delegate {
+
+ // Needed to do the moving
+ SparkleHelpers.ClearAttributes (tmp_folder);
+ string target_folder_path = Path.Combine (
+ SparkleConfig.DefaultConfig.FoldersPath, target_folder_name);
+
+ try {
+ Directory.Move (tmp_folder, target_folder_path);
+ } catch (Exception e) {
+ SparkleHelpers.DebugInfo ("Controller", "Error moving folder: " + e.Message);
+ }
+
+ SparkleConfig.DefaultConfig.AddFolder (target_folder_name, this.fetcher.RemoteUrl, backend);
+ AddRepository (target_folder_path);
+
+ if (FolderFetched != null)
+ FolderFetched ();
+
+ FolderSize = GetFolderSize ();
+
+ if (FolderSizeChanged != null)
+ FolderSizeChanged (FolderSize);
+
+ if (FolderListChanged != null)
+ FolderListChanged ();
+
+ this.fetcher.Dispose ();
+
+ if (Directory.Exists (tmp_path))
+ Directory.Delete (tmp_path, true);
+ };
+
+
+ this.fetcher.Failed += delegate {
+ if (FolderFetchError != null)
+ FolderFetchError (this.fetcher.RemoteUrl);
+
+ this.fetcher.Dispose ();
+
+ if (Directory.Exists (tmp_path))
+ Directory.Delete (tmp_path, true);
+ };
+
+
+ this.fetcher.ProgressChanged += delegate (double percentage) {
+ if (FolderFetching != null)
+ FolderFetching (percentage);
+ };
+
+
+ this.fetcher.Start ();
+ }
+
+
+ public void StopFetcher ()
+ {
+ if (fetcher != null)
+ fetcher.Stop ();
+ }
+
+
+ // Creates an MD5 hash of input
+ private string GetMD5 (string s)
+ {
+ MD5 md5 = new MD5CryptoServiceProvider ();
+ Byte[] bytes = ASCIIEncoding.Default.GetBytes (s);
+ Byte[] encoded_bytes = md5.ComputeHash (bytes);
+ return BitConverter.ToString (encoded_bytes).ToLower ().Replace ("-", "");
+ }
+
+
+ // Checks whether there are any folders syncing and
+ // quits if safe
+ public void TryQuit ()
+ {
+ foreach (SparkleRepoBase repo in Repositories) {
+ if (repo.Status == SyncStatus.SyncUp ||
+ repo.Status == SyncStatus.SyncDown ||
+ repo.IsBuffering) {
+
+ if (OnQuitWhileSyncing != null)
+ OnQuitWhileSyncing ();
+
+ return;
+ }
+ }
+
+ Quit ();
+ }
+
+
+ public void Quit ()
+ {
+ foreach (SparkleRepoBase repo in Repositories)
+ repo.Dispose ();
+
+ Environment.Exit (0);
+ }
+
+
+ // Checks to see if an email address is valid
+ public bool IsValidEmail (string email)
+ {
+ Regex regex = new Regex (@"^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$", RegexOptions.IgnoreCase);
+ return regex.IsMatch (email);
+ }
+
+
+
+
+ public void AddNoteToFolder (string folder_name, string revision, string note)
+ {
+ folder_name = folder_name.Replace ("%20", " ");
+ note = note.Replace ("%20", " ");
+
+ foreach (SparkleRepoBase repo in Repositories) {
+ if (repo.Name.Equals (folder_name))
+ repo.AddNote (revision, note);
+ }
+ }
+
+
+
+
+ private string [] tango_palette = new string [] {"#eaab00", "#e37222",
+ "#3892ab", "#33c2cb", "#19b271", "#9eab05", "#8599a8", "#9ca696",
+ "#b88454", "#cc0033", "#8f6678", "#8c6cd0", "#796cbf", "#4060af",
+ "#aa9c8f", "#818a8f"};
+
+ private string AssignColor (string s)
+ {
+ string hash = GetMD5 (s).Substring (0, 8);
+ string numbers = Regex.Replace (hash, "[a-z]", "");
+ int number = 3 + int.Parse (numbers);
+ return this.tango_palette [number % this.tango_palette.Length];
+ }
+ }
+
+
+ public class ChangeSet : SparkleChangeSet { }
+
+
+ // All change sets that happened on a day
+ public class ActivityDay : List
+ {
+ public DateTime DateTime;
+
+ public ActivityDay (DateTime date_time)
+ {
+ DateTime = date_time;
+ DateTime = new DateTime (DateTime.Year, DateTime.Month, DateTime.Day);
+ }
+ }
+}
diff --git a/SparkleShare/SparkleLinController.cs b/SparkleShare/SparkleLinController.cs
deleted file mode 100755
index 0cc2168e..00000000
--- a/SparkleShare/SparkleLinController.cs
+++ /dev/null
@@ -1,214 +0,0 @@
-// SparkleShare, a collaboration and sharing tool.
-// Copyright (C) 2010 Hylke Bons
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU 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 .
-
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading;
-
-using Mono.Unix;
-using SparkleLib;
-
-namespace SparkleShare {
-
- public class SparkleLinController : SparkleController {
-
- public SparkleLinController () : base ()
- {
-
- }
-
-
- // Creates a .desktop entry in autostart folder to
- // start SparkleShare automatically at login
- public override void EnableSystemAutostart ()
- {
- string autostart_path = Path.Combine (Environment.GetFolderPath (
- Environment.SpecialFolder.ApplicationData), "autostart");
-
- string desktopfile_path = Path.Combine (autostart_path, "sparkleshare.desktop");
-
- if (!Directory.Exists (autostart_path))
- Directory.CreateDirectory (autostart_path);
-
- if (!File.Exists (desktopfile_path)) {
- TextWriter writer = new StreamWriter (desktopfile_path);
- writer.WriteLine ("[Desktop Entry]\n" +
- "Type=Application\n" +
- "Name=SparkleShare\n" +
- "Exec=sparkleshare start\n" +
- "Icon=folder-sparkleshare\n" +
- "Terminal=false\n" +
- "X-GNOME-Autostart-enabled=true\n" +
- "Categories=Network");
- writer.Close ();
-
- // Give the launcher the right permissions so it can be launched by the user
- UnixFileInfo file_info = new UnixFileInfo (desktopfile_path);
- file_info.Create (FileAccessPermissions.UserReadWriteExecute);
-
- SparkleHelpers.DebugInfo ("Controller", "Enabled autostart on login");
- }
- }
-
-
- // Installs a launcher so the user can launch SparkleShare
- // from the Internet category if needed
- public override void InstallLauncher ()
- {
- string apps_path =
- new string [] {SparkleConfig.DefaultConfig.HomePath,
- ".local", "share", "applications"}.Combine ();
-
- string desktopfile_path = Path.Combine (apps_path, "sparkleshare.desktop");
-
- if (!File.Exists (desktopfile_path)) {
- if (!Directory.Exists (apps_path))
- Directory.CreateDirectory (apps_path);
-
- TextWriter writer = new StreamWriter (desktopfile_path);
- writer.WriteLine ("[Desktop Entry]\n" +
- "Type=Application\n" +
- "Name=SparkleShare\n" +
- "Comment=Share documents\n" +
- "Exec=sparkleshare start\n" +
- "Icon=folder-sparkleshare\n" +
- "Terminal=false\n" +
- "Categories=Network;");
- writer.Close ();
-
- // Give the launcher the right permissions so it can be launched by the user
- UnixFileInfo file_info = new UnixFileInfo (desktopfile_path);
- file_info.FileAccessPermissions = FileAccessPermissions.UserReadWriteExecute;
-
- SparkleHelpers.DebugInfo ("Controller", "Created '" + desktopfile_path + "'");
- }
- }
-
-
- // Adds the SparkleShare folder to the user's
- // list of bookmarked places
- public override void AddToBookmarks ()
- {
- string bookmarks_file_path = Path.Combine (SparkleConfig.DefaultConfig.HomePath, ".gtk-bookmarks");
- string sparkleshare_bookmark = "file://" + SparkleConfig.DefaultConfig.FoldersPath + " SparkleShare";
-
- if (File.Exists (bookmarks_file_path)) {
- StreamReader reader = new StreamReader (bookmarks_file_path);
- string bookmarks = reader.ReadToEnd ();
- reader.Close ();
-
- if (!bookmarks.Contains (sparkleshare_bookmark)) {
- TextWriter writer = File.AppendText (bookmarks_file_path);
- writer.WriteLine ("file://" + SparkleConfig.DefaultConfig.FoldersPath + " SparkleShare");
- writer.Close ();
- }
- } else {
- StreamWriter writer = new StreamWriter (bookmarks_file_path);
- writer.WriteLine ("file://" + SparkleConfig.DefaultConfig.FoldersPath + " SparkleShare");
- writer.Close ();
- }
- }
-
-
- // Creates the SparkleShare folder in the user's home folder
- public override bool CreateSparkleShareFolder ()
- {
- if (!Directory.Exists (SparkleConfig.DefaultConfig.FoldersPath)) {
-
- Directory.CreateDirectory (SparkleConfig.DefaultConfig.FoldersPath);
- SparkleHelpers.DebugInfo ("Controller", "Created '" + SparkleConfig.DefaultConfig.FoldersPath + "'");
-
- string gvfs_command_path =
- new string [] {Path.VolumeSeparatorChar.ToString (),
- "usr", "bin", "gvfs-set-attribute"}.Combine ();
-
- // Add a special icon to the SparkleShare folder
- if (File.Exists (gvfs_command_path)) {
- Process process = new Process ();
-
- process.StartInfo.RedirectStandardOutput = true;
- process.StartInfo.UseShellExecute = false;
- process.StartInfo.FileName = "gvfs-set-attribute";
-
- // Clear the custom (legacy) icon path
- process.StartInfo.Arguments = "-t unset " + SparkleConfig.DefaultConfig.FoldersPath + " metadata::custom-icon";
- process.Start ();
- process.WaitForExit ();
-
- // Give the SparkleShare folder an icon name, so that it scales
- process.StartInfo.Arguments = SparkleConfig.DefaultConfig.FoldersPath + " metadata::custom-icon-name 'folder-sparkleshare'";
- process.Start ();
- process.WaitForExit ();
- }
-
- return true;
- }
-
- return false;
- }
-
-
- public override string EventLogHTML {
- get {
- string path = new string [] {Defines.PREFIX,
- "share", "sparkleshare", "html", "event-log.html"}.Combine ();
-
- string html = String.Join (Environment.NewLine, File.ReadAllLines (path));
-
- html = html.Replace ("", "file://" +
- new string [] {Defines.PREFIX, "share", "sparkleshare", "html", "jquery.js"}.Combine ());
-
- return html;
- }
- }
-
-
- public override string DayEntryHTML {
- get {
- string path = new string [] {Defines.PREFIX,
- "share", "sparkleshare", "html", "day-entry.html"}.Combine ();
-
- return String.Join (Environment.NewLine, File.ReadAllLines (path));
- }
- }
-
-
- public override string EventEntryHTML {
- get {
- string path = new string [] {Defines.PREFIX,
- "share", "sparkleshare", "html", "event-entry.html"}.Combine ();
-
- return String.Join (Environment.NewLine, File.ReadAllLines (path));
- }
- }
-
-
- public override void OpenSparkleShareFolder (string subfolder)
- {
- string folder = Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, subfolder);
-
- Process process = new Process ();
- process.StartInfo.FileName = "xdg-open";
- process.StartInfo.Arguments = "\"" + folder + "\"";
- process.Start ();
- }
- }
-}
diff --git a/SparkleShare/SparkleShare.csproj b/SparkleShare/SparkleShare.csproj
index ad2795f7..199f702d 100755
--- a/SparkleShare/SparkleShare.csproj
+++ b/SparkleShare/SparkleShare.csproj
@@ -1,5 +1,5 @@
-
+
Debug
AnyCPU
@@ -9,6 +9,7 @@
SparkleShare
2.0
SparkleShare
+ v3.5
true
@@ -37,15 +38,9 @@
-
-
- {2C914413-B31C-4362-93C7-1AE34F09112A}
- SparkleLib
-
-
-
+
@@ -63,7 +58,6 @@
-
@@ -78,5 +72,6 @@
+
diff --git a/SparkleShare/SparkleShare.sln b/SparkleShare/SparkleShare.sln
new file mode 100644
index 00000000..9716fc21
--- /dev/null
+++ b/SparkleShare/SparkleShare.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkleShare", "SparkleShare.csproj", "{728483AA-E34B-4441-BF2C-C8BC2901E4E0}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = SparkleShare.csproj
+ EndGlobalSection
+EndGlobal
" + - note.User.Name + "
" + - note.Body + - "