f-spot r4357 - in trunk: . extensions extensions/TabbloExport extensions/TabbloExport/Tabblo
- From: lmilesi svn gnome org
- To: svn-commits-list gnome org
- Subject: f-spot r4357 - in trunk: . extensions extensions/TabbloExport extensions/TabbloExport/Tabblo
- Date: Tue, 16 Sep 2008 09:18:33 +0000 (UTC)
Author: lmilesi
Date: Tue Sep 16 09:18:33 2008
New Revision: 4357
URL: http://svn.gnome.org/viewvc/f-spot?rev=4357&view=rev
Log:
2008-09-16 Lorenzo Milesi <maxxer yetopen it>
* TabbloExport/*: Tabblo.com export extension by Wojciech
DzierÅanowski. Fix bgo#382658.
Added:
trunk/extensions/TabbloExport/
trunk/extensions/TabbloExport/ApplicationCentricCertificatePolicy.cs
trunk/extensions/TabbloExport/AssemblyInfo.cs
trunk/extensions/TabbloExport/BlindTrustCertificatePolicy.cs
trunk/extensions/TabbloExport/FSpotUploadProgress.cs
trunk/extensions/TabbloExport/Makefile.am
trunk/extensions/TabbloExport/Preferences.cs
trunk/extensions/TabbloExport/Tabblo/
trunk/extensions/TabbloExport/Tabblo/AssemblyInfo.cs
trunk/extensions/TabbloExport/Tabblo/Connection.cs
trunk/extensions/TabbloExport/Tabblo/IPreferences.cs
trunk/extensions/TabbloExport/Tabblo/Makefile.am
trunk/extensions/TabbloExport/Tabblo/MultipartRequest.cs
trunk/extensions/TabbloExport/Tabblo/Picture.cs
trunk/extensions/TabbloExport/Tabblo/TabbloException.cs
trunk/extensions/TabbloExport/Tabblo/TotalUploadProgress.cs
trunk/extensions/TabbloExport/Tabblo/UploadProgressEventArgs.cs
trunk/extensions/TabbloExport/Tabblo/UploadProgressEventHandler.cs
trunk/extensions/TabbloExport/TabbloExport.addin.xml
trunk/extensions/TabbloExport/TabbloExport.cs
trunk/extensions/TabbloExport/TabbloExport.glade
trunk/extensions/TabbloExport/TrustError.glade
trunk/extensions/TabbloExport/UserDecisionCertificatePolicy.cs
Modified:
trunk/configure.in
trunk/extensions/ChangeLog
trunk/extensions/Makefile.am
Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in (original)
+++ trunk/configure.in Tue Sep 16 09:18:33 2008
@@ -368,6 +368,8 @@
extensions/SmugMugExport/SmugMugNet/Makefile
extensions/SmugMugExport/Makefile
extensions/MergeDb/Makefile
+extensions/TabbloExport/Makefile
+extensions/TabbloExport/Tabblo/Makefile
extensions/PicasaWebExport/Makefile
extensions/PicasaWebExport/google-sharp/Makefile
f-spot.pc
Modified: trunk/extensions/Makefile.am
==============================================================================
--- trunk/extensions/Makefile.am (original)
+++ trunk/extensions/Makefile.am Tue Sep 16 09:18:33 2008
@@ -8,6 +8,7 @@
FolderExport \
MergeDb \
PicasaWebExport \
+ TabbloExport \
SmugMugExport
addinsdir = $(pkglibdir)
Added: trunk/extensions/TabbloExport/ApplicationCentricCertificatePolicy.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/ApplicationCentricCertificatePolicy.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,165 @@
+//
+// FSpotTabbloExport.ApplicationCentricCertificatePolicy
+//
+// Authors:
+// Wojciech Dzierzanowski (wojciech dzierzanowski gmail com)
+//
+// (C) Copyright 2008 Wojciech Dzierzanowski
+//
+
+// 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.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.IO.IsolatedStorage;
+using System.Net;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Security.Cryptography.X509Certificates;
+
+using FSpot.Utils;
+
+namespace FSpotTabbloExport {
+
+ class ApplicationCentricCertificatePolicy : ICertificatePolicy {
+
+ protected enum Decision {
+ DontTrust,
+ TrustOnce,
+ TrustAlways
+ };
+
+ private Dictionary<string, int> cert_hashes;
+
+ private static readonly IsolatedStorageFile isolated_store =
+ IsolatedStorageFile.GetUserStoreForAssembly ();
+
+ private const string StoreName = "cert_hashes";
+
+
+ public bool CheckValidationResult (ServicePoint service_point,
+ X509Certificate certificate,
+ WebRequest request,
+ int problem)
+ {
+ Log.DebugFormat ("Checking validation result for {0}: problem={1}", request.RequestUri, problem);
+
+ if (0 == problem) {
+ return true;
+ }
+
+ // Only try to deal with the problem if it is a trust
+ // failure.
+ if (-2146762486 != problem) {
+ return false;
+ }
+
+ LoadCertificates ();
+
+ string hash = certificate.GetCertHashString ();
+ Log.DebugFormat ("Certificate hash: " + hash);
+
+ int stored_problem = 0;
+ if (cert_hashes.TryGetValue (hash, out stored_problem)
+ && problem == stored_problem) {
+ Log.DebugFormat ("We already trust this site");
+ return true;
+ }
+
+ Decision decision = GetDecision (certificate, request);
+ Log.DebugFormat ("Decision: " + decision);
+
+ switch (decision) {
+ case Decision.DontTrust:
+ return false;
+ case Decision.TrustOnce:
+ return true;
+ case Decision.TrustAlways:
+ SaveCertificate (hash, problem);
+ return true;
+ default:
+ Debug.Assert (false, "Unknown decision");
+ return false;
+ }
+ }
+
+
+ protected virtual Decision GetDecision (
+ X509Certificate certificate,
+ WebRequest request)
+ {
+ Decision decision = Decision.DontTrust;
+ Log.DebugFormat ("Making the default decision: " + decision);
+ return decision;
+ }
+
+
+ private void LoadCertificates ()
+ {
+ using (IsolatedStorageFileStream isol_stream =
+ new IsolatedStorageFileStream (
+ StoreName,
+ FileMode.OpenOrCreate,
+ FileAccess.Read,
+ isolated_store)) {
+ try {
+ BinaryFormatter formatter =
+ new BinaryFormatter ();
+ cert_hashes = (Dictionary<string, int>)
+ formatter.Deserialize (
+ isol_stream);
+ } catch (SerializationException e) {
+ // FIXME: handle
+ Log.Exception (e);
+ }
+ }
+
+ if (null == cert_hashes) {
+ cert_hashes = new Dictionary<string,int> ();
+ }
+ }
+
+
+ private void SaveCertificate (string hash, int problem)
+ {
+ cert_hashes.Add (hash, problem);
+
+ using (IsolatedStorageFileStream isolated_stream =
+ new IsolatedStorageFileStream (
+ StoreName,
+ FileMode.OpenOrCreate,
+ FileAccess.Write,
+ isolated_store)) {
+ try {
+ BinaryFormatter formatter =
+ new BinaryFormatter ();
+ formatter.Serialize (isolated_stream,
+ cert_hashes);
+ } catch (SerializationException e) {
+ // FIXME: handle
+ Log.Exception (e);
+ }
+ }
+ }
+ }
+}
Added: trunk/extensions/TabbloExport/AssemblyInfo.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/AssemblyInfo.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,32 @@
+#region Using directives
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+#endregion
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle ("TabbloExport")]
+[assembly: AssemblyDescription ("TabbloExport is an F-Spot extension "
+ + "adding support for uploading images to Tabblo.")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("TabbloExport")]
+[assembly: AssemblyCopyright ("")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+
+// This sets the default COM visibility of types in the assembly to invisible.
+// If you need to expose a type to COM, use [ComVisible(true)] on that type.
+[assembly: ComVisible (false)]
+
+// The assembly version has following format :
+//
+// Major.Minor.Build.Revision
+//
+// You can specify all the values or you can use the default the Revision and
+// Build Numbers by using the '*' as shown below:
+[assembly: AssemblyVersion ("0.1.*")]
Added: trunk/extensions/TabbloExport/BlindTrustCertificatePolicy.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/BlindTrustCertificatePolicy.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,46 @@
+//
+// FSpotTabbloExport.BlindTrustCertificatePolicy
+//
+// Authors:
+// Wojciech Dzierzanowski (wojciech dzierzanowski gmail com)
+//
+// (C) Copyright 2008 Wojciech Dzierzanowski
+//
+
+// 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.Net;
+using System.Security.Cryptography.X509Certificates;
+
+using FSpot.Utils;
+
+namespace FSpotTabbloExport {
+ class BlindTrustCertificatePolicy : ICertificatePolicy {
+ public bool CheckValidationResult (ServicePoint service_point,
+ X509Certificate certificate,
+ WebRequest request,
+ int problem)
+ {
+ Log.DebugFormat ("Blindly trusting " + request.RequestUri);
+ return true;
+ }
+ }
+}
Added: trunk/extensions/TabbloExport/FSpotUploadProgress.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/FSpotUploadProgress.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,64 @@
+//
+// FSpotTabbloExport.FSpotUploadProgress
+//
+// Authors:
+// Wojciech Dzierzanowski (wojciech dzierzanowski gmail com)
+//
+// (C) Copyright 2008 Wojciech Dzierzanowski
+//
+
+// 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 Mono.Tabblo;
+using Mono.Unix;
+using System;
+
+namespace FSpotTabbloExport {
+
+ class FSpotUploadProgress : TotalUploadProgress {
+
+ private FSpot.ThreadProgressDialog progress_dialog;
+
+
+ internal FSpotUploadProgress (
+ Picture [] pictures,
+ FSpot.ThreadProgressDialog progress_dialog)
+ : base (pictures)
+ {
+ this.progress_dialog = progress_dialog;
+ }
+
+
+ protected override void ShowProgress (string title,
+ long bytes_sent)
+ {
+ progress_dialog.Message = title;
+ progress_dialog.ProgressText = String.Format (
+ Catalog.GetString (
+ "{0} of approx. {1}"),
+ SizeUtil.ToHumanReadable (bytes_sent),
+ SizeUtil.ToHumanReadable (
+ (long) TotalFileSize));
+ progress_dialog.Fraction =
+ (double) bytes_sent / TotalFileSize;
+ }
+ }
+}
Added: trunk/extensions/TabbloExport/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/Makefile.am Tue Sep 16 09:18:33 2008
@@ -0,0 +1,63 @@
+include $(top_srcdir)/Makefile.include
+
+PLUGIN_NAME = TabbloExport
+
+PLUGIN_MANIFEST = $(PLUGIN_NAME).addin.xml
+
+PLUGIN_ASSEMBLY = $(PLUGIN_NAME).dll
+
+PLUGIN_SOURCES = \
+ $(srcdir)/ApplicationCentricCertificatePolicy.cs \
+ $(srcdir)/AssemblyInfo.cs \
+ $(srcdir)/BlindTrustCertificatePolicy.cs \
+ $(srcdir)/FSpotUploadProgress.cs \
+ $(srcdir)/Preferences.cs \
+ $(srcdir)/TabbloExport.cs \
+ $(srcdir)/UserDecisionCertificatePolicy.cs
+
+
+REFS = \
+ -r:Tabblo/Mono.Tabblo.dll \
+ $(LINK_KEYRING) \
+ -r:Mono.Posix.dll
+
+PKGS = \
+ -pkg:f-spot \
+ -pkg:gtk-sharp-2.0 \
+ -pkg:glade-sharp-2.0 \
+ -pkg:gnome-vfs-sharp-2.0
+
+SUBDIRS = \
+ Tabblo
+
+RESOURCES = \
+ -resource:$(srcdir)/$(PLUGIN_MANIFEST) \
+ -resource:$(srcdir)/$(PLUGIN_NAME).glade \
+ -resource:$(srcdir)/TrustError.glade
+
+all: $(PLUGIN_ASSEMBLY)
+
+mpack: $(PLUGIN_ASSEMBLY)
+ mautil p $(PLUGIN_ASSEMBLY)
+
+$(PLUGIN_ASSEMBLY): $(PLUGIN_SOURCES) $(PLUGIN_MANIFEST)
+ $(MAKE) -C $(SUBDIRS)
+ $(CSC_LIB) -out:$@ $(PLUGIN_SOURCES) $(REFS) $(PKGS) $(ASSEMBLIES) $(RESOURCES)
+
+plugindir = $(pkglibdir)/extensions
+
+install-data-hook:
+ rm -f $(plugindir)/$(PLUGIN_NAME).addin.xml
+
+plugin_DATA = \
+ $(PLUGIN_ASSEMBLY)
+
+EXTRA_DIST = \
+ $(PLUGIN_SOURCES) \
+ $(PLUGIN_MANIFEST) \
+ $(PLUGIN_NAME).glade
+
+CLEANFILES = \
+ $(PLUGIN_ASSEMBLY) \
+ $(PLUGIN_ASSEMBLY).mdb \
+ *.mpack
Added: trunk/extensions/TabbloExport/Preferences.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/Preferences.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,63 @@
+//
+// FSpotTabbloExport.Preferences
+//
+// Authors:
+// Wojciech Dzierzanowski (wojciech dzierzanowski gmail com)
+//
+// (C) Copyright 2008 Wojciech Dzierzanowski
+//
+
+// 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;
+
+namespace FSpotTabbloExport {
+
+ class Preferences : Mono.Tabblo.IPreferences {
+
+ private string username;
+ private string password;
+
+ public string Username {
+ get {
+ return username;
+ }
+ }
+ public string Password {
+ get {
+ return password;
+ }
+ }
+ public string Privacy {
+ get {
+ return "circle";
+ }
+ }
+
+ internal void SetUsername (string username) {
+ this.username = username;
+ }
+
+ internal void SetPassword (string password) {
+ this.password = password;
+ }
+ }
+}
Added: trunk/extensions/TabbloExport/Tabblo/AssemblyInfo.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/Tabblo/AssemblyInfo.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,32 @@
+#region Using directives
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+#endregion
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle ("Mono.Tabblo")]
+[assembly: AssemblyDescription ("A library implementing photo upload to Tabblo"
+ + " over HTTP")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("Mono.Tabblo")]
+[assembly: AssemblyCopyright ("")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+
+// This sets the default COM visibility of types in the assembly to invisible.
+// If you need to expose a type to COM, use [ComVisible(true)] on that type.
+[assembly: ComVisible (false)]
+
+// The assembly version has following format :
+//
+// Major.Minor.Build.Revision
+//
+// You can specify all the values or you can use the default the Revision and
+// Build Numbers by using the '*' as shown below:
+[assembly: AssemblyVersion ("0.1.*")]
Added: trunk/extensions/TabbloExport/Tabblo/Connection.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/Tabblo/Connection.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,464 @@
+//
+// Mono.Tabblo.Connection
+//
+// Authors:
+// Wojciech Dzierzanowski (wojciech dzierzanowski gmail com)
+//
+// (C) Copyright 2008 Wojciech Dzierzanowski
+//
+
+// 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 Mono.Unix;
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Net;
+using System.Text;
+
+using FSpot.Utils;
+
+namespace Mono.Tabblo {
+
+ public class Connection {
+
+ private const string LoginUrl =
+ "https://store.tabblo.com:443/studio/authtoken";
+ private const string AuthorizeUrl = "https://store.tabblo.com"
+ + ":443/studio/upload/getposturl";
+ private const string RedirUrl = "http://www.tabblo.com/studio"
+ + "/token/{0}/?url=/studio"
+ + "/report_upload_session";
+
+ private readonly IPreferences preferences;
+
+ private string auth_token = null;
+ private string session_upload_url = null;
+
+ private CookieCollection cookies;
+
+
+ public Connection (IPreferences preferences)
+ {
+ if (null == preferences) {
+ throw new ArgumentNullException ("preferences");
+ }
+ this.preferences = preferences;
+ this.cookies = new CookieCollection ();
+ }
+
+
+ public void UploadFile (string name, Stream data_stream,
+ string mime_type, string [,] arguments)
+ {
+ if (!IsAuthenticated ()) {
+ Login ();
+ }
+
+ Log.DebugFormat ("Uploading " + mime_type + " file " + name);
+ DoUploadFile (name, data_stream, mime_type, arguments);
+ }
+
+
+ private void DoUploadFile (string name, Stream data_stream,
+ string mime_type,
+ string [,] arguments)
+ {
+ string upload_url = GetUploadUrl (arguments);
+ HttpWebRequest http_request = CreateHttpRequest (
+ upload_url, "POST", true);
+ MultipartRequest request =
+ new MultipartRequest (http_request);
+
+ MemoryStream mem_stream = null;
+ if (null != UploadProgressHandler) {
+ // "Manual buffering" using a MemoryStream.
+ request.Request.AllowWriteStreamBuffering =
+ false;
+ mem_stream = new MemoryStream ();
+ request.OutputStream = mem_stream;
+ }
+
+ request.BeginPart (true);
+ request.AddHeader ("Content-Disposition",
+ "form-data; name=\"filename0\"; "
+ + "filename=\"" + name
+ + '"',
+ false);
+ request.AddHeader ("Content-Type", mime_type, true);
+
+ byte [] data_buffer = new byte [8192];
+ int read_count;
+ while ((read_count = data_stream.Read (
+ data_buffer, 0, data_buffer.Length))
+ > 0) {
+ request.WritePartialContent (
+ data_buffer, 0, read_count);
+ }
+ request.EndPartialContent ();
+ request.EndPart (true);
+
+ if (null != UploadProgressHandler) {
+
+ int total = (int) request.OutputStream.Length;
+ request.Request.ContentLength = total;
+
+ string progress_title = String.Format (
+ Catalog.GetString ("Uploading "
+ + "photo "
+ + "\"{0}\""),
+ name);
+
+ using (Stream request_stream = request.Request
+ .GetRequestStream ()) {
+ byte [] buffer =
+ mem_stream.GetBuffer ();
+ int write_count = 0;
+ for (int offset = 0; offset < total;
+ offset += write_count) {
+ FireUploadProgress (
+ progress_title,
+ offset, total);
+ write_count = System.Math.Min (
+ 16384,
+ total - offset);
+ request_stream.Write (buffer,
+ offset,
+ write_count);
+ }
+ FireUploadProgress (progress_title,
+ total, total);
+ }
+ }
+
+ SendRequest ("upload", request.Request, true);
+ }
+
+
+ public event UploadProgressEventHandler UploadProgressHandler;
+
+ private void FireUploadProgress (string title, int sent,
+ int total)
+ {
+ if (null != UploadProgressHandler) {
+ UploadProgressEventArgs args =
+ new UploadProgressEventArgs (
+ title, sent,
+ total);
+ UploadProgressHandler (this, args);
+ }
+ }
+
+
+ private bool IsAuthenticated ()
+ {
+ return null != auth_token;
+ }
+
+
+ private void Login ()
+ {
+ FireUploadProgress (Catalog.GetString (
+ "Logging into Tabblo"),
+ 0, 0);
+
+ auth_token = null;
+
+ HttpWebRequest request = CreateHttpRequest (
+ LoginUrl, "POST");
+ request.ContentType =
+ "application/x-www-form-urlencoded";
+
+ string [,] arguments = {
+ {"username", preferences.Username},
+ {"password", preferences.Password}
+ };
+
+ try {
+ WriteRequestContent (request,
+ FormatRequestArguments (
+ arguments));
+ string response = SendRequest (
+ "login", request);
+ if ("BAD".Equals (response)) {
+ Log.DebugFormat ("Invalid username or password");
+ throw new TabbloException (
+ "Login failed: Invalid username"
+ + " or password");
+ }
+
+ auth_token = response;
+
+ } catch (TabbloException e) {
+ // Here's us trying to produce a more
+ // descriptive message when we have... trust
+ // issues. This doesn't work, though, at least
+ // as long as Mono bug #346635 is not fixed.
+ //
+ // TODO: When it _starts_ to work, we should
+ // think about doing the same for
+ // `GetUploadUrl()'.
+ WebException we = e.InnerException
+ as WebException;
+ if (null != we)
+ Log.DebugFormat ("Caught a WebException, status=" + we.Status);
+ if (null != we
+ && WebExceptionStatus.TrustFailure
+ == we.Status) {
+ throw new TabbloException (
+ "Trust failure", we);
+ }
+ throw;
+ }
+
+ if (null != auth_token)
+ Log.DebugFormat ("Login successful. Token: " + auth_token);
+ }
+
+
+ private string GetUploadUrl (string [,] arguments)
+ {
+ FireUploadProgress (Catalog.GetString (
+ "Obtaining URL for upload"),
+ 0, 0);
+
+ if (! IsAuthenticated ())
+ Log.DebugFormat ("Not authenticated");
+
+ if (null == session_upload_url) {
+
+ string [,] auth_arguments =
+ { {"auth_token", auth_token} };
+ string url = AuthorizeUrl + "/?"
+ + FormatRequestArguments (
+ auth_arguments);
+
+ HttpWebRequest request =
+ CreateHttpRequest (url, "GET");
+
+ string response = SendRequest (
+ "getposturl", request);
+
+ if (response.StartsWith ("@")) {
+ session_upload_url =
+ response.Substring (1);
+ } else {
+ throw new TabbloException (
+ "Session upload URL "
+ + "retrieval failed");
+ }
+ }
+
+ string upload_url = session_upload_url;
+ upload_url += "&redir=" + String.Format (
+ RedirUrl, auth_token);
+ if (null != arguments && arguments.GetLength (0) > 0) {
+ upload_url += '&' + FormatRequestArguments (
+ arguments);
+ }
+
+ Log.DebugFormat ("Upload URL: " + upload_url);
+ return upload_url;
+ }
+
+
+ private HttpWebRequest CreateHttpRequest (string url,
+ string method)
+ {
+ return CreateHttpRequest (url, method, false);
+ }
+
+ private HttpWebRequest CreateHttpRequest (string url,
+ string method,
+ bool with_cookies)
+ {
+ HttpWebRequest request = (HttpWebRequest)
+ WebRequest.Create (url);
+ // For some reason, POST requests are _really_ slow with
+ // HTTP 1.1.
+ request.ProtocolVersion = HttpVersion.Version10;
+ request.Method = method;
+ if (with_cookies) {
+ HandleRequestCookies (request);
+ }
+ return request;
+ }
+
+
+ private void HandleRequestCookies (HttpWebRequest request)
+ {
+ request.CookieContainer = new CookieContainer ();
+ // Instead of just doing a
+ // `request.CookieContainer.Add(cookies)', add cookies
+ // mannually to work around the fact that some cookies
+ // are not properly formatted as they are received from
+ // the server.
+ foreach (Cookie c in cookies) {
+ Cookie new_cookie = new Cookie (c.Name, c.Value,
+ "/", ".tabblo.com");
+ request.CookieContainer.Add (new_cookie);
+ }
+
+ string cookie_header = request.CookieContainer
+ .GetCookieHeader (request.RequestUri);
+ if (cookie_header.Length > 0)
+ Log.DebugFormat ("Cookie: " + cookie_header);
+ }
+
+
+ private static void WriteRequestContent (HttpWebRequest request,
+ string content)
+ {
+ byte [] content_bytes =
+ Encoding.UTF8.GetBytes (content);
+
+ request.ContentLength = content_bytes.Length;
+
+ try {
+ using (Stream request_stream =
+ request.GetRequestStream ()) {
+ request_stream.Write (content_bytes, 0,
+ content_bytes.Length);
+ }
+ } catch (WebException e) {
+ Log.Exception (e);
+ throw new TabbloException (
+ "HTTP request failure: "
+ + e.Message,
+ e);
+ }
+
+ char [] content_chars = new char [content_bytes.Length];
+ content_bytes.CopyTo (content_chars, 0);
+ Log.DebugFormat ("Request content: " + new string (content_chars));
+ }
+
+
+ private static string FormatRequestArguments (
+ string [,] arguments)
+ {
+ StringBuilder content = new StringBuilder ();
+
+ for (int i = 0; i < arguments.GetLength (0); ++i) {
+ content.AppendFormat( "{0}={1}&",
+ arguments [i, 0],
+ arguments [i, 1]);
+ }
+
+ if (content.Length > 0) {
+ content.Remove (content.Length - 1, 1);
+ }
+
+ byte [] content_bytes = Encoding.UTF8.GetBytes (
+ content.ToString ());
+ char [] content_chars = new char [content_bytes.Length];
+ content_bytes.CopyTo (content_chars, 0);
+
+ return new string (content_chars);
+ }
+
+
+ private string SendRequest (string description,
+ HttpWebRequest request)
+ {
+ return SendRequest (description, request, false);
+ }
+
+ /// <summary>
+ /// Sends an HTTP request.
+ /// </summary>
+ /// <param name="description"></param>
+ /// <param name="request"></param>
+ /// <returns>the HTTP response as string</returns>
+ private string SendRequest (string description,
+ HttpWebRequest request,
+ bool keep_cookies)
+ {
+ Log.DebugFormat ("Sending " + description + ' ' + request.Method + " request to " + request.Address);
+
+ HttpWebResponse response = null;
+ try {
+ response = (HttpWebResponse)
+ request.GetResponse ();
+ if (keep_cookies) {
+ cookies.Add (response.Cookies);
+ Log.DebugFormat (response.Cookies.Count + " cookie(s)");
+ foreach (Cookie c in response.Cookies) {
+ Log.DebugFormat ("Set-Cookie: " + c.Name + '=' + c.Value + "; Domain=" + c.Domain + "; expires=" + c.Expires);
+ }
+ }
+ return GetResponseAsString (response);
+ } catch (WebException e) {
+ Log.Exception (e);
+ HttpWebResponse error_response =
+ e.Response as HttpWebResponse;
+ string response_string = null != error_response
+ ? GetResponseAsString (
+ error_response)
+ : "reason unknown";
+ throw new TabbloException (description
+ + " failed: "
+ + response_string,
+ e);
+ } finally {
+ if (null != response) {
+ response.Close ();
+ }
+ }
+ }
+
+
+ private static string GetResponseAsString (HttpWebResponse response)
+ {
+ Log.DebugFormat ("Response: ");
+
+ Encoding encoding = Encoding.UTF8;
+ if (response.ContentEncoding.Length > 0) {
+ try {
+ encoding = Encoding.GetEncoding (
+ response
+ .ContentEncoding);
+ } catch (ArgumentException) {
+ // Swallow invalid encoding exception
+ // and use the default one.
+ }
+ }
+
+ string response_string = null;
+
+ using (Stream stream = response.GetResponseStream ()) {
+ StreamReader reader = new StreamReader (
+ stream, encoding);
+ response_string = reader.ReadToEnd ();
+ stream.Close ();
+ }
+
+ if (null != response_string)
+ try {
+ Log.DebugFormat (response_string);
+ } catch (System.FormatException e) {
+ Log.DebugFormat ("Unable to print respose string: not in correct format");
+ }
+ return response_string;
+ }
+ }
+}
Added: trunk/extensions/TabbloExport/Tabblo/IPreferences.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/Tabblo/IPreferences.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,50 @@
+//
+// Mono.Tabblo.IPreferences
+//
+// Authors:
+// Wojciech Dzierzanowski (wojciech dzierzanowski gmail com)
+//
+// (C) Copyright 2008 Wojciech Dzierzanowski
+//
+
+// 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;
+
+namespace Mono.Tabblo {
+
+ /// <summary>
+ /// Interface for a set of Tabblo user preferences.
+ /// </summary>
+ public interface IPreferences {
+ string Username {
+ get;
+ }
+ string Password {
+ get;
+ }
+ // FIXME: It _should_ be possible to set a photo's privacy when
+ // uploading, but that's not implemented yet.
+ string Privacy {
+ get;
+ }
+ }
+}
Added: trunk/extensions/TabbloExport/Tabblo/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/Tabblo/Makefile.am Tue Sep 16 09:18:33 2008
@@ -0,0 +1,38 @@
+include $(top_srcdir)/Makefile.include
+
+ASSEMBLY_NAME = Mono.Tabblo
+
+ASSEMBLY_SOURCES = \
+ $(srcdir)/AssemblyInfo.cs \
+ $(srcdir)/Connection.cs \
+ $(srcdir)/IPreferences.cs \
+ $(srcdir)/MultipartRequest.cs \
+ $(srcdir)/Picture.cs \
+ $(srcdir)/TabbloException.cs \
+ $(srcdir)/TotalUploadProgress.cs \
+ $(srcdir)/UploadProgressEventArgs.cs \
+ $(srcdir)/UploadProgressEventHandler.cs
+
+REFS = \
+ -r:Mono.Posix.dll
+
+PKGS = \
+ -pkg:f-spot
+
+ASSEMBLY = $(ASSEMBLY_NAME).dll
+
+all: $(ASSEMBLY)
+
+$(ASSEMBLY): $(ASSEMBLY_SOURCES)
+ $(CSC_LIB) -out:$@ $(PKGS) $(REFS) $(ASSEMBLY_SOURCES)
+
+assemblydir = $(pkglibdir)
+assembly_DATA = $(ASSEMBLY)
+
+EXTRA_DIST = \
+ $(ASSEMBLY_SOURCES) \
+ License.txt
+
+CLEANFILES = \
+ $(ASSEMBLY) \
+ $(ASSEMBLY).mdb
Added: trunk/extensions/TabbloExport/Tabblo/MultipartRequest.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/Tabblo/MultipartRequest.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,223 @@
+//
+// Mono.Tabblo.MultipartRequest
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo ximian com)
+// Stephane Delcroix (stephane delcroix org)
+// Wojciech Dzierzanowski (wojciech dzierzanowski gmail com)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+// (C) Copyright 2007 S. Delcroix
+// (C) Copyright 2008 Wojciech Dzierzanowski
+//
+
+// 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.Collections;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Net;
+using System.Text;
+
+using FSpot.Utils;
+
+namespace Mono.Tabblo {
+
+ class MultipartRequest {
+
+ private const string VerboseSymbol =
+ "FSPOT_TABBLO_EXPORT_VERBOSE";
+
+ private static readonly byte [] CRLF = { 13, 10 };
+
+ private const string SeparatorString = "PART_SEPARATOR";
+ private const string Separator =
+ "--" + SeparatorString + "\r\n";
+ private const string SeparatorEnd =
+ "--" + SeparatorString + "--\r\n";
+
+ private static readonly byte [] SeparatorBytes =
+ Encoding.ASCII.GetBytes (Separator);
+ private static readonly byte [] SeparatorEndBytes =
+ Encoding.ASCII.GetBytes (SeparatorEnd);
+
+ private HttpWebRequest request;
+ private Stream output_stream;
+
+ bool output_set;
+
+
+ public MultipartRequest (HttpWebRequest http_request)
+ {
+ request = http_request;
+ request.ContentType = "multipart/form-data; boundary="
+ + SeparatorString;
+ }
+
+
+ public HttpWebRequest Request {
+ get {
+ return request;
+ }
+ }
+
+ public Stream OutputStream {
+ get {
+ return output_stream;
+ }
+ set {
+ output_set = true;
+ output_stream = value;
+ }
+ }
+
+
+ public void BeginPart ()
+ {
+ BeginPart (false);
+ }
+
+ public void BeginPart (bool first)
+ {
+ if (!first) {
+ return;
+ }
+
+ LogBeginPart ();
+ InitContent ();
+ AppendContent (SeparatorBytes, 0,
+ SeparatorBytes.Length);
+ }
+
+
+ public void AddHeader (string name, string val)
+ {
+ AddHeader (name, val, false);
+ }
+
+ public void AddHeader (string name, string val, bool last)
+ {
+ AddHeader (String.Format ("{0}: {1}", name, val), last);
+ }
+
+ public void AddHeader (string header)
+ {
+ AddHeader (header, false);
+ }
+
+ public void AddHeader (string header, bool last)
+ {
+ bool need_crlf = !header.EndsWith ("\r\n");
+ byte [] bytes = Encoding.UTF8.GetBytes (header);
+ AppendContent (bytes, 0, bytes.Length);
+ if (need_crlf) {
+ AppendContent (CRLF, 0, CRLF.Length);
+ }
+ if (last) {
+ AppendContent (CRLF, 0, CRLF.Length);
+ }
+ }
+
+
+ public void WriteContent (string content)
+ {
+ WriteContent (Encoding.UTF8.GetBytes (content));
+ }
+
+ public void WriteContent (byte [] content)
+ {
+ AppendContent (content, 0, content.Length);
+ AppendContent (CRLF, 0, CRLF.Length);
+ }
+
+ public void WritePartialContent (byte [] content, int offset,
+ int nbytes)
+ {
+ AppendContent (content, offset, nbytes);
+ }
+
+
+ public void EndPartialContent ()
+ {
+ AppendContent (CRLF, 0, CRLF.Length);
+ }
+
+ public void EndPart (bool last)
+ {
+ if (last) {
+ LogEndPart ();
+ AppendContent (SeparatorEndBytes, 0,
+ SeparatorEndBytes.Length);
+ CloseContent ();
+ } else {
+ AppendContent (SeparatorBytes, 0,
+ SeparatorBytes.Length);
+ }
+ }
+
+
+ private void InitContent ()
+ {
+ if (output_stream == null) {
+ output_stream = request.GetRequestStream ();
+ }
+ }
+
+ private void CloseContent ()
+ {
+ if (!output_set) {
+ output_stream.Close ();
+ }
+ }
+
+ private void AppendContent (byte [] content, int offset,
+ int length)
+ {
+ LogContent (content, offset, length);
+ output_stream.Write (content, offset, length);
+ }
+
+
+
+ [Conditional (VerboseSymbol)]
+ private static void LogBeginPart ()
+ {
+ Log.DebugFormat (">>>START MultipartRequest content");
+ }
+
+ [Conditional (VerboseSymbol)]
+ private static void LogEndPart ()
+ {
+ Log.DebugFormat ("<<<END MultipartRequest content");
+ }
+
+ [Conditional (VerboseSymbol)]
+ private static void LogContent (byte [] content, int offset,
+ int length)
+ {
+ char [] content_chars = new char [length];
+ Array.Copy (content, offset, content_chars, 0, length);
+ Log.DebugFormat (new string (content_chars));
+ }
+ }
+}
Added: trunk/extensions/TabbloExport/Tabblo/Picture.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/Tabblo/Picture.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,100 @@
+//
+// Mono.Tabblo.Picture
+//
+// Authors:
+// Wojciech Dzierzanowski (wojciech dzierzanowski gmail com)
+//
+// (C) Copyright 2008 Wojciech Dzierzanowski
+//
+
+// 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.IO;
+
+namespace Mono.Tabblo {
+
+ public class Picture {
+
+ private readonly string name;
+ private readonly Uri uri;
+ private readonly string mime_type;
+ private readonly string privacy;
+
+
+ public string Name {
+ get {
+ return name;
+ }
+ }
+ public Uri Uri {
+ get {
+ return uri;
+ }
+ }
+ public string MimeType {
+ get {
+ return mime_type;
+ }
+ }
+ public string Privacy {
+ get {
+ return privacy;
+ }
+ }
+
+
+ public Picture (string name, Uri uri, string mime_type,
+ string privacy)
+ {
+ if (null == name) {
+ throw new ArgumentNullException ("name");
+ }
+ if (null == uri) {
+ throw new ArgumentNullException ("uri");
+ }
+ if (null == mime_type) {
+ throw new ArgumentNullException ("mime_type");
+ }
+ if (null == privacy) {
+ throw new ArgumentNullException ("privacy");
+ }
+ this.name = name;
+ this.uri = uri;
+ this.mime_type = mime_type;
+ this.privacy = privacy;
+ }
+
+
+ public void Upload (Connection connection)
+ {
+ if (null == connection) {
+ throw new ArgumentNullException ("connection");
+ }
+
+ using (Stream data_stream =
+ File.OpenRead (Uri.LocalPath)) {
+ connection.UploadFile (Name, data_stream,
+ MimeType, null);
+ }
+ }
+ }
+}
Added: trunk/extensions/TabbloExport/Tabblo/TabbloException.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/Tabblo/TabbloException.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,53 @@
+//
+// Mono.Tabblo.TabbloException
+//
+// Authors:
+// Wojciech Dzierzanowski (wojciech dzierzanowski gmail com)
+//
+// (C) Copyright 2008 Wojciech Dzierzanowski
+//
+
+// 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;
+
+namespace Mono.Tabblo {
+
+ public class TabbloException : ApplicationException {
+
+ public TabbloException ()
+ {
+ }
+
+ public TabbloException (string message) : base (message)
+ {
+ }
+
+ public TabbloException (Exception cause) : base ("", cause)
+ {
+ }
+
+ public TabbloException (string message, Exception cause)
+ : base (message, cause)
+ {
+ }
+ }
+}
Added: trunk/extensions/TabbloExport/Tabblo/TotalUploadProgress.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/Tabblo/TotalUploadProgress.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,114 @@
+//
+// Mono.Tabblo.TotalUploadProgress
+//
+// Authors:
+// Wojciech Dzierzanowski (wojciech dzierzanowski gmail com)
+//
+// (C) Copyright 2008 Wojciech Dzierzanowski
+//
+
+// 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.IO;
+using System.Diagnostics;
+
+using FSpot.Utils;
+
+namespace Mono.Tabblo {
+
+ public class TotalUploadProgress {
+
+ private long prev_bytes_sent = 0;
+ private long bytes_sent_total = 0;
+
+ private int total_file_count;
+ private ulong total_file_size;
+
+
+ public TotalUploadProgress (Picture [] pictures)
+ {
+ if (null == pictures) Log.DebugFormat ("No pictures!");
+
+ total_file_count = pictures.Length;
+ total_file_size = GetTotalFileSize (pictures);
+ }
+
+
+ protected int TotalFileCount {
+ get {
+ return total_file_count;
+ }
+ }
+ protected ulong TotalFileSize {
+ get {
+ return total_file_size;
+ }
+ }
+
+
+ public void HandleProgress (object sender,
+ UploadProgressEventArgs args)
+ {
+ bytes_sent_total += args.BytesSent - prev_bytes_sent;
+ ShowProgress (args.Title, bytes_sent_total);
+
+ int percent = (int)
+ ((double) bytes_sent_total * 100
+ / TotalFileSize);
+ Log.DebugFormat ("{0}%...", percent);
+
+ if (args.BytesTotal == args.BytesSent) {
+ prev_bytes_sent = 0;
+ } else {
+ prev_bytes_sent = args.BytesSent;
+ }
+ }
+
+
+ /// <summary>
+ /// Overriden by subclasses to display upload progress.
+ /// </summary>
+ /// <remarks>
+ /// The default implementation does nothing.
+ /// </remarks>
+ protected virtual void ShowProgress (string title,
+ long bytes_sent)
+ {
+ }
+
+
+ private static ulong GetTotalFileSize (Picture [] pictures)
+ {
+ if (null == pictures) Log.DebugFormat ("No pictures!");
+
+ ulong size = 0;
+
+ foreach (Picture picture in pictures) {
+ FileInfo info = new FileInfo (
+ picture.Uri.LocalPath);
+ size += (ulong) info.Length;
+ }
+
+ return size;
+ }
+ }
+}
Added: trunk/extensions/TabbloExport/Tabblo/UploadProgressEventArgs.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/Tabblo/UploadProgressEventArgs.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,68 @@
+//
+// Mono.Tabblo.UploadProgressEventArgs
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo ximian com)
+// Wojciech Dzierzanowski (wojciech dzierzanowski gmail com)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+// (C) Copyright 2008 Wojciech Dzierzanowski
+//
+
+// 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;
+
+namespace Mono.Tabblo {
+
+ public sealed class UploadProgressEventArgs : EventArgs {
+
+ private readonly string title;
+ private readonly long bytes_sent;
+ private readonly long bytes_total;
+
+ internal UploadProgressEventArgs (string title, long bytes_sent,
+ long bytes_total)
+ {
+ this.title = title;
+ this.bytes_sent = bytes_sent;
+ this.bytes_total = bytes_total;
+ }
+
+ public string Title {
+ get {
+ return title;
+ }
+ }
+
+ public long BytesSent {
+ get {
+ return bytes_sent;
+ }
+ }
+
+ public long BytesTotal {
+ get {
+ return bytes_total;
+ }
+ }
+ }
+}
Added: trunk/extensions/TabbloExport/Tabblo/UploadProgressEventHandler.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/Tabblo/UploadProgressEventHandler.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,37 @@
+//
+// Mono.abblo.UploadProgressEventHandler
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo ximian com)
+// Wojciech Dzierzanowski (wojciech dzierzanowski gmail com)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+// (C) Copyright 2008 Wojciech Dzierzanowski
+//
+
+// 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.
+//
+
+namespace Mono.Tabblo {
+
+ public delegate void UploadProgressEventHandler (
+ object sender, UploadProgressEventArgs args);
+
+}
Added: trunk/extensions/TabbloExport/TabbloExport.addin.xml
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/TabbloExport.addin.xml Tue Sep 16 09:18:33 2008
@@ -0,0 +1,16 @@
+<Addin namespace="FSpot"
+ version="0.4.4.100"
+ name="Tabblo Export"
+ description="This extension allows you to export your photos to Tabblo."
+ author="Wojciech Dzierzanowski"
+ defaultEnabled="false"
+ category="Export">
+
+ <Dependencies>
+ <Addin id="Core" version="0.4.4.100"/>
+ </Dependencies>
+
+ <Extension path = "/FSpot/Menus/Exports">
+ <ExportMenuItem id="Tabblo" _label = "_Tabblo..." class = "FSpotTabbloExport.TabbloExport" />
+ </Extension>
+</Addin>
Added: trunk/extensions/TabbloExport/TabbloExport.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/TabbloExport.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,284 @@
+//
+// FSpotTabbloExport.TabbloExport
+//
+// Authors:
+// Wojciech Dzierzanowski (wojciech dzierzanowski gmail com)
+//
+// (C) Copyright 2008 Wojciech Dzierzanowski
+//
+
+// 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 Mono.Tabblo;
+using Mono.Unix;
+
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.Net;
+using System.Threading;
+
+using FSpot.Utils;
+
+namespace FSpotTabbloExport {
+ /// <summary>
+ /// </summary>
+ public class TabbloExport : FSpot.Extensions.IExporter {
+
+ private readonly Preferences preferences;
+ private readonly Connection connection;
+
+ private FSpot.IBrowsableCollection photos;
+
+ private const string DialogName = "tabblo_export_dialog";
+ [Glade.Widget] Gtk.Dialog dialog;
+ [Glade.Widget] Gtk.Entry username_entry;
+ [Glade.Widget] Gtk.Entry password_entry;
+ [Glade.Widget] Gtk.Button export_button;
+ [Glade.Widget] Gtk.Button cancel_button;
+ [Glade.Widget] Gtk.ScrolledWindow thumb_scrolled_window;
+
+ private FSpot.ThreadProgressDialog progress_dialog;
+
+ // Keyring constants.
+ private const string KeyringItemName = "Tabblo Account";
+ private const string KeyringItemApp = "FSpotTabbloExport";
+ private const string KeyringItemNameAttr = "name";
+ private const string KeyringItemUsernameAttr = "username";
+ private const string KeyringItemAppAttr = "application";
+
+
+ public TabbloExport ()
+ {
+ preferences = new Preferences ();
+ connection = new Connection (preferences);
+ }
+
+
+ public void Run (FSpot.IBrowsableCollection photos)
+ {
+ if (null == photos) {
+ throw new ArgumentNullException ("photos");
+ }
+
+ this.photos = photos;
+
+ Glade.XML glade_xml = new Glade.XML (
+ null, "TabbloExport.glade", DialogName,
+ "f-spot");
+ glade_xml.Autoconnect (this);
+
+ dialog = (Gtk.Dialog) glade_xml.GetWidget (DialogName);
+
+ FSpot.Widgets.IconView icon_view =
+ new FSpot.Widgets.IconView (photos);
+ icon_view.DisplayDates = false;
+ icon_view.DisplayTags = false;
+
+ username_entry.Changed += HandleAccountDataChanged;
+ password_entry.Changed += HandleAccountDataChanged;
+ ReadAccountData ();
+ HandleAccountDataChanged (null, null);
+
+ dialog.Modal = false;
+ dialog.TransientFor = null;
+
+ dialog.Response += HandleResponse;
+
+ thumb_scrolled_window.Add (icon_view);
+ icon_view.Show ();
+ dialog.Show ();
+ }
+
+
+ private void HandleAccountDataChanged (object sender,
+ EventArgs args)
+ {
+ preferences.SetUsername (username_entry.Text);
+ preferences.SetPassword (password_entry.Text);
+
+ export_button.Sensitive =
+ preferences.Username.Length > 0
+ && preferences.Password.Length > 0;
+ }
+
+
+ private void HandleResponse (object sender,
+ Gtk.ResponseArgs args)
+ {
+ dialog.Destroy ();
+
+ if (Gtk.ResponseType.Ok != args.ResponseId) {
+ Log.DebugFormat ("Tabblo export was canceled.");
+ return;
+ }
+
+ WriteAccountData ();
+
+ Log.DebugFormat ("Starting Tabblo export");
+
+ Thread upload_thread =
+ new Thread (new ThreadStart (Upload));
+ progress_dialog = new FSpot.ThreadProgressDialog (
+ upload_thread, photos.Items.Length);
+ progress_dialog.Start ();
+ }
+
+
+ private void Upload ()
+ {
+ if (null == connection) Log.DebugFormat ("No connection");
+
+ Picture [] pictures = GetPicturesForUpload ();
+
+ FSpotUploadProgress fup = new FSpotUploadProgress (
+ pictures, progress_dialog);
+ connection.UploadProgressHandler += fup.HandleProgress;
+
+ ServicePointManager.CertificatePolicy =
+ new UserDecisionCertificatePolicy ();
+
+ try {
+ foreach (Picture picture in pictures) {
+ picture.Upload (connection);
+ }
+
+ progress_dialog.Message = Catalog.GetString (
+ "Done sending photos");
+ progress_dialog.ProgressText = Catalog
+ .GetString ("Upload complete");
+ progress_dialog.Fraction = 1;
+ progress_dialog.ButtonLabel = Gtk.Stock.Ok;
+
+ } catch (TabbloException e) {
+ progress_dialog.Message = Catalog.GetString (
+ "Error uploading to Tabblo: ")
+ + e.Message;
+ progress_dialog.ProgressText =
+ Catalog.GetString ("Error");
+ // FIXME: Retry logic?
+// progressDialog.PerformRetrySkip ();
+ Log.DebugFormat ("Error uploading:\n" + e);
+ } finally {
+ connection.UploadProgressHandler -=
+ fup.HandleProgress;
+ }
+ }
+
+
+ private Picture [] GetPicturesForUpload ()
+ {
+ if (null == photos) Log.DebugFormat ("No photos");
+ if (null == preferences) Log.DebugFormat ("No preferences");
+
+ Picture [] pictures = new Picture [photos.Items.Length];
+
+ for (int i = 0; i < pictures.Length; ++i) {
+ FSpot.IBrowsableItem photo = photos.Items [i];
+
+ // FIXME: GnomeVFS is deprecated, we should use
+ // GIO instead. However, I don't know how to
+ // call `GLib.Content.TypeGuess ()'.
+ string path = photo.DefaultVersionUri.LocalPath;
+ string mime_type = Gnome.Vfs.MimeType
+ .GetMimeTypeForUri (path);
+
+ pictures [i] = new Picture (photo.Name,
+ photo.DefaultVersionUri,
+ mime_type,
+ preferences.Privacy);
+ }
+
+ return pictures;
+ }
+
+
+ private void ReadAccountData ()
+ {
+ Hashtable attrs = new Hashtable ();
+ attrs [KeyringItemNameAttr] = KeyringItemName;
+ attrs [KeyringItemAppAttr] = KeyringItemApp;
+
+ try {
+ Gnome.Keyring.ItemType type = Gnome.Keyring
+ .ItemType.GenericSecret;
+ Gnome.Keyring.ItemData [] items =
+ Gnome.Keyring.Ring.Find (
+ type, attrs);
+ if (items.Length > 1)
+ Log.Warning ("More than one " + KeyringItemName + "found in keyring");
+
+ if (1 <= items.Length) {
+ Log.DebugFormat (KeyringItemName + " data found in " + "keyring");
+ attrs = items [0].Attributes;
+ username_entry.Text = (string) attrs [
+ KeyringItemUsernameAttr];
+ password_entry.Text = items [0].Secret;
+ }
+
+ } catch (Gnome.Keyring.KeyringException e) {
+ Log.DebugFormat ("Error while reading account data:\n" + e);
+ }
+ }
+
+
+ private void WriteAccountData ()
+ {
+ try {
+ string keyring = Gnome.Keyring
+ .Ring.GetDefaultKeyring ();
+
+ Hashtable attrs = new Hashtable ();
+ attrs [KeyringItemNameAttr] = KeyringItemName;
+ attrs [KeyringItemAppAttr] = KeyringItemApp;
+
+ Gnome.Keyring.ItemType type = Gnome.Keyring
+ .ItemType.GenericSecret;
+
+ try {
+ Gnome.Keyring.ItemData [] items = Gnome
+ .Keyring.Ring.Find (
+ type,
+ attrs);
+
+ foreach (Gnome.Keyring.ItemData item
+ in items) {
+ Gnome.Keyring.Ring.DeleteItem (
+ keyring,
+ item.ItemID);
+ }
+ } catch (Gnome.Keyring.KeyringException e) {
+ Log.DebugFormat ("Error while deleting old account data:\n" + e);
+ }
+
+ attrs [KeyringItemUsernameAttr] =
+ preferences.Username;
+
+ Gnome.Keyring.Ring.CreateItem (keyring, type,
+ KeyringItemName, attrs,
+ preferences.Password, true);
+
+ } catch (Gnome.Keyring.KeyringException e) {
+ Log.DebugFormat ("Error while writing account data:\n" + e);
+ }
+ }
+ }
+}
Added: trunk/extensions/TabbloExport/TabbloExport.glade
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/TabbloExport.glade Tue Sep 16 09:18:33 2008
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <requires lib="canvas"/>
+ <requires lib="gnome"/>
+ <widget class="GtkDialog" id="tabblo_export_dialog">
+ <property name="title" translatable="yes">Export</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox11">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkHBox" id="hbox17">
+ <property name="visible">True</property>
+ <property name="border_width">6</property>
+ <child>
+ <widget class="GtkFrame" id="frame8">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment12">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="thumb_scrolled_window">
+ <property name="width_request">180</property>
+ <property name="height_request">180</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="photo_frame">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>Photos</b></property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox11">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <widget class="GtkFrame" id="frame9">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkLabel" id="label44">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>Tabblo account</b></property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkTable" id="table10">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">7</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <widget class="GtkLabel" id="password_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">_Password:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">password_entry</property>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="password_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ <property name="invisible_char">*</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="username_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">_Username:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">username_entry</property>
+ </widget>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="username_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">*</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area11">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="cancelButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="export_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="label">_Export</property>
+ <property name="use_underline">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
Added: trunk/extensions/TabbloExport/TrustError.glade
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/TrustError.glade Tue Sep 16 09:18:33 2008
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Sun Sep 7 21:22:13 2008 -->
+<glade-interface>
+ <widget class="GtkDialog" id="trust_error_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Trust Error</property>
+ <property name="resizable">False</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="deletable">False</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <widget class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <widget class="GtkLabel" id="label0">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="xpad">12</property>
+ <property name="label" translatable="yes">A trust error occured while attempting to access</property>
+ <property name="wrap">True</property>
+ </widget>
+ <packing>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="url_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="xpad">12</property>
+ <property name="label" translatable="yes"><b>{0}</b>.</property>
+ <property name="use_markup">True</property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ <packing>
+ <property name="fill">False</property>
+ <property name="position">-1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="xpad">12</property>
+ <property name="label" translatable="yes">Do you wish to:</property>
+ </widget>
+ <packing>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVButtonBox" id="vbuttonbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkRadioButton" id="abort_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Abort this session</property>
+ <property name="response_id">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkRadioButton" id="once_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Trust the site's certificate this once</property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">abort_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkRadioButton" id="always_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Always trust this site's certificate</property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">once_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="ok_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
Added: trunk/extensions/TabbloExport/UserDecisionCertificatePolicy.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/TabbloExport/UserDecisionCertificatePolicy.cs Tue Sep 16 09:18:33 2008
@@ -0,0 +1,112 @@
+//
+// FSpotTabbloExport.UserDecisionCertificatePolicy
+//
+// Authors:
+// Wojciech Dzierzanowski (wojciech dzierzanowski gmail com)
+//
+// (C) Copyright 2008 Wojciech Dzierzanowski
+//
+
+// 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.Diagnostics;
+using System.Net;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading;
+
+using FSpot.Utils;
+
+namespace FSpotTabbloExport {
+
+ class UserDecisionCertificatePolicy
+ : ApplicationCentricCertificatePolicy {
+
+ private const string DialogName = "trust_error_dialog";
+ [Glade.Widget] Gtk.Dialog dialog;
+ [Glade.Widget] Gtk.Label url_label;
+ [Glade.Widget] Gtk.RadioButton abort_radiobutton;
+ [Glade.Widget] Gtk.RadioButton once_radiobutton;
+ [Glade.Widget] Gtk.RadioButton always_radiobutton;
+
+ private X509Certificate certificate;
+ private WebRequest request;
+ private Decision decision;
+
+ private Object decision_lock = new Object ();
+ private ManualResetEvent decision_event;
+
+
+ protected override Decision GetDecision (
+ X509Certificate certificate,
+ WebRequest request)
+ {
+ this.certificate = certificate;
+ this.request = request;
+
+ lock (decision_lock) {
+ GLib.Idle.Add (this.DoGetDecision);
+ decision_event = new ManualResetEvent (false);
+ decision_event.WaitOne ();
+ }
+
+ return decision;
+ }
+
+ private bool DoGetDecision ()
+ {
+ Glade.XML glade_xml = new Glade.XML (
+ null, "TrustError.glade", DialogName,
+ "f-spot");
+ glade_xml.Autoconnect (this);
+
+ dialog = (Gtk.Dialog) glade_xml.GetWidget (DialogName);
+
+ url_label.Markup = String.Format (
+ url_label.Text, String.Format (
+ "<b>{0}</b>",
+ request.RequestUri));
+
+ Gtk.ResponseType response =
+ (Gtk.ResponseType) dialog.Run ();
+ Log.DebugFormat ("Decision dialog response: " + response);
+
+ dialog.Destroy ();
+
+ decision = Decision.DontTrust;
+ if (0 == response) {
+ if (abort_radiobutton.Active) {
+ decision = Decision.DontTrust;
+ } else if (once_radiobutton.Active) {
+ decision = Decision.TrustOnce;
+ } else if (always_radiobutton.Active) {
+ decision = Decision.TrustAlways;
+ } else {
+ Debug.Assert (false,
+ "Unhandled decision");
+ }
+ }
+
+ decision_event.Set ();
+ return false;
+ }
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]