controller: Move avatar logic to its own class

This commit is contained in:
Hylke Bons 2013-06-30 16:54:04 +01:00
parent b4fabcf944
commit 3675d2a449
11 changed files with 192 additions and 150 deletions

View file

@ -24,6 +24,8 @@ namespace SparkleLib {
public readonly string Name;
public readonly string Email;
public string AvatarFilePath;
public string PrivateKey;
public string PrivateKeyFilePath;

View file

@ -43,12 +43,12 @@ namespace SparkleLib {
public string ToMessage ()
{
string message = "added '{0}'";
string message = "added: {0}";
switch (Changes [0].Type) {
case SparkleChangeType.Edited: message = "edited '{0}'"; break;
case SparkleChangeType.Deleted: message = "deleted '{0}'"; break;
case SparkleChangeType.Moved: message = "moved '{0}'"; break;
case SparkleChangeType.Edited: message = "edited: {0}"; break;
case SparkleChangeType.Deleted: message = "deleted: {0}"; break;
case SparkleChangeType.Moved: message = "moved: {0}"; break;
}
if (Changes.Count > 0)

View file

@ -22,6 +22,7 @@ SOURCES = \
../SparkleSetupController.cs \
../SparkleStatusIconController.cs \
SparkleAbout.cs \
SparkleAvatars.cs \
SparkleBubbles.cs \
SparkleController.cs \
SparkleEventLog.cs \

View file

@ -0,0 +1,111 @@
// 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.IO;
using System.Collections.Generic;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using SparkleLib;
namespace SparkleShare
{
public static class SparkleAvatars
{
private static List<string> skipped_avatars = new List<string> ();
public static string GetAvatar (string email, int size, string target_path)
{
ServicePointManager.ServerCertificateValidationCallback = GetAvatarValidationCallBack;
email = email.ToLower ();
if (skipped_avatars.Contains (email))
return null;
string avatars_path = new string [] { Path.GetDirectoryName (target_path),
"avatars", size + "x" + size }.Combine ();
string avatar_file_path;
try {
avatar_file_path = Path.Combine (avatars_path, email.MD5 () + ".png");
} catch (InvalidOperationException e) {
SparkleLogger.LogInfo ("Avatars", "Error fetching avatar for " + email, e);
return null;
}
if (File.Exists (avatar_file_path)) {
if (new FileInfo (avatar_file_path).CreationTime < DateTime.Now.AddDays (-1))
File.Delete (avatar_file_path);
else
return avatar_file_path;
}
WebClient client = new WebClient ();
string url = "https://gravatar.com/avatar/" + email.MD5 () + ".png?s=" + size + "&d=404";
try {
byte [] buffer = client.DownloadData (url);
if (buffer.Length > 255) {
if (!Directory.Exists (avatars_path)) {
Directory.CreateDirectory (avatars_path);
SparkleLogger.LogInfo ("Avatars", "Created '" + avatars_path + "'");
}
File.WriteAllBytes (avatar_file_path, buffer);
SparkleLogger.LogInfo ("Avatars", "Fetched " + size + "x" + size + " avatar for " + email);
return avatar_file_path;
} else {
return null;
}
} catch (Exception e) {
SparkleLogger.LogInfo ("Avatars", "Error fetching avatar for " + email, e);
skipped_avatars.Add (email);
return null;
}
}
private static bool GetAvatarValidationCallBack (Object sender,
X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
X509Certificate2 certificate2 = new X509Certificate2 (certificate.GetRawCertData ());
// On some systems (mostly Linux) we can't assume the needed certificates are
// available, so we have to check the certificate's SHA-1 fingerprint manually.
//
// Obtained from https://www.gravatar.com/ on Aug 18 2012 and expires on Oct 24 2015.
string gravatar_cert_fingerprint = "217ACB08C0A1ACC23A21B6ECDE82CD45E14DEC19";
if (!certificate2.Thumbprint.Equals (gravatar_cert_fingerprint)) {
SparkleLogger.LogInfo ("Avatars", "Invalid certificate for https://www.gravatar.com/");
return false;
}
return true;
}
}
}

View file

@ -39,7 +39,7 @@ namespace SparkleShare {
InformativeText = subtext,
DeliveryDate = DateTime.Now
};
NSUserNotificationCenter center = NSUserNotificationCenter.DefaultUserNotificationCenter;
center.ShouldPresentNotification = delegate { return true; };
center.DidActivateNotification += delegate { Controller.BubbleClicked (); };

View file

@ -99,6 +99,7 @@
<Compile Include="..\SparkleKeys.cs">
<Link>SparkleKeys.cs</Link>
</Compile>
<Compile Include="SparkleAvatars.cs" />
</ItemGroup>
<ItemGroup>
<InterfaceDefinition Include="MainMenu.xib" xmlns="" />

View file

@ -32,7 +32,7 @@ namespace SparkleShare {
public readonly string WebsiteLinkAddress = "http://www.sparkleshare.org/";
public readonly string CreditsLinkAddress = "http://www.github.com/hbons/SparkleShare/tree/master/legal/AUTHORS";
public readonly string ReportProblemLinkAddress = "http://www.github.com/hbons/SparkleShare/issues";
public readonly string DebugLogLinkAddress = "file://" + Program.Controller.ConfigPath;
public readonly string DebugLogLinkAddress = "file://" + Program.Controller.Config.LogFilePath;
public string RunningVersion;

View file

@ -35,8 +35,7 @@ namespace SparkleShare {
};
Program.Controller.NotificationRaised += delegate (SparkleChangeSet change_set) {
ShowBubble (change_set.User.Name, change_set.ToMessage (),
Program.Controller.GetAvatar (change_set.User.Email, 48));
ShowBubble (change_set.User.Name, change_set.ToMessage (), change_set.User.AvatarFilePath);
};
}

View file

@ -19,9 +19,6 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using SparkleLib;
@ -37,7 +34,9 @@ namespace SparkleShare {
}
}
public bool RepositoriesLoaded { get; private set;}
public SparkleConfig Config { get; private set; }
public bool RepositoriesLoaded { get; private set; }
public string FoldersPath { get; private set; }
public double ProgressPercentage = 0.0;
@ -78,31 +77,27 @@ namespace SparkleShare {
public bool FirstRun {
get { return this.config.User.Email.Equals ("Unknown"); }
get { return Config.User.Email.Equals ("Unknown"); }
}
public List<string> Folders {
get {
List<string> folders = this.config.Folders;
List<string> folders = Config.Folders;
return folders;
}
}
public string ConfigPath {
get { return this.config.LogFilePath; }
}
public SparkleUser CurrentUser {
get { return this.config.User; }
set { this.config.User = value; }
get { return Config.User; }
set { Config.User = value; }
}
public bool NotificationsEnabled {
get {
string notifications_enabled = this.config.GetConfigOption ("notifications");
string notifications_enabled = Config.GetConfigOption ("notifications");
if (string.IsNullOrEmpty (notifications_enabled)) {
this.config.SetConfigOption ("notifications", bool.TrueString);
Config.SetConfigOption ("notifications", bool.TrueString);
return true;
} else {
@ -111,6 +106,17 @@ namespace SparkleShare {
}
}
public bool AvatarsEnabled {
get {
string fetch_avatars_option = Config.GetConfigOption ("fetch_avatars");
if (fetch_avatars_option != null && fetch_avatars_option.Equals (bool.FalseString))
return false;
return true;
}
}
// Path where the plugins are kept
public abstract string PluginsPath { get; }
@ -145,12 +151,10 @@ namespace SparkleShare {
public abstract string EventEntryHTML { get; }
private SparkleConfig config;
private SparkleFetcherBase fetcher;
private FileSystemWatcher watcher;
private Object repo_lock = new Object ();
private Object check_repos_lock = new Object ();
private List<string> skipped_avatars = new List<string> ();
private List<SparkleRepoBase> repositories = new List<SparkleRepoBase> ();
private bool lost_folders_path = false;
@ -160,9 +164,9 @@ namespace SparkleShare {
string app_data_path = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
string config_path = Path.Combine (app_data_path, "sparkleshare");
this.config = new SparkleConfig (config_path, "config.xml");
SparkleConfig.DefaultConfig = this.config;
FoldersPath = this.config.FoldersPath;
Config = new SparkleConfig (config_path, "config.xml");
SparkleConfig.DefaultConfig = Config;
FoldersPath = Config.FoldersPath;
}
@ -181,10 +185,10 @@ namespace SparkleShare {
}
if (FirstRun) {
this.config.SetConfigOption ("notifications", bool.TrueString);
Config.SetConfigOption ("notifications", bool.TrueString);
} else {
string keys_path = Path.GetDirectoryName (this.config.FullPath);
string keys_path = Path.GetDirectoryName (Config.FullPath);
string key_file_path = "";
foreach (string file_path in Directory.GetFiles (keys_path)) {
@ -281,7 +285,7 @@ namespace SparkleShare {
public void OpenSparkleShareFolder ()
{
OpenFolder (this.config.FoldersPath);
OpenFolder (Config.FoldersPath);
}
@ -293,15 +297,15 @@ namespace SparkleShare {
public void ToggleNotifications ()
{
bool notifications_enabled = this.config.GetConfigOption ("notifications").Equals (bool.TrueString);
this.config.SetConfigOption ("notifications", (!notifications_enabled).ToString ());
bool notifications_enabled = Config.GetConfigOption ("notifications").Equals (bool.TrueString);
Config.SetConfigOption ("notifications", (!notifications_enabled).ToString ());
}
private void CheckRepositories ()
{
lock (this.check_repos_lock) {
string path = this.config.FoldersPath;
string path = Config.FoldersPath;
// Detect any renames
foreach (string folder_path in Directory.GetDirectories (path)) {
@ -310,7 +314,7 @@ namespace SparkleShare {
if (folder_name.Equals (".tmp"))
continue;
if (this.config.GetIdentifierForFolder (folder_name) == null) {
if (Config.GetIdentifierForFolder (folder_name) == null) {
string identifier_file_path = Path.Combine (folder_path, ".sparkleshare");
if (!File.Exists (identifier_file_path))
@ -318,9 +322,9 @@ namespace SparkleShare {
string identifier = File.ReadAllText (identifier_file_path).Trim ();
if (this.config.IdentifierExists (identifier)) {
if (Config.IdentifierExists (identifier)) {
RemoveRepository (folder_path);
this.config.RenameFolder (identifier, folder_name);
Config.RenameFolder (identifier, folder_name);
string new_folder_path = Path.Combine (path, folder_name);
AddRepository (new_folder_path);
@ -332,11 +336,11 @@ namespace SparkleShare {
}
// Remove any deleted folders
foreach (string folder_name in this.config.Folders) {
foreach (string folder_name in Config.Folders) {
string folder_path = new SparkleFolder (folder_name).FullPath;
if (!Directory.Exists (folder_path)) {
this.config.RemoveFolder (folder_name);
Config.RemoveFolder (folder_name);
RemoveRepository (folder_path);
SparkleLogger.LogInfo ("Controller", "Removed folder '" + folder_name + "' from config");
@ -348,9 +352,9 @@ namespace SparkleShare {
// Remove any duplicate folders
string previous_name = "";
foreach (string folder_name in this.config.Folders) {
foreach (string folder_name in Config.Folders) {
if (!string.IsNullOrEmpty (previous_name) && folder_name.Equals (previous_name))
this.config.RemoveFolder (folder_name);
Config.RemoveFolder (folder_name);
else
previous_name = folder_name;
}
@ -364,12 +368,12 @@ namespace SparkleShare {
{
SparkleRepoBase repo = null;
string folder_name = Path.GetFileName (folder_path);
string backend = this.config.GetBackendForFolder (folder_name);
string backend = Config.GetBackendForFolder (folder_name);
try {
repo = (SparkleRepoBase) Activator.CreateInstance (
Type.GetType ("SparkleLib." + backend + ".SparkleRepo, SparkleLib." + backend),
new object [] { folder_path, this.config });
new object [] { folder_path, Config });
} catch (Exception e) {
SparkleLogger.LogInfo ("Controller", "Failed to load backend '" + backend + "' for '" + folder_name + "': ", e);
@ -418,6 +422,9 @@ namespace SparkleShare {
};
repo.NewChangeSet += delegate (SparkleChangeSet change_set) {
if (AvatarsEnabled)
change_set.User.AvatarFilePath = SparkleAvatars.GetAvatar (change_set.User.Email, 48, Config.FullPath);
NotificationRaised (change_set);
};
@ -441,12 +448,6 @@ namespace SparkleShare {
}
}
private void StartupInviteScan ()
{
foreach (string invite in Directory.GetFiles (FoldersPath, "*.xml")) {
HandleInvite (invite);
}
}
private void OnFolderActivity (object o, FileSystemEventArgs args)
{
@ -467,11 +468,20 @@ namespace SparkleShare {
}
private void StartupInviteScan ()
{
foreach (string invite in Directory.GetFiles (FoldersPath, "*.xml")) {
HandleInvite (invite);
}
}
private void HandleInvite (FileSystemEventArgs args)
{
HandleInvite (args.FullPath);
}
private void HandleInvite (string path)
{
if (this.fetcher != null &&
@ -531,7 +541,7 @@ namespace SparkleShare {
public void StartFetcher (SparkleFetcherInfo info)
{
string tmp_path = this.config.TmpPath;
string tmp_path = Config.TmpPath;
if (!Directory.Exists (tmp_path)) {
Directory.CreateDirectory (tmp_path);
@ -623,7 +633,7 @@ namespace SparkleShare {
canonical_name = canonical_name.Replace ("%20", " ");
bool target_folder_exists = Directory.Exists (
Path.Combine (this.config.FoldersPath, canonical_name));
Path.Combine (Config.FoldersPath, canonical_name));
// Add a numbered suffix to the name if a folder with the same name
// already exists. Example: "Folder (2)"
@ -631,7 +641,7 @@ namespace SparkleShare {
while (target_folder_exists) {
suffix++;
target_folder_exists = Directory.Exists (
Path.Combine (this.config.FoldersPath, canonical_name + " (" + suffix + ")"));
Path.Combine (Config.FoldersPath, canonical_name + " (" + suffix + ")"));
}
string target_folder_name = canonical_name;
@ -639,7 +649,7 @@ namespace SparkleShare {
if (suffix > 1)
target_folder_name += " (" + suffix + ")";
string target_folder_path = Path.Combine (this.config.FoldersPath, target_folder_name);
string target_folder_path = Path.Combine (Config.FoldersPath, target_folder_name);
try {
Directory.Move (this.fetcher.TargetFolder, target_folder_path);
@ -663,11 +673,11 @@ namespace SparkleShare {
string backend = SparkleFetcherBase.GetBackend (this.fetcher.RemoteUrl.ToString ());
this.config.AddFolder (target_folder_name, this.fetcher.Identifier,
Config.AddFolder (target_folder_name, this.fetcher.Identifier,
this.fetcher.RemoteUrl.ToString (), backend);
if (this.fetcher.OriginalFetcherInfo.AnnouncementsUrl != null) {
this.config.SetFolderOptionalAttribute (target_folder_name, "announcements_url",
Config.SetFolderOptionalAttribute (target_folder_name, "announcements_url",
this.fetcher.OriginalFetcherInfo.AnnouncementsUrl);
}
@ -684,69 +694,6 @@ namespace SparkleShare {
}
public string GetAvatar (string email, int size)
{
ServicePointManager.ServerCertificateValidationCallback = GetAvatarValidationCallBack;
string fetch_avatars_option = this.config.GetConfigOption ("fetch_avatars");
if (fetch_avatars_option != null && fetch_avatars_option.Equals (bool.FalseString))
return null;
email = email.ToLower ();
if (this.skipped_avatars.Contains (email))
return null;
string avatars_path = new string [] { Path.GetDirectoryName (this.config.FullPath),
"avatars", size + "x" + size }.Combine ();
string avatar_file_path;
try {
avatar_file_path = Path.Combine (avatars_path, email.MD5 () + ".png");
} catch (InvalidOperationException e) {
SparkleLogger.LogInfo ("Controller", "Error fetching avatar for " + email, e);
return null;
}
if (File.Exists (avatar_file_path)) {
if (new FileInfo (avatar_file_path).CreationTime < DateTime.Now.AddDays (-1))
File.Delete (avatar_file_path);
else
return avatar_file_path;
}
WebClient client = new WebClient ();
string url = "https://gravatar.com/avatar/" + email.MD5 () + ".png?s=" + size + "&d=404";
try {
byte [] buffer = client.DownloadData (url);
if (buffer.Length > 255) {
if (!Directory.Exists (avatars_path)) {
Directory.CreateDirectory (avatars_path);
SparkleLogger.LogInfo ("Controller", "Created '" + avatars_path + "'");
}
File.WriteAllBytes (avatar_file_path, buffer);
SparkleLogger.LogInfo ("Controller", "Fetched " + size + "x" + size + " avatar for " + email);
return avatar_file_path;
} else {
return null;
}
} catch (Exception e) {
SparkleLogger.LogInfo ("Controller", "Error fetching avatar for " + email, e);
skipped_avatars.Add (email);
return null;
}
}
public virtual void Quit ()
{
foreach (SparkleRepoBase repo in Repositories)
@ -756,26 +703,6 @@ namespace SparkleShare {
}
private bool GetAvatarValidationCallBack (Object sender,
X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
X509Certificate2 certificate2 = new X509Certificate2 (certificate.GetRawCertData ());
// On some systems (mostly Linux) we can't assume the needed certificates are
// available, so we have to check the certificate's SHA-1 fingerprint manually.
//
// Obtained from https://www.gravatar.com/ on Aug 18 2012 and expires on Oct 24 2015.
string gravatar_cert_fingerprint = "217ACB08C0A1ACC23A21B6ECDE82CD45E14DEC19";
if (!certificate2.Thumbprint.Equals (gravatar_cert_fingerprint)) {
SparkleLogger.LogInfo ("Controller", "Invalid certificate for https://www.gravatar.com/");
return false;
}
return true;
}
private void ClearDirectoryAttributes (string path)
{
if (!Directory.Exists (path))

View file

@ -368,13 +368,13 @@ namespace SparkleShare {
if (count == 1)
continue;
string change_set_avatar = Program.Controller.GetAvatar (change_set.User.Email, 24);
if (change_set_avatar != null)
string change_set_avatar = "file://<!-- $pixmaps-path -->/user-icon-default.png";
if (Program.Controller.AvatarsEnabled) {
change_set_avatar = SparkleAvatars.GetAvatar (change_set.User.Email, 24, Program.Controller.Config.FullPath);
change_set_avatar = "file://" + change_set_avatar.Replace ("\\", "/");
else
change_set_avatar = "file://<!-- $pixmaps-path -->/user-icon-default.png";
}
html += "<tr>" +
"<td class='avatar'><img src='" + change_set_avatar + "'></td>" +
@ -472,12 +472,12 @@ namespace SparkleShare {
}
}
string change_set_avatar = Program.Controller.GetAvatar (change_set.User.Email, 48);
if (change_set_avatar != null)
change_set_avatar = "file://" + change_set_avatar.Replace ("\\", "/");
else
change_set_avatar = "file://<!-- $pixmaps-path -->/user-icon-default.png";
string change_set_avatar = "file://<!-- $pixmaps-path -->/user-icon-default.png";
if (Program.Controller.AvatarsEnabled) {
change_set_avatar = SparkleAvatars.GetAvatar (change_set.User.Email, 48, Program.Controller.Config.FullPath);
change_set_avatar = "file://" + change_set_avatar.Replace ("\\", "/");
}
event_entry += "</dl>";

View file

@ -79,6 +79,7 @@
<Compile Include="SparkleShortcut.cs" />
<Compile Include="SparkleUI.cs" />
<Compile Include="..\SparkleAboutController.cs" />
<Compile Include="..\SparkleAvatars.cs" />
<Compile Include="SparkleBubbles.cs" />
<Compile Include="SparkleAbout.cs" />
<Compile Include="SparkleController.cs" />
@ -258,4 +259,4 @@
<ItemGroup>
<Content Include="Pixmaps\sparkleshare-folder.ico" />
</ItemGroup>
</Project>
</Project>