Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 564 lines (415 sloc) 19.851 kb
// 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;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using SparkleLib;
namespace SparkleShare {
public enum PageType {
None,
Setup,
Add,
Invite,
Syncing,
Error,
Finished,
Tutorial,
CryptoSetup,
CryptoPassword
}
public enum FieldState {
Enabled,
Disabled
}
public class SparkleSetupController {
public event Action ShowWindowEvent = delegate { };
public event Action HideWindowEvent = delegate { };
public event ChangePageEventHandler ChangePageEvent = delegate { };
public delegate void ChangePageEventHandler (PageType page, string [] warnings);
public event UpdateProgressBarEventHandler UpdateProgressBarEvent = delegate { };
public delegate void UpdateProgressBarEventHandler (double percentage);
public event UpdateSetupContinueButtonEventHandler UpdateSetupContinueButtonEvent = delegate { };
public delegate void UpdateSetupContinueButtonEventHandler (bool button_enabled);
public event UpdateCryptoSetupContinueButtonEventHandler UpdateCryptoSetupContinueButtonEvent = delegate { };
public delegate void UpdateCryptoSetupContinueButtonEventHandler (bool button_enabled);
public event UpdateCryptoPasswordContinueButtonEventHandler UpdateCryptoPasswordContinueButtonEvent = delegate { };
public delegate void UpdateCryptoPasswordContinueButtonEventHandler (bool button_enabled);
public event UpdateAddProjectButtonEventHandler UpdateAddProjectButtonEvent = delegate { };
public delegate void UpdateAddProjectButtonEventHandler (bool button_enabled);
public event ChangeAddressFieldEventHandler ChangeAddressFieldEvent = delegate { };
public delegate void ChangeAddressFieldEventHandler (string text, string example_text, FieldState state);
public event ChangePathFieldEventHandler ChangePathFieldEvent = delegate { };
public delegate void ChangePathFieldEventHandler (string text, string example_text, FieldState state);
public readonly List<SparklePlugin> Plugins = new List<SparklePlugin> ();
public SparklePlugin SelectedPlugin;
public bool WindowIsOpen { get; private set; }
public SparkleInvite PendingInvite { get; private set; }
public int TutorialPageNumber { get; private set; }
public string PreviousUrl { get; private set; }
public string PreviousAddress { get; private set; }
public string PreviousPath { get; private set; }
public string SyncingFolder { get; private set; }
public double ProgressBarPercentage { get; private set; }
public int SelectedPluginIndex {
get {
return Plugins.IndexOf (SelectedPlugin);
}
}
public bool FetchPriorHistory {
get {
return this.fetch_prior_history;
}
}
private PageType current_page;
private string saved_address = "";
private string saved_remote_path = "";
private bool create_startup_item = true;
private bool fetch_prior_history = false;
public SparkleSetupController ()
{
ChangePageEvent += delegate (PageType page_type, string [] warnings) {
this.current_page = page_type;
};
TutorialPageNumber = 0;
PreviousAddress = "";
PreviousPath = "";
PreviousUrl = "";
SyncingFolder = "";
string local_plugins_path = SparklePlugin.LocalPluginsPath;
int local_plugins_count = 0;
// Import all of the plugins
if (Directory.Exists (local_plugins_path))
// Local plugins go first...
foreach (string xml_file_path in Directory.GetFiles (local_plugins_path, "*.xml")) {
Plugins.Add (new SparklePlugin (xml_file_path));
local_plugins_count++;
}
// ...system plugins after that...
if (Directory.Exists (Program.Controller.PluginsPath)) {
foreach (string xml_file_path in Directory.GetFiles (Program.Controller.PluginsPath, "*.xml")) {
// ...and "Own server" at the very top
if (xml_file_path.EndsWith ("own-server.xml")) {
Plugins.Insert (0, new SparklePlugin (xml_file_path));
} else if (xml_file_path.EndsWith ("ssnet.xml")) {
// Plugins.Insert ((local_plugins_count + 1), new SparklePlugin (xml_file_path)); TODO: Skip this plugin for now
} else {
Plugins.Add (new SparklePlugin (xml_file_path));
}
}
}
SelectedPlugin = Plugins [0];
Program.Controller.InviteReceived += delegate (SparkleInvite invite) {
PendingInvite = invite;
ChangePageEvent (PageType.Invite, null);
ShowWindowEvent ();
};
Program.Controller.ShowSetupWindowEvent += delegate (PageType page_type) {
if (page_type == PageType.CryptoSetup || page_type == PageType.CryptoPassword) {
ChangePageEvent (page_type, null);
return;
}
if (PendingInvite != null) {
WindowIsOpen = true;
ShowWindowEvent ();
return;
}
if (this.current_page == PageType.Syncing ||
this.current_page == PageType.Finished ||
this.current_page == PageType.CryptoSetup ||
this.current_page == PageType.CryptoPassword) {
ShowWindowEvent ();
return;
}
if (page_type == PageType.Add) {
if (WindowIsOpen) {
if (this.current_page == PageType.Error ||
this.current_page == PageType.Finished ||
this.current_page == PageType.None) {
ChangePageEvent (PageType.Add, null);
}
ShowWindowEvent ();
} else if (!Program.Controller.FirstRun && TutorialPageNumber == 0) {
WindowIsOpen = true;
ChangePageEvent (PageType.Add, null);
ShowWindowEvent ();
}
return;
}
WindowIsOpen = true;
ChangePageEvent (page_type, null);
ShowWindowEvent ();
};
}
public void PageCancelled ()
{
PendingInvite = null;
SelectedPlugin = Plugins [0];
PreviousAddress = "";
PreviousPath = "";
PreviousUrl = "";
this.fetch_prior_history = false;
WindowIsOpen = false;
HideWindowEvent ();
}
public void CheckSetupPage (string full_name, string email)
{
full_name = full_name.Trim ();
email = email.Trim ();
bool fields_valid = (!string.IsNullOrEmpty (full_name) && IsValidEmail (email));
UpdateSetupContinueButtonEvent (fields_valid);
}
public void SetupPageCancelled ()
{
Program.Controller.Quit ();
}
public void SetupPageCompleted (string full_name, string email)
{
Program.Controller.CurrentUser = new SparkleUser (full_name, email);
new Thread (() => {
string keys_path = Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath);
string key_file_name = DateTime.Now.ToString ("yyyy-MM-dd HH\\hmm");
string [] key_pair = SparkleKeys.GenerateKeyPair (keys_path, key_file_name);
SparkleKeys.ImportPrivateKey (key_pair [0]);
string link_code_file_path = Path.Combine (Program.Controller.FoldersPath,
Program.Controller.CurrentUser.Name + "'s link code.txt");
// Create an easily accessible copy of the public
// key in the user's SparkleShare folder
File.Copy (key_pair [1], link_code_file_path, true);
}).Start ();
TutorialPageNumber = 1;
ChangePageEvent (PageType.Tutorial, null);
}
public void TutorialSkipped ()
{
TutorialPageNumber = 4;
ChangePageEvent (PageType.Tutorial, null);
}
public void HistoryItemChanged (bool fetch_prior_history)
{
this.fetch_prior_history = fetch_prior_history;
}
public void TutorialPageCompleted ()
{
TutorialPageNumber++;
if (TutorialPageNumber == 5) {
TutorialPageNumber = 0;
WindowIsOpen = false;
HideWindowEvent ();
if (this.create_startup_item)
new Thread (() => Program.Controller.CreateStartupItem ()).Start ();
} else {
ChangePageEvent (PageType.Tutorial, null);
}
}
public void SelectedPluginChanged (int plugin_index)
{
SelectedPlugin = Plugins [plugin_index];
if (SelectedPlugin.Address != null) {
ChangeAddressFieldEvent (SelectedPlugin.Address, "", FieldState.Disabled);
} else if (SelectedPlugin.AddressExample != null) {
ChangeAddressFieldEvent (this.saved_address, SelectedPlugin.AddressExample, FieldState.Enabled);
} else {
ChangeAddressFieldEvent (this.saved_address, "", FieldState.Enabled);
}
if (SelectedPlugin.Path != null) {
ChangePathFieldEvent (SelectedPlugin.Path, "", FieldState.Disabled);
} else if (SelectedPlugin.PathExample != null) {
ChangePathFieldEvent (this.saved_remote_path, SelectedPlugin.PathExample, FieldState.Enabled);
} else {
ChangePathFieldEvent (this.saved_remote_path, "", FieldState.Enabled);
}
}
public void StartupItemChanged (bool create_startup_item)
{
this.create_startup_item = create_startup_item;
}
public void CheckAddPage (string address, string remote_path, int selected_plugin)
{
address = address.Trim ();
remote_path = remote_path.Trim ();
if (selected_plugin == 0)
this.saved_address = address;
this.saved_remote_path = remote_path;
bool fields_valid = (!string.IsNullOrEmpty (address) &&
!string.IsNullOrEmpty (remote_path) && !remote_path.Contains ("\""));
UpdateAddProjectButtonEvent (fields_valid);
}
public void AddPageCompleted (string address, string remote_path)
{
SyncingFolder = Path.GetFileNameWithoutExtension (remote_path);
SyncingFolder = SyncingFolder.Replace ("-crypto", "");
ProgressBarPercentage = 1.0;
ChangePageEvent (PageType.Syncing, null);
address = Uri.EscapeUriString (address.Trim ());
remote_path = remote_path.Trim ();
remote_path = remote_path.TrimEnd ("/".ToCharArray ());
if (SelectedPlugin.PathUsesLowerCase)
remote_path = remote_path.ToLower ();
PreviousAddress = address;
PreviousPath = remote_path;
Program.Controller.FolderFetched += AddPageFetchedDelegate;
Program.Controller.FolderFetchError += AddPageFetchErrorDelegate;
Program.Controller.FolderFetching += SyncingPageFetchingDelegate;
new Thread (() => {
Program.Controller.StartFetcher (address, SelectedPlugin.Fingerprint, remote_path,
SelectedPlugin.AnnouncementsUrl, this.fetch_prior_history);
}).Start ();
}
// The following private methods are
// delegates used by the previous method
private void AddPageFetchedDelegate (string remote_url, string [] warnings)
{
SyncingFolder = "";
// Create a local plugin for succesfully added projects, so
// so the user can easily use the same host again
if (SelectedPluginIndex == 0) {
SparklePlugin new_plugin;
Uri uri = new Uri (remote_url);
try {
string address = remote_url.Replace (uri.AbsolutePath, "");
new_plugin = SparklePlugin.Create (uri.Host, address, address, "", "", "/path/to/project");
if (new_plugin != null) {
Plugins.Insert (1, new_plugin);
SparkleLogger.LogInfo ("Controller", "Added plugin for " + uri.Host);
}
} catch {
SparkleLogger.LogInfo ("Controller", "Failed adding plugin for " + uri.Host);
}
}
ChangePageEvent (PageType.Finished, warnings);
Program.Controller.FolderFetched -= AddPageFetchedDelegate;
Program.Controller.FolderFetchError -= AddPageFetchErrorDelegate;
Program.Controller.FolderFetching -= SyncingPageFetchingDelegate;
}
private void AddPageFetchErrorDelegate (string remote_url, string [] errors)
{
SyncingFolder = "";
PreviousUrl = remote_url;
ChangePageEvent (PageType.Error, errors);
Program.Controller.FolderFetched -= AddPageFetchedDelegate;
Program.Controller.FolderFetchError -= AddPageFetchErrorDelegate;
Program.Controller.FolderFetching -= SyncingPageFetchingDelegate;
}
private void SyncingPageFetchingDelegate (double percentage)
{
ProgressBarPercentage = percentage;
UpdateProgressBarEvent (ProgressBarPercentage);
}
public void InvitePageCompleted ()
{
SyncingFolder = Path.GetFileNameWithoutExtension (PendingInvite.RemotePath);
PreviousAddress = PendingInvite.Address;
PreviousPath = PendingInvite.RemotePath;
ChangePageEvent (PageType.Syncing, null);
new Thread (() => {
if (!PendingInvite.Accept (Program.Controller.CurrentUser.PublicKey)) {
PreviousUrl = PendingInvite.Address +
PendingInvite.RemotePath.TrimStart ("/".ToCharArray ());
ChangePageEvent (PageType.Error, new string [] { "error: Failed to upload the public key" });
return;
}
Program.Controller.FolderFetched += InvitePageFetchedDelegate;
Program.Controller.FolderFetchError += InvitePageFetchErrorDelegate;
Program.Controller.FolderFetching += SyncingPageFetchingDelegate;
Program.Controller.StartFetcher (PendingInvite.Address, PendingInvite.Fingerprint,
PendingInvite.RemotePath, PendingInvite.AnnouncementsUrl, false); // TODO: checkbox on invite page
}).Start ();
}
// The following private methods are
// delegates used by the previous method
private void InvitePageFetchedDelegate (string remote_url, string [] warnings)
{
SyncingFolder = "";
PendingInvite = null;
ChangePageEvent (PageType.Finished, warnings);
Program.Controller.FolderFetched -= AddPageFetchedDelegate;
Program.Controller.FolderFetchError -= AddPageFetchErrorDelegate;
Program.Controller.FolderFetching -= SyncingPageFetchingDelegate;
}
private void InvitePageFetchErrorDelegate (string remote_url, string [] errors)
{
SyncingFolder = "";
PreviousUrl = remote_url;
ChangePageEvent (PageType.Error, errors);
Program.Controller.FolderFetched -= AddPageFetchedDelegate;
Program.Controller.FolderFetchError -= AddPageFetchErrorDelegate;
Program.Controller.FolderFetching -= SyncingPageFetchingDelegate;
}
public void SyncingCancelled ()
{
Program.Controller.StopFetcher ();
if (PendingInvite != null)
ChangePageEvent (PageType.Invite, null);
else
ChangePageEvent (PageType.Add, null);
}
public void ErrorPageCompleted ()
{
if (PendingInvite != null)
ChangePageEvent (PageType.Invite, null);
else
ChangePageEvent (PageType.Add, null);
}
public void CheckCryptoSetupPage (string password)
{
bool valid_password = (password.Length > 0 && !password.Contains (" "));
UpdateCryptoSetupContinueButtonEvent (valid_password);
}
public void CheckCryptoPasswordPage (string password)
{
bool password_correct = Program.Controller.CheckPassword (password);
UpdateCryptoPasswordContinueButtonEvent (password_correct);
}
public void CryptoPageCancelled ()
{
SyncingCancelled ();
}
public void CryptoSetupPageCompleted (string password)
{
CryptoPasswordPageCompleted (password);
}
public void CryptoPasswordPageCompleted (string password)
{
ProgressBarPercentage = 100.0;
ChangePageEvent (PageType.Syncing, null);
new Thread (() => {
Thread.Sleep (1000);
Program.Controller.FinishFetcher (password);
}).Start ();
}
public void OpenFolderClicked ()
{
Program.Controller.OpenSparkleShareFolder (Path.GetFileName (PreviousPath));
FinishPageCompleted ();
}
public void FinishPageCompleted ()
{
SelectedPlugin = Plugins [0];
PreviousUrl = "";
PreviousAddress = "";
PreviousPath = "";
this.fetch_prior_history = false;
this.current_page = PageType.None;
HideWindowEvent ();
}
private bool IsValidEmail (string email)
{
return new Regex (@"^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$", RegexOptions.IgnoreCase).IsMatch (email);
}
}
}
Jump to Line
Something went wrong with that request. Please try again.