diff --git a/SparkleLib/SparkleFetcher.cs b/SparkleLib/SparkleFetcher.cs index 378fac49..951e5ae1 100644 --- a/SparkleLib/SparkleFetcher.cs +++ b/SparkleLib/SparkleFetcher.cs @@ -20,6 +20,8 @@ using System.Diagnostics; namespace SparkleLib { + // A helper class that fetches and and configures + // a remote repository public class SparkleFetcher { public delegate void CloningStartedEventHandler (object o, SparkleEventArgs args); @@ -98,7 +100,6 @@ namespace SparkleLib { private void InstallUserInfo () { - // TODO: Use TargetFolder and move SparklePaths out of SparkleLib string global_config_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, "config"); if (File.Exists (global_config_file_path)) { @@ -124,11 +125,18 @@ namespace SparkleLib { private void InstallExcludeRules () { - TextWriter writer = new StreamWriter (SparkleHelpers.CombineMore (TargetFolder, ".git/info/exclude")); + string exlude_rules_file_path = SparkleHelpers.CombineMore (TargetFolder, ".git", "info", "exclude"); - writer.WriteLine ("*~"); // Ignore gedit swap files - writer.WriteLine (".*.sw?"); // Ignore vi swap files - writer.WriteLine (".DS_store"); // Ignore OSX's invisible directories + TextWriter writer = new StreamWriter (exlude_rules_file_path); + + // Ignore gedit swap files + writer.WriteLine ("*~"); + + // Ignore vi swap files + writer.WriteLine (".*.sw?"); + + // Ignore OSX's invisible directories + writer.WriteLine (".DS_store"); writer.Close (); diff --git a/SparkleLib/SparkleRepo.cs b/SparkleLib/SparkleRepo.cs index a8734677..181789d0 100644 --- a/SparkleLib/SparkleRepo.cs +++ b/SparkleLib/SparkleRepo.cs @@ -558,7 +558,7 @@ namespace SparkleLib { UnixUserInfo unix_user_info = new UnixUserInfo (UnixEnvironment.UserName); if (unix_user_info.RealName.Equals ("")) - user_name = "???"; + user_name = "Mysterious Stranger"; else user_name = unix_user_info.RealName; @@ -582,8 +582,12 @@ namespace SparkleLib { process.StartInfo.WorkingDirectory = LocalPath; process.StartInfo.Arguments = "config --get user.email"; process.Start (); + user_email = process.StandardOutput.ReadToEnd ().Trim (); + if (user_email.Equals ("")) + user_email = "Unknown Email"; + return user_email; } diff --git a/SparkleShare/SparkleIntro.cs b/SparkleShare/SparkleIntro.cs index ce253633..a7f0f0e2 100644 --- a/SparkleShare/SparkleIntro.cs +++ b/SparkleShare/SparkleIntro.cs @@ -724,14 +724,22 @@ namespace SparkleShare { string config_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, "config"); + string name = NameEntry.Text; + string email = EmailEntry.Text; + + // Write the user's information to a text file TextWriter writer = new StreamWriter (config_file_path); writer.WriteLine ("[user]\n" + - "\tname = " + NameEntry.Text + "\n" + - "\temail = " + EmailEntry.Text); + "\tname = " + name + "\n" + + "\temail = " + email); writer.Close (); SparkleHelpers.DebugInfo ("Config", "Created '" + config_file_path + "'"); + // Set the user's name and email globally + SparkleShare.UserName = name; + SparkleShare.UserEmail = email; + GenerateKeyPair (); } diff --git a/SparkleShare/SparkleInvitation.cs b/SparkleShare/SparkleInvitation.cs index e9d0bfef..e127df48 100644 --- a/SparkleShare/SparkleInvitation.cs +++ b/SparkleShare/SparkleInvitation.cs @@ -14,17 +14,29 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using Gtk; +using Mono.Unix; +using SparkleLib; using System; using System.IO; +using System.Net; using System.Xml; namespace SparkleShare { - class SparkleInvitation { + class SparkleInvitation : SparkleWindow { public string Server; - public string Repository; - public string Key; + public string Folder; + public string InviteKey; + public string FilePath; + + + // Short alias for the translations + public static string _ (string s) + { + return Catalog.GetString (s); + } public SparkleInvitation (string file_path) @@ -33,25 +45,132 @@ namespace SparkleShare { if (!File.Exists (file_path)) return; + FilePath = file_path; + XmlDocument xml_doc = new XmlDocument (); xml_doc.Load (file_path); XmlNodeList server_xml = xml_doc.GetElementsByTagName ("server"); - XmlNodeList repository_xml = xml_doc.GetElementsByTagName ("repository"); - XmlNodeList key_xml = xml_doc.GetElementsByTagName ("key"); + XmlNodeList folder_xml = xml_doc.GetElementsByTagName ("folder"); + XmlNodeList invite_key_xml = xml_doc.GetElementsByTagName ("invitekey"); - Server = server_xml [0].InnerText; - Repository = repository_xml [0].InnerText; - Key = key_xml [0].InnerText; + Server = server_xml [0].InnerText; + Folder = folder_xml [0].InnerText; + InviteKey = invite_key_xml [0].InnerText; } - public void Activate () + // Uploads the user's public key to the + // server and starts the syncing process + public void Configure () { - string url = "http://" + Server + "/repo=" + Repository + "&key=" + Key; - Console.WriteLine (url); + // The location of the user's public key for SparkleShare + string public_key_file_path = SparkleHelpers.CombineMore (SparklePaths.HomePath, ".ssh", + "sparkleshare." + SparkleShare.UserEmail + ".key.pub"); + + if (!File.Exists (public_key_file_path)) + return; + + StreamReader reader = new StreamReader (public_key_file_path); + string public_key = reader.ReadToEnd (); + reader.Close (); + + string url = "http://" + Server + "/folder=" + Folder + + "&invite=" + InviteKey + + "&key=" + public_key; + + SparkleHelpers.DebugInfo ("WebRequest", url); + + HttpWebRequest request = (HttpWebRequest) WebRequest.Create (url); + HttpWebResponse response = (HttpWebResponse) request.GetResponse(); + + if (response.StatusCode == HttpStatusCode.OK) + File.Delete (FilePath); + + response.Close (); + + } + + + public void PresentInvitation () + { + + VBox layout_vertical = new VBox (false, 0); + + Label header = new Label ("" + + _("Invitation received!") + + "") { + UseMarkup = true, + Xalign = 0 + }; + + Label information = new Label (_("You've received an invitation to join a shared folder.\n" + + "We're ready to hook you up immediately if you wish.")) { + Xalign = 0, + Wrap = true + }; + + Label question = new Label (_("Do you accept this invitation?")) { + Xalign = 0, + Wrap = true + }; + + Table table = new Table (2, 2, true) { + RowSpacing = 6 + }; + + Label server_label = new Label (_("Server Address:")) { + Xalign = 0 + }; + + Label server = new Label ("" + Server + "") { + UseMarkup = true, + Xalign = 0 + }; + + Label folder_label = new Label (_("Folder Name:")) { + Xalign = 0 + }; + + Label folder = new Label ("" + Folder + "") { + UseMarkup = true, + Xalign = 0 + }; + + table.Attach (folder_label, 0, 1, 0, 1); + table.Attach (folder, 1, 2, 0, 1); + table.Attach (server_label, 0, 1, 1, 2); + table.Attach (server, 1, 2, 1, 2); + + Button reject_button = new Button (_("Reject")); + Button accept_button = new Button (_("Accept")); + + reject_button.Clicked += delegate { + + // Delete the invitation + File.Delete (FilePath); + + Destroy (); + + }; + + AddButton (reject_button); + AddButton (accept_button); + + layout_vertical.PackStart (header, false, false, 0); + layout_vertical.PackStart (information, false, false, 21); + layout_vertical.PackStart (new Label (""), false, false, 0); + layout_vertical.PackStart (table, false, false, 0); + layout_vertical.PackStart (new Label (""), false, false, 0); + layout_vertical.PackStart (question, false, false, 21); + + Add (layout_vertical); + + ShowAll (); + + Present (); } diff --git a/SparkleShare/SparkleShare.cs b/SparkleShare/SparkleShare.cs index 1bb77ad1..90750cd5 100644 --- a/SparkleShare/SparkleShare.cs +++ b/SparkleShare/SparkleShare.cs @@ -18,6 +18,7 @@ using Gtk; using Mono.Unix; using System; using System.Diagnostics; +using System.IO; using SparkleLib; namespace SparkleShare { @@ -26,6 +27,8 @@ namespace SparkleShare { public class SparkleShare { public static SparkleUI SparkleUI; + public static string UserName; + public static string UserEmail; // Short alias for the translations @@ -42,26 +45,39 @@ namespace SparkleShare { Catalog.Init (Defines.GETTEXT_PACKAGE, Defines.LOCALE_DIR); // Check whether git is installed - Process Process = new Process (); - Process.StartInfo.FileName = "git"; - Process.StartInfo.RedirectStandardOutput = true; - Process.StartInfo.UseShellExecute = false; - Process.Start (); + Process process = new Process (); + process.StartInfo.FileName = "git"; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.UseShellExecute = false; + process.Start (); + + if (process.StandardOutput.ReadToEnd ().IndexOf ("version") == -1) { - if (Process.StandardOutput.ReadToEnd ().IndexOf ("version") == -1) { Console.WriteLine (_("Git wasn't found.")); Console.WriteLine (_("You can get Git from http://git-scm.com/.")); + Environment.Exit (0); + } + + UnixUserInfo user_info = new UnixUserInfo (UnixEnvironment.UserName); + // Don't allow running as root - UnixUserInfo UnixUserInfo = new UnixUserInfo (UnixEnvironment.UserName); - if (UnixUserInfo.UserId == 0) { + if (user_info.UserId == 0) { + Console.WriteLine (_("Sorry, you can't run SparkleShare with these permissions.")); Console.WriteLine (_("Things would go utterly wrong.")); + Environment.Exit (0); + } + + UserName = GetUserName (); + UserEmail = GetUserEmail (); + + bool HideUI = false; // Parse the command line arguments @@ -132,6 +148,49 @@ namespace SparkleShare { } + + // Looks up the user's name from the global configuration + public static string GetUserName () + { + + string global_config_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, "config"); + + StreamReader reader = new StreamReader (global_config_file_path); + + // Discard the first line + reader.ReadLine (); + + string line = reader.ReadLine (); + reader.Close (); + + string name = line.Substring (line.IndexOf ("=") + 2); + + return name; + + } + + + // Looks up the user's email from the global configuration + public static string GetUserEmail () + { + + string global_config_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, "config"); + + StreamReader reader = new StreamReader (global_config_file_path); + + // Discard the first two lines + reader.ReadLine (); + reader.ReadLine (); + + string line = reader.ReadLine (); + reader.Close (); + + string email = line.Substring (line.IndexOf ("=") + 2); + + return email; + + } + } } diff --git a/SparkleShare/SparkleUI.cs b/SparkleShare/SparkleUI.cs index 7e404828..c2cf8597 100644 --- a/SparkleShare/SparkleUI.cs +++ b/SparkleShare/SparkleUI.cs @@ -30,10 +30,8 @@ namespace SparkleShare { public class SparkleUI { - public static SparkleStatusIcon NotificationIcon; public static List Repositories; - - private Process Process; + public static SparkleStatusIcon NotificationIcon; // Short alias for the translations @@ -51,17 +49,13 @@ namespace SparkleShare { SetProcessName ("sparkleshare"); + // The list of repositories Repositories = new List (); - Process = new Process () { - EnableRaisingEvents = true - }; - Process.StartInfo.RedirectStandardOutput = true; - Process.StartInfo.UseShellExecute = false; - EnableSystemAutostart (); InstallLauncher (); + // Create the SparkleShare folder and add it to the bookmarks if (!Directory.Exists (SparklePaths.SparklePath)) { @@ -79,20 +73,25 @@ namespace SparkleShare { Filter = "*" }; + + // Remove the repository when a delete event occurs watcher.Deleted += delegate (object o, FileSystemEventArgs args) { RemoveRepository (args.FullPath); }; + // Add the repository when a create event occurs watcher.Created += delegate (object o, FileSystemEventArgs args) { + // Handle invitations when the user saves an + // invitation into the SparkleShare folder if (args.Name.EndsWith ("sparkleshare.invitation")) { SparkleInvitation invitation; invitation = new SparkleInvitation (args.FullPath); - invitation.Activate (); + Application.Invoke (delegate { invitation.PresentInvitation (); }); } else if (Directory.Exists (args.FullPath)) { @@ -106,18 +105,22 @@ namespace SparkleShare { CreateConfigurationFolders (); PopulateRepositories (); - // Don't create the window and status - // icon when --disable-gui was given + + // Don't create the window and status icon when + // the --disable-gui command line argument was given if (!HideUI) { - // Show the intro screen if there are no folders - if (Repositories.Count == 0) { + string global_config_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, "config"); + + // Show the introduction screen if SparkleShare isn't configured + if (!File.Exists (global_config_file_path)) { SparkleIntro intro = new SparkleIntro (); intro.ShowAll (); } + // Create the statusicon NotificationIcon = new SparkleStatusIcon (); } @@ -125,10 +128,10 @@ namespace SparkleShare { } + // Runs the main loop public void Run () { - // The main loop Gtk.Application.Run (); } @@ -165,8 +168,8 @@ namespace SparkleShare { } - // Creates .desktop entry in autostart folder to - // start SparkleShare automnatically at login + // Creates a .desktop entry in autostart folder to + // start SparkleShare automatically at login public void EnableSystemAutostart () { @@ -235,7 +238,7 @@ namespace SparkleShare { // Adds the SparkleShare folder to the user's - // list of bookmarked folders + // list of bookmarked places public void AddToBookmarks () { @@ -267,20 +270,26 @@ namespace SparkleShare { } - // Creates the SparkleShare folder in the user's home folder if - // it's not already there + // Creates the SparkleShare folder in the user's home folder public void CreateSparkleShareFolder () { Directory.CreateDirectory (SparklePaths.SparklePath); SparkleHelpers.DebugInfo ("Config", "Created '" + SparklePaths.SparklePath + "'"); - + + string icon_file_path = SparkleHelpers.CombineMore (Defines.PREFIX, "share", "icons", "hicolor", "48x48", + "apps", "folder-sparkleshare.png"); + + Process process = new Process (); + + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.UseShellExecute = false; + // Add a special icon to the SparkleShare folder - Process.StartInfo.FileName = "gvfs-set-attribute"; - Process.StartInfo.Arguments = SparklePaths.SparklePath + " metadata::custom-icon " + - "file://" + SparkleHelpers.CombineMore (Defines.PREFIX, "share", "icons", - "hicolor", "48x48", "apps", "folder-sparkleshare.png"); - Process.Start (); + process.StartInfo.FileName = "gvfs-set-attribute"; + process.StartInfo.Arguments = SparklePaths.SparklePath + " metadata::custom-icon " + + "file://" + icon_file_path; + process.Start (); } @@ -305,7 +314,8 @@ namespace SparkleShare { // Shows a notification bubble when there // was a conflict - public void ShowConflictBubble (object o, EventArgs args) { + public void ShowConflictBubble (object o, EventArgs args) + { string title = _("Ouch! Mid-air collision!"); string subtext = _("Don't worry, SparkleShare made a copy of each conflicting file."); @@ -336,7 +346,10 @@ namespace SparkleShare { } - public void AddRepository (string folder_path) { + // Adds a repository to the list of repositories and + // updates the statusicon menu + public void AddRepository (string folder_path) + { // Check if the folder is a git repo if (!Directory.Exists (SparkleHelpers.CombineMore (folder_path, ".git"))) @@ -380,7 +393,10 @@ namespace SparkleShare { } - public void RemoveRepository (string folder_path) { + // Removes a repository from the list of repositories and + // updates the statusicon menu + public void RemoveRepository (string folder_path) + { string repo_name = Path.GetFileName (folder_path); @@ -435,10 +451,7 @@ namespace SparkleShare { } - [DllImport ("libc")] - private static extern int prctl (int option, byte [] arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5); - - + // Method to set the unix process name to 'sparkleshare' instead of 'mono' private void SetProcessName (string name) { @@ -451,10 +464,19 @@ namespace SparkleShare { } - } catch (EntryPointNotFoundException) {} + } catch (EntryPointNotFoundException) { + + Console.WriteLine ("SetProcessName: Entry point not found"); + + } } + + // Strange magic needed by SetProcessName + [DllImport ("libc")] + private static extern int prctl (int option, byte [] arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5); + } }