Merge branch 'master' into gettext-cs
Conflicts: SparkleLib/Git/SparkleFetcherGit.cs
This commit is contained in:
commit
e2e706dc6a
|
@ -1,4 +1,4 @@
|
||||||
basedirs = build help SparkleLib data po
|
basedirs = build SparkleLib data po
|
||||||
|
|
||||||
SUBDIRS = $(basedirs) $(GUISUBDIRS)
|
SUBDIRS = $(basedirs) $(GUISUBDIRS)
|
||||||
DIST_SUBDIRS = $(basedirs) SparkleShare
|
DIST_SUBDIRS = $(basedirs) SparkleShare
|
||||||
|
|
11
NEWS
11
NEWS
|
@ -1,4 +1,11 @@
|
||||||
0.8.1 for Linux and Mac (Sun Jan 29):
|
0.8.2 for Linux and Mac (Sat Feb 11 2012):
|
||||||
|
|
||||||
|
Hylke:
|
||||||
|
- Use the more reliable and less resource intensive FSEvents on Mac.
|
||||||
|
- Improvements to the reconnect mechanism of the notification system
|
||||||
|
|
||||||
|
|
||||||
|
0.8.1 for Linux and Mac (Sun Jan 29 2012):
|
||||||
|
|
||||||
Hylke:
|
Hylke:
|
||||||
- Disable the Quit menu item when a sync is going on
|
- Disable the Quit menu item when a sync is going on
|
||||||
|
@ -9,7 +16,7 @@
|
||||||
- Close event log on Cmd+W on Mac
|
- Close event log on Cmd+W on Mac
|
||||||
|
|
||||||
|
|
||||||
0.8.0 for Linux and Mac (Sun Jan 22):
|
0.8.0 for Linux and Mac (Sun Jan 22 2012):
|
||||||
|
|
||||||
Hylke:
|
Hylke:
|
||||||
- Show syncing progress in the status icon
|
- Show syncing progress in the status icon
|
||||||
|
|
|
@ -82,8 +82,7 @@ $ sudo apt-get install libappindicator0.1-cil-dev
|
||||||
```bash
|
```bash
|
||||||
$ sudo yum install gtk-sharp2-devel mono-core mono-devel monodevelop \
|
$ sudo yum install gtk-sharp2-devel mono-core mono-devel monodevelop \
|
||||||
ndesk-dbus-devel ndesk-dbus-glib-devel nautilus-python-devel nant \
|
ndesk-dbus-devel ndesk-dbus-glib-devel nautilus-python-devel nant \
|
||||||
notify-sharp-devel webkit-sharp-devel webkitgtk-devel libtool intltool \
|
notify-sharp-devel webkit-sharp-devel webkitgtk-devel libtool intltool
|
||||||
gnome-doc-utils
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -79,8 +79,8 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
base.target_folder = target_folder;
|
TargetFolder = target_folder;
|
||||||
base.remote_url = uri.ToString ();
|
RemoteUrl = uri.ToString ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,8 +89,7 @@ namespace SparkleLib {
|
||||||
this.git = new SparkleGit (SparkleConfig.DefaultConfig.TmpPath,
|
this.git = new SparkleGit (SparkleConfig.DefaultConfig.TmpPath,
|
||||||
"clone " +
|
"clone " +
|
||||||
"--progress " + // Redirects progress stats to standarderror
|
"--progress " + // Redirects progress stats to standarderror
|
||||||
"\"" + base.remote_url + "\" " +
|
"\"" + RemoteUrl + "\" " + "\"" + SparkleHelpers.NormalizeSeparatorsToOS(TargetFolder) + "\"");
|
||||||
"\"" + SparkleHelpers.NormalizeSeparatorsToOS(base.target_folder) + "\"");
|
|
||||||
|
|
||||||
this.git.StartInfo.RedirectStandardError = true;
|
this.git.StartInfo.RedirectStandardError = true;
|
||||||
this.git.Start ();
|
this.git.Start ();
|
||||||
|
@ -140,13 +139,14 @@ namespace SparkleLib {
|
||||||
} else {
|
} else {
|
||||||
InstallConfiguration ();
|
InstallConfiguration ();
|
||||||
InstallExcludeRules ();
|
InstallExcludeRules ();
|
||||||
|
AddWarnings ();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override string [] Warnings {
|
private void AddWarnings ()
|
||||||
get {
|
{
|
||||||
SparkleGit git = new SparkleGit (SparkleConfig.DefaultConfig.TmpPath,
|
SparkleGit git = new SparkleGit (SparkleConfig.DefaultConfig.TmpPath,
|
||||||
"config --global core.excludesfile");
|
"config --global core.excludesfile");
|
||||||
|
|
||||||
|
@ -158,16 +158,16 @@ namespace SparkleLib {
|
||||||
git.WaitForExit ();
|
git.WaitForExit ();
|
||||||
|
|
||||||
if (string.IsNullOrEmpty (output)) {
|
if (string.IsNullOrEmpty (output)) {
|
||||||
return null;
|
return;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return new string [] {
|
Warnings = new string [] {
|
||||||
string.Format ("You seem to have configured a system ‘gitignore’ file. " +
|
string.Format ("You seem to have configured a system ‘gitignore’ file. " +
|
||||||
"This may interfere with SparkleShare.\n({0})", output)
|
"This may interfere with SparkleShare.\n({0})", output)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public override void Stop ()
|
public override void Stop ()
|
||||||
{
|
{
|
||||||
|
@ -176,7 +176,7 @@ namespace SparkleLib {
|
||||||
this.git.Dispose ();
|
this.git.Dispose ();
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Stop ();
|
Dispose ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ namespace SparkleLib {
|
||||||
// the newly cloned repository
|
// the newly cloned repository
|
||||||
private void InstallConfiguration ()
|
private void InstallConfiguration ()
|
||||||
{
|
{
|
||||||
string repo_config_file_path = SparkleHelpers.CombineMore (base.target_folder, ".git", "config");
|
string repo_config_file_path = SparkleHelpers.CombineMore (TargetFolder, ".git", "config");
|
||||||
string config = String.Join (Environment.NewLine, File.ReadAllLines (repo_config_file_path));
|
string config = String.Join (Environment.NewLine, File.ReadAllLines (repo_config_file_path));
|
||||||
|
|
||||||
string n = Environment.NewLine;
|
string n = Environment.NewLine;
|
||||||
|
@ -220,7 +220,7 @@ namespace SparkleLib {
|
||||||
private void InstallExcludeRules ()
|
private void InstallExcludeRules ()
|
||||||
{
|
{
|
||||||
DirectoryInfo info = Directory.CreateDirectory (
|
DirectoryInfo info = Directory.CreateDirectory (
|
||||||
SparkleHelpers.CombineMore (this.target_folder, ".git", "info"));
|
SparkleHelpers.CombineMore (TargetFolder, ".git", "info"));
|
||||||
|
|
||||||
// File that lists the files we want git to ignore
|
// File that lists the files we want git to ignore
|
||||||
string exclude_rules_file_path = Path.Combine (info.FullName, "exclude");
|
string exclude_rules_file_path = Path.Combine (info.FullName, "exclude");
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace SparkleLib {
|
namespace SparkleLib {
|
||||||
|
@ -23,28 +24,58 @@ namespace SparkleLib {
|
||||||
public class SparkleGit : Process {
|
public class SparkleGit : Process {
|
||||||
|
|
||||||
public static string ExecPath = null;
|
public static string ExecPath = null;
|
||||||
|
public static string Path = null;
|
||||||
|
|
||||||
|
|
||||||
public SparkleGit (string path, string args) : base ()
|
public SparkleGit (string path, string args) : base ()
|
||||||
{
|
{
|
||||||
|
Path = LocateGit ();
|
||||||
|
|
||||||
EnableRaisingEvents = true;
|
EnableRaisingEvents = true;
|
||||||
StartInfo.FileName = SparkleBackend.DefaultBackend.Path;
|
StartInfo.FileName = Path;
|
||||||
StartInfo.RedirectStandardOutput = true;
|
StartInfo.RedirectStandardOutput = true;
|
||||||
StartInfo.UseShellExecute = false;
|
StartInfo.UseShellExecute = false;
|
||||||
StartInfo.WorkingDirectory = path;
|
StartInfo.WorkingDirectory = path;
|
||||||
StartInfo.CreateNoWindow = true;
|
StartInfo.CreateNoWindow = true;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty (ExecPath))
|
if (string.IsNullOrEmpty (ExecPath))
|
||||||
StartInfo.Arguments = "--exec-path=\"" + ExecPath + "\" " + args;
|
|
||||||
else
|
|
||||||
StartInfo.Arguments = args;
|
StartInfo.Arguments = args;
|
||||||
|
else
|
||||||
|
StartInfo.Arguments = "--exec-path=\"" + ExecPath + "\" " + args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
new public void Start ()
|
new public void Start ()
|
||||||
{
|
{
|
||||||
SparkleHelpers.DebugInfo ("Cmd", "git " + StartInfo.Arguments);
|
SparkleHelpers.DebugInfo ("Cmd", "git " + StartInfo.Arguments);
|
||||||
|
|
||||||
|
try {
|
||||||
base.Start ();
|
base.Start ();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
SparkleHelpers.DebugInfo ("Cmd", "There's a problem running Git: " + e.Message);
|
||||||
|
Environment.Exit (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string LocateGit ()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty (Path))
|
||||||
|
return Path;
|
||||||
|
|
||||||
|
string [] possible_git_paths = new string [] {
|
||||||
|
"/usr/bin/git",
|
||||||
|
"/usr/local/bin/git",
|
||||||
|
"/opt/local/bin/git",
|
||||||
|
"/usr/local/git/bin/git"
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (string path in possible_git_paths)
|
||||||
|
if (File.Exists (path))
|
||||||
|
return path;
|
||||||
|
|
||||||
|
return "git";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,8 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Xml;
|
|
||||||
|
|
||||||
namespace SparkleLib {
|
namespace SparkleLib {
|
||||||
|
|
||||||
|
@ -63,7 +61,7 @@ namespace SparkleLib {
|
||||||
public override List<string> ExcludePaths {
|
public override List<string> ExcludePaths {
|
||||||
get {
|
get {
|
||||||
List<string> rules = new List<string> ();
|
List<string> rules = new List<string> ();
|
||||||
rules.Add (Path.DirectorySeparatorChar + ".git");
|
rules.Add (".git");
|
||||||
|
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
@ -98,12 +96,12 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void CalculateSizes ()
|
private void UpdateSizes ()
|
||||||
{
|
{
|
||||||
double size = CalculateSize (
|
double size = CalculateSizes (
|
||||||
new DirectoryInfo (LocalPath));
|
new DirectoryInfo (LocalPath));
|
||||||
|
|
||||||
double history_size = CalculateSize (
|
double history_size = CalculateSizes (
|
||||||
new DirectoryInfo (Path.Combine (LocalPath, ".git")));
|
new DirectoryInfo (Path.Combine (LocalPath, ".git")));
|
||||||
|
|
||||||
string size_file_path = new string [] {LocalPath, ".git", "repo_size"}.Combine ();
|
string size_file_path = new string [] {LocalPath, ".git", "repo_size"}.Combine ();
|
||||||
|
@ -167,8 +165,9 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override bool CheckForRemoteChanges ()
|
public override bool HasRemoteChanges
|
||||||
{
|
{
|
||||||
|
get {
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Checking for remote changes...");
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Checking for remote changes...");
|
||||||
SparkleGit git = new SparkleGit (LocalPath, "ls-remote " + Url + " master");
|
SparkleGit git = new SparkleGit (LocalPath, "ls-remote " + Url + " master");
|
||||||
|
|
||||||
|
@ -181,18 +180,21 @@ namespace SparkleLib {
|
||||||
string remote_revision = git.StandardOutput.ReadToEnd ().TrimEnd ();
|
string remote_revision = git.StandardOutput.ReadToEnd ().TrimEnd ();
|
||||||
|
|
||||||
if (!remote_revision.StartsWith (CurrentRevision)) {
|
if (!remote_revision.StartsWith (CurrentRevision)) {
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Remote changes found. (" + remote_revision + ")");
|
SparkleHelpers.DebugInfo ("Git",
|
||||||
|
"[" + Name + "] Remote changes found. (" + remote_revision + ")");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public override bool SyncUp ()
|
public override bool SyncUp ()
|
||||||
{
|
{
|
||||||
if (AnyDifferences) {
|
if (HasLocalChanges) {
|
||||||
Add ();
|
Add ();
|
||||||
|
|
||||||
string message = FormatCommitMessage ();
|
string message = FormatCommitMessage ();
|
||||||
|
@ -242,13 +244,13 @@ namespace SparkleLib {
|
||||||
|
|
||||||
if (number >= percentage) {
|
if (number >= percentage) {
|
||||||
percentage = number;
|
percentage = number;
|
||||||
base.OnSyncProgressChanged (percentage, speed);
|
base.OnProgressChanged (percentage, speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
git.WaitForExit ();
|
git.WaitForExit ();
|
||||||
|
|
||||||
CalculateSizes ();
|
UpdateSizes ();
|
||||||
|
|
||||||
if (git.ExitCode == 0)
|
if (git.ExitCode == 0)
|
||||||
return true;
|
return true;
|
||||||
|
@ -299,13 +301,13 @@ namespace SparkleLib {
|
||||||
|
|
||||||
if (number >= percentage) {
|
if (number >= percentage) {
|
||||||
percentage = number;
|
percentage = number;
|
||||||
base.OnSyncProgressChanged (percentage, speed);
|
base.OnProgressChanged (percentage, speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
git.WaitForExit ();
|
git.WaitForExit ();
|
||||||
|
|
||||||
CalculateSizes ();
|
UpdateSizes ();
|
||||||
|
|
||||||
if (git.ExitCode == 0) {
|
if (git.ExitCode == 0) {
|
||||||
Rebase ();
|
Rebase ();
|
||||||
|
@ -317,7 +319,7 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override bool AnyDifferences {
|
public override bool HasLocalChanges {
|
||||||
get {
|
get {
|
||||||
PrepareDirectories (LocalPath);
|
PrepareDirectories (LocalPath);
|
||||||
|
|
||||||
|
@ -412,7 +414,7 @@ namespace SparkleLib {
|
||||||
{
|
{
|
||||||
DisableWatching ();
|
DisableWatching ();
|
||||||
|
|
||||||
if (AnyDifferences) {
|
if (HasLocalChanges) {
|
||||||
Add ();
|
Add ();
|
||||||
|
|
||||||
string commit_message = FormatCommitMessage ();
|
string commit_message = FormatCommitMessage ();
|
||||||
|
@ -427,7 +429,7 @@ namespace SparkleLib {
|
||||||
if (git.ExitCode != 0) {
|
if (git.ExitCode != 0) {
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Conflict detected. Trying to get out...");
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Conflict detected. Trying to get out...");
|
||||||
|
|
||||||
while (AnyDifferences)
|
while (HasLocalChanges)
|
||||||
ResolveConflict ();
|
ResolveConflict ();
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Conflict resolved.");
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Conflict resolved.");
|
||||||
|
@ -653,7 +655,8 @@ namespace SparkleLib {
|
||||||
string to_file_path;
|
string to_file_path;
|
||||||
|
|
||||||
if (file_path.EndsWith (".empty"))
|
if (file_path.EndsWith (".empty"))
|
||||||
file_path = file_path.Substring (0, file_path.Length - ".empty".Length);
|
file_path = file_path.Substring (0,
|
||||||
|
file_path.Length - ".empty".Length);
|
||||||
|
|
||||||
if (change_type.Equals ("A") && !file_path.Contains (".notes")) {
|
if (change_type.Equals ("A") && !file_path.Contains (".notes")) {
|
||||||
change_set.Added.Add (file_path);
|
change_set.Added.Add (file_path);
|
||||||
|
@ -669,6 +672,14 @@ namespace SparkleLib {
|
||||||
file_path = entry_line.Substring (42, tab_pos - 42);
|
file_path = entry_line.Substring (42, tab_pos - 42);
|
||||||
to_file_path = entry_line.Substring (tab_pos + 1);
|
to_file_path = entry_line.Substring (tab_pos + 1);
|
||||||
|
|
||||||
|
if (file_path.EndsWith (".empty"))
|
||||||
|
file_path = file_path.Substring (0,
|
||||||
|
file_path.Length - ".empty".Length);
|
||||||
|
|
||||||
|
if (to_file_path.EndsWith (".empty"))
|
||||||
|
to_file_path = to_file_path.Substring (0,
|
||||||
|
to_file_path.Length - ".empty".Length);
|
||||||
|
|
||||||
change_set.MovedFrom.Add (file_path);
|
change_set.MovedFrom.Add (file_path);
|
||||||
change_set.MovedTo.Add (to_file_path);
|
change_set.MovedTo.Add (to_file_path);
|
||||||
}
|
}
|
||||||
|
@ -807,34 +818,15 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override bool UsesNotificationCenter
|
|
||||||
{
|
|
||||||
get {
|
|
||||||
string file_path = SparkleHelpers.CombineMore (LocalPath, ".git", "disable_notification_center");
|
|
||||||
return !File.Exists (file_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override void CreateInitialChangeSet ()
|
|
||||||
{
|
|
||||||
base.CreateInitialChangeSet ();
|
|
||||||
SyncUp ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Recursively gets a folder's size in bytes
|
// Recursively gets a folder's size in bytes
|
||||||
public override double CalculateSize (DirectoryInfo parent)
|
private double CalculateSizes (DirectoryInfo parent)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists (parent.ToString ()))
|
if (!Directory.Exists (parent.ToString ()))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
double size = 0;
|
double size = 0;
|
||||||
|
|
||||||
// Ignore the temporary 'rebase-apply' and '.tmp' directories. This prevents potential
|
if (parent.Name.Equals ("rebase-apply"))
|
||||||
// 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;
|
return 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -846,7 +838,7 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (DirectoryInfo directory in parent.GetDirectories ())
|
foreach (DirectoryInfo directory in parent.GetDirectories ())
|
||||||
size += CalculateSize (directory);
|
size += CalculateSizes (directory);
|
||||||
|
|
||||||
} catch (Exception) {
|
} catch (Exception) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -6,6 +6,7 @@ SOURCES = \
|
||||||
Git/SparkleFetcherGit.cs \
|
Git/SparkleFetcherGit.cs \
|
||||||
Git/SparkleGit.cs \
|
Git/SparkleGit.cs \
|
||||||
Git/SparkleRepoGit.cs \
|
Git/SparkleRepoGit.cs \
|
||||||
|
SparkleAnnouncement.cs \
|
||||||
SparkleBackend.cs \
|
SparkleBackend.cs \
|
||||||
SparkleChangeSet.cs \
|
SparkleChangeSet.cs \
|
||||||
SparkleConfig.cs \
|
SparkleConfig.cs \
|
||||||
|
@ -13,6 +14,7 @@ SOURCES = \
|
||||||
SparkleFetcherBase.cs \
|
SparkleFetcherBase.cs \
|
||||||
SparkleHelpers.cs \
|
SparkleHelpers.cs \
|
||||||
SparkleListenerBase.cs \
|
SparkleListenerBase.cs \
|
||||||
|
SparkleListenerFactory.cs \
|
||||||
SparkleListenerTcp.cs \
|
SparkleListenerTcp.cs \
|
||||||
SparkleRepoBase.cs \
|
SparkleRepoBase.cs \
|
||||||
SparkleWatcher.cs
|
SparkleWatcher.cs
|
||||||
|
|
34
SparkleLib/SparkleAnnouncement.cs
Normal file
34
SparkleLib/SparkleAnnouncement.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// SparkleShare, a collaboration and sharing tool.
|
||||||
|
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
||||||
|
//
|
||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace SparkleLib {
|
||||||
|
|
||||||
|
public class SparkleAnnouncement {
|
||||||
|
|
||||||
|
public readonly string FolderIdentifier;
|
||||||
|
public readonly string Message;
|
||||||
|
|
||||||
|
|
||||||
|
public SparkleAnnouncement (string folder_identifier, string message)
|
||||||
|
{
|
||||||
|
FolderIdentifier = folder_identifier;
|
||||||
|
Message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,40 +21,7 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace SparkleLib {
|
namespace SparkleLib {
|
||||||
|
|
||||||
public class SparkleBackend {
|
public static class SparkleBackend {
|
||||||
|
|
||||||
public static SparkleBackend DefaultBackend = new SparkleBackendGit ();
|
|
||||||
|
|
||||||
public string Name;
|
|
||||||
public string Path;
|
|
||||||
|
|
||||||
|
|
||||||
public SparkleBackend (string name, string [] paths)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
Path = "git";
|
|
||||||
|
|
||||||
foreach (string path in paths) {
|
|
||||||
if (File.Exists (path)) {
|
|
||||||
Path = path;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public bool IsPresent {
|
|
||||||
get {
|
|
||||||
return (Path != null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public bool IsUsablePath (string path)
|
|
||||||
{
|
|
||||||
return (path.Length > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static string Version {
|
public static string Version {
|
||||||
get {
|
get {
|
||||||
|
@ -65,7 +32,7 @@ namespace SparkleLib {
|
||||||
|
|
||||||
// Strange magic needed by Platform ()
|
// Strange magic needed by Platform ()
|
||||||
[DllImport ("libc")]
|
[DllImport ("libc")]
|
||||||
static extern int uname (IntPtr buf);
|
private static extern int uname (IntPtr buf);
|
||||||
|
|
||||||
|
|
||||||
// This fixes the PlatformID enumeration for MacOSX in Environment.OSVersion.Platform,
|
// This fixes the PlatformID enumeration for MacOSX in Environment.OSVersion.Platform,
|
||||||
|
@ -90,44 +57,4 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class SparkleBackendGit : SparkleBackend {
|
|
||||||
|
|
||||||
private static string name = "Git";
|
|
||||||
private static string [] paths = new string [] {
|
|
||||||
"/opt/local/bin/git",
|
|
||||||
"/usr/bin/git",
|
|
||||||
"/usr/local/bin/git",
|
|
||||||
"/usr/local/git/bin/git"
|
|
||||||
};
|
|
||||||
|
|
||||||
public SparkleBackendGit () : base (name, paths) { }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class SparkleBackendHg : SparkleBackend {
|
|
||||||
|
|
||||||
private static string name = "Hg";
|
|
||||||
private static string [] paths = new string [] {
|
|
||||||
"/opt/local/bin/hg",
|
|
||||||
"/usr/bin/hg"
|
|
||||||
};
|
|
||||||
|
|
||||||
public SparkleBackendHg () : base (name, paths) { }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class SparkleBackendScp : SparkleBackend {
|
|
||||||
|
|
||||||
private static string name = "Scp";
|
|
||||||
private static string [] paths = new string [] {
|
|
||||||
"/usr/bin/scp"
|
|
||||||
};
|
|
||||||
|
|
||||||
public SparkleBackendScp () : base (name, paths) { }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ namespace SparkleLib {
|
||||||
Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
|
Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
|
||||||
"sparkleshare");
|
"sparkleshare");
|
||||||
|
|
||||||
|
// TODO: declare elsewhere
|
||||||
public static SparkleConfig DefaultConfig = new SparkleConfig (default_config_path, "config.xml");
|
public static SparkleConfig DefaultConfig = new SparkleConfig (default_config_path, "config.xml");
|
||||||
public static bool DebugMode = true;
|
public static bool DebugMode = true;
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,7 @@
|
||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.AccessControl;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
@ -37,18 +35,21 @@ namespace SparkleLib {
|
||||||
public event FailedEventHandler Failed;
|
public event FailedEventHandler Failed;
|
||||||
public event ProgressChangedEventHandler ProgressChanged;
|
public event ProgressChangedEventHandler ProgressChanged;
|
||||||
|
|
||||||
public string [] ExcludeRules;
|
public abstract bool Fetch ();
|
||||||
|
public abstract void Stop ();
|
||||||
|
|
||||||
protected string target_folder;
|
public string TargetFolder;
|
||||||
protected string remote_url;
|
public string RemoteUrl;
|
||||||
|
public string [] ExcludeRules;
|
||||||
|
public string [] Warnings;
|
||||||
|
|
||||||
private Thread thread;
|
private Thread thread;
|
||||||
|
|
||||||
|
|
||||||
public SparkleFetcherBase (string server, string remote_folder, string target_folder)
|
public SparkleFetcherBase (string server, string remote_folder, string target_folder)
|
||||||
{
|
{
|
||||||
this.target_folder = target_folder;
|
TargetFolder = target_folder;
|
||||||
this.remote_url = server + "/" + remote_folder;
|
RemoteUrl = server + "/" + remote_folder;
|
||||||
|
|
||||||
ExcludeRules = new string [] {
|
ExcludeRules = new string [] {
|
||||||
// gedit and emacs
|
// gedit and emacs
|
||||||
|
@ -121,22 +122,18 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public abstract bool Fetch ();
|
|
||||||
public abstract string [] Warnings { get; }
|
|
||||||
|
|
||||||
|
|
||||||
// Clones the remote repository
|
// Clones the remote repository
|
||||||
public void Start ()
|
public void Start ()
|
||||||
{
|
{
|
||||||
SparkleHelpers.DebugInfo ("Fetcher", "[" + this.target_folder + "] Fetching folder: " + this.remote_url);
|
SparkleHelpers.DebugInfo ("Fetcher", "[" + TargetFolder + "] Fetching folder: " + RemoteUrl);
|
||||||
|
|
||||||
if (Started != null)
|
if (Started != null)
|
||||||
Started ();
|
Started ();
|
||||||
|
|
||||||
if (Directory.Exists (this.target_folder))
|
if (Directory.Exists (TargetFolder))
|
||||||
Directory.Delete (this.target_folder, true);
|
Directory.Delete (TargetFolder, true);
|
||||||
|
|
||||||
string host = GetHost (this.remote_url);
|
string host = GetHost (RemoteUrl);
|
||||||
|
|
||||||
if (String.IsNullOrEmpty (host)) {
|
if (String.IsNullOrEmpty (host)) {
|
||||||
if (Failed != null)
|
if (Failed != null)
|
||||||
|
@ -170,20 +167,6 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public virtual void Stop ()
|
|
||||||
{
|
|
||||||
this.thread.Abort ();
|
|
||||||
this.thread.Join ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public string RemoteUrl {
|
|
||||||
get {
|
|
||||||
return this.remote_url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Dispose ()
|
public void Dispose ()
|
||||||
{
|
{
|
||||||
if (this.thread != null) {
|
if (this.thread != null) {
|
||||||
|
|
|
@ -40,12 +40,14 @@
|
||||||
<Compile Include="Git/SparkleFetcherGit.cs" />
|
<Compile Include="Git/SparkleFetcherGit.cs" />
|
||||||
<Compile Include="Hg/SparkleFetcherHg.cs" />
|
<Compile Include="Hg/SparkleFetcherHg.cs" />
|
||||||
<Compile Include="Defines.cs" />
|
<Compile Include="Defines.cs" />
|
||||||
|
<Compile Include="SparkleAnnouncement.cs" />
|
||||||
<Compile Include="SparkleHelpers.cs" />
|
<Compile Include="SparkleHelpers.cs" />
|
||||||
<Compile Include="SparklePaths.cs" />
|
<Compile Include="SparklePaths.cs" />
|
||||||
<Compile Include="SparkleOptions.cs" />
|
<Compile Include="SparkleOptions.cs" />
|
||||||
<Compile Include="SparkleChangeSet.cs" />
|
<Compile Include="SparkleChangeSet.cs" />
|
||||||
<Compile Include="SparkleListenerBase.cs" />
|
<Compile Include="SparkleListenerBase.cs" />
|
||||||
<Compile Include="SparkleListenerIrc.cs" />
|
<Compile Include="SparkleListenerFactory.cs" />
|
||||||
|
<Compile Include="SparkleListenerTcp.cs" />
|
||||||
<Compile Include="SparkleBackend.cs" />
|
<Compile Include="SparkleBackend.cs" />
|
||||||
<Compile Include="SparkleConfig.cs" />
|
<Compile Include="SparkleConfig.cs" />
|
||||||
<Compile Include="SparkleWatcher.cs" />
|
<Compile Include="SparkleWatcher.cs" />
|
||||||
|
|
|
@ -16,76 +16,11 @@
|
||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace SparkleLib {
|
namespace SparkleLib {
|
||||||
|
|
||||||
public class SparkleAnnouncement {
|
|
||||||
|
|
||||||
public readonly string FolderIdentifier;
|
|
||||||
public readonly string Message;
|
|
||||||
|
|
||||||
|
|
||||||
public SparkleAnnouncement (string folder_identifier, string message)
|
|
||||||
{
|
|
||||||
FolderIdentifier = folder_identifier;
|
|
||||||
Message = message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class SparkleListenerFactory {
|
|
||||||
|
|
||||||
private static List<SparkleListenerBase> listeners = new List<SparkleListenerBase> ();
|
|
||||||
|
|
||||||
public static SparkleListenerBase CreateListener (string folder_name, string folder_identifier)
|
|
||||||
{
|
|
||||||
string uri = SparkleConfig.DefaultConfig.GetFolderOptionalAttribute (
|
|
||||||
folder_name, "announcements_url");
|
|
||||||
|
|
||||||
if (uri == null) {
|
|
||||||
// This is SparkleShare's centralized notification service.
|
|
||||||
// Don't worry, we only use this server as a backup if you
|
|
||||||
// don't have your own. All data needed to connect is hashed and
|
|
||||||
// we don't store any personal information ever
|
|
||||||
|
|
||||||
uri = "tcp://notifications.sparkleshare.org:1986";
|
|
||||||
}
|
|
||||||
|
|
||||||
Uri announce_uri = new Uri (uri);
|
|
||||||
|
|
||||||
// We use only one listener per server to keep
|
|
||||||
// the number of connections as low as possible
|
|
||||||
foreach (SparkleListenerBase listener in listeners) {
|
|
||||||
if (listener.Server.Equals (announce_uri)) {
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerFactory",
|
|
||||||
"Refered to existing listener for " + announce_uri);
|
|
||||||
|
|
||||||
listener.AlsoListenToBase (folder_identifier);
|
|
||||||
return (SparkleListenerBase) listener;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new listener with the appropriate
|
|
||||||
// type if one doesn't exist yet for that server
|
|
||||||
switch (announce_uri.Scheme) {
|
|
||||||
case "tcp":
|
|
||||||
listeners.Add (new SparkleListenerTcp (announce_uri, folder_identifier));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
listeners.Add (new SparkleListenerTcp (announce_uri, folder_identifier));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerFactory", "Issued new listener for " + announce_uri);
|
|
||||||
return (SparkleListenerBase) listeners [listeners.Count - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// A persistent connection to the server that
|
// A persistent connection to the server that
|
||||||
// listens for change notifications
|
// listens for change notifications
|
||||||
public abstract class SparkleListenerBase {
|
public abstract class SparkleListenerBase {
|
||||||
|
@ -105,8 +40,8 @@ namespace SparkleLib {
|
||||||
public abstract void Connect ();
|
public abstract void Connect ();
|
||||||
public abstract bool IsConnected { get; }
|
public abstract bool IsConnected { get; }
|
||||||
public abstract bool IsConnecting { get; }
|
public abstract bool IsConnecting { get; }
|
||||||
protected abstract void Announce (SparkleAnnouncement announcent);
|
protected abstract void AnnounceInternal (SparkleAnnouncement announcent);
|
||||||
protected abstract void AlsoListenTo (string folder_identifier);
|
protected abstract void AlsoListenToInternal (string folder_identifier);
|
||||||
|
|
||||||
|
|
||||||
protected List<string> channels = new List<string> ();
|
protected List<string> channels = new List<string> ();
|
||||||
|
@ -143,7 +78,7 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void AnnounceBase (SparkleAnnouncement announcement)
|
public void Announce (SparkleAnnouncement announcement)
|
||||||
{
|
{
|
||||||
if (!IsRecentAnnouncement (announcement)) {
|
if (!IsRecentAnnouncement (announcement)) {
|
||||||
if (IsConnected) {
|
if (IsConnected) {
|
||||||
|
@ -151,7 +86,7 @@ namespace SparkleLib {
|
||||||
"Announcing message " + announcement.Message + " to " +
|
"Announcing message " + announcement.Message + " to " +
|
||||||
announcement.FolderIdentifier + " on " + Server);
|
announcement.FolderIdentifier + " on " + Server);
|
||||||
|
|
||||||
Announce (announcement);
|
AnnounceInternal (announcement);
|
||||||
AddRecentAnnouncement (announcement);
|
AddRecentAnnouncement (announcement);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -170,14 +105,14 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void AlsoListenToBase (string channel)
|
public void AlsoListenTo (string channel)
|
||||||
{
|
{
|
||||||
if (!this.channels.Contains (channel) && IsConnected) {
|
if (!this.channels.Contains (channel) && IsConnected) {
|
||||||
SparkleHelpers.DebugInfo ("Listener",
|
SparkleHelpers.DebugInfo ("Listener",
|
||||||
"Subscribing to channel " + channel);
|
"Subscribing to channel " + channel);
|
||||||
|
|
||||||
this.channels.Add (channel);
|
this.channels.Add (channel);
|
||||||
AlsoListenTo (channel);
|
AlsoListenToInternal (channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +137,7 @@ namespace SparkleLib {
|
||||||
|
|
||||||
foreach (KeyValuePair<string, SparkleAnnouncement> item in this.queue_up) {
|
foreach (KeyValuePair<string, SparkleAnnouncement> item in this.queue_up) {
|
||||||
SparkleAnnouncement announcement = item.Value;
|
SparkleAnnouncement announcement = item.Value;
|
||||||
AnnounceBase (announcement);
|
Announce (announcement);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.queue_down.Clear ();
|
this.queue_down.Clear ();
|
||||||
|
@ -210,9 +145,9 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void OnDisconnected ()
|
public void OnDisconnected (string message)
|
||||||
{
|
{
|
||||||
SparkleHelpers.DebugInfo ("Listener", "Signal of " + Server + " lost");
|
SparkleHelpers.DebugInfo ("Listener", "Disconnected from " + Server + ": " + message);
|
||||||
|
|
||||||
if (Disconnected != null)
|
if (Disconnected != null)
|
||||||
Disconnected ();
|
Disconnected ();
|
||||||
|
@ -294,4 +229,3 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
89
SparkleLib/SparkleListenerFactory.cs
Normal file
89
SparkleLib/SparkleListenerFactory.cs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
// SparkleShare, a collaboration and sharing tool.
|
||||||
|
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
||||||
|
//
|
||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace SparkleLib {
|
||||||
|
|
||||||
|
public static class SparkleListenerFactory {
|
||||||
|
|
||||||
|
private static List<SparkleListenerBase> listeners = new List<SparkleListenerBase> ();
|
||||||
|
|
||||||
|
|
||||||
|
public static SparkleListenerBase CreateListener (string folder_name, string folder_identifier)
|
||||||
|
{
|
||||||
|
// Check if the user wants to use a global custom notification service
|
||||||
|
string uri = SparkleConfig.DefaultConfig.GetConfigOption ("announcements_url");
|
||||||
|
|
||||||
|
// Check if the user wants a use a custom notification service for this folder
|
||||||
|
if (string.IsNullOrEmpty (uri))
|
||||||
|
uri = SparkleConfig.DefaultConfig.GetFolderOptionalAttribute (
|
||||||
|
folder_name, "announcements_url");
|
||||||
|
|
||||||
|
// Fall back to the fallback service is neither is the case
|
||||||
|
if (string.IsNullOrEmpty (uri)) {
|
||||||
|
// This is SparkleShare's centralized notification service.
|
||||||
|
// It communicates "It's time to sync!" signals between clients.
|
||||||
|
//
|
||||||
|
// Here's how it works: the client listens to a channel (the
|
||||||
|
// folder identifier, a SHA-1 hash) for when it's time to sync.
|
||||||
|
// Clients also send the current revision hash to the channel
|
||||||
|
// for other clients to pick up when you've synced up any
|
||||||
|
// changes.
|
||||||
|
//
|
||||||
|
// Please see the SparkleShare wiki if you wish to run
|
||||||
|
// your own service instead
|
||||||
|
|
||||||
|
uri = "tcp://notifications.sparkleshare.org:1986";
|
||||||
|
}
|
||||||
|
|
||||||
|
Uri announce_uri = new Uri (uri);
|
||||||
|
|
||||||
|
// We use only one listener per notification service to keep
|
||||||
|
// the number of connections as low as possible
|
||||||
|
foreach (SparkleListenerBase listener in listeners) {
|
||||||
|
if (listener.Server.Equals (announce_uri)) {
|
||||||
|
SparkleHelpers.DebugInfo ("ListenerFactory",
|
||||||
|
"Refered to existing " + announce_uri.Scheme +
|
||||||
|
" listener for " + announce_uri);
|
||||||
|
|
||||||
|
// We already seem to have a listener for this server,
|
||||||
|
// refer to the existing one instead
|
||||||
|
listener.AlsoListenTo (folder_identifier);
|
||||||
|
return (SparkleListenerBase) listener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new listener with the appropriate
|
||||||
|
// type if one doesn't exist yet for that server
|
||||||
|
switch (announce_uri.Scheme) {
|
||||||
|
case "tcp":
|
||||||
|
listeners.Add (new SparkleListenerTcp (announce_uri, folder_identifier));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
listeners.Add (new SparkleListenerTcp (announce_uri, folder_identifier));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SparkleHelpers.DebugInfo ("ListenerFactory",
|
||||||
|
"Issued new " + announce_uri.Scheme + " listener for " + announce_uri);
|
||||||
|
|
||||||
|
return (SparkleListenerBase) listeners [listeners.Count - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,23 +16,20 @@
|
||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Net.Sockets;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Xml.Serialization;
|
|
||||||
|
|
||||||
namespace SparkleLib {
|
namespace SparkleLib {
|
||||||
|
|
||||||
public class SparkleListenerTcp : SparkleListenerBase {
|
public class SparkleListenerTcp : SparkleListenerBase {
|
||||||
|
|
||||||
private Socket socket;
|
private Socket socket;
|
||||||
private Object socket_lock = new Object ();
|
|
||||||
private Thread thread;
|
private Thread thread;
|
||||||
|
private Object socket_lock = new Object ();
|
||||||
private bool is_connected = false;
|
private bool is_connected = false;
|
||||||
private bool is_connecting = false;
|
private bool is_connecting = false;
|
||||||
|
private DateTime last_ping = DateTime.Now;
|
||||||
|
|
||||||
|
|
||||||
public SparkleListenerTcp (Uri server, string folder_identifier) :
|
public SparkleListenerTcp (Uri server, string folder_identifier) :
|
||||||
|
@ -60,27 +57,24 @@ namespace SparkleLib {
|
||||||
// Starts a new thread and listens to the channel
|
// Starts a new thread and listens to the channel
|
||||||
public override void Connect ()
|
public override void Connect ()
|
||||||
{
|
{
|
||||||
SparkleHelpers.DebugInfo ("ListenerTcp", "Connecting to " + Server.Host);
|
|
||||||
|
|
||||||
this.is_connecting = true;
|
this.is_connecting = true;
|
||||||
|
|
||||||
this.thread = new Thread (
|
this.thread = new Thread (
|
||||||
new ThreadStart (delegate {
|
new ThreadStart (delegate {
|
||||||
try {
|
|
||||||
// Connect and subscribe to the channel
|
|
||||||
int port = Server.Port;
|
int port = Server.Port;
|
||||||
|
|
||||||
if (port < 0)
|
if (port < 0)
|
||||||
port = 9999;
|
port = 1986;
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
lock (this.socket_lock) {
|
lock (this.socket_lock) {
|
||||||
this.socket = new Socket (AddressFamily.InterNetwork,
|
this.socket = new Socket (AddressFamily.InterNetwork,
|
||||||
SocketType.Stream, ProtocolType.Tcp) {
|
SocketType.Stream, ProtocolType.Tcp) {
|
||||||
|
ReceiveTimeout = 5 * 1000,
|
||||||
ReceiveTimeout = 30 * 1000
|
SendTimeout = 5 * 1000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Try to connect to the server
|
||||||
this.socket.Connect (Server.Host, port);
|
this.socket.Connect (Server.Host, port);
|
||||||
|
|
||||||
this.is_connecting = false;
|
this.is_connecting = false;
|
||||||
|
@ -88,19 +82,96 @@ namespace SparkleLib {
|
||||||
|
|
||||||
OnConnected ();
|
OnConnected ();
|
||||||
|
|
||||||
foreach (string channel in base.channels) {
|
// Subscribe to channels of interest to us
|
||||||
SparkleHelpers.DebugInfo ("ListenerTcp", "Subscribing to channel " + channel);
|
foreach (string channel in base.channels)
|
||||||
this.socket.Send (Encoding.UTF8.GetBytes ("subscribe " + channel + "\n"));
|
AlsoListenToInternal (channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} catch (SocketException e) {
|
||||||
|
this.is_connected = false;
|
||||||
|
this.is_connecting = false;
|
||||||
|
|
||||||
|
this.socket.Dispose ();
|
||||||
|
|
||||||
|
OnDisconnected (e.Message);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
byte [] bytes = new byte [4096];
|
byte [] bytes = new byte [4096];
|
||||||
|
int bytes_read = 0;
|
||||||
|
this.last_ping = DateTime.Now;
|
||||||
|
|
||||||
// List to the channels, this blocks the thread
|
// Wait for messages
|
||||||
while (this.socket.Connected) {
|
while (this.is_connected) {
|
||||||
int bytes_read = this.socket.Receive (bytes);
|
|
||||||
|
|
||||||
|
// This blocks the thread
|
||||||
|
int i = 0;
|
||||||
|
while (this.socket.Available < 1) {
|
||||||
|
Thread.Sleep (1000);
|
||||||
|
i++;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// We've timed out, let's ping the server to
|
||||||
|
// see if the connection is still up
|
||||||
|
if (i == 180) {
|
||||||
|
SparkleHelpers.DebugInfo ("ListenerTcp",
|
||||||
|
"Pinging " + Server);
|
||||||
|
|
||||||
|
byte [] ping_bytes = Encoding.UTF8.GetBytes ("ping\n");
|
||||||
|
byte [] pong_bytes = new byte [4096];
|
||||||
|
|
||||||
|
lock (this.socket_lock)
|
||||||
|
this.socket.Send (ping_bytes);
|
||||||
|
|
||||||
|
if (this.socket.Receive (pong_bytes) < 1)
|
||||||
|
// 10057 means "Socket is not connected"
|
||||||
|
throw new SocketException (10057);
|
||||||
|
|
||||||
|
SparkleHelpers.DebugInfo ("ListenerTcp",
|
||||||
|
"Received pong from " + Server);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
this.last_ping = DateTime.Now;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Check when the last ping occured. If it's
|
||||||
|
// significantly longer than our regular interval the
|
||||||
|
// system likely woke up from sleep and we want to
|
||||||
|
// simulate a disconnect
|
||||||
|
int sleepiness = DateTime.Compare (
|
||||||
|
this.last_ping.AddMilliseconds (180 * 1000 * 1.2),
|
||||||
|
DateTime.Now
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sleepiness <= 0) {
|
||||||
|
SparkleHelpers.DebugInfo ("ListenerTcp",
|
||||||
|
"System woke up from sleep");
|
||||||
|
|
||||||
|
// 10057 means "Socket is not connected"
|
||||||
|
throw new SocketException (10057);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ping failed: disconnect completely
|
||||||
|
} catch (SocketException) {
|
||||||
|
this.is_connected = false;
|
||||||
|
this.is_connecting = false;;
|
||||||
|
|
||||||
|
this.socket.Dispose ();
|
||||||
|
|
||||||
|
OnDisconnected ("Ping timeout");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (this.socket.Available > 0)
|
||||||
|
lock (this.socket_lock)
|
||||||
|
bytes_read = this.socket.Receive (bytes);
|
||||||
|
|
||||||
|
|
||||||
|
// Parse the received message
|
||||||
if (bytes_read > 0) {
|
if (bytes_read > 0) {
|
||||||
string received = Encoding.UTF8.GetString (bytes);
|
string received = Encoding.UTF8.GetString (bytes);
|
||||||
string line = received.Substring (0, received.IndexOf ("\n"));
|
string line = received.Substring (0, received.IndexOf ("\n"));
|
||||||
|
@ -114,30 +185,11 @@ namespace SparkleLib {
|
||||||
if (!folder_identifier.Equals ("debug") &&
|
if (!folder_identifier.Equals ("debug") &&
|
||||||
!String.IsNullOrEmpty (message)) {
|
!String.IsNullOrEmpty (message)) {
|
||||||
|
|
||||||
|
// We have a message!
|
||||||
OnAnnouncement (new SparkleAnnouncement (folder_identifier, message));
|
OnAnnouncement (new SparkleAnnouncement (folder_identifier, message));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerTcp", "Error on socket");
|
|
||||||
|
|
||||||
lock (this.socket_lock) {
|
|
||||||
this.socket.Close ();
|
|
||||||
this.is_connected = false;
|
|
||||||
|
|
||||||
OnDisconnected ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerTcp", "Disconnected from " + Server.Host);
|
|
||||||
|
|
||||||
} catch (SocketException e) {
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerTcp", "Could not connect to " + Server + ": " + e.Message);
|
|
||||||
this.is_connected = false;
|
|
||||||
this.is_connecting = false;
|
|
||||||
|
|
||||||
OnDisconnected ();
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -145,28 +197,29 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override void AlsoListenTo (string folder_identifier)
|
protected override void AlsoListenToInternal (string folder_identifier)
|
||||||
{
|
{
|
||||||
|
SparkleHelpers.DebugInfo ("ListenerTcp",
|
||||||
|
"Subscribing to channel " + folder_identifier + " on " + Server);
|
||||||
|
|
||||||
string to_send = "subscribe " + folder_identifier + "\n";
|
string to_send = "subscribe " + folder_identifier + "\n";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
lock (this.socket_lock) {
|
lock (this.socket_lock)
|
||||||
this.socket.Send (Encoding.UTF8.GetBytes (to_send));
|
this.socket.Send (Encoding.UTF8.GetBytes (to_send));
|
||||||
}
|
|
||||||
|
this.last_ping = DateTime.Now;
|
||||||
|
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
SparkleHelpers.DebugInfo ("ListenerTcp",
|
|
||||||
"Could not connect to " + Server + ": " + e.Message);
|
|
||||||
|
|
||||||
this.is_connected = false;
|
this.is_connected = false;
|
||||||
this.is_connecting = false;
|
this.is_connecting = false;
|
||||||
|
|
||||||
OnDisconnected ();
|
OnDisconnected (e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override void Announce (SparkleAnnouncement announcement)
|
protected override void AnnounceInternal (SparkleAnnouncement announcement)
|
||||||
{
|
{
|
||||||
string to_send = "announce " + announcement.FolderIdentifier
|
string to_send = "announce " + announcement.FolderIdentifier
|
||||||
+ " " + announcement.Message + "\n";
|
+ " " + announcement.Message + "\n";
|
||||||
|
@ -175,14 +228,13 @@ namespace SparkleLib {
|
||||||
lock (this.socket_lock)
|
lock (this.socket_lock)
|
||||||
this.socket.Send (Encoding.UTF8.GetBytes (to_send));
|
this.socket.Send (Encoding.UTF8.GetBytes (to_send));
|
||||||
|
|
||||||
} catch (SocketException e) {
|
this.last_ping = DateTime.Now;
|
||||||
SparkleHelpers.DebugInfo ("ListenerTcp",
|
|
||||||
"Could not connect to " + Server + ": " + e.Message);
|
|
||||||
|
|
||||||
|
} catch (SocketException e) {
|
||||||
this.is_connected = false;
|
this.is_connected = false;
|
||||||
this.is_connecting = false;
|
this.is_connecting = false;
|
||||||
|
|
||||||
OnDisconnected ();
|
OnDisconnected (e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -23,7 +23,6 @@ using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
using System.Xml;
|
|
||||||
|
|
||||||
namespace SparkleLib {
|
namespace SparkleLib {
|
||||||
|
|
||||||
|
@ -39,45 +38,28 @@ namespace SparkleLib {
|
||||||
|
|
||||||
private TimeSpan short_interval = new TimeSpan (0, 0, 3, 0);
|
private TimeSpan short_interval = new TimeSpan (0, 0, 3, 0);
|
||||||
private TimeSpan long_interval = new TimeSpan (0, 0, 10, 0);
|
private TimeSpan long_interval = new TimeSpan (0, 0, 10, 0);
|
||||||
|
|
||||||
private SparkleWatcher watcher;
|
|
||||||
private TimeSpan poll_interval;
|
private TimeSpan poll_interval;
|
||||||
|
private SparkleWatcher watcher;
|
||||||
|
private SparkleListenerBase listener;
|
||||||
private System.Timers.Timer local_timer = new System.Timers.Timer () { Interval = 0.25 * 1000 };
|
private System.Timers.Timer local_timer = new System.Timers.Timer () { Interval = 0.25 * 1000 };
|
||||||
private System.Timers.Timer remote_timer = new System.Timers.Timer () { Interval = 10 * 1000 };
|
private System.Timers.Timer remote_timer = new System.Timers.Timer () { Interval = 10 * 1000 };
|
||||||
private DateTime last_poll = DateTime.Now;
|
private DateTime last_poll = DateTime.Now;
|
||||||
private List<double> sizebuffer = new List<double> ();
|
private List<double> size_buffer = new List<double> ();
|
||||||
private bool has_changed = false;
|
|
||||||
private Object change_lock = new Object ();
|
private Object change_lock = new Object ();
|
||||||
private Object watch_lock = new Object ();
|
private Object watch_lock = new Object ();
|
||||||
private double progress_percentage = 0.0;
|
private double progress_percentage = 0.0;
|
||||||
private string progress_speed = "";
|
private string progress_speed = "";
|
||||||
|
private bool has_changed = false;
|
||||||
|
private bool is_buffering = false;
|
||||||
|
private bool server_online = true;
|
||||||
|
private SyncStatus status;
|
||||||
|
|
||||||
protected SparkleListenerBase listener;
|
|
||||||
protected SyncStatus status;
|
|
||||||
protected bool is_buffering = false;
|
|
||||||
protected bool server_online = true;
|
|
||||||
|
|
||||||
public readonly string LocalPath;
|
|
||||||
public readonly string Name;
|
|
||||||
public readonly Uri Url;
|
|
||||||
|
|
||||||
public abstract bool AnyDifferences { get; }
|
|
||||||
public abstract string Identifier { get; }
|
|
||||||
public abstract string CurrentRevision { get; }
|
|
||||||
public abstract bool SyncUp ();
|
|
||||||
public abstract bool SyncDown ();
|
|
||||||
public abstract double CalculateSize (DirectoryInfo parent);
|
|
||||||
public abstract bool HasUnsyncedChanges { get; set; }
|
|
||||||
public abstract List<string> ExcludePaths { get; }
|
|
||||||
|
|
||||||
public abstract double Size { get; }
|
|
||||||
public abstract double HistorySize { get; }
|
|
||||||
|
|
||||||
public delegate void SyncStatusChangedEventHandler (SyncStatus new_status);
|
public delegate void SyncStatusChangedEventHandler (SyncStatus new_status);
|
||||||
public event SyncStatusChangedEventHandler SyncStatusChanged;
|
public event SyncStatusChangedEventHandler SyncStatusChanged;
|
||||||
|
|
||||||
public delegate void SyncProgressChangedEventHandler (double percentage, string speed);
|
public delegate void ProgressChangedEventHandler (double percentage, string speed);
|
||||||
public event SyncProgressChangedEventHandler SyncProgressChanged;
|
public event ProgressChangedEventHandler ProgressChanged;
|
||||||
|
|
||||||
public delegate void NewChangeSetEventHandler (SparkleChangeSet change_set);
|
public delegate void NewChangeSetEventHandler (SparkleChangeSet change_set);
|
||||||
public event NewChangeSetEventHandler NewChangeSet;
|
public event NewChangeSetEventHandler NewChangeSet;
|
||||||
|
@ -92,6 +74,68 @@ namespace SparkleLib {
|
||||||
public event ChangesDetectedEventHandler ChangesDetected;
|
public event ChangesDetectedEventHandler ChangesDetected;
|
||||||
|
|
||||||
|
|
||||||
|
public readonly string LocalPath;
|
||||||
|
public readonly string Name;
|
||||||
|
public readonly Uri Url;
|
||||||
|
|
||||||
|
public abstract string Identifier { get; }
|
||||||
|
public abstract string CurrentRevision { get; }
|
||||||
|
public abstract double Size { get; }
|
||||||
|
public abstract double HistorySize { get; }
|
||||||
|
public abstract List<string> ExcludePaths { get; }
|
||||||
|
public abstract bool HasUnsyncedChanges { get; set; }
|
||||||
|
public abstract bool HasLocalChanges { get; }
|
||||||
|
public abstract bool HasRemoteChanges { get; }
|
||||||
|
public abstract bool SyncUp ();
|
||||||
|
public abstract bool SyncDown ();
|
||||||
|
public abstract List<SparkleChangeSet> GetChangeSets (int count);
|
||||||
|
|
||||||
|
|
||||||
|
public bool ServerOnline {
|
||||||
|
get {
|
||||||
|
return this.server_online;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SyncStatus Status {
|
||||||
|
get {
|
||||||
|
return this.status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double ProgressPercentage {
|
||||||
|
get {
|
||||||
|
return this.progress_percentage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ProgressSpeed {
|
||||||
|
get {
|
||||||
|
return this.progress_speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string [] UnsyncedFilePaths {
|
||||||
|
get {
|
||||||
|
return new string [0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSyncing {
|
||||||
|
get {
|
||||||
|
return (Status == SyncStatus.SyncUp ||
|
||||||
|
Status == SyncStatus.SyncDown ||
|
||||||
|
this.is_buffering);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsBuffering {
|
||||||
|
get {
|
||||||
|
return this.is_buffering;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public SparkleRepoBase (string path)
|
public SparkleRepoBase (string path)
|
||||||
{
|
{
|
||||||
LocalPath = path;
|
LocalPath = path;
|
||||||
|
@ -121,7 +165,7 @@ namespace SparkleLib {
|
||||||
if (time_to_poll) {
|
if (time_to_poll) {
|
||||||
this.last_poll = DateTime.Now;
|
this.last_poll = DateTime.Now;
|
||||||
|
|
||||||
if (CheckForRemoteChanges ())
|
if (HasRemoteChanges)
|
||||||
SyncDownBase ();
|
SyncDownBase ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +183,7 @@ namespace SparkleLib {
|
||||||
{
|
{
|
||||||
// Sync up everything that changed
|
// Sync up everything that changed
|
||||||
// since we've been offline
|
// since we've been offline
|
||||||
if (AnyDifferences) {
|
if (HasLocalChanges) {
|
||||||
DisableWatching ();
|
DisableWatching ();
|
||||||
SyncUpBase ();
|
SyncUpBase ();
|
||||||
|
|
||||||
|
@ -154,96 +198,15 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public bool ServerOnline {
|
|
||||||
get {
|
|
||||||
return this.server_online;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public SyncStatus Status {
|
|
||||||
get {
|
|
||||||
return this.status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public double ProgressPercentage {
|
|
||||||
get {
|
|
||||||
return this.progress_percentage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public string ProgressSpeed {
|
|
||||||
get {
|
|
||||||
return this.progress_speed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public virtual string [] UnsyncedFilePaths {
|
|
||||||
get {
|
|
||||||
return new string [0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public string Domain {
|
|
||||||
get {
|
|
||||||
Regex regex = new Regex (@"(@|://)([a-z0-9\.-]+)(/|:)");
|
|
||||||
Match match = regex.Match (SparkleConfig.DefaultConfig.GetUrlForFolder (Name));
|
|
||||||
|
|
||||||
if (match.Success)
|
|
||||||
return match.Groups [2].Value;
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void OnConflictResolved ()
|
protected void OnConflictResolved ()
|
||||||
{
|
{
|
||||||
HasUnsyncedChanges = true;
|
HasUnsyncedChanges = true; // ?
|
||||||
|
|
||||||
if (ConflictResolved != null)
|
if (ConflictResolved != null)
|
||||||
ConflictResolved ();
|
ConflictResolved ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public virtual bool CheckForRemoteChanges () // TODO: HasRemoteChanges { get; }
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public virtual List<SparkleChangeSet> GetChangeSets (int count) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public virtual bool UsesNotificationCenter {
|
|
||||||
get {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public string RemoteName {
|
|
||||||
get {
|
|
||||||
string url = SparkleConfig.DefaultConfig.GetUrlForFolder (Name);
|
|
||||||
return Path.GetFileNameWithoutExtension (url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public bool IsBuffering {
|
|
||||||
get {
|
|
||||||
return this.is_buffering;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Disposes all resourses of this object
|
// Disposes all resourses of this object
|
||||||
public void Dispose ()
|
public void Dispose ()
|
||||||
{
|
{
|
||||||
|
@ -253,114 +216,6 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void CreateWatcher ()
|
|
||||||
{
|
|
||||||
this.watcher = new SparkleWatcher (LocalPath);
|
|
||||||
this.watcher.ChangeEvent += delegate (FileSystemEventArgs args) {
|
|
||||||
OnFileActivity (args);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void CreateListener ()
|
|
||||||
{
|
|
||||||
this.listener = SparkleListenerFactory.CreateListener (Name, Identifier);
|
|
||||||
|
|
||||||
if (this.listener.IsConnected) {
|
|
||||||
this.poll_interval = this.long_interval;
|
|
||||||
|
|
||||||
new Thread (new ThreadStart (delegate {
|
|
||||||
if (!IsSyncing && CheckForRemoteChanges ())
|
|
||||||
SyncDownBase ();
|
|
||||||
})).Start ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop polling when the connection to the irc channel is succesful
|
|
||||||
this.listener.Connected += delegate {
|
|
||||||
this.poll_interval = this.long_interval;
|
|
||||||
this.last_poll = DateTime.Now;
|
|
||||||
|
|
||||||
if (!IsSyncing) {
|
|
||||||
|
|
||||||
// Check for changes manually one more time
|
|
||||||
if (CheckForRemoteChanges ())
|
|
||||||
SyncDownBase ();
|
|
||||||
|
|
||||||
// Push changes that were made since the last disconnect
|
|
||||||
if (HasUnsyncedChanges)
|
|
||||||
SyncUpBase ();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Start polling when the connection to the irc channel is lost
|
|
||||||
this.listener.Disconnected += delegate {
|
|
||||||
this.poll_interval = this.short_interval;
|
|
||||||
SparkleHelpers.DebugInfo (Name, "Falling back to polling");
|
|
||||||
};
|
|
||||||
|
|
||||||
// Fetch changes when there is a message in the irc channel
|
|
||||||
this.listener.Received += delegate (SparkleAnnouncement announcement) {
|
|
||||||
string identifier = Identifier;
|
|
||||||
|
|
||||||
if (announcement.FolderIdentifier.Equals (identifier) &&
|
|
||||||
!announcement.Message.Equals (CurrentRevision)) {
|
|
||||||
|
|
||||||
while (this.IsSyncing)
|
|
||||||
System.Threading.Thread.Sleep (100);
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Listener", "Syncing due to announcement");
|
|
||||||
SyncDownBase ();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (announcement.FolderIdentifier.Equals (identifier))
|
|
||||||
SparkleHelpers.DebugInfo ("Listener", "Not syncing, message is for current revision");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Start listening
|
|
||||||
if (!this.listener.IsConnected && !this.listener.IsConnecting)
|
|
||||||
this.listener.Connect ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public bool IsSyncing {
|
|
||||||
get {
|
|
||||||
return (Status == SyncStatus.SyncUp ||
|
|
||||||
Status == SyncStatus.SyncDown ||
|
|
||||||
this.is_buffering);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void CheckForChanges ()
|
|
||||||
{
|
|
||||||
lock (this.change_lock) {
|
|
||||||
if (this.has_changed) {
|
|
||||||
if (this.sizebuffer.Count >= 4)
|
|
||||||
this.sizebuffer.RemoveAt (0);
|
|
||||||
|
|
||||||
DirectoryInfo dir_info = new DirectoryInfo (LocalPath);
|
|
||||||
this.sizebuffer.Add (CalculateSize (dir_info));
|
|
||||||
|
|
||||||
if (this.sizebuffer.Count >= 4 &&
|
|
||||||
this.sizebuffer [0].Equals (this.sizebuffer [1]) &&
|
|
||||||
this.sizebuffer [1].Equals (this.sizebuffer [2]) &&
|
|
||||||
this.sizebuffer [2].Equals (this.sizebuffer [3])) {
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Local", "[" + Name + "] Changes have settled.");
|
|
||||||
this.is_buffering = false;
|
|
||||||
this.has_changed = false;
|
|
||||||
|
|
||||||
DisableWatching ();
|
|
||||||
while (AnyDifferences)
|
|
||||||
SyncUpBase ();
|
|
||||||
EnableWatching ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Starts a timer when something changes
|
// Starts a timer when something changes
|
||||||
public void OnFileActivity (FileSystemEventArgs args)
|
public void OnFileActivity (FileSystemEventArgs args)
|
||||||
{
|
{
|
||||||
|
@ -378,7 +233,7 @@ namespace SparkleLib {
|
||||||
|
|
||||||
WatcherChangeTypes wct = args.ChangeType;
|
WatcherChangeTypes wct = args.ChangeType;
|
||||||
|
|
||||||
if (AnyDifferences) {
|
if (HasLocalChanges) {
|
||||||
this.is_buffering = true;
|
this.is_buffering = true;
|
||||||
|
|
||||||
// We want to disable wathcing temporarily, but
|
// We want to disable wathcing temporarily, but
|
||||||
|
@ -440,6 +295,44 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void AddNote (string revision, string note)
|
||||||
|
{
|
||||||
|
string notes_path = Path.Combine (LocalPath, ".notes");
|
||||||
|
|
||||||
|
if (!Directory.Exists (notes_path))
|
||||||
|
Directory.CreateDirectory (notes_path);
|
||||||
|
|
||||||
|
// Add a timestamp in seconds since unix epoch
|
||||||
|
int timestamp = (int) (DateTime.UtcNow - new DateTime (1970, 1, 1)).TotalSeconds;
|
||||||
|
|
||||||
|
string n = Environment.NewLine;
|
||||||
|
note = "<note>" + n +
|
||||||
|
" <user>" + n +
|
||||||
|
" <name>" + SparkleConfig.DefaultConfig.User.Name + "</name>" + n +
|
||||||
|
" <email>" + SparkleConfig.DefaultConfig.User.Email + "</email>" + n +
|
||||||
|
" </user>" + n +
|
||||||
|
" <timestamp>" + timestamp + "</timestamp>" + n +
|
||||||
|
" <body>" + note + "</body>" + n +
|
||||||
|
"</note>" + n;
|
||||||
|
|
||||||
|
string note_name = revision + SHA1 (timestamp.ToString () + note);
|
||||||
|
string note_path = Path.Combine (notes_path, note_name);
|
||||||
|
|
||||||
|
StreamWriter writer = new StreamWriter (note_path);
|
||||||
|
writer.Write (note);
|
||||||
|
writer.Close ();
|
||||||
|
|
||||||
|
|
||||||
|
// The watcher doesn't like .*/ so we need to trigger
|
||||||
|
// a change manually
|
||||||
|
FileSystemEventArgs args = new FileSystemEventArgs (WatcherChangeTypes.Changed,
|
||||||
|
notes_path, note_name);
|
||||||
|
|
||||||
|
OnFileActivity (args);
|
||||||
|
SparkleHelpers.DebugInfo ("Note", "Added note to " + revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void SyncUpBase ()
|
private void SyncUpBase ()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
@ -459,7 +352,7 @@ namespace SparkleLib {
|
||||||
if (SyncStatusChanged != null)
|
if (SyncStatusChanged != null)
|
||||||
SyncStatusChanged (SyncStatus.Idle);
|
SyncStatusChanged (SyncStatus.Idle);
|
||||||
|
|
||||||
this.listener.AnnounceBase (new SparkleAnnouncement (Identifier, CurrentRevision));
|
this.listener.Announce (new SparkleAnnouncement (Identifier, CurrentRevision));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
SparkleHelpers.DebugInfo ("SyncUp", "[" + Name + "] Error");
|
SparkleHelpers.DebugInfo ("SyncUp", "[" + Name + "] Error");
|
||||||
|
@ -474,7 +367,7 @@ namespace SparkleLib {
|
||||||
if (SyncStatusChanged != null)
|
if (SyncStatusChanged != null)
|
||||||
SyncStatusChanged (SyncStatus.Idle);
|
SyncStatusChanged (SyncStatus.Idle);
|
||||||
|
|
||||||
this.listener.AnnounceBase (new SparkleAnnouncement (Identifier, CurrentRevision));
|
this.listener.Announce (new SparkleAnnouncement (Identifier, CurrentRevision));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.server_online = false;
|
this.server_online = false;
|
||||||
|
@ -561,7 +454,106 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void DisableWatching ()
|
private void CreateWatcher ()
|
||||||
|
{
|
||||||
|
this.watcher = new SparkleWatcher (LocalPath);
|
||||||
|
this.watcher.ChangeEvent += delegate (FileSystemEventArgs args) {
|
||||||
|
OnFileActivity (args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void CreateListener ()
|
||||||
|
{
|
||||||
|
this.listener = SparkleListenerFactory.CreateListener (Name, Identifier);
|
||||||
|
|
||||||
|
if (this.listener.IsConnected) {
|
||||||
|
this.poll_interval = this.long_interval;
|
||||||
|
|
||||||
|
new Thread (new ThreadStart (delegate {
|
||||||
|
if (!IsSyncing && HasRemoteChanges)
|
||||||
|
SyncDownBase ();
|
||||||
|
})).Start ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop polling when the connection to the irc channel is succesful
|
||||||
|
this.listener.Connected += delegate {
|
||||||
|
this.poll_interval = this.long_interval;
|
||||||
|
this.last_poll = DateTime.Now;
|
||||||
|
|
||||||
|
if (!IsSyncing) {
|
||||||
|
|
||||||
|
// Check for changes manually one more time
|
||||||
|
if (HasRemoteChanges)
|
||||||
|
SyncDownBase ();
|
||||||
|
|
||||||
|
// Push changes that were made since the last disconnect
|
||||||
|
if (HasUnsyncedChanges)
|
||||||
|
SyncUpBase ();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start polling when the connection to the irc channel is lost
|
||||||
|
this.listener.Disconnected += delegate {
|
||||||
|
this.poll_interval = this.short_interval;
|
||||||
|
SparkleHelpers.DebugInfo (Name, "Falling back to polling");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch changes when there is a message in the irc channel
|
||||||
|
this.listener.Received += delegate (SparkleAnnouncement announcement) {
|
||||||
|
string identifier = Identifier;
|
||||||
|
|
||||||
|
if (announcement.FolderIdentifier.Equals (identifier) &&
|
||||||
|
!announcement.Message.Equals (CurrentRevision)) {
|
||||||
|
|
||||||
|
while (this.IsSyncing)
|
||||||
|
System.Threading.Thread.Sleep (100);
|
||||||
|
|
||||||
|
SparkleHelpers.DebugInfo ("Listener", "Syncing due to announcement");
|
||||||
|
SyncDownBase ();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (announcement.FolderIdentifier.Equals (identifier))
|
||||||
|
SparkleHelpers.DebugInfo ("Listener", "Not syncing, message is for current revision");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start listening
|
||||||
|
if (!this.listener.IsConnected && !this.listener.IsConnecting)
|
||||||
|
this.listener.Connect ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void CheckForChanges ()
|
||||||
|
{
|
||||||
|
lock (this.change_lock) {
|
||||||
|
if (this.has_changed) {
|
||||||
|
if (this.size_buffer.Count >= 4)
|
||||||
|
this.size_buffer.RemoveAt (0);
|
||||||
|
|
||||||
|
DirectoryInfo dir_info = new DirectoryInfo (LocalPath);
|
||||||
|
this.size_buffer.Add (CalculateSize (dir_info));
|
||||||
|
|
||||||
|
if (this.size_buffer.Count >= 4 &&
|
||||||
|
this.size_buffer [0].Equals (this.size_buffer [1]) &&
|
||||||
|
this.size_buffer [1].Equals (this.size_buffer [2]) &&
|
||||||
|
this.size_buffer [2].Equals (this.size_buffer [3])) {
|
||||||
|
|
||||||
|
SparkleHelpers.DebugInfo ("Local", "[" + Name + "] Changes have settled.");
|
||||||
|
this.is_buffering = false;
|
||||||
|
this.has_changed = false;
|
||||||
|
|
||||||
|
DisableWatching ();
|
||||||
|
while (HasLocalChanges)
|
||||||
|
SyncUpBase ();
|
||||||
|
EnableWatching ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void DisableWatching ()
|
||||||
{
|
{
|
||||||
lock (this.watch_lock) {
|
lock (this.watch_lock) {
|
||||||
this.watcher.EnableRaisingEvents = false;
|
this.watcher.EnableRaisingEvents = false;
|
||||||
|
@ -570,7 +562,7 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void EnableWatching ()
|
protected void EnableWatching ()
|
||||||
{
|
{
|
||||||
lock (this.watch_lock) {
|
lock (this.watch_lock) {
|
||||||
this.watcher.EnableRaisingEvents = true;
|
this.watcher.EnableRaisingEvents = true;
|
||||||
|
@ -579,17 +571,39 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private DateTime progress_last_change = DateTime.Now;
|
||||||
|
private TimeSpan progress_change_interval = new TimeSpan (0, 0, 0, 1);
|
||||||
|
|
||||||
|
protected void OnProgressChanged (double progress_percentage, string progress_speed)
|
||||||
|
{
|
||||||
|
if (DateTime.Compare (this.progress_last_change,
|
||||||
|
DateTime.Now.Subtract (this.progress_change_interval)) < 0) {
|
||||||
|
|
||||||
|
if (ProgressChanged != null) {
|
||||||
|
if (progress_percentage == 100.0)
|
||||||
|
progress_percentage = 99.0;
|
||||||
|
|
||||||
|
this.progress_percentage = progress_percentage;
|
||||||
|
this.progress_speed = progress_speed;
|
||||||
|
this.progress_last_change = DateTime.Now;
|
||||||
|
|
||||||
|
ProgressChanged (progress_percentage, progress_speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Create an initial change set when the
|
// Create an initial change set when the
|
||||||
// user has fetched an empty remote folder
|
// user has fetched an empty remote folder
|
||||||
public virtual void CreateInitialChangeSet ()
|
private void CreateInitialChangeSet ()
|
||||||
{
|
{
|
||||||
string file_path = Path.Combine (LocalPath, "SparkleShare.txt");
|
string file_path = Path.Combine (LocalPath, "SparkleShare.txt");
|
||||||
TextWriter writer = new StreamWriter (file_path);
|
TextWriter writer = new StreamWriter (file_path);
|
||||||
|
|
||||||
writer.WriteLine ("Congratulations, you've successfully created a SparkleShare repository!");
|
writer.WriteLine ("Congratulations, you've successfully created a SparkleShare repository!");
|
||||||
writer.WriteLine ("");
|
writer.WriteLine ("");
|
||||||
writer.WriteLine ("Any files you add or change in this folder will be automatically synced to ");
|
writer.WriteLine ("Any files you add or change in this folder will be automatically synced to ");
|
||||||
writer.WriteLine (SparkleConfig.DefaultConfig.GetUrlForFolder (Name) + " and everyone connected to it.");
|
writer.WriteLine (Url + " and everyone connected to it.");
|
||||||
// TODO: Url property? ^
|
|
||||||
|
|
||||||
writer.WriteLine ("");
|
writer.WriteLine ("");
|
||||||
writer.WriteLine ("SparkleShare is a Free and Open Source software program that helps people ");
|
writer.WriteLine ("SparkleShare is a Free and Open Source software program that helps people ");
|
||||||
|
@ -600,66 +614,8 @@ namespace SparkleLib {
|
||||||
writer.WriteLine ("");
|
writer.WriteLine ("");
|
||||||
|
|
||||||
writer.Close ();
|
writer.Close ();
|
||||||
}
|
|
||||||
|
|
||||||
|
SyncUp ();
|
||||||
public void AddNote (string revision, string note)
|
|
||||||
{
|
|
||||||
string notes_path = Path.Combine (LocalPath, ".notes");
|
|
||||||
|
|
||||||
if (!Directory.Exists (notes_path))
|
|
||||||
Directory.CreateDirectory (notes_path);
|
|
||||||
|
|
||||||
// Add a timestamp in seconds since unix epoch
|
|
||||||
int timestamp = (int) (DateTime.UtcNow - new DateTime (1970, 1, 1)).TotalSeconds;
|
|
||||||
|
|
||||||
string n = Environment.NewLine;
|
|
||||||
note = "<note>" + n +
|
|
||||||
" <user>" + n +
|
|
||||||
" <name>" + SparkleConfig.DefaultConfig.User.Name + "</name>" + n +
|
|
||||||
" <email>" + SparkleConfig.DefaultConfig.User.Email + "</email>" + n +
|
|
||||||
" </user>" + n +
|
|
||||||
" <timestamp>" + timestamp + "</timestamp>" + n +
|
|
||||||
" <body>" + note + "</body>" + n +
|
|
||||||
"</note>" + n;
|
|
||||||
|
|
||||||
string note_name = revision + SHA1 (timestamp.ToString () + note);
|
|
||||||
string note_path = Path.Combine (notes_path, note_name);
|
|
||||||
|
|
||||||
StreamWriter writer = new StreamWriter (note_path);
|
|
||||||
writer.Write (note);
|
|
||||||
writer.Close ();
|
|
||||||
|
|
||||||
|
|
||||||
// The watcher doesn't like .*/ so we need to trigger
|
|
||||||
// a change manually
|
|
||||||
FileSystemEventArgs args = new FileSystemEventArgs (WatcherChangeTypes.Changed,
|
|
||||||
notes_path, note_name);
|
|
||||||
|
|
||||||
OnFileActivity (args);
|
|
||||||
SparkleHelpers.DebugInfo ("Note", "Added note to " + revision);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private DateTime progress_last_change = DateTime.Now;
|
|
||||||
private TimeSpan progress_change_interval = new TimeSpan (0, 0, 0, 1);
|
|
||||||
|
|
||||||
protected void OnSyncProgressChanged (double progress_percentage, string progress_speed)
|
|
||||||
{
|
|
||||||
if (DateTime.Compare (this.progress_last_change,
|
|
||||||
DateTime.Now.Subtract (this.progress_change_interval)) < 0) {
|
|
||||||
|
|
||||||
if (SyncProgressChanged != null) {
|
|
||||||
if (progress_percentage == 100.0)
|
|
||||||
progress_percentage = 99.0;
|
|
||||||
|
|
||||||
this.progress_percentage = progress_percentage;
|
|
||||||
this.progress_speed = progress_speed;
|
|
||||||
this.progress_last_change = DateTime.Now;
|
|
||||||
|
|
||||||
SyncProgressChanged (progress_percentage, progress_speed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -671,5 +627,35 @@ namespace SparkleLib {
|
||||||
Byte[] encoded_bytes = sha1.ComputeHash (bytes);
|
Byte[] encoded_bytes = sha1.ComputeHash (bytes);
|
||||||
return BitConverter.ToString (encoded_bytes).ToLower ().Replace ("-", "");
|
return BitConverter.ToString (encoded_bytes).ToLower ().Replace ("-", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Recursively gets a folder's size in bytes
|
||||||
|
private double CalculateSize (DirectoryInfo parent)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists (parent.ToString ()))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
double size = 0;
|
||||||
|
|
||||||
|
if (ExcludePaths.Contains (parent.Name))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
foreach (FileInfo file in parent.GetFiles()) {
|
||||||
|
if (!file.Exists)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size += file.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (DirectoryInfo directory in parent.GetDirectories ())
|
||||||
|
size += CalculateSize (directory);
|
||||||
|
|
||||||
|
} catch (Exception) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,11 @@ using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
using MonoMac.Foundation;
|
|
||||||
using MonoMac.AppKit;
|
using MonoMac.AppKit;
|
||||||
|
using MonoMac.Foundation;
|
||||||
using MonoMac.ObjCRuntime;
|
using MonoMac.ObjCRuntime;
|
||||||
using MonoMac.WebKit;
|
using MonoMac.WebKit;
|
||||||
|
|
||||||
|
|
||||||
namespace SparkleShare {
|
namespace SparkleShare {
|
||||||
|
|
||||||
public class SparkleAbout : NSWindow {
|
public class SparkleAbout : NSWindow {
|
||||||
|
@ -54,9 +53,12 @@ namespace SparkleShare {
|
||||||
BackingType = NSBackingStore.Buffered;
|
BackingType = NSBackingStore.Buffered;
|
||||||
|
|
||||||
CreateAbout ();
|
CreateAbout ();
|
||||||
OrderFrontRegardless ();
|
|
||||||
|
NSApplication.SharedApplication.ActivateIgnoringOtherApps (true);
|
||||||
MakeKeyAndOrderFront (this);
|
MakeKeyAndOrderFront (this);
|
||||||
|
|
||||||
|
OrderFrontRegardless ();
|
||||||
|
|
||||||
Program.UI.UpdateDockIconVisibility ();
|
Program.UI.UpdateDockIconVisibility ();
|
||||||
|
|
||||||
Controller.NewVersionEvent += delegate (string new_version) {
|
Controller.NewVersionEvent += delegate (string new_version) {
|
||||||
|
|
|
@ -54,7 +54,7 @@ namespace SparkleShare {
|
||||||
|
|
||||||
|
|
||||||
// Let's use the bundled git first
|
// Let's use the bundled git first
|
||||||
SparkleBackend.DefaultBackend.Path =
|
SparkleGit.Path =
|
||||||
Path.Combine (NSBundle.MainBundle.ResourcePath,
|
Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||||
"git", "libexec", "git-core", "git");
|
"git", "libexec", "git-core", "git");
|
||||||
|
|
||||||
|
@ -68,7 +68,13 @@ namespace SparkleShare {
|
||||||
{
|
{
|
||||||
base.Initialize ();
|
base.Initialize ();
|
||||||
|
|
||||||
this.watcher.Changed += delegate (string path) {
|
this.watcher.Changed += delegate (object sender, SparkleMacWatcherEventArgs args) {
|
||||||
|
string path = args.Path;
|
||||||
|
|
||||||
|
// Don't even bother with paths in .git/
|
||||||
|
if (path.Contains (".git"))
|
||||||
|
return;
|
||||||
|
|
||||||
string repo_name;
|
string repo_name;
|
||||||
|
|
||||||
if (path.Contains ("/"))
|
if (path.Contains ("/"))
|
||||||
|
@ -77,17 +83,20 @@ namespace SparkleShare {
|
||||||
repo_name = path;
|
repo_name = path;
|
||||||
|
|
||||||
// Ignore changes in the root of each subfolder, these
|
// Ignore changes in the root of each subfolder, these
|
||||||
// are already handled bu the repository
|
// are already handled by the repository
|
||||||
if (Path.GetFileNameWithoutExtension (path).Equals (repo_name))
|
if (Path.GetFileNameWithoutExtension (path).Equals (repo_name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
repo_name = repo_name.Trim ("/".ToCharArray ());
|
repo_name = repo_name.Trim ("/".ToCharArray ());
|
||||||
FileSystemEventArgs args = new FileSystemEventArgs (WatcherChangeTypes.Changed,
|
FileSystemEventArgs fse_args = new FileSystemEventArgs (
|
||||||
Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, path), Path.GetFileName (path));
|
WatcherChangeTypes.Changed,
|
||||||
|
Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, path),
|
||||||
|
Path.GetFileName (path)
|
||||||
|
);
|
||||||
|
|
||||||
foreach (SparkleRepoBase repo in Repositories) {
|
foreach (SparkleRepoBase repo in Repositories) {
|
||||||
if (repo.Name.Equals (repo_name))
|
if (repo.Name.Equals (repo_name))
|
||||||
repo.OnFileActivity (args);
|
repo.OnFileActivity (fse_args);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,8 @@ namespace SparkleShare {
|
||||||
|
|
||||||
this.progress_indicator = new NSProgressIndicator () {
|
this.progress_indicator = new NSProgressIndicator () {
|
||||||
Style = NSProgressIndicatorStyle.Spinning,
|
Style = NSProgressIndicatorStyle.Spinning,
|
||||||
Frame = new RectangleF (this.web_view.Frame.Width / 2 - 10, this.web_view.Frame.Height / 2 + 10, 20, 20)
|
Frame = new RectangleF (this.web_view.Frame.Width / 2 - 10,
|
||||||
|
this.web_view.Frame.Height / 2 + 10, 20, 20)
|
||||||
};
|
};
|
||||||
|
|
||||||
this.progress_indicator.StartAnimation (this);
|
this.progress_indicator.StartAnimation (this);
|
||||||
|
@ -226,15 +227,24 @@ namespace SparkleShare {
|
||||||
html = html.Replace ("<!-- $a-color -->", "#0085cf");
|
html = html.Replace ("<!-- $a-color -->", "#0085cf");
|
||||||
html = html.Replace ("<!-- $a-hover-color -->", "#009ff8");
|
html = html.Replace ("<!-- $a-hover-color -->", "#009ff8");
|
||||||
html = html.Replace ("<!-- $no-buddy-icon-background-image -->",
|
html = html.Replace ("<!-- $no-buddy-icon-background-image -->",
|
||||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "avatar-default.png"));
|
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||||
|
"Pixmaps","avatar-default.png"));
|
||||||
|
|
||||||
html = html.Replace ("<!-- $document-added-background-image -->",
|
html = html.Replace ("<!-- $document-added-background-image -->",
|
||||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "document-added-12.png"));
|
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||||
|
"Pixmaps", "document-added-12.png"));
|
||||||
|
|
||||||
html = html.Replace ("<!-- $document-deleted-background-image -->",
|
html = html.Replace ("<!-- $document-deleted-background-image -->",
|
||||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "document-deleted-12.png"));
|
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||||
|
"Pixmaps", "document-deleted-12.png"));
|
||||||
|
|
||||||
html = html.Replace ("<!-- $document-edited-background-image -->",
|
html = html.Replace ("<!-- $document-edited-background-image -->",
|
||||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "document-edited-12.png"));
|
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||||
|
"Pixmaps", "document-edited-12.png"));
|
||||||
|
|
||||||
html = html.Replace ("<!-- $document-moved-background-image -->",
|
html = html.Replace ("<!-- $document-moved-background-image -->",
|
||||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "document-moved-12.png"));
|
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||||
|
"Pixmaps", "document-moved-12.png"));
|
||||||
|
|
||||||
InvokeOnMainThread (delegate {
|
InvokeOnMainThread (delegate {
|
||||||
if (this.progress_indicator.Superview == ContentView)
|
if (this.progress_indicator.Superview == ContentView)
|
||||||
|
|
|
@ -14,88 +14,216 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Originally taken from:
|
||||||
|
// https://github.com/jesse99/Continuum/blob/master/source/shared/DirectoryWatcher.cs
|
||||||
|
// Modified to use MonoMac and integrate into SparkleShare
|
||||||
|
|
||||||
|
// Copyright (C) 2008 Jesse Jones
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
// a copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
// the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be
|
||||||
|
// included in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
|
|
||||||
|
using MonoMac.AppKit;
|
||||||
|
using MonoMac.Foundation;
|
||||||
|
|
||||||
namespace SparkleShare {
|
namespace SparkleShare {
|
||||||
|
|
||||||
public class SparkleMacWatcher {
|
[Serializable]
|
||||||
|
public sealed class SparkleMacWatcherEventArgs : EventArgs {
|
||||||
|
|
||||||
public delegate void ChangedEventHandler (string path);
|
public string Path { get; private set; }
|
||||||
public event ChangedEventHandler Changed;
|
|
||||||
|
|
||||||
private FileSystemInfo last_changed;
|
|
||||||
private Thread thread;
|
public SparkleMacWatcherEventArgs (string path)
|
||||||
private int poll_count = 0;
|
{
|
||||||
|
Path = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public sealed class SparkleMacWatcher : IDisposable
|
||||||
|
{
|
||||||
|
public event EventHandler<SparkleMacWatcherEventArgs> Changed;
|
||||||
|
public string Path { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
[Serializable]
|
||||||
|
private enum FSEventStreamCreateFlags : uint
|
||||||
|
{
|
||||||
|
kFSEventStreamCreateFlagNone = 0x00000000,
|
||||||
|
kFSEventStreamCreateFlagUseCFTypes = 0x00000001,
|
||||||
|
kFSEventStreamCreateFlagNoDefer = 0x00000002,
|
||||||
|
kFSEventStreamCreateFlagWatchRoot = 0x00000004,
|
||||||
|
}
|
||||||
|
|
||||||
|
private DateTime last_found_timestamp;
|
||||||
|
private IntPtr m_stream;
|
||||||
|
private FSEventStreamCallback m_callback; // need to keep a reference around so that it isn't GC'ed
|
||||||
|
private static readonly IntPtr kCFRunLoopDefaultMode = (new NSString ("kCFRunLoopDefaultMode")).Handle;
|
||||||
|
private ulong kFSEventStreamEventIdSinceNow = 0xFFFFFFFFFFFFFFFFUL;
|
||||||
|
|
||||||
|
private delegate void FSEventStreamCallback (
|
||||||
|
IntPtr streamRef,
|
||||||
|
IntPtr clientCallBackInfo,
|
||||||
|
int numEvents,
|
||||||
|
IntPtr eventPaths,
|
||||||
|
IntPtr eventFlags,
|
||||||
|
IntPtr eventIds);
|
||||||
|
|
||||||
|
|
||||||
|
~SparkleMacWatcher ()
|
||||||
|
{
|
||||||
|
Dispose (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public SparkleMacWatcher (string path)
|
public SparkleMacWatcher (string path)
|
||||||
{
|
{
|
||||||
this.thread = new Thread (new ThreadStart (delegate {
|
Path = path;
|
||||||
DateTime timestamp;
|
m_callback = DoCallback;
|
||||||
DirectoryInfo parent = new DirectoryInfo (path);
|
|
||||||
this.last_changed = new DirectoryInfo (path);
|
|
||||||
|
|
||||||
while (true) {
|
NSString [] s = new NSString [1];
|
||||||
timestamp = this.last_changed.LastWriteTime;
|
s [0] = new NSString (path);
|
||||||
GetLastChange (parent);
|
NSArray path_p = NSArray.FromNSObjects (s);
|
||||||
|
|
||||||
if (DateTime.Compare (this.last_changed.LastWriteTime, timestamp) != 0) {
|
m_stream = FSEventStreamCreate ( // note that the stream will always be valid
|
||||||
string relative_path = this.last_changed.FullName.Substring (path.Length + 1);
|
IntPtr.Zero, // allocator
|
||||||
|
m_callback, // callback
|
||||||
|
IntPtr.Zero, // context
|
||||||
|
path_p.Handle, // pathsToWatch
|
||||||
|
kFSEventStreamEventIdSinceNow, // sinceWhen
|
||||||
|
2, // latency (in seconds)
|
||||||
|
FSEventStreamCreateFlags.kFSEventStreamCreateFlagNone); // flags
|
||||||
|
|
||||||
if (Changed != null)
|
FSEventStreamScheduleWithRunLoop (
|
||||||
Changed (relative_path);
|
m_stream, // streamRef
|
||||||
|
CFRunLoopGetMain(), // runLoop
|
||||||
|
kCFRunLoopDefaultMode); // runLoopMode
|
||||||
|
|
||||||
|
bool started = FSEventStreamStart (m_stream);
|
||||||
|
if (!started) {
|
||||||
|
GC.SuppressFinalize (this);
|
||||||
|
throw new InvalidOperationException ("Failed to start FSEvent stream for " + path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread.Sleep (7500);
|
|
||||||
this.poll_count++;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.thread.Start ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void GetLastChange (DirectoryInfo parent)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (DateTime.Compare (parent.LastWriteTime, this.last_changed.LastWriteTime) > 0)
|
|
||||||
this.last_changed = parent;
|
|
||||||
|
|
||||||
foreach (DirectoryInfo info in parent.GetDirectories ()) {
|
|
||||||
if (!info.FullName.Contains ("/.")) {
|
|
||||||
if (DateTime.Compare (info.LastWriteTime, this.last_changed.LastWriteTime) > 0)
|
|
||||||
this.last_changed = info;
|
|
||||||
|
|
||||||
GetLastChange (info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.poll_count >= 8) {
|
|
||||||
foreach (FileInfo info in parent.GetFiles ()) {
|
|
||||||
if (!info.FullName.Contains ("/.")) {
|
|
||||||
if (DateTime.Compare (info.LastWriteTime, this.last_changed.LastWriteTime) > 0)
|
|
||||||
this.last_changed = info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.poll_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception) {
|
|
||||||
// Don't care...
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Dispose ()
|
public void Dispose ()
|
||||||
{
|
{
|
||||||
this.thread.Join ();
|
Dispose (true);
|
||||||
this.thread.Abort ();
|
GC.SuppressFinalize (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void Dispose (bool disposing)
|
||||||
|
{
|
||||||
|
if (m_stream != IntPtr.Zero) {
|
||||||
|
FSEventStreamStop (m_stream);
|
||||||
|
FSEventStreamInvalidate (m_stream);
|
||||||
|
FSEventStreamRelease (m_stream);
|
||||||
|
|
||||||
|
m_stream = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void checkDirectory (string dir)
|
||||||
|
{
|
||||||
|
DirectoryInfo parent = new DirectoryInfo (dir);
|
||||||
|
|
||||||
|
if (!parent.FullName.Contains ("/.") &&
|
||||||
|
DateTime.Compare (parent.LastWriteTime, this.last_found_timestamp) > 0) {
|
||||||
|
|
||||||
|
last_found_timestamp = parent.LastWriteTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void DoCallback (IntPtr streamRef, IntPtr clientCallBackInfo,
|
||||||
|
int numEvents, IntPtr eventPaths, IntPtr eventFlags, IntPtr eventIds)
|
||||||
|
{
|
||||||
|
int bytes = Marshal.SizeOf (typeof (IntPtr));
|
||||||
|
string [] paths = new string [numEvents];
|
||||||
|
|
||||||
|
for (int i = 0; i < numEvents; ++i) {
|
||||||
|
IntPtr p = Marshal.ReadIntPtr (eventPaths, i * bytes);
|
||||||
|
paths [i] = Marshal.PtrToStringAnsi (p);
|
||||||
|
checkDirectory (paths [i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var handler = Changed;
|
||||||
|
if (handler != null) {
|
||||||
|
string path = paths [0];
|
||||||
|
path = path.Substring (Path.Length);
|
||||||
|
path = path.Trim ("/".ToCharArray ());
|
||||||
|
handler (this, new SparkleMacWatcherEventArgs (path));
|
||||||
|
}
|
||||||
|
|
||||||
|
GC.KeepAlive (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")]
|
||||||
|
private extern static IntPtr CFRunLoopGetMain ();
|
||||||
|
|
||||||
|
[DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")]
|
||||||
|
private extern static IntPtr FSEventStreamCreate (
|
||||||
|
IntPtr allocator,
|
||||||
|
FSEventStreamCallback callback,
|
||||||
|
IntPtr context,
|
||||||
|
IntPtr pathsToWatch,
|
||||||
|
ulong sinceWhen,
|
||||||
|
double latency,
|
||||||
|
FSEventStreamCreateFlags flags);
|
||||||
|
|
||||||
|
[DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")]
|
||||||
|
private extern static void FSEventStreamScheduleWithRunLoop (
|
||||||
|
IntPtr streamRef,
|
||||||
|
IntPtr runLoop,
|
||||||
|
IntPtr runLoopMode);
|
||||||
|
|
||||||
|
[DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")]
|
||||||
|
[return: MarshalAs (UnmanagedType.U1)]
|
||||||
|
private extern static bool FSEventStreamStart (
|
||||||
|
IntPtr streamRef);
|
||||||
|
|
||||||
|
[DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")]
|
||||||
|
private extern static void FSEventStreamStop (
|
||||||
|
IntPtr streamRef);
|
||||||
|
|
||||||
|
[DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")]
|
||||||
|
private extern static void FSEventStreamInvalidate (
|
||||||
|
IntPtr streamRef);
|
||||||
|
|
||||||
|
[DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")]
|
||||||
|
private extern static void FSEventStreamRelease (
|
||||||
|
IntPtr streamRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<RootNamespace>SparkleShare</RootNamespace>
|
<RootNamespace>SparkleShare</RootNamespace>
|
||||||
<AssemblyName>SparkleShare</AssemblyName>
|
<AssemblyName>SparkleShare</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||||
<ReleaseVersion>0.8.1</ReleaseVersion>
|
<ReleaseVersion>0.8.2</ReleaseVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System.Net" />
|
<Reference Include="System.Net" />
|
||||||
<Reference Include="SparkleLib, Version=0.8.0.0, Culture=neutral, PublicKeyToken=null">
|
<Reference Include="SparkleLib, Version=0.8.1.0, Culture=neutral, PublicKeyToken=null">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\..\bin\SparkleLib.dll</HintPath>
|
<HintPath>..\..\bin\SparkleLib.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|
|
@ -16,6 +16,6 @@ Global
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(MonoDevelopProperties) = preSolution
|
GlobalSection(MonoDevelopProperties) = preSolution
|
||||||
StartupItem = SparkleShare.csproj
|
StartupItem = SparkleShare.csproj
|
||||||
version = 0.8.1
|
version = 0.8.2
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace SparkleShare {
|
||||||
|
|
||||||
public SparkleStatusIconController Controller = new SparkleStatusIconController ();
|
public SparkleStatusIconController Controller = new SparkleStatusIconController ();
|
||||||
|
|
||||||
|
// TODO: Fix case
|
||||||
private Timer Animation;
|
private Timer Animation;
|
||||||
private int FrameNumber;
|
private int FrameNumber;
|
||||||
private string StateText;
|
private string StateText;
|
||||||
|
|
|
@ -39,7 +39,5 @@ include $(top_srcdir)/build/build.mk
|
||||||
|
|
||||||
bin_SCRIPTS = sparkleshare
|
bin_SCRIPTS = sparkleshare
|
||||||
|
|
||||||
dist_man_MANS = $(top_srcdir)/man/sparkleshare.1
|
|
||||||
|
|
||||||
Applicationsdir = $(datadir)/applications
|
Applicationsdir = $(datadir)/applications
|
||||||
dist_Applications_DATA = sparkleshare.desktop
|
dist_Applications_DATA = sparkleshare.desktop
|
||||||
|
|
|
@ -23,7 +23,6 @@ using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
using Mono.Unix;
|
using Mono.Unix;
|
||||||
//using Mono.Unix.Native;
|
|
||||||
using SparkleLib;
|
using SparkleLib;
|
||||||
|
|
||||||
namespace SparkleShare {
|
namespace SparkleShare {
|
||||||
|
@ -88,10 +87,10 @@ namespace SparkleShare {
|
||||||
Console.WriteLine (_("This is free software, and you are welcome to redistribute it "));
|
Console.WriteLine (_("This is free software, and you are welcome to redistribute it "));
|
||||||
Console.WriteLine (_("under certain conditions. Please read the GNU GPLv3 for details."));
|
Console.WriteLine (_("under certain conditions. Please read the GNU GPLv3 for details."));
|
||||||
Console.WriteLine (" ");
|
Console.WriteLine (" ");
|
||||||
Console.WriteLine (_("SparkleShare automatically syncs Git repositories in "));
|
Console.WriteLine (_("SparkleShare is a collaboration and sharing tool that is "));
|
||||||
Console.WriteLine (_("the ~/SparkleShare folder with their remote origins."));
|
Console.WriteLine (_("designed to keep things simple and to stay out of your way."));
|
||||||
Console.WriteLine (" ");
|
Console.WriteLine (" ");
|
||||||
Console.WriteLine (_("Usage: sparkleshare [start|stop|restart] [OPTION]..."));
|
Console.WriteLine (_("Usage: sparkleshare [start|stop|restart|version] [OPTION]..."));
|
||||||
Console.WriteLine (_("Sync SparkleShare folder with remote repositories."));
|
Console.WriteLine (_("Sync SparkleShare folder with remote repositories."));
|
||||||
Console.WriteLine (" ");
|
Console.WriteLine (" ");
|
||||||
Console.WriteLine (_("Arguments:"));
|
Console.WriteLine (_("Arguments:"));
|
||||||
|
@ -107,24 +106,5 @@ namespace SparkleShare {
|
||||||
Console.WriteLine (_("SparkleShare " + Defines.VERSION));
|
Console.WriteLine (_("SparkleShare " + Defines.VERSION));
|
||||||
Environment.Exit (0);
|
Environment.Exit (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Strange magic needed by SetProcessName ()
|
|
||||||
// [DllImport ("libc")]
|
|
||||||
// private static extern int prctl (int option, byte [] arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5);
|
|
||||||
|
|
||||||
|
|
||||||
// Sets the Unix process name to 'sparkleshare' instead of 'mono'
|
|
||||||
/* private static void SetProcessName (string name)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (prctl (15, Encoding.ASCII.GetBytes (name + "\0"), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) != 0)
|
|
||||||
throw new ApplicationException ("Error setting process name: " +
|
|
||||||
Mono.Unix.Native.Stdlib.GetLastError ());
|
|
||||||
|
|
||||||
} catch (EntryPointNotFoundException) {
|
|
||||||
Console.WriteLine ("SetProcessName: Entry point not found");
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,9 +42,6 @@ namespace SparkleShare {
|
||||||
public double ProgressPercentage = 0.0;
|
public double ProgressPercentage = 0.0;
|
||||||
public string ProgressSpeed = "";
|
public string ProgressSpeed = "";
|
||||||
|
|
||||||
public event OnQuitWhileSyncingHandler OnQuitWhileSyncing;
|
|
||||||
public delegate void OnQuitWhileSyncingHandler ();
|
|
||||||
|
|
||||||
public event FolderFetchedEventHandler FolderFetched;
|
public event FolderFetchedEventHandler FolderFetched;
|
||||||
public delegate void FolderFetchedEventHandler (string [] warnings);
|
public delegate void FolderFetchedEventHandler (string [] warnings);
|
||||||
|
|
||||||
|
@ -132,10 +129,9 @@ namespace SparkleShare {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
SparkleInviteListener invite_listener = new SparkleInviteListener (1986);
|
SparkleInviteListener invite_listener = new SparkleInviteListener (1987);
|
||||||
|
|
||||||
invite_listener.InviteReceived += delegate (SparkleInvite invite) {
|
invite_listener.InviteReceived += delegate (SparkleInvite invite) {
|
||||||
|
|
||||||
if (OnInvite != null && !FirstRun)
|
if (OnInvite != null && !FirstRun)
|
||||||
OnInvite (invite);
|
OnInvite (invite);
|
||||||
};
|
};
|
||||||
|
@ -351,37 +347,40 @@ namespace SparkleShare {
|
||||||
} else {
|
} else {
|
||||||
if (change_set.Edited.Count > 0) {
|
if (change_set.Edited.Count > 0) {
|
||||||
foreach (string file_path in change_set.Edited) {
|
foreach (string file_path in change_set.Edited) {
|
||||||
string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
|
event_entry += "<dd class='document edited'>";
|
||||||
change_set.Folder, file_path}.Combine ();
|
|
||||||
|
|
||||||
if (File.Exists (absolute_file_path))
|
event_entry += FormatBreadCrumbs (
|
||||||
event_entry += "<dd class='document edited'><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
|
Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, change_set.Folder),
|
||||||
else
|
file_path
|
||||||
event_entry += "<dd class='document edited'>" + file_path + "</dd>";
|
);
|
||||||
|
|
||||||
|
event_entry += "</dd>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (change_set.Added.Count > 0) {
|
if (change_set.Added.Count > 0) {
|
||||||
foreach (string file_path in change_set.Added) {
|
foreach (string file_path in change_set.Added) {
|
||||||
string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
|
event_entry += "<dd class='document added'>";
|
||||||
change_set.Folder, file_path}.Combine ();
|
|
||||||
|
|
||||||
if (File.Exists (absolute_file_path))
|
event_entry += FormatBreadCrumbs (
|
||||||
event_entry += "<dd class='document added'><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
|
Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, change_set.Folder),
|
||||||
else
|
file_path
|
||||||
event_entry += "<dd class='document added'>" + file_path + "</dd>";
|
);
|
||||||
|
|
||||||
|
event_entry += "</dd>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (change_set.Deleted.Count > 0) {
|
if (change_set.Deleted.Count > 0) {
|
||||||
foreach (string file_path in change_set.Deleted) {
|
foreach (string file_path in change_set.Deleted) {
|
||||||
string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
|
event_entry += "<dd class='document deleted'>";
|
||||||
change_set.Folder, file_path}.Combine ();
|
|
||||||
|
|
||||||
if (File.Exists (absolute_file_path))
|
event_entry += FormatBreadCrumbs (
|
||||||
event_entry += "<dd class='document deleted'><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
|
Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, change_set.Folder),
|
||||||
else
|
file_path
|
||||||
event_entry += "<dd class='document deleted'>" + file_path + "</dd>";
|
);
|
||||||
|
|
||||||
|
event_entry += "</dd>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,21 +389,19 @@ namespace SparkleShare {
|
||||||
foreach (string file_path in change_set.MovedFrom) {
|
foreach (string file_path in change_set.MovedFrom) {
|
||||||
string to_file_path = change_set.MovedTo [i];
|
string to_file_path = change_set.MovedTo [i];
|
||||||
|
|
||||||
string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
|
event_entry += "<dd class='document moved'>";
|
||||||
change_set.Folder, file_path}.Combine ();
|
event_entry += FormatBreadCrumbs (
|
||||||
|
Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, change_set.Folder),
|
||||||
|
file_path
|
||||||
|
);
|
||||||
|
|
||||||
string absolute_to_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
|
event_entry += "<br>";
|
||||||
change_set.Folder, to_file_path}.Combine ();
|
event_entry += FormatBreadCrumbs (
|
||||||
|
Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, change_set.Folder),
|
||||||
|
to_file_path
|
||||||
|
);
|
||||||
|
|
||||||
if (File.Exists (absolute_file_path))
|
event_entry += "</dd>";
|
||||||
event_entry += "<dd class='document moved'><a href='" + absolute_file_path + "'>" + file_path + "</a><br/>";
|
|
||||||
else
|
|
||||||
event_entry += "<dd class='document moved'>" + file_path + "<br/>";
|
|
||||||
|
|
||||||
if (File.Exists (absolute_to_file_path))
|
|
||||||
event_entry += "<a href='" + absolute_to_file_path + "'>" + to_file_path + "</a></dd>";
|
|
||||||
else
|
|
||||||
event_entry += to_file_path + "</dd>";
|
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -620,7 +617,7 @@ namespace SparkleShare {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
repo.SyncProgressChanged += delegate (double percentage, string speed) {
|
repo.ProgressChanged += delegate (double percentage, string speed) {
|
||||||
ProgressPercentage = percentage;
|
ProgressPercentage = percentage;
|
||||||
ProgressSpeed = speed;
|
ProgressSpeed = speed;
|
||||||
|
|
||||||
|
@ -785,13 +782,6 @@ namespace SparkleShare {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public bool BackendIsPresent {
|
|
||||||
get {
|
|
||||||
return SparkleBackend.DefaultBackend.IsPresent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Looks up the user's name from the global configuration
|
// Looks up the user's name from the global configuration
|
||||||
public string UserName
|
public string UserName
|
||||||
{
|
{
|
||||||
|
@ -1099,16 +1089,6 @@ namespace SparkleShare {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 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
|
// Checks whether there are any folders syncing and
|
||||||
// quits if safe
|
// quits if safe
|
||||||
public void TryQuit ()
|
public void TryQuit ()
|
||||||
|
@ -1118,9 +1098,6 @@ namespace SparkleShare {
|
||||||
repo.Status == SyncStatus.SyncDown ||
|
repo.Status == SyncStatus.SyncDown ||
|
||||||
repo.IsBuffering) {
|
repo.IsBuffering) {
|
||||||
|
|
||||||
if (OnQuitWhileSyncing != null)
|
|
||||||
OnQuitWhileSyncing ();
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1166,6 +1143,55 @@ namespace SparkleShare {
|
||||||
int number = 3 + int.Parse (numbers);
|
int number = 3 + int.Parse (numbers);
|
||||||
return this.tango_palette [number % this.tango_palette.Length];
|
return this.tango_palette [number % this.tango_palette.Length];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 ("-", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string FormatBreadCrumbs (string path_root, string path)
|
||||||
|
{
|
||||||
|
string link = "";
|
||||||
|
string [] crumbs = path.Split (Path.DirectorySeparatorChar);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
string new_path_root = path_root;
|
||||||
|
bool previous_was_folder = false;
|
||||||
|
foreach (string crumb in crumbs) {
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty (crumb))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string crumb_path = Path.Combine (new_path_root, crumb);
|
||||||
|
|
||||||
|
if (Directory.Exists (crumb_path)) {
|
||||||
|
link += "<a href='" + crumb_path + "'>" + crumb + Path.DirectorySeparatorChar + "</a>";
|
||||||
|
previous_was_folder = true;
|
||||||
|
|
||||||
|
} else if (File.Exists (crumb_path)) {
|
||||||
|
link += "<a href='" + crumb_path + "'>" + crumb + "</a>";
|
||||||
|
previous_was_folder = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (i > 0 && !previous_was_folder)
|
||||||
|
link += Path.DirectorySeparatorChar;
|
||||||
|
|
||||||
|
link += crumb;
|
||||||
|
previous_was_folder = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_path_root = Path.Combine (new_path_root, crumb);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return link;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,37 @@ namespace SparkleShare {
|
||||||
|
|
||||||
public SparkleInvite (string xml_file_path)
|
public SparkleInvite (string xml_file_path)
|
||||||
{
|
{
|
||||||
// TODO
|
XmlDocument xml_document = new XmlDocument ();
|
||||||
|
XmlNode node;
|
||||||
|
|
||||||
|
string host = "", path = "", token = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
xml_document.Load (xml_file_path);
|
||||||
|
|
||||||
|
node = xml_document.SelectSingleNode ("/sparkleshare/invite/host/text()");
|
||||||
|
if (node != null) { host = node.Value; }
|
||||||
|
|
||||||
|
node = xml_document.SelectSingleNode ("/sparkleshare/invite/path/text()");
|
||||||
|
if (node != null) { path = node.Value; }
|
||||||
|
|
||||||
|
node = xml_document.SelectSingleNode ("/sparkleshare/invite/token/text()");
|
||||||
|
if (node != null) { token = node.Value; }
|
||||||
|
|
||||||
|
} catch (XmlException e) {
|
||||||
|
SparkleHelpers.DebugInfo ("Invite", "Invalid XML: " + e.Message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (path.StartsWith ("/"))
|
||||||
|
path = path.Substring (1);
|
||||||
|
|
||||||
|
if (!host.EndsWith ("/"))
|
||||||
|
host = host + "/";
|
||||||
|
|
||||||
|
FullAddress = new Uri ("ssh://" + host + path);
|
||||||
|
Token = token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,9 +198,8 @@ namespace SparkleShare {
|
||||||
|
|
||||||
XmlDocument xml_document = new XmlDocument ();
|
XmlDocument xml_document = new XmlDocument ();
|
||||||
XmlNode node;
|
XmlNode node;
|
||||||
string host = "";
|
|
||||||
string path = "";
|
string host = "", path = "", token = "";
|
||||||
string token = "";
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
xml_document.LoadXml (invite_xml);
|
xml_document.LoadXml (invite_xml);
|
||||||
|
@ -185,7 +214,7 @@ namespace SparkleShare {
|
||||||
if (node != null) { token = node.Value; }
|
if (node != null) { token = node.Value; }
|
||||||
|
|
||||||
} catch (XmlException e) {
|
} catch (XmlException e) {
|
||||||
SparkleHelpers.DebugInfo ("Invite", "Not valid XML: " + received_message + " " + e.Message);
|
SparkleHelpers.DebugInfo ("Invite", "Invalid XML: " + received_message + " " + e.Message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,56 +16,83 @@
|
||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
|
||||||
namespace SparkleShare {
|
namespace SparkleShare {
|
||||||
|
|
||||||
public class SparklePlugin {
|
public class SparklePlugin {
|
||||||
|
|
||||||
public string Name;
|
public string Name {
|
||||||
public string Description;
|
get {
|
||||||
public string ImagePath;
|
return GetValue ("info", "name");
|
||||||
public string Backend;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string Address;
|
public string Description {
|
||||||
public string AddressExample;
|
get {
|
||||||
public string Path;
|
return GetValue ("info", "description");
|
||||||
public string PathExample;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ImagePath {
|
||||||
|
get {
|
||||||
|
return System.IO.Path.Combine (
|
||||||
|
this.plugin_directory,
|
||||||
|
GetValue ("info", "icon")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Backend {
|
||||||
|
get {
|
||||||
|
return GetValue ("info", "backend");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Address {
|
||||||
|
get {
|
||||||
|
return GetValue ("address", "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string AddressExample {
|
||||||
|
get {
|
||||||
|
return GetValue ("address", "example");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Path {
|
||||||
|
get {
|
||||||
|
return GetValue ("path", "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PathExample {
|
||||||
|
get {
|
||||||
|
return GetValue ("path", "example");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private XmlDocument xml = new XmlDocument ();
|
||||||
|
private string plugin_directory;
|
||||||
|
|
||||||
public SparklePlugin (string plugin_path)
|
public SparklePlugin (string plugin_path)
|
||||||
{
|
{
|
||||||
string plugin_directory = System.IO.Path.GetDirectoryName (plugin_path);
|
this.plugin_directory = System.IO.Path.GetDirectoryName (plugin_path);
|
||||||
|
this.xml.Load (plugin_path);
|
||||||
|
}
|
||||||
|
|
||||||
XmlDocument xml = new XmlDocument ();
|
|
||||||
xml.Load (plugin_path);
|
|
||||||
|
|
||||||
XmlNode node;
|
private string GetValue (string a, string b)
|
||||||
|
{
|
||||||
|
XmlNode node = this.xml.SelectSingleNode (
|
||||||
|
"/sparkleshare/plugin/" + a + "/" + b + "/text()");
|
||||||
|
|
||||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/info/name/text()");
|
if (node != null)
|
||||||
if (node != null) { Name = node.Value; }
|
return node.Value;
|
||||||
|
else
|
||||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/info/description/text()");
|
return null;
|
||||||
if (node != null) { Description = node.Value; }
|
|
||||||
|
|
||||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/info/icon/text()");
|
|
||||||
if (node != null) { ImagePath = System.IO.Path.Combine (plugin_directory, node.Value); }
|
|
||||||
|
|
||||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/info/backend/text()");
|
|
||||||
if (node != null) { Backend = node.Value; }
|
|
||||||
|
|
||||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/address/value/text()");
|
|
||||||
if (node != null) { Address = node.Value; }
|
|
||||||
|
|
||||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/address/example/text()");
|
|
||||||
if (node != null) { AddressExample = node.Value; }
|
|
||||||
|
|
||||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/path/value/text()");
|
|
||||||
if (node != null) { Path = node.Value; }
|
|
||||||
|
|
||||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/path/example/text()");
|
|
||||||
if (node != null) { PathExample = node.Value; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,12 +33,11 @@ namespace SparkleShare {
|
||||||
|
|
||||||
public SparkleStatusIconController Controller = new SparkleStatusIconController ();
|
public SparkleStatusIconController Controller = new SparkleStatusIconController ();
|
||||||
|
|
||||||
// TODO: fix case
|
private Timer animation;
|
||||||
private Timer Animation;
|
private Gdk.Pixbuf [] animation_frames;
|
||||||
private Gdk.Pixbuf [] AnimationFrames;
|
private int frame_number;
|
||||||
private int FrameNumber;
|
private string state_text;
|
||||||
private string StateText;
|
private Menu menu;
|
||||||
private Menu Menu;
|
|
||||||
private MenuItem quit_item;
|
private MenuItem quit_item;
|
||||||
|
|
||||||
#if HAVE_APP_INDICATOR
|
#if HAVE_APP_INDICATOR
|
||||||
|
@ -56,8 +55,8 @@ namespace SparkleShare {
|
||||||
|
|
||||||
public SparkleStatusIcon ()
|
public SparkleStatusIcon ()
|
||||||
{
|
{
|
||||||
AnimationFrames = CreateAnimationFrames ();
|
CreateAnimationFrames ();
|
||||||
Animation = CreateAnimation ();
|
CreateAnimation ();
|
||||||
|
|
||||||
#if HAVE_APP_INDICATOR
|
#if HAVE_APP_INDICATOR
|
||||||
this.indicator = new ApplicationIndicator ("sparkleshare",
|
this.indicator = new ApplicationIndicator ("sparkleshare",
|
||||||
|
@ -70,13 +69,13 @@ namespace SparkleShare {
|
||||||
|
|
||||||
this.status_icon.Activate += ShowMenu; // Primary mouse button click
|
this.status_icon.Activate += ShowMenu; // Primary mouse button click
|
||||||
this.status_icon.PopupMenu += ShowMenu; // Secondary mouse button click
|
this.status_icon.PopupMenu += ShowMenu; // Secondary mouse button click
|
||||||
this.status_icon.Pixbuf = AnimationFrames [0];
|
this.status_icon.Pixbuf = this.animation_frames [0];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (Controller.Folders.Length == 0)
|
if (Controller.Folders.Length == 0)
|
||||||
StateText = _("Welcome to SparkleShare!");
|
this.state_text = _("Welcome to SparkleShare!");
|
||||||
else
|
else
|
||||||
StateText = _("Up to date") + Controller.FolderSize;
|
this.state_text = _("Up to date") + Controller.FolderSize;
|
||||||
|
|
||||||
CreateMenu ();
|
CreateMenu ();
|
||||||
|
|
||||||
|
@ -85,7 +84,7 @@ namespace SparkleShare {
|
||||||
Application.Invoke (delegate {
|
Application.Invoke (delegate {
|
||||||
if (this.quit_item != null) {
|
if (this.quit_item != null) {
|
||||||
this.quit_item.Sensitive = quit_item_enabled;
|
this.quit_item.Sensitive = quit_item_enabled;
|
||||||
Menu.ShowAll ();
|
this.menu.ShowAll ();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -95,17 +94,17 @@ namespace SparkleShare {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case IconState.Idle:
|
case IconState.Idle:
|
||||||
|
|
||||||
Animation.Stop ();
|
this.animation.Stop ();
|
||||||
|
|
||||||
if (Controller.Folders.Length == 0)
|
if (Controller.Folders.Length == 0)
|
||||||
StateText = _("Welcome to SparkleShare!");
|
this.state_text = _("Welcome to SparkleShare!");
|
||||||
else
|
else
|
||||||
StateText = _("Up to date") + Controller.FolderSize;
|
this.state_text = _("Up to date") + Controller.FolderSize;
|
||||||
|
|
||||||
#if HAVE_APP_INDICATOR
|
#if HAVE_APP_INDICATOR
|
||||||
this.indicator.IconName = "process-syncing-sparkleshare-i";
|
this.indicator.IconName = "process-syncing-sparkleshare-i";
|
||||||
#else
|
#else
|
||||||
this.status_icon.Pixbuf = AnimationFrames [0];
|
this.status_icon.Pixbuf = this.animation_frames [0];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
UpdateStateText ();
|
UpdateStateText ();
|
||||||
|
@ -115,22 +114,22 @@ namespace SparkleShare {
|
||||||
|
|
||||||
case IconState.Syncing:
|
case IconState.Syncing:
|
||||||
|
|
||||||
StateText = _("Syncing… ") +
|
this.state_text = _("Syncing… ") +
|
||||||
Controller.ProgressPercentage + "% " +
|
Controller.ProgressPercentage + "% " +
|
||||||
Controller.ProgressSpeed;
|
Controller.ProgressSpeed;
|
||||||
|
|
||||||
UpdateStateText ();
|
UpdateStateText ();
|
||||||
|
|
||||||
if (!Animation.Enabled)
|
if (!this.animation.Enabled)
|
||||||
Animation.Start ();
|
this.animation.Start ();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IconState.Error:
|
case IconState.Error:
|
||||||
|
|
||||||
Animation.Stop ();
|
this.animation.Stop ();
|
||||||
|
|
||||||
StateText = _("Not everything is synced");
|
this.state_text = _("Not everything is synced");
|
||||||
UpdateStateText ();
|
UpdateStateText ();
|
||||||
CreateMenu ();
|
CreateMenu ();
|
||||||
|
|
||||||
|
@ -143,7 +142,7 @@ namespace SparkleShare {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu.ShowAll ();
|
this.menu.ShowAll ();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -151,47 +150,43 @@ namespace SparkleShare {
|
||||||
|
|
||||||
// Slices up the graphic that contains the
|
// Slices up the graphic that contains the
|
||||||
// animation frames.
|
// animation frames.
|
||||||
private Gdk.Pixbuf [] CreateAnimationFrames ()
|
private void CreateAnimationFrames ()
|
||||||
{
|
{
|
||||||
Gdk.Pixbuf [] animation_frames = new Gdk.Pixbuf [5];
|
this.animation_frames = new Gdk.Pixbuf [5];
|
||||||
Gdk.Pixbuf frames_pixbuf = SparkleUIHelpers.GetIcon ("process-syncing-sparkleshare", 24);
|
Gdk.Pixbuf frames_pixbuf = SparkleUIHelpers.GetIcon ("process-syncing-sparkleshare", 24);
|
||||||
|
|
||||||
for (int i = 0; i < animation_frames.Length; i++)
|
for (int i = 0; i < this.animation_frames.Length; i++)
|
||||||
animation_frames [i] = new Gdk.Pixbuf (frames_pixbuf, (i * 24), 0, 24, 24);
|
animation_frames [i] = new Gdk.Pixbuf (frames_pixbuf, (i * 24), 0, 24, 24);
|
||||||
|
|
||||||
return animation_frames;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Creates the Animation that handles the syncing animation
|
// Creates the animation that handles the syncing animation
|
||||||
private Timer CreateAnimation ()
|
private void CreateAnimation ()
|
||||||
{
|
{
|
||||||
FrameNumber = 0;
|
this.frame_number = 0;
|
||||||
|
|
||||||
Timer Animation = new Timer () {
|
this.animation = new Timer () {
|
||||||
Interval = 35
|
Interval = 35
|
||||||
};
|
};
|
||||||
|
|
||||||
Animation.Elapsed += delegate {
|
this.animation.Elapsed += delegate {
|
||||||
if (FrameNumber < AnimationFrames.Length - 1)
|
if (this.frame_number < this.animation_frames.Length - 1)
|
||||||
FrameNumber++;
|
this.frame_number++;
|
||||||
else
|
else
|
||||||
FrameNumber = 0;
|
this.frame_number = 0;
|
||||||
|
|
||||||
string icon_name = "process-syncing-sparkleshare-";
|
string icon_name = "process-syncing-sparkleshare-";
|
||||||
for (int i = 0; i <= FrameNumber; i++)
|
for (int i = 0; i <= this.frame_number; i++)
|
||||||
icon_name += "i";
|
icon_name += "i";
|
||||||
|
|
||||||
Application.Invoke (delegate {
|
Application.Invoke (delegate {
|
||||||
#if HAVE_APP_INDICATOR
|
#if HAVE_APP_INDICATOR
|
||||||
this.indicator.IconName = icon_name;
|
this.indicator.IconName = icon_name;
|
||||||
#else
|
#else
|
||||||
this.status_icon.Pixbuf = AnimationFrames [FrameNumber];
|
this.status_icon.Pixbuf = this.animation_frames [this.frame_number];
|
||||||
#endif
|
#endif
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return Animation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -199,15 +194,15 @@ namespace SparkleShare {
|
||||||
// user clicks the status icon
|
// user clicks the status icon
|
||||||
public void CreateMenu ()
|
public void CreateMenu ()
|
||||||
{
|
{
|
||||||
Menu = new Menu ();
|
this.menu = new Menu ();
|
||||||
|
|
||||||
// The menu item showing the status and size of the SparkleShare folder
|
// The menu item showing the status and size of the SparkleShare folder
|
||||||
MenuItem status_menu_item = new MenuItem (StateText) {
|
MenuItem status_menu_item = new MenuItem (this.state_text) {
|
||||||
Sensitive = false
|
Sensitive = false
|
||||||
};
|
};
|
||||||
|
|
||||||
Menu.Add (status_menu_item);
|
this.menu.Add (status_menu_item);
|
||||||
Menu.Add (new SeparatorMenuItem ());
|
this.menu.Add (new SeparatorMenuItem ());
|
||||||
|
|
||||||
ImageMenuItem folder_item = new SparkleMenuItem ("SparkleShare"){
|
ImageMenuItem folder_item = new SparkleMenuItem ("SparkleShare"){
|
||||||
Image = new Image (SparkleUIHelpers.GetIcon ("folder-sparkleshare", 16))
|
Image = new Image (SparkleUIHelpers.GetIcon ("folder-sparkleshare", 16))
|
||||||
|
@ -217,7 +212,7 @@ namespace SparkleShare {
|
||||||
Program.Controller.OpenSparkleShareFolder ();
|
Program.Controller.OpenSparkleShareFolder ();
|
||||||
};
|
};
|
||||||
|
|
||||||
Menu.Add (folder_item);
|
this.menu.Add (folder_item);
|
||||||
|
|
||||||
if (Program.Controller.Folders.Count > 0) {
|
if (Program.Controller.Folders.Count > 0) {
|
||||||
|
|
||||||
|
@ -239,7 +234,7 @@ namespace SparkleShare {
|
||||||
};
|
};
|
||||||
|
|
||||||
subfolder_item.Activated += OpenFolderDelegate (folder_name);
|
subfolder_item.Activated += OpenFolderDelegate (folder_name);
|
||||||
Menu.Add (subfolder_item);
|
this.menu.Add (subfolder_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -247,10 +242,10 @@ namespace SparkleShare {
|
||||||
Sensitive = false
|
Sensitive = false
|
||||||
};
|
};
|
||||||
|
|
||||||
Menu.Add (no_folders_item);
|
this.menu.Add (no_folders_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu.Add (new SeparatorMenuItem ());
|
this.menu.Add (new SeparatorMenuItem ());
|
||||||
|
|
||||||
// Opens the wizard to add a new remote folder
|
// Opens the wizard to add a new remote folder
|
||||||
MenuItem sync_item = new MenuItem (_("Add Hosted Project…"));
|
MenuItem sync_item = new MenuItem (_("Add Hosted Project…"));
|
||||||
|
@ -274,8 +269,8 @@ namespace SparkleShare {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Menu.Add (sync_item);
|
this.menu.Add (sync_item);
|
||||||
Menu.Add (new SeparatorMenuItem ());
|
this.menu.Add (new SeparatorMenuItem ());
|
||||||
|
|
||||||
MenuItem recent_events_item = new MenuItem (_("Open Recent Events"));
|
MenuItem recent_events_item = new MenuItem (_("Open Recent Events"));
|
||||||
|
|
||||||
|
@ -291,7 +286,7 @@ namespace SparkleShare {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Menu.Add (recent_events_item);
|
this.menu.Add (recent_events_item);
|
||||||
|
|
||||||
MenuItem notify_item;
|
MenuItem notify_item;
|
||||||
|
|
||||||
|
@ -305,8 +300,8 @@ namespace SparkleShare {
|
||||||
CreateMenu ();
|
CreateMenu ();
|
||||||
};
|
};
|
||||||
|
|
||||||
Menu.Add (notify_item);
|
this.menu.Add (notify_item);
|
||||||
Menu.Add (new SeparatorMenuItem ());
|
this.menu.Add (new SeparatorMenuItem ());
|
||||||
|
|
||||||
// A menu item that takes the user to http://www.sparkleshare.org/
|
// A menu item that takes the user to http://www.sparkleshare.org/
|
||||||
MenuItem about_item = new MenuItem (_("About SparkleShare"));
|
MenuItem about_item = new MenuItem (_("About SparkleShare"));
|
||||||
|
@ -321,8 +316,8 @@ namespace SparkleShare {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Menu.Add (about_item);
|
this.menu.Add (about_item);
|
||||||
Menu.Add (new SeparatorMenuItem ());
|
this.menu.Add (new SeparatorMenuItem ());
|
||||||
|
|
||||||
// A menu item that quits the application
|
// A menu item that quits the application
|
||||||
this.quit_item = new MenuItem (_("Quit")) {
|
this.quit_item = new MenuItem (_("Quit")) {
|
||||||
|
@ -333,11 +328,11 @@ namespace SparkleShare {
|
||||||
Program.Controller.Quit ();
|
Program.Controller.Quit ();
|
||||||
};
|
};
|
||||||
|
|
||||||
Menu.Add (this.quit_item);
|
this.menu.Add (this.quit_item);
|
||||||
Menu.ShowAll ();
|
this.menu.ShowAll ();
|
||||||
|
|
||||||
#if HAVE_APP_INDICATOR
|
#if HAVE_APP_INDICATOR
|
||||||
this.indicator.Menu = Menu;
|
this.indicator.Menu = this.menu;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,15 +349,15 @@ namespace SparkleShare {
|
||||||
|
|
||||||
public void UpdateStateText ()
|
public void UpdateStateText ()
|
||||||
{
|
{
|
||||||
((Menu.Children [0] as MenuItem).Child as Label).Text = StateText;
|
((this.menu.Children [0] as MenuItem).Child as Label).Text = this.state_text;
|
||||||
Menu.ShowAll ();
|
this.menu.ShowAll ();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !HAVE_APP_INDICATOR
|
#if !HAVE_APP_INDICATOR
|
||||||
// Makes the menu visible
|
// Makes the menu visible
|
||||||
private void ShowMenu (object o, EventArgs args)
|
private void ShowMenu (object o, EventArgs args)
|
||||||
{
|
{
|
||||||
Menu.Popup (null, null, SetPosition, 0, Global.CurrentEventTime);
|
this.menu.Popup (null, null, SetPosition, 0, Global.CurrentEventTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -69,12 +69,9 @@ namespace SparkleShare {
|
||||||
Setup = new SparkleSetup ();
|
Setup = new SparkleSetup ();
|
||||||
Setup.Controller.ShowSetupPage ();
|
Setup.Controller.ShowSetupPage ();
|
||||||
}
|
}
|
||||||
|
|
||||||
Program.Controller.OnQuitWhileSyncing += delegate {
|
|
||||||
// TODO: Pop up a warning when quitting whilst syncing
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Runs the application
|
// Runs the application
|
||||||
public void Run ()
|
public void Run ()
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,7 +42,7 @@ stop() {
|
||||||
rm -f ${pidfile}
|
rm -f ${pidfile}
|
||||||
echo "Done."
|
echo "Done."
|
||||||
else
|
else
|
||||||
echo "SparkleShare is not running, removing stale pid file."
|
echo "SparkleShare is not running, removing stale pid file..."
|
||||||
rm -f ${pidfile}
|
rm -f ${pidfile}
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
@ -64,14 +64,10 @@ case $1 in
|
||||||
help|--help|-h)
|
help|--help|-h)
|
||||||
mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" --help
|
mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" --help
|
||||||
;;
|
;;
|
||||||
-d|--disable-gui)
|
version|--version|-v)
|
||||||
mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" --disable-gui
|
|
||||||
;;
|
|
||||||
-v|--version)
|
|
||||||
mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" --version
|
mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" --version
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Usage: sparkleshare {start|stop|restart|help}"
|
echo "Usage: sparkleshare {start|stop|restart|help|version}"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
dnl Process this file with autoconf to produce a configure script.
|
dnl Process this file with autoconf to produce a configure script.
|
||||||
m4_define([sparkleshare_version],
|
m4_define([sparkleshare_version],
|
||||||
[0.8.1])
|
[0.8.2])
|
||||||
|
|
||||||
m4_define([sparkleshare_asm_version],
|
m4_define([sparkleshare_asm_version],
|
||||||
[0.8.1])
|
[0.8.2])
|
||||||
|
|
||||||
AC_PREREQ([2.54])
|
AC_PREREQ([2.54])
|
||||||
AC_INIT([SparkleShare], sparkleshare_version)
|
AC_INIT([SparkleShare], sparkleshare_version)
|
||||||
|
@ -154,7 +154,6 @@ data/Makefile
|
||||||
data/icons/Makefile
|
data/icons/Makefile
|
||||||
data/html/Makefile
|
data/html/Makefile
|
||||||
data/plugins/Makefile
|
data/plugins/Makefile
|
||||||
help/Makefile
|
|
||||||
SparkleLib/AssemblyInfo.cs
|
SparkleLib/AssemblyInfo.cs
|
||||||
SparkleLib/Defines.cs
|
SparkleLib/Defines.cs
|
||||||
SparkleLib/Makefile
|
SparkleLib/Makefile
|
||||||
|
@ -176,7 +175,6 @@ Configuration:
|
||||||
Build Gtk+ UI : ${enable_gtkui}
|
Build Gtk+ UI : ${enable_gtkui}
|
||||||
Nautilus 2.x plugin : ${have_nautilus2_python}
|
Nautilus 2.x plugin : ${have_nautilus2_python}
|
||||||
Nautilus 3.x plugin : ${have_nautilus3_python}
|
Nautilus 3.x plugin : ${have_nautilus3_python}
|
||||||
User Help : ${enable_user_help} (requires gnome-doc-utils >= 0.17.3)
|
|
||||||
|
|
||||||
"
|
"
|
||||||
|
|
||||||
|
|
|
@ -139,6 +139,7 @@
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
color: <!-- $a-hover-color -->;
|
color: <!-- $a-hover-color -->;
|
||||||
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.event-timestamp {
|
.event-timestamp {
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
<page xmlns="http://projectmallard.org/1.0/"
|
|
||||||
xmlns:e="http://projectmallard.org/experimental/"
|
|
||||||
type="topic" style="task"
|
|
||||||
id="accounts">
|
|
||||||
|
|
||||||
<info>
|
|
||||||
<link type="guide" xref="index#account"/>
|
|
||||||
<link type="seealso" xref=""/>
|
|
||||||
<desc>Add the location of your remote folders.</desc>
|
|
||||||
<revision pkgversion="0.1" version="0.1" date="2010-08-9" status="stub"/>
|
|
||||||
<credit type="author">
|
|
||||||
<name>Paul Cutler</name>
|
|
||||||
<email>pcutler@gnome.org</email>
|
|
||||||
</credit>
|
|
||||||
<!--
|
|
||||||
<copyright>
|
|
||||||
<year>2010</year>
|
|
||||||
<name>GNOME Documentation Project</name>
|
|
||||||
</copyright>
|
|
||||||
-->
|
|
||||||
<include href="legal.xml" xmlns="http://www.w3.org/2001/XInclude"/>
|
|
||||||
</info>
|
|
||||||
|
|
||||||
<title>Account Setup</title>
|
|
||||||
|
|
||||||
<p>Insert how to setup your accounts here)
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>Insert more help here, if needed.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</page>
|
|
|
@ -1,32 +0,0 @@
|
||||||
<page xmlns="http://projectmallard.org/1.0/"
|
|
||||||
xmlns:e="http://projectmallard.org/experimental/"
|
|
||||||
type="guide" style="2column"
|
|
||||||
id="advanced">
|
|
||||||
|
|
||||||
<info>
|
|
||||||
<link type="guide" xref="index#advanced"/>
|
|
||||||
<desc>Get help for advanced actions.</desc>
|
|
||||||
<revision pkgversion="0.1" version="0.1" date="2010-08-29" status="draft"/>
|
|
||||||
<credit type="author">
|
|
||||||
<name>Paul Cutler</name>
|
|
||||||
<email>pcutler@gnome.org</email>
|
|
||||||
</credit>
|
|
||||||
<!--
|
|
||||||
<copyright>
|
|
||||||
<year>2010</year>
|
|
||||||
<name>GNOME Documentation Project</name>
|
|
||||||
</copyright>
|
|
||||||
-->
|
|
||||||
<include href="legal.xml" xmlns="http://www.w3.org/2001/XInclude"/>
|
|
||||||
</info>
|
|
||||||
|
|
||||||
<title>Advanced Options and Help</title>
|
|
||||||
|
|
||||||
<section id="tbd" style="2column">
|
|
||||||
<info>
|
|
||||||
<title type="link">TBD</title>
|
|
||||||
</info>
|
|
||||||
<title>TBD</title>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</page>
|
|
|
@ -1,40 +0,0 @@
|
||||||
<page xmlns="http://projectmallard.org/1.0/"
|
|
||||||
xmlns:e="http://projectmallard.org/experimental/"
|
|
||||||
type="guide"
|
|
||||||
id="index">
|
|
||||||
|
|
||||||
<info>
|
|
||||||
<revision pkgversion="0.1" version="0.1" date="2010-08-29"
|
|
||||||
status="incomplete"/>
|
|
||||||
<credit type="author">
|
|
||||||
<name>Paul Cutler</name>
|
|
||||||
<email>pcutler@gnome.org</email>
|
|
||||||
</credit>
|
|
||||||
<!--
|
|
||||||
<copyright>
|
|
||||||
<year>2010</year>
|
|
||||||
<name>GNOME Documentation Project</name>
|
|
||||||
</copyright>
|
|
||||||
-->
|
|
||||||
<include href="legal.xml" xmlns="http://www.w3.org/2001/XInclude" />
|
|
||||||
</info>
|
|
||||||
|
|
||||||
<title>SparkleShare</title>
|
|
||||||
|
|
||||||
<section id="account" style="2column">
|
|
||||||
<title>Account Setup</title>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="share" style="2column">
|
|
||||||
<title>Sync and Share Files</title>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="advanced" style="2column">
|
|
||||||
<title>Advanced options and help</title>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="problems">
|
|
||||||
<title>Common Problems</title>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</page>
|
|
|
@ -1,42 +0,0 @@
|
||||||
<page xmlns="http://projectmallard.org/1.0/"
|
|
||||||
type="topic"
|
|
||||||
id="introduction">
|
|
||||||
|
|
||||||
<info>
|
|
||||||
<link type="guide" xref="index"/>
|
|
||||||
<revision pkgversion="0.1" version="0.1" date="2010-08-29" status="draft"/>
|
|
||||||
<desc>
|
|
||||||
Introduction to <app>SparkleShare</app>.
|
|
||||||
</desc>
|
|
||||||
<credit type="author">
|
|
||||||
<name>Paul Cutler</name>
|
|
||||||
<email>pcutler@gnome.org</email>
|
|
||||||
</credit>
|
|
||||||
<!--
|
|
||||||
<copyright>
|
|
||||||
<year>2010</year>
|
|
||||||
<name>GNOME Documentation Project</name>
|
|
||||||
</copyright>
|
|
||||||
-->
|
|
||||||
<include href="legal.xml" xmlns="http://www.w3.org/2001/XInclude" />
|
|
||||||
</info>
|
|
||||||
|
|
||||||
<title>Introduction</title>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<app>SparkleShare</app> is an application that allows you to easily
|
|
||||||
sync and share your files and folders. SparkeShare uses the
|
|
||||||
distributed version control system <app>Git</app> to keep a record
|
|
||||||
of all the changes in your files, making it easy to easily go back
|
|
||||||
to an earlier version of the file if you make a mistake.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<figure>
|
|
||||||
<title><gui>SparkleShare</gui> screenshot</title>
|
|
||||||
<desc><app>SparkleShare</app></desc>
|
|
||||||
<media type="image" src="figures/sparkleshare.png" mime="image/png" style="right">
|
|
||||||
<p><app>Sparkleshare</app></p>
|
|
||||||
</media>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
</page>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<license xmlns="http://projectmallard.org/1.0/"
|
|
||||||
href="http://creativecommons.org/licenses/by-sa/3.0/">
|
|
||||||
<p>This work is licensed under a
|
|
||||||
<link href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons
|
|
||||||
Attribution-Share Alike 3.0 Unported License</link>.</p>
|
|
||||||
<p>As a special exception, the copyright holders give you permission to copy,
|
|
||||||
modify, and distribute the example code contained in this document under the
|
|
||||||
terms of your choosing, without restriction.</p>
|
|
||||||
</license>
|
|
|
@ -1,32 +0,0 @@
|
||||||
<page xmlns="http://projectmallard.org/1.0/"
|
|
||||||
xmlns:e="http://projectmallard.org/experimental/"
|
|
||||||
type="topic" style="task"
|
|
||||||
id="share">
|
|
||||||
|
|
||||||
<info>
|
|
||||||
<link type="guide" xref="index#share"/>
|
|
||||||
<link type="seealso" xref=""/>
|
|
||||||
<desc>Sync and share your folders and files.</desc>
|
|
||||||
<revision pkgversion="1.6" version="0.1" date="2010-07-11" status="draft"/>
|
|
||||||
<credit type="author">
|
|
||||||
<name>Paul Cutler</name>
|
|
||||||
<email>pcutler@gnome.org</email>
|
|
||||||
</credit>
|
|
||||||
<!--
|
|
||||||
<copyright>
|
|
||||||
<year>2010</year>
|
|
||||||
<name>GNOME Documentation Project</name>
|
|
||||||
</copyright>
|
|
||||||
-->
|
|
||||||
<include href="legal.xml" xmlns="http://www.w3.org/2001/XInclude"/>
|
|
||||||
</info>
|
|
||||||
|
|
||||||
<title>Sync and share your files and folders</title>
|
|
||||||
|
|
||||||
<p>Insert help here.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</page>
|
|
|
@ -1,17 +0,0 @@
|
||||||
if HAVE_GNOME_DOC_UTILS
|
|
||||||
include $(top_srcdir)/gnome-doc-utils.make
|
|
||||||
|
|
||||||
DOC_ID = sparkleshare
|
|
||||||
|
|
||||||
DOC_INCLUDES = legal.xml
|
|
||||||
|
|
||||||
DOC_PAGES = account-creation.page \
|
|
||||||
advanced.page \
|
|
||||||
index.page \
|
|
||||||
introduction.page \
|
|
||||||
share.page
|
|
||||||
|
|
||||||
DOC_LINGUAS =
|
|
||||||
|
|
||||||
dist-hook: doc-dist-hook
|
|
||||||
endif
|
|
|
@ -1,36 +0,0 @@
|
||||||
.TH sparkleshare 1 "August 16, 2010" "version 0.2" "USER COMMANDS"
|
|
||||||
.SH NAME
|
|
||||||
sparkleshare \- sharing work made easy
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B sparkleshare
|
|
||||||
[start|stop|restart|help]
|
|
||||||
.SH DESCRIPTION
|
|
||||||
A file sharing system for the desktop that retains a full history of
|
|
||||||
changes made, and allows work to be sychronized across many systems.
|
|
||||||
Based on the underlying `git' version control system, sparkleshare is
|
|
||||||
fast and secure, but the interface is straightforward enough for all
|
|
||||||
to use.
|
|
||||||
.SH OPTIONS
|
|
||||||
.TP
|
|
||||||
start
|
|
||||||
Start the sparkleshare system, presenting an introductory dialog if
|
|
||||||
this is the first time that it has been run.
|
|
||||||
.TP
|
|
||||||
stop
|
|
||||||
Stop sparkleshare, halting all current file sharing and no longer watch
|
|
||||||
for changes in the configured shares.
|
|
||||||
.TP
|
|
||||||
restart
|
|
||||||
Restart sparkleshare.
|
|
||||||
.SH RETURN VALUES
|
|
||||||
Currently sparkleshare only ever returns 0 on exit.
|
|
||||||
.SH FILES
|
|
||||||
.TP
|
|
||||||
~/SparkleShare
|
|
||||||
Directories set up to be shared are placed under this directory.
|
|
||||||
.SH BUGS
|
|
||||||
SparkleShare is currently under development, it is likely that there
|
|
||||||
are a number of bugs present in the system. Since the underlying
|
|
||||||
file sharing is simply based on `git', even if SparkleShare itself fails,
|
|
||||||
the data is retrievable in an open format. On-disk corruption is
|
|
||||||
extremely unlikely.
|
|
Loading…
Reference in a new issue