f-spot r3646 - in trunk: . extensions extensions/DefaultExporters extensions/PicasaWebExport extensions/PicasaWebExport/google-sharp po src



Author: sdelcroix
Date: Fri Feb  8 15:37:13 2008
New Revision: 3646
URL: http://svn.gnome.org/viewvc/f-spot?rev=3646&view=rev

Log:
2008-02-08  Stphane Delcroix  <sdelcroix novell com>

	Patch from lorenzo to addin-ify picasawebexport


Added:
   trunk/extensions/PicasaWebExport/
   trunk/extensions/PicasaWebExport/Makefile.am
   trunk/extensions/PicasaWebExport/PicasaWebExport.addin.xml
   trunk/extensions/PicasaWebExport/PicasaWebExport.cs
   trunk/extensions/PicasaWebExport/PicasaWebExport.glade
   trunk/extensions/PicasaWebExport/google-sharp/
   trunk/extensions/PicasaWebExport/google-sharp/AlbumAccess.cs
   trunk/extensions/PicasaWebExport/google-sharp/AssemblyInfo.cs
   trunk/extensions/PicasaWebExport/google-sharp/Authentication.cs
   trunk/extensions/PicasaWebExport/google-sharp/CaptchaException.cs
   trunk/extensions/PicasaWebExport/google-sharp/CreateAlbumException.cs
   trunk/extensions/PicasaWebExport/google-sharp/DeleteAlbumException.cs
   trunk/extensions/PicasaWebExport/google-sharp/GDataApi.cs
   trunk/extensions/PicasaWebExport/google-sharp/GoogleConnection.cs
   trunk/extensions/PicasaWebExport/google-sharp/GoogleService.cs
   trunk/extensions/PicasaWebExport/google-sharp/Makefile.am
   trunk/extensions/PicasaWebExport/google-sharp/MultipartRequest.cs
   trunk/extensions/PicasaWebExport/google-sharp/NoCheckCertificatePolicy.cs
   trunk/extensions/PicasaWebExport/google-sharp/PicasaAlbum.cs
   trunk/extensions/PicasaWebExport/google-sharp/PicasaAlbumCollection.cs
   trunk/extensions/PicasaWebExport/google-sharp/PicasaPicture.cs
   trunk/extensions/PicasaWebExport/google-sharp/PicasaPictureCollection.cs
   trunk/extensions/PicasaWebExport/google-sharp/PicasaWeb.cs
   trunk/extensions/PicasaWebExport/google-sharp/UploadPictureException.cs
   trunk/extensions/PicasaWebExport/google-sharp/UploadProgressEventArgs.cs
   trunk/extensions/PicasaWebExport/google-sharp/UploadProgressEventHandler.cs
   trunk/extensions/PicasaWebExport/google-sharp/XmlUtil.cs
Removed:
   trunk/src/PicasaWebExport.cs
Modified:
   trunk/ChangeLog
   trunk/Makefile.include
   trunk/configure.in
   trunk/extensions/ChangeLog
   trunk/extensions/DefaultExporters/DefaultExporters.addin.xml
   trunk/extensions/Makefile.am
   trunk/po/POTFILES.in
   trunk/po/POTFILES.skip
   trunk/src/Makefile.am
   trunk/src/Preferences.cs
   trunk/src/f-spot.glade

Modified: trunk/Makefile.include
==============================================================================
--- trunk/Makefile.include	(original)
+++ trunk/Makefile.include	Fri Feb  8 15:37:13 2008
@@ -9,7 +9,6 @@
 DIR_DOCS = $(top_builddir)/docs
 DIR_EXTENSIONS = $(top_builddir)/extensions
 DIR_GLITZ = $(top_builddir)/glitz-sharp/src
-DIR_GOOGLE = $(top_builddir)/google-sharp
 DIR_GPHOTO2 = $(top_builddir)/libgphoto2-sharp
 DIR_ICONS = $(top_builddir)/icons
 DIR_JPEGTRAN = $(top_builddir)/libjpegtran

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Fri Feb  8 15:37:13 2008
@@ -265,7 +265,6 @@
 dbus-sharp/Makefile
 dbus-sharp-glib/Makefile
 docs/Makefile
-google-sharp/Makefile
 gnome-keyring-sharp/Makefile
 icons/Makefile
 libeog/Makefile
@@ -300,6 +299,8 @@
 extensions/FolderExport/Makefile
 extensions/SmugMugExport/SmugMugNet/Makefile
 extensions/SmugMugExport/Makefile
+extensions/PicasaWebExport/Makefile
+extensions/PicasaWebExport/google-sharp/Makefile
 f-spot.pc
 f-spot.spec
 f-spot.desktop.in

Modified: trunk/extensions/DefaultExporters/DefaultExporters.addin.xml
==============================================================================
--- trunk/extensions/DefaultExporters/DefaultExporters.addin.xml	(original)
+++ trunk/extensions/DefaultExporters/DefaultExporters.addin.xml	Fri Feb  8 15:37:13 2008
@@ -1,5 +1,5 @@
 <Addin namespace="FSpot"
-	version="1.5"
+	version="1.6"
 	name="Default Exporters"
 	description="This extension contains all the default exporters for f-spot. Most of them will be moved out of this extension in the future, and, at that time, this extension will be deprecated."
 	author="F-Spot team"
@@ -8,10 +8,9 @@
 	category="Export">
 
 	<Dependencies>
-		<Addin id="Core" version="0.4.0.0"/>
+		<Addin id="Core" version="0.4.2.0"/>
 	</Dependencies>
 
 	<Extension path = "/FSpot/Menus/Exports">
-		<ExportMenuItem id="PicasaWeb" _label = "_PicasaWeb..." class = "FSpot.GoogleExport" />
 	</Extension>
 </Addin>

Modified: trunk/extensions/Makefile.am
==============================================================================
--- trunk/extensions/Makefile.am	(original)
+++ trunk/extensions/Makefile.am	Fri Feb  8 15:37:13 2008
@@ -3,6 +3,7 @@
 	GalleryExport		\
 	FlickrExport		\
 	FolderExport		\
+ 	PicasaWebExport		\
  	SmugMugExport		\
 	DefaultExporters	
 

Added: trunk/extensions/PicasaWebExport/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/Makefile.am	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,58 @@
+include $(top_srcdir)/Makefile.include
+
+PLUGIN_NAME = PicasaWebExport
+
+PLUGIN_MANIFEST = $(PLUGIN_NAME).addin.xml
+
+PLUGIN_ASSEMBLY = $(PLUGIN_NAME).dll
+
+PLUGIN_SOURCES =			\
+	$(srcdir)/PicasaWebExport.cs
+
+REFS =					\
+	-r:../../src/f-spot.exe		\
+	-r:../../src/FSpot.Core.dll	\
+	-r:../../src/FSpot.Utils.dll	\
+	-r:../../semweb/SemWeb.dll	\
+	-r:google-sharp/Mono.Google.dll	\
+	$(LINK_KEYRING)			\
+	-r:System.Web			\
+	-r:Mono.Posix
+
+PKGS =					\
+	-pkg:gnome-vfs-sharp-2.0	\
+	-pkg:gtk-sharp-2.0		\
+	-pkg:glade-sharp-2.0
+
+SUBDIRS = 			\
+	google-sharp
+
+RESOURCES =				\
+	-resource:$(srcdir)/$(PLUGIN_MANIFEST)	\
+	-resource:$(srcdir)/$(PLUGIN_NAME).glade
+
+all: $(PLUGIN_ASSEMBLY)
+
+mpack: $(PLUGIN_ASSEMBLY)
+	mautil p $(PLUGIN_ASSEMBLY)
+
+$(PLUGIN_ASSEMBLY): $(PLUGIN_SOURCES) $(PLUGIN_MANIFEST)
+	$(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/PicasaWebExport/PicasaWebExport.addin.xml
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/PicasaWebExport.addin.xml	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,17 @@
+<Addin namespace="FSpot"
+	version="1.0"
+	name="PicasaWeb Export"
+	description="This extension allows you to export your photos to PicasaWeb."
+	author="F-Spot team"
+	url="http://f-spot.org";
+	defaultEnabled="true"
+	category="Export">
+
+	<Dependencies>
+		<Addin id="Core" version="0.4.0.0"/>
+	</Dependencies>
+
+	<Extension path = "/FSpot/Menus/Exports">
+		<ExportMenuItem id="PicasaWeb" _label = "_PicasaWeb..." class = "FSpotGoogleExport.GoogleExport" />
+	</Extension>
+</Addin>

Added: trunk/extensions/PicasaWebExport/PicasaWebExport.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/PicasaWebExport.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,944 @@
+/*
+ * PicasaWebExport.cs
+ *
+ * Authors:
+ *   Stephane Delcroix <stephane delcroix org>
+ *
+ * Copyright (C) 2006 Stephane Delcroix
+ */
+
+using System;
+using System.Net;
+using System.IO;
+using System.Text;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Web;
+using Mono.Unix;
+
+using FSpot;
+using FSpot.Filters;
+using FSpot.Widgets;
+using FSpot.Utils;
+using FSpot.UI.Dialog;
+
+using Gnome.Keyring;
+
+using Mono.Google;
+using Mono.Google.Picasa;
+
+namespace FSpotGoogleExport {
+	public class GoogleAccount {
+
+		private string username;
+		private string password;
+		private string token;
+		private string unlock_captcha;
+		private GoogleConnection connection;
+		private PicasaWeb picasa;
+
+		public GoogleAccount (string username, string password) 
+		{
+			this.username = username;
+			this.password = password;
+		}
+
+		public GoogleAccount (string username, string password, string token, string unlock_captcha)
+		{
+			this.username = username;
+			this.password = password;
+			this.token = token;
+			this.unlock_captcha = unlock_captcha;
+		}
+
+		public PicasaWeb Connect ()
+		{
+			System.Console.WriteLine ("GoogleAccount.Connect()");
+			GoogleConnection conn = new GoogleConnection (GoogleService.Picasa);
+			ServicePointManager.CertificatePolicy = new NoCheckCertificatePolicy ();
+			if (unlock_captcha == null || token == null)
+				conn.Authenticate(username, password);
+			else {
+				conn.Authenticate(username, password, token, unlock_captcha);
+				token = null; 
+				unlock_captcha = null;
+			}
+			connection = conn;
+			PicasaWeb picasa = new PicasaWeb(conn);
+			this.picasa = picasa;
+			return picasa;
+		}
+
+		private void MarkChanged()
+		{
+			connection = null;
+		}
+
+		public bool Connected {
+			get {
+				return (connection != null);
+			}
+		}
+
+		public string Username {
+			get {
+				return username;
+			}
+			set {
+				if (username != value) {
+					username = value;
+					MarkChanged ();
+				}
+			}
+		}
+
+		public string Password {
+			get {
+				return password;
+			}
+			set {
+				if (password != value) {
+					password = value;
+					MarkChanged ();
+				}
+			}
+		}
+
+		public string Token {
+			get {
+				return token;
+			}
+			set {
+				token = value;
+			}
+		}
+
+		public string UnlockCaptcha {
+			get {
+				return unlock_captcha;
+			}
+			set {
+				unlock_captcha = value;
+			}
+		}
+
+		public PicasaWeb Picasa {
+			get {
+				return picasa;
+			}
+		}
+	}
+
+	
+	public class GoogleAccountManager 
+	{
+		private static GoogleAccountManager instance;
+		private const string keyring_item_name = "Google Account";
+		ArrayList accounts;
+
+		public delegate void AccountListChangedHandler (GoogleAccountManager manager, GoogleAccount changed_account);
+		public event AccountListChangedHandler AccountListChanged;
+		
+		public static GoogleAccountManager GetInstance ()
+		{
+			if (instance == null) {
+				instance = new GoogleAccountManager ();
+			}
+
+			return instance;
+		}
+
+		private GoogleAccountManager ()
+		{
+			accounts = new ArrayList ();
+			ReadAccounts ();
+		}	
+
+		public void MarkChanged ()
+		{
+			MarkChanged (true, null);
+		}
+
+		public void MarkChanged (bool write, GoogleAccount changed_account)
+		{
+			if (write)
+				WriteAccounts ();
+
+			if (AccountListChanged != null)
+				AccountListChanged (this, changed_account);
+		}
+
+		public ArrayList GetAccounts ()
+		{
+			return accounts;
+		}
+
+		public void AddAccount (GoogleAccount account)
+		{
+			AddAccount (account, true);
+		}
+
+		public void AddAccount (GoogleAccount account, bool write)
+		{
+			accounts.Add (account);
+			MarkChanged (write, account);
+		}
+
+		public void RemoveAccount (GoogleAccount account)
+		{
+			string keyring;
+			try {
+				keyring = Ring.GetDefaultKeyring();
+			} catch {
+				return;
+			}
+			Hashtable request_attributes = new Hashtable();
+			request_attributes["name"] = keyring_item_name;
+			request_attributes["username"] = account.Username;
+			try {
+				foreach(ItemData result in Ring.Find(ItemType.GenericSecret, request_attributes)) {
+					Ring.DeleteItem(keyring, result.ItemID);
+				}
+			} catch (Exception e) {
+				Console.WriteLine(e);
+			}
+			accounts.Remove (account);
+			MarkChanged ();
+		}
+
+		public void WriteAccounts ()
+		{
+			string keyring;
+			try {
+				keyring = Ring.GetDefaultKeyring();
+			} catch {
+				return;
+			}
+			foreach (GoogleAccount account in accounts) {
+				Hashtable update_request_attributes = new Hashtable();
+				update_request_attributes["name"] = keyring_item_name;
+				update_request_attributes["username"] = account.Username;
+
+				try {
+					Ring.CreateItem(keyring, ItemType.GenericSecret, keyring_item_name, update_request_attributes, account.Password, true);
+				} catch {
+					continue;
+				}
+			}
+		}
+
+		private void ReadAccounts ()
+		{
+
+			Hashtable request_attributes = new Hashtable();
+			request_attributes["name"] = keyring_item_name;
+			try {
+				foreach(ItemData result in Ring.Find(ItemType.GenericSecret, request_attributes)) {
+					if(!result.Attributes.ContainsKey("name") || !result.Attributes.ContainsKey("username") ||
+						(result.Attributes["name"] as string) != keyring_item_name) 
+						continue;
+					
+					string username = (string)result.Attributes["username"];
+					string password = result.Secret;
+	
+					if (username == null || username == String.Empty || password == null || password == String.Empty)
+						throw new ApplicationException ("Invalid username/password in keyring");
+	
+					GoogleAccount account = new GoogleAccount(username, password);
+					if (account != null)
+						AddAccount (account, false);
+
+				}
+			} catch (Exception e) {
+				Console.Error.WriteLine(e);
+			}
+
+			MarkChanged ();
+		}
+	}
+	
+	public class GoogleAccountDialog {
+		public GoogleAccountDialog (Gtk.Window parent) : this (parent, null, false, null) { 
+			Dialog.Response += HandleAddResponse;
+			add_button.Sensitive = false;
+		}
+		
+		public GoogleAccountDialog (Gtk.Window parent, GoogleAccount account, bool show_error, CaptchaException captcha_exception)
+		{
+			xml = new Glade.XML (null, "PicasaWebExport.glade", dialog_name, "f-spot");
+			xml.Autoconnect (this);
+			Dialog.Modal = false;
+			Dialog.TransientFor = parent;
+			Dialog.DefaultResponse = Gtk.ResponseType.Ok;
+			
+			this.account = account;
+
+			bool show_captcha = (captcha_exception != null);
+			status_area.Visible = show_error;
+			locked_area.Visible = show_captcha;
+			captcha_label.Visible = show_captcha;
+			captcha_entry.Visible = show_captcha;
+			captcha_image.Visible = show_captcha;
+			
+			password_entry.ActivatesDefault = true;
+			username_entry.ActivatesDefault = true;
+
+			if (show_captcha) {
+				try {
+					using  (ImageFile img = ImageFile.Create(new Uri(captcha_exception.CaptchaUrl))) {
+						captcha_image.Pixbuf = img.Load();
+						token = captcha_exception.Token;
+					}
+				} catch (Exception) {}
+			}
+
+			if (account != null) {
+				password_entry.Text = account.Password;
+				username_entry.Text = account.Username;
+				add_button.Label = Gtk.Stock.Ok;
+				Dialog.Response += HandleEditResponse;
+			}
+
+			if (remove_button != null)
+				remove_button.Visible = account != null;
+
+			this.Dialog.Show ();
+
+			password_entry.Changed += HandleChanged;
+			username_entry.Changed += HandleChanged;
+			HandleChanged (null, null);
+		}
+
+		private void HandleChanged (object sender, System.EventArgs args)
+		{
+			password = password_entry.Text;
+			username = username_entry.Text;
+
+			add_button.Sensitive = !(password == String.Empty || username == String.Empty);
+		}
+		
+		[GLib.ConnectBefore]
+		protected void HandleAddResponse (object sender, Gtk.ResponseArgs args)
+		{
+			if (args.ResponseId == Gtk.ResponseType.Ok) {
+				GoogleAccount account = new GoogleAccount (username, password);
+				GoogleAccountManager.GetInstance ().AddAccount (account);
+			}
+			Dialog.Destroy ();
+		}
+
+		protected void HandleEditResponse (object sender, Gtk.ResponseArgs args)
+		{
+			if (args.ResponseId == Gtk.ResponseType.Ok) {
+				account.Username = username;
+				account.Password = password;
+				account.Token = token;
+				account.UnlockCaptcha = captcha_entry.Text;
+				GoogleAccountManager.GetInstance ().MarkChanged (true, account);
+			} else if (args.ResponseId == Gtk.ResponseType.Reject) {
+				// NOTE we are using Reject to signal the remove action.
+				GoogleAccountManager.GetInstance ().RemoveAccount (account);
+			}
+			Dialog.Destroy ();				
+		}
+
+		private Gtk.Dialog Dialog {
+			get {
+				if (dialog == null)
+					dialog = (Gtk.Dialog) xml.GetWidget (dialog_name);
+
+				return dialog;
+			}
+		}
+
+		private GoogleAccount account;
+		private string password;
+		private string username;
+		private string token;
+
+		private Glade.XML xml;
+		private string dialog_name = "google_add_dialog";
+
+		// widgets 
+		[Glade.Widget] Gtk.Dialog dialog;
+		[Glade.Widget] Gtk.Entry password_entry;
+		[Glade.Widget] Gtk.Entry username_entry;
+		[Glade.Widget] Gtk.Entry captcha_entry;
+
+		[Glade.Widget] Gtk.Button add_button;
+		[Glade.Widget] Gtk.Button remove_button;
+		[Glade.Widget] Gtk.Button cancel_button;
+
+		[Glade.Widget] Gtk.HBox status_area;
+		[Glade.Widget] Gtk.HBox locked_area;
+
+		[Glade.Widget] Gtk.Image captcha_image;
+		[Glade.Widget] Gtk.Label captcha_label;
+
+	}
+
+	public class GoogleAddAlbum {
+		[Glade.Widget] Gtk.Dialog dialog;
+		[Glade.Widget] Gtk.OptionMenu album_optionmenu;
+
+		[Glade.Widget] Gtk.Entry title_entry;
+		[Glade.Widget] Gtk.Entry description_entry;
+		[Glade.Widget] Gtk.CheckButton public_check;
+		
+		[Glade.Widget] Gtk.Button add_button;
+		[Glade.Widget] Gtk.Button cancel_button;
+
+		private Glade.XML xml;
+		private string dialog_name = "google_add_album_dialog";
+
+		private GoogleExport export;
+		private PicasaWeb picasa;
+		private string description;
+		private string title;
+		private bool public_album;
+
+		public GoogleAddAlbum (GoogleExport export, PicasaWeb picasa)
+		{
+			xml = new Glade.XML (null, "PicasaWebExport.glade", dialog_name, "f-spot");
+			xml.Autoconnect (this);
+
+			this.export = export;
+			this.picasa = picasa;	
+			
+			Dialog.Response += HandleAddResponse;
+
+			description_entry.Changed += HandleChanged;
+			title_entry.Changed += HandleChanged;
+			HandleChanged (null, null);
+		}
+		
+		private void HandleChanged (object sender, EventArgs args)
+		{
+			description = description_entry.Text;
+			title = title_entry.Text;
+			public_album = public_check.Active;
+
+			if (title == String.Empty)
+				add_button.Sensitive = false;
+			else
+				add_button.Sensitive = true;
+		}
+		
+		[GLib.ConnectBefore]
+		protected void HandleAddResponse (object sender, Gtk.ResponseArgs args)
+		{
+			if (args.ResponseId == Gtk.ResponseType.Ok) {
+				public_album = public_check.Active;
+				
+				try {
+					picasa.CreateAlbum (System.Web.HttpUtility.HtmlEncode (title), description, public_album ? AlbumAccess.Public : AlbumAccess.Private);
+				} catch (System.Exception e) {
+					HigMessageDialog md =
+					new HigMessageDialog (Dialog, 
+							      Gtk.DialogFlags.Modal |
+							      Gtk.DialogFlags.DestroyWithParent,
+								      Gtk.MessageType.Error, Gtk.ButtonsType.Ok,
+							      Catalog.GetString ("Error while creating Album"),
+							      String.Format (Catalog.GetString ("The following error was encountered while attempting to create an album: {0}"), e.Message));
+					md.Run ();
+					md.Destroy ();
+					return;
+				}
+				export.HandleAlbumAdded (title);
+			}
+			Dialog.Destroy ();
+		}
+
+		private Gtk.Dialog Dialog {
+			get {
+				if (dialog == null)
+					dialog = (Gtk.Dialog) xml.GetWidget (dialog_name);
+
+				return dialog;
+			}
+		}
+	}
+
+	
+	public class GoogleExport : FSpot.Extensions.IExporter {
+		public GoogleExport ()
+		{
+		}
+
+		public void Run (IBrowsableCollection selection)
+		{
+			xml = new Glade.XML (null, "PicasaWebExport.glade", dialog_name, "f-spot");
+			xml.Autoconnect (this);
+
+			this.items = selection.Items;
+			album_button.Sensitive = false;
+			IconView view = new IconView (selection);
+			view.DisplayDates = false;
+			view.DisplayTags = false;
+
+			Dialog.Modal = false;
+			Dialog.TransientFor = null;
+
+			thumb_scrolledwindow.Add (view);
+			view.Show ();
+			Dialog.Show ();
+
+
+			GoogleAccountManager manager = GoogleAccountManager.GetInstance ();
+			manager.AccountListChanged += PopulateGoogleOptionMenu;
+			PopulateGoogleOptionMenu (manager, null);
+
+			if (edit_button != null)
+				edit_button.Clicked += HandleEditGallery;
+			
+			Dialog.Response += HandleResponse;
+			connect = true;
+			HandleSizeActive (null, null);
+			Connect ();
+
+			scale_check.Toggled += HandleScaleCheckToggled;
+			
+			LoadPreference (SCALE_KEY);
+			LoadPreference (SIZE_KEY);
+			LoadPreference (ROTATE_KEY);
+			LoadPreference (BROWSER_KEY);
+//			LoadPreference (Preferences.EXPORT_PICASAWEB_META);
+			LoadPreference (TAG_KEY);
+		}
+		
+		private bool scale;
+		private int size;
+		private bool browser;
+		private bool rotate;
+//		private bool meta;
+		private bool export_tag;
+		private bool connect = false;
+
+		private long approx_size = 0;
+		private long sent_bytes = 0;
+
+		IBrowsableItem [] items;
+		int photo_index;
+		FSpot.ThreadProgressDialog progress_dialog;
+		
+		ArrayList accounts;
+		private GoogleAccount account;
+		private PicasaAlbum album;
+
+		private string xml_path;
+
+		private Glade.XML xml;
+		private string dialog_name = "google_export_dialog";
+
+		public const string EXPORT_SERVICE = "picasaweb/";
+		public const string SCALE_KEY = Preferences.APP_FSPOT_EXPORT + EXPORT_SERVICE + "scale";
+		public const string SIZE_KEY = Preferences.APP_FSPOT_EXPORT + EXPORT_SERVICE + "size";
+		public const string ROTATE_KEY = Preferences.APP_FSPOT_EXPORT + EXPORT_SERVICE + "rotate";
+		public const string BROWSER_KEY = Preferences.APP_FSPOT_EXPORT + EXPORT_SERVICE + "browser";
+		public const string TAG_KEY = Preferences.APP_FSPOT_EXPORT + EXPORT_SERVICE + "tag";
+
+		// widgets 
+		[Glade.Widget] Gtk.Dialog dialog;
+		[Glade.Widget] Gtk.OptionMenu gallery_optionmenu;
+		[Glade.Widget] Gtk.OptionMenu album_optionmenu;
+		
+		[Glade.Widget] Gtk.Entry width_entry;
+		[Glade.Widget] Gtk.Entry height_entry;
+
+		[Glade.Widget] Gtk.Label status_label;
+
+		[Glade.Widget] Gtk.CheckButton browser_check;
+		[Glade.Widget] Gtk.CheckButton scale_check;
+		[Glade.Widget] Gtk.CheckButton rotate_check;
+//		[Glade.Widget] Gtk.CheckButton meta_check;
+		[Glade.Widget] Gtk.CheckButton tag_check;
+		
+		[Glade.Widget] Gtk.SpinButton size_spin;
+
+		[Glade.Widget] Gtk.Button album_button;
+		[Glade.Widget] Gtk.Button add_button;
+		[Glade.Widget] Gtk.Button edit_button;
+		
+		[Glade.Widget] Gtk.Button export_button;
+		[Glade.Widget] Gtk.Button cancel_button;
+
+		[Glade.Widget] Gtk.ScrolledWindow thumb_scrolledwindow;
+
+		System.Threading.Thread command_thread;
+		
+
+		private void HandleResponse (object sender, Gtk.ResponseArgs args)
+		{
+			if (args.ResponseId != Gtk.ResponseType.Ok) {
+				Dialog.Destroy ();
+				return;
+			}
+
+			if (scale_check != null) {
+				scale = scale_check.Active;
+				size = size_spin.ValueAsInt;
+			} else
+				scale = false;
+
+			browser = browser_check.Active;
+			rotate = rotate_check.Active;
+//			meta = meta_check.Active;
+			export_tag = tag_check.Active;
+
+			if (account != null) { 
+				//System.Console.WriteLine ("history = {0}", album_optionmenu.History);
+				album = (PicasaAlbum) account.Picasa.GetAlbums() [Math.Max (0, album_optionmenu.History)]; 
+				photo_index = 0;
+				
+				Dialog.Destroy ();
+
+				command_thread = new System.Threading.Thread (new System.Threading.ThreadStart (this.Upload));
+				command_thread.Name = Catalog.GetString ("Uploading Pictures");
+				
+				progress_dialog = new FSpot.ThreadProgressDialog (command_thread, items.Length);
+				progress_dialog.Start ();
+
+				// Save these settings for next time
+				Preferences.Set (SCALE_KEY, scale);
+				Preferences.Set (SIZE_KEY, size);
+				Preferences.Set (ROTATE_KEY, rotate);
+				Preferences.Set (BROWSER_KEY, browser);
+//				Preferences.Set (Preferences.EXPORT_GALLERY_META, meta);
+				Preferences.Set (TAG_KEY, export_tag);
+			}
+		}
+		
+		public void HandleSizeActive (object sender, EventArgs args)
+		{
+			size_spin.Sensitive = scale_check.Active;
+		}
+
+		private void HandleUploadProgress(object o, UploadProgressEventArgs args)
+		{
+				if (approx_size == 0)
+					progress_dialog.ProgressText = System.String.Format (Catalog.GetString ("{0} Sent"), SizeUtil.ToHumanReadable(args.BytesSent));
+				else
+					progress_dialog.ProgressText = System.String.Format (Catalog.GetString ("{0} of approx. {1}"), SizeUtil.ToHumanReadable(sent_bytes + args.BytesSent), SizeUtil.ToHumanReadable(approx_size));
+				progress_dialog.Fraction = ((photo_index - 1) / (double) items.Length) + (args.BytesSent / (args.BytesTotal * (double) items.Length));
+		}
+
+		private void Upload ()
+		{
+			album.UploadProgress += HandleUploadProgress;
+			sent_bytes = 0;
+			approx_size = 0;
+
+			System.Console.WriteLine ("Starting Upload to Picasa");
+
+			FilterSet filters = new FilterSet ();
+			filters.Add (new JpegFilter ());
+
+			if (scale)
+				filters.Add (new ResizeFilter ((uint)size));
+
+			if (rotate)
+				filters.Add (new OrientationFilter ());
+
+			Array.Sort (items as Photo[], new Photo.CompareDateName ());
+
+			while (photo_index < items.Length) {
+				try {
+					IBrowsableItem item = items[photo_index];
+
+					FileInfo file_info;
+					Console.WriteLine ("uploading {0}", photo_index);
+
+					progress_dialog.Message = String.Format (Catalog.GetString ("Uploading picture \"{0}\" ({1} of {2})"), 
+										 item.Name, photo_index+1, items.Length);
+					photo_index++;
+					
+					FilterRequest request = new FilterRequest (item.DefaultVersionUri);
+
+					filters.Convert (request);
+
+					file_info = new FileInfo (request.Current.LocalPath);
+
+					if (approx_size == 0) //first image
+						approx_size = file_info.Length * items.Length;
+					else
+						approx_size = sent_bytes * items.Length / (photo_index - 1);
+
+					PicasaPicture picture = album.UploadPicture (request.Current.LocalPath, Path.ChangeExtension (item.Name, "jpg"), item.Description);
+					if (Core.Database != null && item is Photo)
+						Core.Database.Exports.Create ((item as Photo).Id,
+									      (item as Photo).DefaultVersionId,
+									      ExportStore.PicasaExportType,
+									      picture.Link);
+
+					sent_bytes += file_info.Length;
+
+					request.Dispose ();
+					//tagging
+					if (item.Tags != null && export_tag)
+						foreach (Tag tag in item.Tags)
+							picture.AddTag (tag.Name);
+
+				} catch (System.Exception e) {
+					progress_dialog.Message = String.Format (Catalog.GetString ("Error Uploading To Gallery: {0}"),
+										 e.Message);
+					progress_dialog.ProgressText = Catalog.GetString ("Error");
+					System.Console.WriteLine (e);
+
+					if (progress_dialog.PerformRetrySkip ())
+					 	photo_index--;
+				}
+			}
+				
+			progress_dialog.Message = Catalog.GetString ("Done Sending Photos");
+			progress_dialog.Fraction = 1.0;
+			progress_dialog.ProgressText = Catalog.GetString ("Upload Complete");
+			progress_dialog.ButtonLabel = Gtk.Stock.Ok;
+
+			if (browser) {
+				GnomeUtil.UrlShow (null, album.Link);
+			}
+		}
+
+		private void HandleScaleCheckToggled (object o, EventArgs e)
+		{
+			rotate_check.Sensitive = !scale_check.Active;
+		}
+		
+		private void PopulateGoogleOptionMenu (GoogleAccountManager manager, GoogleAccount changed_account)
+		{
+			Gtk.Menu menu = new Gtk.Menu ();
+			this.account = changed_account;
+			int pos = -1;
+
+			accounts = manager.GetAccounts ();
+			if (accounts == null || accounts.Count == 0) {
+				Gtk.MenuItem item = new Gtk.MenuItem (Catalog.GetString ("(No Gallery)"));
+				menu.Append (item);
+				gallery_optionmenu.Sensitive = false;
+				edit_button.Sensitive = false;
+			} else {
+				int i = 0;
+				foreach (GoogleAccount account in accounts) {
+					if (account == changed_account)
+						pos = i;
+					
+					Gtk.MenuItem item = new Gtk.MenuItem (account.Username);
+					menu.Append (item);		
+					i++;
+				}
+				gallery_optionmenu.Sensitive = true;
+				edit_button.Sensitive = true;
+			}
+
+			menu.ShowAll ();
+			gallery_optionmenu.Menu = menu;
+			gallery_optionmenu.SetHistory ((uint)pos);
+		}
+
+		private void Connect ()
+		{
+			Connect (null);
+		}
+
+		private void Connect (GoogleAccount selected)
+		{
+			Connect (selected, null, null);
+		}
+
+		private void Connect (GoogleAccount selected, string token, string text)
+		{
+			try {
+				if (accounts.Count != 0 && connect) {
+					if (selected == null)
+						account = (GoogleAccount) accounts [gallery_optionmenu.History];
+					else
+						account = selected;
+
+					if (!account.Connected)
+						account.Connect ();
+					
+					PopulateAlbumOptionMenu (account.Picasa);
+
+					long qu = account.Picasa.QuotaUsed;
+					long ql = account.Picasa.QuotaLimit;
+
+					StringBuilder sb = new StringBuilder("<small>");
+					sb.Append(Catalog.GetString("Available space :"));
+					sb.Append(SizeUtil.ToHumanReadable (ql - qu));
+					sb.Append(" (");
+					sb.Append(100 * qu / ql);
+					sb.Append("% used out of ");
+					sb.Append(SizeUtil.ToHumanReadable (ql));
+					sb.Append(")");
+					sb.Append("</small>");
+
+					status_label.Text = sb.ToString();
+					status_label.UseMarkup = true;
+
+					album_button.Sensitive = true;
+				}
+			} catch (CaptchaException exc){
+				System.Console.WriteLine("Your google account is locked");
+				if (selected != null)
+					account = selected;
+
+				PopulateAlbumOptionMenu (account.Picasa);
+				album_button.Sensitive = false;
+
+				new GoogleAccountDialog (this.Dialog, account, false, exc);
+				
+				System.Console.WriteLine ("Your google account is locked, you can unlock it by visiting: {0}", CaptchaException.UnlockCaptchaURL);
+
+			} catch (System.Exception) {
+				System.Console.WriteLine ("Can not connect to Picasa. Bad username ? password ? network connection ?");
+				//System.Console.WriteLine ("{0}",ex);
+				if (selected != null)
+					account = selected;
+
+				PopulateAlbumOptionMenu (account.Picasa);
+
+				status_label.Text = String.Empty;
+				album_button.Sensitive = false;
+				
+				new GoogleAccountDialog (this.Dialog, account, true, null);
+			} 
+		}
+
+		private void HandleAccountSelected (object sender, System.EventArgs args)
+		{
+			Connect ();
+		}
+
+		public void HandleAlbumAdded (string title) {
+			GoogleAccount account = (GoogleAccount) accounts [gallery_optionmenu.History];
+			PopulateAlbumOptionMenu (account.Picasa);
+				
+			// make the newly created album selected
+			PicasaAlbumCollection albums = account.Picasa.GetAlbums();
+			for (int i=0; i < albums.Count; i++) {
+				if (((PicasaAlbum)albums[i]).Title == title) {
+					album_optionmenu.SetHistory((uint)i);
+				}
+			}
+		}
+
+		private void PopulateAlbumOptionMenu (PicasaWeb picasa)
+		{
+			PicasaAlbumCollection albums = null;
+			if (picasa != null) {
+				try {
+					albums = picasa.GetAlbums();
+				} catch {
+					Console.WriteLine("Can't get the albums");
+					picasa = null;
+				}
+			}
+
+			Gtk.Menu menu = new Gtk.Menu ();
+
+			bool disconnected = picasa == null || !account.Connected || albums == null;
+
+			if (disconnected || albums.Count == 0) {
+				string msg = disconnected ? Catalog.GetString ("(Not Connected)") 
+					: Catalog.GetString ("(No Albums)");
+
+				Gtk.MenuItem item = new Gtk.MenuItem (msg);
+				menu.Append (item);
+
+				export_button.Sensitive = false;
+				album_optionmenu.Sensitive = false;
+				album_button.Sensitive = false;
+
+				if (disconnected) 
+					album_button.Sensitive = false;
+			} else {
+				foreach (PicasaAlbum album in albums.AllValues) {
+					System.Text.StringBuilder label_builder = new System.Text.StringBuilder ();
+					
+					label_builder.Append (album.Title);
+
+					Gtk.MenuItem item = new Gtk.MenuItem (label_builder.ToString ());
+					((Gtk.Label)item.Child).UseUnderline = false;
+					menu.Append (item);
+				}
+
+				export_button.Sensitive = items.Length > 0;
+				album_optionmenu.Sensitive = true;
+				album_button.Sensitive = true;
+			}
+
+			menu.ShowAll ();
+			album_optionmenu.Menu = menu;
+		}
+		
+		public void HandleAddGallery (object sender, System.EventArgs args)
+		{
+			new GoogleAccountDialog (this.Dialog);
+		}
+		
+		public void HandleEditGallery (object sender, System.EventArgs args)
+		{
+			new GoogleAccountDialog (this.Dialog, account, false, null);
+		}
+
+		public void HandleAddAlbum (object sender, System.EventArgs args)
+		{
+			if (account == null)
+				throw new Exception (Catalog.GetString ("No account selected"));
+				
+			new GoogleAddAlbum (this, account.Picasa);
+		}
+
+		void LoadPreference (string key)
+		{
+			object val = Preferences.Get (key);
+
+			if (val == null)
+				return;
+			
+			//System.Console.WriteLine ("Setting {0} to {1}", key, val);
+
+			switch (key) {
+			case SCALE_KEY:
+				if (scale_check.Active != (bool) val) {
+					scale_check.Active = (bool) val;
+					rotate_check.Sensitive = !(bool) val;
+				}
+				break;
+
+			case SIZE_KEY:
+				size_spin.Value = (double) (int) val;
+				break;
+			
+			case BROWSER_KEY:
+				if (browser_check.Active != (bool) val)
+					browser_check.Active = (bool) val;
+				break;
+			
+			case ROTATE_KEY:
+				if (rotate_check.Active != (bool) val)
+					rotate_check.Active = (bool) val;
+				break;
+			
+//			case Preferences.EXPORT_GALLERY_META:
+//				if (meta_check.Active != (bool) val)
+//					meta_check.Active = (bool) val;
+//				break;
+			
+			case TAG_KEY:
+				if (tag_check.Active != (bool) val)
+					tag_check.Active = (bool) val;
+				break;
+			}
+		}
+
+		private Gtk.Dialog Dialog {
+			get {
+				if (dialog == null)
+					dialog = (Gtk.Dialog) xml.GetWidget (dialog_name);
+
+				return dialog;
+			}
+		}
+	}
+}

Added: trunk/extensions/PicasaWebExport/PicasaWebExport.glade
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/PicasaWebExport.glade	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,835 @@
+<?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="google_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_scrolledwindow">
+                        <property name="width_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">&lt;b&gt;Photos&lt;/b&gt;</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="GtkAlignment" id="alignment13">
+                        <property name="visible">True</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <widget class="GtkVBox" id="vbox12">
+                            <property name="visible">True</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <widget class="GtkHBox" id="hbox20">
+                                <property name="visible">True</property>
+                                <property name="spacing">6</property>
+                                <child>
+                                  <widget class="GtkLabel" id="gallery_label">
+                                    <property name="visible">True</property>
+                                    <property name="label" translatable="yes">_Gallery:</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="mnemonic_widget">gallery_optionmenu</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkOptionMenu" id="gallery_optionmenu">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="response_id">0</property>
+                                    <signal name="changed" handler="HandleAccountSelected"/>
+                                  </widget>
+                                  <packing>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkButton" id="gallery_button">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="label">gtk-add</property>
+                                    <property name="use_stock">True</property>
+                                    <property name="response_id">0</property>
+                                    <signal name="clicked" handler="HandleAddGallery"/>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkButton" id="edit_button">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="label">gtk-edit</property>
+                                    <property name="use_stock">True</property>
+                                    <property name="response_id">0</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">3</property>
+                                  </packing>
+                                </child>
+                              </widget>
+                            </child>
+                            <child>
+                              <widget class="GtkLabel" id="status_label">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="use_markup">True</property>
+                              </widget>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label44">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">&lt;b&gt;PicasaWeb Export&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </widget>
+                      <packing>
+                        <property name="type">label_item</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkFrame" id="frame10">
+                    <property name="visible">True</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">GTK_SHADOW_NONE</property>
+                    <child>
+                      <widget class="GtkAlignment" id="alignment14">
+                        <property name="visible">True</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <widget class="GtkVBox" id="vbox13">
+                            <property name="visible">True</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <widget class="GtkHBox" id="hbox18">
+                                <property name="visible">True</property>
+                                <property name="spacing">6</property>
+                                <child>
+                                  <widget class="GtkLabel" id="album_label">
+                                    <property name="visible">True</property>
+                                    <property name="label" translatable="yes">_Export to Album:</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="mnemonic_widget">album_optionmenu</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkOptionMenu" id="album_optionmenu">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="response_id">0</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkButton" id="album_button">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="label">gtk-add</property>
+                                    <property name="use_stock">True</property>
+                                    <property name="response_id">0</property>
+                                    <signal name="clicked" handler="HandleAddAlbum"/>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                              </widget>
+                            </child>
+                            <child>
+                              <widget class="GtkCheckButton" id="browser_check">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="label" translatable="yes">Open _album in browser when done uploading</property>
+                                <property name="use_underline">True</property>
+                                <property name="response_id">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                              </widget>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label45">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">&lt;b&gt;Album&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </widget>
+                      <packing>
+                        <property name="type">label_item</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkFrame" id="frame11">
+                    <property name="visible">True</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">GTK_SHADOW_NONE</property>
+                    <child>
+                      <widget class="GtkAlignment" id="alignment15">
+                        <property name="visible">True</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <widget class="GtkVBox" id="vbox14">
+                            <property name="visible">True</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <widget class="GtkHBox" id="hbox58">
+                                <property name="visible">True</property>
+                                <child>
+                                  <widget class="GtkCheckButton" id="scale_check">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="label" translatable="yes">_Resize to: </property>
+                                    <property name="use_underline">True</property>
+                                    <property name="response_id">0</property>
+                                    <property name="draw_indicator">True</property>
+                                    <signal name="toggled" handler="HandleSizeActive"/>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkSpinButton" id="size_spin">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="adjustment">400 0 10000 1 10 10</property>
+                                    <property name="climb_rate">1</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkLabel" id="label153">
+                                    <property name="visible">True</property>
+                                    <property name="label" translatable="yes">pixels</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <placeholder/>
+                                </child>
+                              </widget>
+                            </child>
+                            <child>
+                              <widget class="GtkCheckButton" id="rotate_check">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="label" translatable="yes">_Autorotate</property>
+                                <property name="use_underline">True</property>
+                                <property name="response_id">0</property>
+                                <property name="draw_indicator">True</property>
+                              </widget>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkCheckButton" id="tag_check">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="label" translatable="yes">_Export tags</property>
+                                <property name="use_underline">True</property>
+                                <property name="response_id">0</property>
+                                <property name="draw_indicator">True</property>
+                              </widget>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label46">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">&lt;b&gt;Style&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </widget>
+                      <packing>
+                        <property name="type">label_item</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="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="cancel_button">
+                <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>
+  <widget class="GtkDialog" id="google_add_album_dialog">
+    <property name="visible">True</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-vbox12">
+        <property name="visible">True</property>
+        <child>
+          <widget class="GtkTable" id="table10">
+            <property name="visible">True</property>
+            <property name="border_width">12</property>
+            <property name="n_rows">3</property>
+            <property name="n_columns">2</property>
+            <property name="column_spacing">7</property>
+            <property name="row_spacing">6</property>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="descroption_label">
+                <property name="visible">True</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">_Description:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">description_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="description_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="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="name_label">
+                <property name="visible">True</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">_Album Title:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">title_entry</property>
+              </widget>
+              <packing>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkEntry" id="title_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>
+            <child>
+              <widget class="GtkCheckButton" id="public_check">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label" translatable="yes">Public Album</property>
+                <property name="use_underline">True</property>
+                <property name="response_id">0</property>
+                <property name="draw_indicator">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area12">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="cancel_button">
+                <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="add_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="has_default">True</property>
+                <property name="label">gtk-add</property>
+                <property name="use_stock">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>
+  <widget class="GtkDialog" id="google_add_dialog">
+    <property name="visible">True</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-vbox12">
+        <property name="visible">True</property>
+        <child>
+          <widget class="GtkVBox" id="vbox63">
+            <property name="visible">True</property>
+            <child>
+              <widget class="GtkHBox" id="status_area">
+                <property name="border_width">12</property>
+                <child>
+                  <widget class="GtkImage" id="image12">
+                    <property name="visible">True</property>
+                    <property name="yalign">0</property>
+                    <property name="stock">gtk-dialog-question</property>
+                    <property name="icon_size">6</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="padding">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkVBox" id="vbox64">
+                    <property name="visible">True</property>
+                    <property name="border_width">6</property>
+                    <child>
+                      <widget class="GtkLabel" id="summary_label">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">&lt;span weight='bold' size='larger'&gt;Error Connecting to Gallery&lt;/span&gt;
+</property>
+                        <property name="use_markup">True</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="description_label">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Please verify that the settings for this gallery are correct.</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="locked_area">
+                <property name="border_width">12</property>
+                <child>
+                  <widget class="GtkImage" id="image45">
+                    <property name="visible">True</property>
+                    <property name="yalign">0</property>
+                    <property name="stock">gtk-missing-image</property>
+                    <property name="icon_size">6</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="padding">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkVBox" id="vbox84">
+                    <property name="visible">True</property>
+                    <property name="border_width">6</property>
+                    <child>
+                      <widget class="GtkLabel" id="label214">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">&lt;span weight='bold' size='larger'&gt;Your Google Account is locked&lt;/span&gt;
+</property>
+                        <property name="use_markup">True</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label215">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Please verify that the settings for this gallery are correct.
+Enter the letters as they are shown in the image in
+the 'Captcha' field. &lt;i&gt;Letters are not case-sensitive&lt;/i&gt;</property>
+                        <property name="use_markup">True</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkTable" id="table10">
+                <property name="visible">True</property>
+                <property name="border_width">12</property>
+                <property name="n_rows">3</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>
+                <child>
+                  <widget class="GtkLabel" id="captcha_label">
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">_Captcha:</property>
+                    <property name="use_underline">True</property>
+                  </widget>
+                  <packing>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkHBox" id="hbox88">
+                    <property name="visible">True</property>
+                    <child>
+                      <widget class="GtkEntry" id="captcha_entry">
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">*</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImage" id="captcha_image">
+                        <property name="stock">gtk-missing-image</property>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</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="pack_type">GTK_PACK_END</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area12">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="cancel_button">
+                <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="remove_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="label">gtk-remove</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-2</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkButton" id="add_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="has_default">True</property>
+                <property name="label">gtk-add</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-5</property>
+              </widget>
+              <packing>
+                <property name="position">2</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/PicasaWebExport/google-sharp/AlbumAccess.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/AlbumAccess.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,36 @@
+//
+// Mono.Google.Picasa.AlbumAccess.cs:
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+//
+
+// 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.Google.Picasa {
+	public enum AlbumAccess {
+		Public,
+		Private
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/AssemblyInfo.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/AssemblyInfo.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,36 @@
+// AssemblyInfo.cs for Mono.Google.dll
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//
+// Copyright (c) 2006 Novell, Inc. (http://www.novell.com)
+//
+// 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.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyVersion("0.1.0")]
+[assembly: AssemblyTitle ("Mono.Google")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyCopyright ("(c) 2006 Novell, Inc.")]
+[assembly: AssemblyCompany ("Novell, Inc.")]
+

Added: trunk/extensions/PicasaWebExport/google-sharp/Authentication.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/Authentication.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,158 @@
+//
+// Mono.Google.Authentication.cs:
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//	Stephane Delcroix (stephane delcroix org)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+// (C) Copyright 2007 S. Delcroix
+//
+
+// 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.
+//
+// Check the Google Authentication Page at http://code.google.com/apis/accounts/AuthForInstalledApps.html
+//
+
+using System;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Web;
+
+namespace Mono.Google {
+	class Authentication {
+		static string client_login_url = "https://www.google.com/accounts/ClientLogin";;
+
+		public static string GetAuthorization (GoogleConnection conn, string email, string password,
+				GoogleService service, string token, string captcha)
+		{
+			if (email == null || email == String.Empty || password == null || password == String.Empty)
+				return null;
+
+			email = HttpUtility.UrlEncode (email);
+			password = HttpUtility.UrlEncode (password);
+			string appname = HttpUtility.UrlEncode (conn.ApplicationName);
+			string service_code = service.ServiceCode;
+
+			StringBuilder content = new StringBuilder ();
+			content.Append ("accountType=HOSTED_OR_GOOGLE");
+			content.AppendFormat ("&Email={0}", email);
+			content.AppendFormat ("&Passwd={0}", password);
+			content.AppendFormat ("&email={0}", email);
+			content.AppendFormat ("&service={0}", service_code);
+			content.AppendFormat ("&source={0}", appname);
+
+			if (token != null) {
+				content.AppendFormat ("&logintoken={0}", token);
+				content.AppendFormat ("&logincaptcha={0}", captcha);
+			}
+			byte [] bytes = Encoding.UTF8.GetBytes (content.ToString ());
+
+			HttpWebRequest request = (HttpWebRequest) WebRequest.Create (client_login_url);
+			request.Method = "POST";
+			request.ContentType = "application/x-www-form-urlencoded";
+			request.ContentLength = bytes.Length;
+
+			Stream output = request.GetRequestStream ();
+			output.Write (bytes, 0, bytes.Length);
+			output.Close ();
+
+			HttpWebResponse response = null;
+			try {
+				response = (HttpWebResponse) request.GetResponse ();
+			} catch (WebException wexc) {
+				response = wexc.Response as HttpWebResponse;
+				if (response == null)
+					throw;
+				ThrowOnError (response);
+				throw; // if the method above does not throw, we do
+			}
+
+			//string sid = null;
+			//string lsid = null;
+			string auth = null;
+
+			using (Stream stream = response.GetResponseStream ()) {
+				StreamReader sr = new StreamReader (stream, Encoding.UTF8);
+				string s;
+				while ((s = sr.ReadLine ()) != null) {
+					if (s.StartsWith ("Auth="))
+						auth = s.Substring (5);	
+					//else if (s.StartsWith ("LSID="))
+					//	lsid = s.Substring (5);
+					//else if (s.StartsWith ("SID="))
+					//	sid = s.Substring (4);
+				}
+			}
+			response.Close ();
+
+			return auth;
+		}
+
+		static void ThrowOnError (HttpWebResponse response)
+		{
+			if (response.StatusCode != HttpStatusCode.Forbidden)
+				return;
+
+			string url = null;
+			string token = null;
+			string captcha_url = null;
+			string code = null;
+			using (StreamReader reader = new StreamReader (response.GetResponseStream ())) {
+				string str;
+				while ((str = reader.ReadLine ()) != null) {
+					if (str.StartsWith ("Url=")) {
+						url = str.Substring (4);
+					} else if (str.StartsWith ("Error=")) {
+						/* These are the values for Error
+							None,
+							BadAuthentication,
+							NotVerified,
+							TermsNotAgreed,
+							CaptchaRequired,
+							Unknown,
+							AccountDeleted,
+							AccountDisabled,
+							ServiceUnavailable
+						*/
+						code = str.Substring (6);
+					} else if (str.StartsWith ("CaptchaToken=")) {
+						token = str.Substring (13);
+					} else if (str.StartsWith ("CaptchaUrl=")) {
+						captcha_url = str.Substring (11);
+					}
+				}
+			}
+			if (code == "CaptchaRequired" && token != null && captcha_url != null) {
+				if (url != null) {
+					Uri uri = new Uri (url);
+					captcha_url = new Uri (uri, captcha_url).ToString ();
+				} else if (!captcha_url.StartsWith ("https://";)) {
+					captcha_url = "https://www.google.com/accounts/"; + captcha_url;
+				}
+				throw new CaptchaException (url, token, captcha_url);
+			}
+
+			throw new UnauthorizedAccessException (String.Format ("Access to '{0}' is denied ({1})", url, code));
+		}
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/CaptchaException.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/CaptchaException.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,87 @@
+//
+// Mono.Google.CaptchaException
+//
+// Authors:
+// 	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2006 Novell, Inc.  (http://www.novell.com)
+//
+// 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.Runtime.Serialization;
+
+namespace Mono.Google {
+	[Serializable]
+	public class CaptchaException : UnauthorizedAccessException, ISerializable
+	{
+		public static string UnlockCaptchaURL = "https://www.google.com/accounts/DisplayUnlockCaptcha";;
+		string url;
+		string token;
+		string captcha_url;
+
+		public CaptchaException ()
+		{
+		}
+
+		public CaptchaException (string url, string token, string captcha_url)
+		{
+			this.url = url;
+			this.token = token;
+			this.captcha_url = captcha_url;
+		}
+
+		protected CaptchaException (SerializationInfo info, StreamingContext context)
+			: base (info, context)
+		{
+			if (info == null)
+				throw new ArgumentNullException ("info");
+
+			url = info.GetString ("url");
+			token = info.GetString ("token");
+			captcha_url = info.GetString ("captcha_url");
+		}
+
+		void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
+		{
+			if (info == null)
+				throw new ArgumentNullException ("info");
+
+			base.GetObjectData (info, context);
+			info.AddValue ("url", url);
+			info.AddValue ("token", token);
+			info.AddValue ("captcha_url", captcha_url);
+		}
+
+		public string Url {
+			get { return url; }
+		}
+
+		public string Token {
+			get { return token; }
+		}
+
+		public string CaptchaUrl {
+			get { return captcha_url; }
+		}
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/CreateAlbumException.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/CreateAlbumException.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,44 @@
+//
+// Mono.Google.Picasa.CreateAlbumException.cs:
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+//
+
+// 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.Runtime.Serialization;
+namespace Mono.Google.Picasa {
+	public class CreateAlbumException : Exception {
+		public CreateAlbumException (string msg) : base (msg)
+		{
+		}
+
+		protected CreateAlbumException (SerializationInfo info, StreamingContext context)
+			: base (info, context)
+		{
+		}
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/DeleteAlbumException.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/DeleteAlbumException.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,44 @@
+//
+// Mono.Google.Picasa.DeleteAlbumException.cs:
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+//
+
+// 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.Runtime.Serialization;
+namespace Mono.Google.Picasa {
+	public class DeleteAlbumException : Exception {
+		public DeleteAlbumException (string msg) : base (msg)
+		{
+		}
+
+		protected DeleteAlbumException (SerializationInfo info, StreamingContext context)
+			: base (info, context)
+		{
+		}
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/GDataApi.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/GDataApi.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,92 @@
+/*
+ * Mono.Google.Picasa.GDataApi.cs
+ *
+ * Author(s):
+ *   Stephane Delcroix  <stephane delcroix org>
+ *
+ * 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.
+ *
+ * Check Picasa Web Albums Data Api at http://code.google.com/apis/picasaweb/gdata.html
+ *
+ */
+
+
+namespace Mono.Google.Picasa {
+	class GDataApi {
+		private const string feed = "http://picasaweb.google.com/data/feed/api/";;
+		private const string entry = "http://picasaweb.google.com/data/entry/api/";;
+		const string gallery = "user/{userid}?kind=album";
+		const string album_by_id = "user/{userid}/albumid/{aid}?kind=photo";
+		//const string album_by_name = entry + "user/{userid}/album/{aname}?kind=photo";
+		const string picture_by_id = "user/{userid}/albumid/{aid}/photoid/{pid}";
+		const string post_url = feed + "user/{userid}";
+		const string post_picture = feed + "user/{userid}/albumid/{aid}";
+		const string date_format = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.000Z'";
+
+		public static string GetGalleryFeed (string user)
+		{
+			return feed + gallery.Replace ("{userid}", user);
+		}
+
+		public static string GetGalleryEntry (string user)
+		{
+			return entry + gallery.Replace ("{userid}", user);
+		}
+
+		public static string GetAlbumFeedById (string user, string aid)
+		{
+			return feed + album_by_id.Replace ("{userid}", user).Replace ("{aid}", aid);
+		}
+
+		public static string GetAlbumEntryById (string user, string aid)
+		{
+			return entry + album_by_id.Replace ("{userid}", user).Replace ("{aid}", aid);
+		}
+
+		//public static string GetAlbumByName (string user, string aname)
+		//{
+		//	return album_by_name.Replace ("{userid}", user).Replace ("{aname}", aname);
+		//}
+
+		public static string GetPictureEntry (string user, string aid, string pid)
+		{
+			return entry + picture_by_id.Replace ("{userid}", user).Replace ("{aid}", aid).Replace ("{pid}", pid);
+		}
+
+		public static string GetPictureFeed (string user, string aid, string pid)
+		{
+			return feed + picture_by_id.Replace ("{userid}", user).Replace ("{aid}", aid).Replace ("{pid}", pid);
+		}
+
+		public static string GetPostURL (string user)
+		{
+			return post_url.Replace ("{userid}", user);
+		}
+		
+		public static string GetURLForUpload (string user, string aid)
+		{
+			return post_picture.Replace ("{userid}", user).Replace ("{aid}", aid);
+		}
+
+		public static string DateFormat {
+			get { return date_format; }
+		}
+	}
+}

Added: trunk/extensions/PicasaWebExport/google-sharp/GoogleConnection.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/GoogleConnection.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,212 @@
+//
+// Mono.Google.GoogleConnection.cs:
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//	Stephane Delcroix (stephane delcroix org)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+// (C) Copyright 2007 S. Delcroix
+//
+
+// 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.
+//
+// Check the Google Authentication Page at http://code.google.com/apis/accounts/AuthForInstalledApps.html
+//
+
+using System;
+using System.Globalization;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Reflection;
+
+namespace Mono.Google {
+	public class GoogleConnection {
+		string user;
+		GoogleService service;
+		string auth;
+		string appname;
+
+		public GoogleConnection (GoogleService service)
+		{
+			this.service = service;
+		}
+
+		public string ApplicationName {
+			get {
+				if (appname == null) {
+					Assembly assembly = Assembly.GetEntryAssembly ();
+					if (assembly == null)
+						throw new InvalidOperationException ("You need to set GoogleConnection.ApplicationName.");
+					AssemblyName aname = assembly.GetName ();
+					appname = String.Format ("{0}-{1}", aname.Name, aname.Version);
+				}
+
+				return appname;
+			}
+
+			set {
+				if (value == null || value == "")
+					throw new ArgumentException ("Cannot be null or empty", "value");
+
+				appname = value;
+			}
+		}
+
+		public void Authenticate (string user, string password)
+		{
+			if (user == null)
+				throw new ArgumentNullException ("user");
+
+			if (this.user != null)
+				throw new InvalidOperationException (String.Format ("Already authenticated for {0}", this.user));
+
+			this.user = user;
+			this.auth = Authentication.GetAuthorization (this, user, password, service, null, null);
+			if (this.auth == null) {
+				this.user = null;
+				throw new Exception (String.Format ("Authentication failed for user {0}", user));
+			}
+		}
+
+		public void Authenticate (string user, string password, string token, string captcha)
+		{
+			if (user == null)
+				throw new ArgumentNullException ("user");
+
+			if (token == null)
+				throw new ArgumentNullException ("token");
+
+			if (captcha == null)
+				throw new ArgumentNullException ("captcha");
+
+			if (this.user != null)
+				throw new InvalidOperationException (String.Format ("Already authenticated for {0}", this.user));
+
+			this.user = user;
+			this.auth = Authentication.GetAuthorization (this, user, password, service, token, captcha);
+			if (this.auth == null) {
+				this.user = null;
+				throw new Exception (String.Format ("Authentication failed for user {0}", user));
+			}
+		}
+
+		public HttpWebRequest AuthenticatedRequest (string url)
+		{
+			if (url == null)
+				throw new ArgumentNullException ("url");
+
+			HttpWebRequest req = (HttpWebRequest) WebRequest.Create (url);
+			if (auth != null)
+				req.Headers.Add ("Authorization: GoogleLogin auth=" + auth);
+			return req;
+		}
+
+		public string DownloadString (string url)
+		{
+			if (url == null)
+				throw new ArgumentNullException ("url");
+
+			string received = null;
+			HttpWebRequest req = AuthenticatedRequest (url);
+			HttpWebResponse response = (HttpWebResponse) req.GetResponse ();
+			Encoding encoding = Encoding.UTF8;
+			if (response.ContentEncoding != "") {
+				try {
+					encoding = Encoding.GetEncoding (response.ContentEncoding);
+				} catch {}
+			}
+
+			using (Stream stream = response.GetResponseStream ()) {
+				StreamReader sr = new StreamReader (stream, encoding);
+				received = sr.ReadToEnd ();
+			}
+			response.Close ();
+			return received;
+		}
+
+		public byte [] DownloadBytes (string url)
+		{
+			if (url == null)
+				throw new ArgumentNullException ("url");
+
+			HttpWebRequest req = AuthenticatedRequest (url);
+			HttpWebResponse response = (HttpWebResponse) req.GetResponse ();
+			byte [] bytes = null;
+			using (Stream stream = response.GetResponseStream ()) {
+				if (response.ContentLength != -1) {
+					bytes = new byte [response.ContentLength];
+					stream.Read (bytes, 0, bytes.Length);
+				} else {
+					MemoryStream ms = new MemoryStream ();
+					bytes = new byte [4096];
+					int nread;
+					while ((nread = stream.Read (bytes, 0, bytes.Length)) > 0) {
+						ms.Write (bytes, 0, nread);
+						if (nread < bytes.Length)
+							break;
+					}
+					bytes = ms.ToArray ();
+				}
+			}
+			response.Close ();
+
+			return bytes;
+		}
+
+		public void DownloadToStream (string url, Stream output)
+		{
+			if (url == null)
+				throw new ArgumentNullException ("url");
+
+			if (output == null)
+				throw new ArgumentNullException ("output");
+
+			if (!output.CanWrite)
+				throw new ArgumentException ("The stream is not writeable", "output");
+
+			HttpWebRequest req = AuthenticatedRequest (url);
+			HttpWebResponse response = (HttpWebResponse) req.GetResponse ();
+			byte [] bytes = null;
+			using (Stream stream = response.GetResponseStream ()) {
+				bytes = new byte [4096];
+				int nread;
+				while ((nread = stream.Read (bytes, 0, bytes.Length)) > 0) {
+					output.Write (bytes, 0, nread);
+				}
+			}
+			response.Close ();
+		}
+
+		public string User {
+			get { return user; }
+		}
+
+		public GoogleService Service {
+			get { return service; }
+		}
+
+		internal string AuthToken {
+			get { return auth; }
+		}
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/GoogleService.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/GoogleService.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,54 @@
+//
+// Mono.Google.GoogleService.cs:
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//	Stephane Delcroix  (stephane delcroix org)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+// (C) Copyright 2007 S. Delcroix
+//
+
+// 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.Google {
+	public class GoogleService {
+		public static GoogleService Picasa {
+			get { return new GoogleService ("lh2"); }
+		}
+
+		public static GoogleService Calendar {
+			get { return new GoogleService ("cl"); }
+		}
+
+		string service_code;
+		public string ServiceCode {
+			get { return service_code; }
+		}
+
+		private GoogleService (string service_code)
+		{
+			this.service_code = service_code;
+		}
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/Makefile.am	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,45 @@
+include $(top_srcdir)/Makefile.include
+
+ASSEMBLY_NAME = Mono.Google
+
+ASSEMBLY_SOURCES =				\
+	$(srcdir)/AlbumAccess.cs  		\
+	$(srcdir)/AssemblyInfo.cs 		\
+	$(srcdir)/Authentication.cs  		\
+	$(srcdir)/CaptchaException.cs  		\
+	$(srcdir)/CreateAlbumException.cs  	\
+	$(srcdir)/DeleteAlbumException.cs  	\
+	$(srcdir)/GDataApi.cs  			\
+	$(srcdir)/GoogleConnection.cs  		\
+	$(srcdir)/GoogleService.cs  		\
+	$(srcdir)/MultipartRequest.cs  		\
+	$(srcdir)/NoCheckCertificatePolicy.cs  	\
+	$(srcdir)/PicasaAlbum.cs  		\
+	$(srcdir)/PicasaAlbumCollection.cs  	\
+	$(srcdir)/PicasaPicture.cs  		\
+	$(srcdir)/PicasaPictureCollection.cs  	\
+	$(srcdir)/PicasaWeb.cs  		\
+	$(srcdir)/UploadPictureException.cs 	\
+	$(srcdir)/UploadProgressEventArgs.cs  	\
+	$(srcdir)/UploadProgressEventHandler.cs \
+	$(srcdir)/XmlUtil.cs
+
+REFS = -r:System.Web
+
+PKGS =
+
+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)
+
+CLEANFILES =			\
+	$(ASSEMBLY)		\
+	$(ASSEMBLY).mdb

Added: trunk/extensions/PicasaWebExport/google-sharp/MultipartRequest.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/MultipartRequest.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,163 @@
+//
+// Mono.Google.MultipartRequest
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//	Stephane Delcroix (stephane delcroix org)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+// (C) Copyright 2007 S. Delcroix
+//
+
+// 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.Globalization;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Xml;
+
+namespace Mono.Google {
+	class MultipartRequest {
+		static byte [] crlf = new byte [] { 13, 10 };
+		HttpWebRequest request;
+		Stream output_stream;
+		const string separator_string = "PART_SEPARATOR";
+		const string separator = "--" + separator_string + "\r\n";
+		const string separator_end = "--" + separator_string + "--\r\n";
+		byte [] separator_bytes = Encoding.ASCII.GetBytes (separator);
+		byte [] separator_end_bytes = Encoding.ASCII.GetBytes (separator_end);
+		bool output_set;
+
+		public MultipartRequest (GoogleConnection conn, string url)
+		{
+			request = conn.AuthenticatedRequest (url);
+			request.Method = "POST";
+			request.ContentType = "multipart/related; boundary=\"" + separator_string + "\"";
+			request.Headers.Add ("MIME-version", "1.0");
+		}
+
+		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;
+			if (output_stream == null)
+				output_stream = request.GetRequestStream ();
+
+			string multipart = "Media multipart posting\r\n";
+			byte [] multipart_bytes = Encoding.ASCII.GetBytes (multipart);
+			output_stream.Write (multipart_bytes, 0, multipart_bytes.Length);
+			output_stream.Write (separator_bytes, 0, separator_bytes.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}"), 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);
+			output_stream.Write (bytes, 0, bytes.Length);
+			if (need_crlf)
+				output_stream.Write (crlf, 0, 2);
+			if (last)
+				output_stream.Write (crlf, 0, 2);
+		}
+
+		public void WriteContent (string content)
+		{
+			WriteContent (Encoding.UTF8.GetBytes (content));
+		}
+
+		public void WriteContent (byte [] content)
+		{
+			output_stream.Write (content, 0, content.Length);
+			output_stream.Write (crlf, 0, crlf.Length);
+		}
+
+		public void WritePartialContent (byte [] content, int offset, int nbytes)
+		{
+			output_stream.Write (content, offset, nbytes);
+		}
+
+		public void EndPartialContent ()
+		{
+			output_stream.Write (crlf, 0, crlf.Length);
+		}
+
+		public void EndPart (bool last)
+		{
+			if (last) {
+				output_stream.Write (separator_end_bytes, 0, separator_end_bytes.Length);
+				if (!output_set)
+					output_stream.Close ();
+			} else {
+				output_stream.Write (separator_bytes, 0, separator_bytes.Length);
+			}
+		}
+
+		public string GetResponseAsString ()
+		{
+			HttpWebResponse response = null;
+			response = (HttpWebResponse) request.GetResponse ();
+			string received = "";
+			// FIXME: use CharacterSet?
+			using (Stream stream = response.GetResponseStream ()) {
+				StreamReader sr = new StreamReader (stream, Encoding.UTF8);
+				received = sr.ReadToEnd ();
+			}
+			response.Close ();
+			return received;
+		}
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/NoCheckCertificatePolicy.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/NoCheckCertificatePolicy.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,41 @@
+//
+// Mono.Google.NoCheckCertificatePolicy
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+//
+
+// 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;
+
+namespace Mono.Google {
+	public class NoCheckCertificatePolicy : ICertificatePolicy {
+		public bool CheckValidationResult (ServicePoint a, X509Certificate b, WebRequest c, int d)
+		{
+			return true;
+		}
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/PicasaAlbum.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/PicasaAlbum.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,338 @@
+//
+// Mono.Google.Picasa.PicasaAlbum.cs:
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//	Stephane Delcroix (stephane delcroix org)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+// (C) Copyright 2007 S. Delcroix
+//
+
+// 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.IO;
+using System.Net;
+using System.Text;
+using System.Xml;
+
+namespace Mono.Google.Picasa {
+	public class PicasaAlbum {
+		GoogleConnection conn;
+		string user;
+		string title;
+		string description;
+		string id;
+		string link;
+		string authkey = null;
+		AlbumAccess access = AlbumAccess.Public;
+		int num_photos = -1;
+		int num_photos_remaining = -1;
+		long bytes_used = -1;
+
+		private PicasaAlbum (GoogleConnection conn)
+		{
+			if (conn == null)
+				throw new ArgumentNullException ("conn");
+
+			this.conn = conn;	
+		}
+
+		public PicasaAlbum (GoogleConnection conn, string aid) : this (conn)
+		{
+			if (conn.User == null)
+				throw new ArgumentException ("Need authentication before being used.", "conn");
+
+			if (aid == null || aid == String.Empty)
+				throw new ArgumentNullException ("aid");			
+
+			this.user = conn.User;
+			this.id = aid;
+
+			string received = conn.DownloadString (GDataApi.GetAlbumEntryById (conn.User, aid));
+			XmlDocument doc = new XmlDocument ();
+			doc.LoadXml (received);
+			XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
+			XmlUtil.AddDefaultNamespaces (nsmgr);
+			XmlNode entry = doc.SelectSingleNode ("atom:entry", nsmgr);
+			ParseAlbum (entry, nsmgr);
+		}
+
+		public PicasaAlbum (GoogleConnection conn, string user, string aid, string authkey) : this (conn)
+		{
+			if (user == null || user == String.Empty)
+				throw new ArgumentNullException ("user");
+
+			if (aid == null || aid == String.Empty)
+				throw new ArgumentNullException ("aid");			
+
+			this.user = user;
+			this.id = aid;
+			this.authkey = authkey;
+
+			string download_link = GDataApi.GetAlbumEntryById (user, id);
+			if (authkey != null && authkey != "")
+				download_link += "&authkey=" + authkey;
+			string received = conn.DownloadString (download_link);
+
+			XmlDocument doc = new XmlDocument ();
+			doc.LoadXml (received);
+			XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
+			XmlUtil.AddDefaultNamespaces (nsmgr);
+			XmlNode entry = doc.SelectSingleNode ("atom:entry", nsmgr);
+			ParseAlbum (entry, nsmgr);
+		}
+
+		internal PicasaAlbum (GoogleConnection conn, string user, XmlNode nodeitem, XmlNamespaceManager nsmgr) : this (conn)
+		{
+			this.user = user ?? conn.User;
+
+			ParseAlbum (nodeitem, nsmgr);
+		}
+
+
+		private void ParseAlbum (XmlNode nodeitem, XmlNamespaceManager nsmgr)
+		{
+
+			title = nodeitem.SelectSingleNode ("atom:title", nsmgr).InnerText;
+			description = nodeitem.SelectSingleNode ("media:group/media:description", nsmgr).InnerText;
+			XmlNode node = nodeitem.SelectSingleNode ("gphoto:id", nsmgr);
+			if (node != null)
+				id = node.InnerText;
+
+			foreach (XmlNode xlink in nodeitem.SelectNodes ("atom:link", nsmgr)) {
+				if (xlink.Attributes.GetNamedItem ("rel").Value == "alternate") {
+					link = xlink.Attributes.GetNamedItem ("href").Value;
+					break;
+				}
+			}
+			node = nodeitem.SelectSingleNode ("gphoto:access", nsmgr);
+			if (node != null) {
+				string acc = node.InnerText;
+				access = (acc == "public") ? AlbumAccess.Public : AlbumAccess.Private;
+			}
+			node = nodeitem.SelectSingleNode ("gphoto:numphotos", nsmgr);
+			if (node != null)
+				num_photos = (int) UInt32.Parse (node.InnerText);
+
+			node = nodeitem.SelectSingleNode ("gphoto:numphotosremaining", nsmgr);
+			if (node != null)
+				num_photos_remaining = (int) UInt32.Parse (node.InnerText);
+			node = nodeitem.SelectSingleNode ("gphoto:bytesused", nsmgr);
+			if (node != null)
+				bytes_used = (long) UInt64.Parse (node.InnerText);
+		}
+
+		public PicasaPictureCollection GetPictures ()
+		{
+
+			string download_link = GDataApi.GetAlbumFeedById (user, id);
+			if (authkey != null && authkey != "")
+				download_link += "&authkey=" + authkey;
+			string received = conn.DownloadString (download_link);
+			XmlDocument doc = new XmlDocument ();
+			doc.LoadXml (received);
+			XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
+			XmlUtil.AddDefaultNamespaces (nsmgr);
+			XmlNode feed = doc.SelectSingleNode ("atom:feed", nsmgr);
+			PicasaPictureCollection coll = new PicasaPictureCollection ();
+			foreach (XmlNode item in feed.SelectNodes ("atom:entry", nsmgr)) {
+				coll.Add (new PicasaPicture (conn, this, item, nsmgr));
+			}
+			coll.SetReadOnly ();
+			return coll;
+		}
+
+		/* from http://code.google.com/apis/picasaweb/gdata.html#Add_Photo
+		<entry xmlns='http://www.w3.org/2005/Atom'>
+		  <title>darcy-beach.jpg</title>
+		  <summary>Darcy on the beach</summary>
+		  <category scheme="http://schemas.google.com/g/2005#kind";
+		    term="http://schemas.google.com/photos/2007#photo"/>
+		</entry>
+		*/
+
+		static string GetXmlForUpload (string title, string description)
+		{
+			XmlUtil xml = new XmlUtil ();
+			xml.WriteElementString ("title", title);	
+			xml.WriteElementString ("summary", description);
+			xml.WriteElementStringWithAttributes ("category", null,
+					"scheme", "http://schemas.google.com/g/2005#kind";, 
+					"term", "http://schemas.google.com/photos/2007#photo";);
+			return xml.GetDocumentString ();
+		}
+
+		public PicasaPicture UploadPicture (string title, Stream input)
+		{
+			return UploadPicture (title, null, input);
+		}
+
+		public PicasaPicture UploadPicture (string title, string description, Stream input)
+		{
+			return UploadPicture (title, description, "image/jpeg", input);
+		}
+
+		public PicasaPicture UploadPicture (string title, string description, string mime_type, Stream input)
+		{
+			if (title == null)
+				throw new ArgumentNullException ("title");
+
+			if (input == null)
+				throw new ArgumentNullException ("input");
+
+			if (!input.CanRead)
+				throw new ArgumentException ("Cannot read from stream", "input");
+
+			string url = GDataApi.GetURLForUpload (conn.User, id);
+			if (url == null)
+				throw new UnauthorizedAccessException ("You are not authorized to upload to this album.");
+
+			MultipartRequest request = new MultipartRequest (conn, url);
+			MemoryStream ms = null;
+			if (UploadProgress != null) {
+				// We do 'manual' buffering
+				request.Request.AllowWriteStreamBuffering = false;
+				ms = new MemoryStream ();
+				request.OutputStream = ms;
+			}
+
+			request.BeginPart (true);
+			request.AddHeader ("Content-Type: application/atom+xml; \r\n", true);
+			string upload = GetXmlForUpload (title, description);
+			request.WriteContent (upload);
+			request.EndPart (false);
+			request.BeginPart ();
+			request.AddHeader ("Content-Type: " + mime_type + "\r\n", true);
+
+			byte [] data = new byte [8192];
+			int nread;
+			while ((nread = input.Read (data, 0, data.Length)) > 0) {
+				request.WritePartialContent (data, 0, nread);
+			}
+			request.EndPartialContent ();
+			request.EndPart (true); // It won't call Close() on the MemoryStream
+
+			if (UploadProgress != null) {
+				int req_length = (int) ms.Length;
+				request.Request.ContentLength = req_length;
+				DoUploadProgress (title, 0, req_length);
+				using (Stream req_stream = request.Request.GetRequestStream ()) {
+					byte [] buffer = ms.GetBuffer ();
+					int nwrite = 0;
+					int offset;
+					for (offset = 0; offset < req_length; offset += nwrite) {
+						nwrite = System.Math.Min (16384, req_length - offset);
+						req_stream.Write (buffer, offset, nwrite);
+						// The progress uses the actual request size, not file size.
+						DoUploadProgress (title, offset, req_length);
+					}
+					DoUploadProgress (title, offset, req_length);
+
+				}
+			}
+
+			string received = request.GetResponseAsString ();
+			XmlDocument doc = new XmlDocument ();
+			doc.LoadXml (received);
+			XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
+			XmlUtil.AddDefaultNamespaces (nsmgr);
+			XmlNode entry = doc.SelectSingleNode ("atom:entry", nsmgr);
+
+			return new PicasaPicture (conn, this, entry, nsmgr);
+		}
+
+		public PicasaPicture UploadPicture (string filename)
+		{
+			return UploadPicture (filename, "");
+		}
+
+		public PicasaPicture UploadPicture (string filename, string description)
+		{
+			return UploadPicture (filename, Path.GetFileName (filename), description);
+		}
+
+		public PicasaPicture UploadPicture (string filename, string title, string description)
+		{
+			if (filename == null)
+				throw new ArgumentNullException ("filename");
+
+			if (title == null)
+				throw new ArgumentNullException ("title");
+
+			using (Stream stream = File.OpenRead (filename)) {
+				return UploadPicture (title, description, stream);
+			}
+		}
+
+		public string Title {
+			get { return title; }
+		}
+
+		public string Description {
+			get { return description; }
+		}
+
+		public string Link {
+			get { return link; }
+		}
+
+		public string UniqueID {
+			get { return id; }
+		}
+
+		public AlbumAccess Access {
+			get { return access; }
+		}
+
+		public int PicturesCount {
+			get { return num_photos; }
+		}
+
+		public int PicturesRemaining {
+			get { return num_photos_remaining; }
+		}
+
+		public string User {
+			get { return user; }
+		}
+
+		public long BytesUsed {
+			get { return bytes_used; }
+		}
+
+		internal GoogleConnection Connection {
+			get { return conn; }
+		}
+
+		void DoUploadProgress (string title, long sent, long total)
+		{
+			if (UploadProgress != null) {
+				UploadProgress (this, new UploadProgressEventArgs (title, sent, total));
+			}
+		}
+
+		public event UploadProgressEventHandler UploadProgress;
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/PicasaAlbumCollection.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/PicasaAlbumCollection.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,92 @@
+//
+// Mono.Google.Picasa.PicasaAlbumCollection
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+
+//
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+//
+// 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.Specialized;
+
+namespace Mono.Google.Picasa {
+	public sealed class PicasaAlbumCollection : NameObjectCollectionBase {
+		internal PicasaAlbumCollection ()
+		{
+		}
+
+		internal void Add (PicasaAlbum album)
+		{
+			if (BaseGet (album.UniqueID) != null)
+				throw new Exception ("Duplicate album?");
+
+			BaseAdd (album.UniqueID, album);
+		}
+
+		internal void SetReadOnly ()
+		{
+			IsReadOnly = true;
+		}
+
+		public PicasaAlbum GetByTitle (string title)
+		{
+			if (title == null)
+				throw new ArgumentNullException ("id");
+
+			int count = Count;
+			for (int i = 0; i < count; i++) {
+				if (this [i].Title == title)
+					return this [i];
+			}
+
+			return null;
+		}
+
+		public PicasaAlbum this [int index] {
+			get { return (PicasaAlbum) BaseGet (index); }
+		}
+
+		public PicasaAlbum this [string uniqueID] {
+			get { return (PicasaAlbum) BaseGet (uniqueID); }
+		}
+
+		public string [] AllKeys {
+			get {
+				NameObjectCollectionBase.KeysCollection keys = Keys;
+				int count = keys.Count;
+				string [] result = new string [count];
+				for (int i = 0; i < count; i++)
+					result [i] = keys [i];
+				
+				return result;
+			}
+		}
+
+		public PicasaAlbum [] AllValues {
+			get { return (PicasaAlbum []) BaseGetAllValues (typeof (PicasaAlbum)); }
+		}
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/PicasaPicture.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/PicasaPicture.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,205 @@
+//
+// Mono.Google.Picasa.PicasaPicture.cs:
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//	Stephane Delcroix (stephane delcroix org)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+// (C) Copyright 2007 S. Delcroix
+//
+
+// 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.Net;
+using System.Text;
+using System.Xml;
+using System.Globalization;
+
+namespace Mono.Google.Picasa {
+	public class PicasaPicture {
+		GoogleConnection conn;
+		PicasaAlbum album;
+		string title;
+		string description;
+		DateTime pub_date;
+		string thumbnail_url;
+		string image_url;
+		int width;
+		int height;
+		int index;
+		string id;
+		string link;
+		string tags;
+
+		internal PicasaPicture (GoogleConnection conn, PicasaAlbum album, XmlNode nodeitem, XmlNamespaceManager nsmgr)
+		{
+			this.conn = conn;
+			this.album = album;
+			ParsePicture (nodeitem, nsmgr);
+		}
+
+		public PicasaPicture (GoogleConnection conn, string aid, string pid)
+		{
+			if (conn == null)
+				throw new ArgumentNullException ("conn");
+			if (conn.User == null)
+				throw new ArgumentException ("Need authentication before being used.", "conn");
+			this.conn = conn;
+
+			if (aid == null || aid == String.Empty)
+				throw new ArgumentNullException ("aid");			
+			this.album = new PicasaAlbum (conn, aid);
+
+			if (pid == null || pid == String.Empty)
+				throw new ArgumentNullException ("pid");			
+
+			string received = conn.DownloadString (GDataApi.GetPictureEntry (conn.User, aid, pid));
+			XmlDocument doc = new XmlDocument ();
+			doc.LoadXml (received);
+			XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
+			XmlUtil.AddDefaultNamespaces (nsmgr);
+			XmlNode entry = doc.SelectSingleNode ("atom:entry", nsmgr);
+			ParsePicture (entry, nsmgr);
+		}
+
+		private void ParsePicture (XmlNode nodeitem, XmlNamespaceManager nsmgr)
+		{
+			title = nodeitem.SelectSingleNode ("atom:title", nsmgr).InnerText;
+			foreach (XmlNode xlink in nodeitem.SelectNodes ("atom:link", nsmgr)) {
+				if (xlink.Attributes.GetNamedItem ("rel").Value == "alternate") {
+					link = xlink.Attributes.GetNamedItem ("href").Value;
+					break;
+				}
+			}
+			description = nodeitem.SelectSingleNode ("media:group/media:description", nsmgr).InnerText;
+			CultureInfo info = CultureInfo.InvariantCulture;
+			pub_date = DateTime.ParseExact (nodeitem.SelectSingleNode ("atom:published", nsmgr).InnerText, GDataApi.DateFormat, info);
+			thumbnail_url = nodeitem.SelectSingleNode ("media:group/media:thumbnail", nsmgr).Attributes.GetNamedItem ("url").Value;
+			image_url = nodeitem.SelectSingleNode ("media:group/media:content", nsmgr).Attributes.GetNamedItem ("url").Value;
+			width = (int) UInt32.Parse (nodeitem.SelectSingleNode ("gphoto:width", nsmgr).InnerText);
+			height = (int) UInt32.Parse (nodeitem.SelectSingleNode ("gphoto:height", nsmgr).InnerText);
+
+			XmlNode node = nodeitem.SelectSingleNode ("gphoto:index", nsmgr);
+			index = (node != null) ? (int) UInt32.Parse (node.InnerText) : -1;
+			node = nodeitem.SelectSingleNode ("gphoto:id", nsmgr);
+			id = (node != null) ? node.InnerText : "auto" + title.GetHashCode ().ToString ();
+			tags = nodeitem.SelectSingleNode ("media:group/media:keywords", nsmgr).InnerText;
+		}
+
+		static string GetXmlForTagging (string tag)
+		{
+			XmlUtil xml = new XmlUtil ();
+			xml.WriteElementString ("title", tag);
+			xml.WriteElementStringWithAttributes ("category", null,
+					"scheme", "http://schemas.google.com/g/2005#kind";, 
+					"term", "http://schemas.google.com/photos/2007#tag";);
+			return xml.GetDocumentString ();
+		
+		}
+
+		public void AddTag (string tag)
+		{
+			if (tag == null)
+				throw new ArgumentNullException ("title");
+
+			string op_string = GetXmlForTagging (tag);
+			byte [] op_bytes = Encoding.UTF8.GetBytes (op_string);
+			string url = GDataApi.GetPictureFeed (conn.User, album.UniqueID, UniqueID);
+			HttpWebRequest request = conn.AuthenticatedRequest (url);
+			request.ContentType = "application/atom+xml; charset=UTF-8";
+			request.Method = "POST";
+			Stream output_stream = request.GetRequestStream ();
+			output_stream.Write (op_bytes, 0, op_bytes.Length);
+			output_stream.Close ();
+
+			HttpWebResponse response = (HttpWebResponse) request.GetResponse ();
+			string received = "";
+			using (Stream stream = response.GetResponseStream ()) {
+				StreamReader sr = new StreamReader (stream, Encoding.UTF8);
+				received = sr.ReadToEnd ();
+			}
+			response.Close ();
+	
+		}
+
+		public void DownloadToStream (Stream stream)
+		{
+			conn.DownloadToStream (image_url, stream);
+		}
+
+		public void DownloadThumbnailToStream (Stream stream)
+		{
+			conn.DownloadToStream (thumbnail_url, stream);
+		}
+
+		public PicasaAlbum Album {
+			get { return album; }
+		}
+
+		public string Title {
+			get { return title; }
+		}
+
+		public string Description {
+			get { return description; }
+		}
+
+		public DateTime Date {
+			get { return pub_date; }
+		}
+
+		public string ThumbnailURL {
+			get { return thumbnail_url; }
+		}
+
+		public string ImageURL {
+			get { return image_url; }
+		}
+
+		public int Width {
+			get { return width; }
+		}
+
+		public int Height {
+			get { return height; }
+		}
+
+		public int Index {
+			get { return index; }
+		}
+
+		public string UniqueID {
+			get { return id; }
+		}
+
+		public string Link {
+			get { return link; }
+		}
+
+		public string Tags {
+			get { return tags; }
+		}
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/PicasaPictureCollection.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/PicasaPictureCollection.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,94 @@
+//
+// Mono.Google.Picasa.PicasaPictureCollection
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+
+//
+// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
+//
+// 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.Collections.Specialized;
+
+namespace Mono.Google.Picasa {
+	public sealed class PicasaPictureCollection : NameObjectCollectionBase {
+		internal PicasaPictureCollection ()
+		{
+		}
+
+		internal void Add (PicasaPicture picture)
+		{
+			if (BaseGet (picture.UniqueID) != null)
+				throw new Exception ("Duplicate picture?");
+
+			BaseAdd (picture.UniqueID, picture);
+		}
+
+		internal void SetReadOnly ()
+		{
+			IsReadOnly = true;
+		}
+
+		public PicasaPicture GetByTitle (string title)
+		{
+			if (title == null)
+				throw new ArgumentNullException ("id");
+
+			int count = Count;
+			for (int i = 0; i < count; i++) {
+				if (this [i].Title == title)
+					return this [i];
+			}
+
+			return null;
+		}
+
+		public PicasaPicture this [int index] {
+			get { return (PicasaPicture) BaseGet (index); }
+		}
+
+		public PicasaPicture this [string uniqueID] {
+			get { return (PicasaPicture) BaseGet (uniqueID); }
+		}
+
+		public string [] AllKeys {
+			get {
+				NameObjectCollectionBase.KeysCollection keys = Keys;
+				int count = keys.Count;
+				string [] result = new string [count];
+				for (int i = 0; i < count; i++)
+					result [i] = keys [i];
+				
+				return result;
+			}
+		}
+
+		public PicasaPicture [] AllValues {
+			get { return (PicasaPicture []) BaseGetAllValues (typeof (PicasaPicture)); }
+		}
+
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/PicasaWeb.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/PicasaWeb.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,291 @@
+//
+// Mono.Google.Picasa.PicasaWeb.cs:
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//	Stephane Delcroix  (stephane delcroix org)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+// (C) Copyright 2007 S. Delcroix
+//
+
+// 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.
+//
+// Check Picasa Web Albums Data Api at http://code.google.com/apis/picasaweb/gdata.html
+//
+
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Xml;
+
+namespace Mono.Google.Picasa {
+	public class PicasaWeb {
+		GoogleConnection conn;
+		string title;
+		string user;
+		string nickname;
+		long quota_used;
+		long quota_limit;
+
+		public PicasaWeb (GoogleConnection conn) : this (conn, null)
+		{
+		}
+
+		public PicasaWeb (GoogleConnection conn, string username)
+		{
+			if (conn == null)
+				throw new ArgumentNullException ("conn");
+
+			if (conn.User == null && username == null)
+				throw new ArgumentException ("The connection should be authenticated OR you should call this constructor with a non-null username argument");
+
+			this.conn = conn;
+			this.user = username ?? conn.User;
+
+			string received = conn.DownloadString (GDataApi.GetGalleryEntry (user));
+			XmlDocument doc = new XmlDocument ();
+			doc.LoadXml (received);
+			XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
+			XmlUtil.AddDefaultNamespaces (nsmgr);
+			XmlNode entry = doc.SelectSingleNode ("atom:entry", nsmgr);
+			ParseGallery (entry, nsmgr);
+		}
+
+		public string Title {
+			get { return title; }
+		}
+
+		public string User {
+			get { return user; }
+		}
+
+		public string NickName {
+			get { return nickname; }
+		}
+
+		public long QuotaUsed {
+			get { return quota_used; }
+		}
+
+		public long QuotaLimit {
+			get { return quota_limit; }
+		}
+
+		internal GoogleConnection Connection {
+			get { return conn; }
+		}
+
+		public PicasaAlbum CreateAlbum (string title)
+		{
+			return CreateAlbum (title, null);
+		}
+
+		public PicasaAlbum CreateAlbum (string title, AlbumAccess access)
+		{
+			return CreateAlbum (title, null, access, DateTime.Now);
+		}
+
+		public PicasaAlbum CreateAlbum (string title, string description)
+		{
+			return CreateAlbum (title, description, AlbumAccess.Public);
+		}
+
+		public PicasaAlbum CreateAlbum (string title, string description, AlbumAccess access)
+		{
+			return CreateAlbum (title, description, access, DateTime.Now);
+		}
+
+		public PicasaAlbum CreateAlbum (string title, string description, AlbumAccess access, DateTime pubDate)
+		{
+			if (title == null)
+				throw new ArgumentNullException ("title");
+
+			if (description == null)
+				description = "";
+
+			if (access != AlbumAccess.Public && access != AlbumAccess.Private)
+				throw new ArgumentException ("Invalid value.", "access");
+
+			// Check if pubDate can be in the past
+			string url = GDataApi.GetPostURL (conn.User);
+			if (url == null)
+				throw new UnauthorizedAccessException ("You are not authorized to create albums.");
+			string op_string = GetXmlForCreate (title, description, pubDate, access);
+			byte [] op_bytes = Encoding.UTF8.GetBytes (op_string);
+			HttpWebRequest request = conn.AuthenticatedRequest (url);
+			request.ContentType = "application/atom+xml; charset=UTF-8";
+			request.Method = "POST";
+			Stream output_stream = request.GetRequestStream ();
+			output_stream.Write (op_bytes, 0, op_bytes.Length);
+			output_stream.Close ();
+
+			HttpWebResponse response = (HttpWebResponse) request.GetResponse ();
+			string received = "";
+			using (Stream stream = response.GetResponseStream ()) {
+				StreamReader sr = new StreamReader (stream, Encoding.UTF8);
+				received = sr.ReadToEnd ();
+			}
+			response.Close ();
+
+			XmlDocument doc = new XmlDocument ();
+			doc.LoadXml (received);
+			XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
+			XmlUtil.AddDefaultNamespaces (nsmgr);
+			XmlNode entry = doc.SelectSingleNode ("atom:entry", nsmgr);
+			return new PicasaAlbum (conn, null, entry, nsmgr);
+		}
+
+		/* (from gdata documentation...)
+		<entry xmlns='http://www.w3.org/2005/Atom'
+		    xmlns:media='http://search.yahoo.com/mrss/'
+		    xmlns:gphoto='http://schemas.google.com/photos/2007'>
+		  <title type='text'>Trip To Italy</title>
+		  <summary type='text'>This was the recent trip I took to Italy.</summary>
+		  <gphoto:location>Italy</gphoto:location>
+		  <gphoto:access>public</gphoto:access>
+		  <gphoto:commentingEnabled>true</gphoto:commentingEnabled>
+		  <gphoto:timestamp>1152255600000</gphoto:timestamp>
+		  <media:group>
+		    <media:keywords>italy, vacation</media:keywords>
+		  </media:group>
+		  <category scheme='http://schemas.google.com/g/2005#kind'
+		    term='http://schemas.google.com/photos/2007#album'></category>
+		</entry>
+		*/
+
+		private static string GetXmlForCreate (string title, string desc, DateTime date, AlbumAccess access)
+		{
+			XmlUtil xml = new XmlUtil ();
+			xml.WriteElementStringWithAttributes ("title", title, "type", "text");
+			xml.WriteElementStringWithAttributes ("summary", desc, "type", "text");
+			// location ?
+			xml.WriteElementString ("access", access.ToString ().ToLower (CultureInfo.InvariantCulture), PicasaNamespaces.GPhoto);
+			// commentingEnabled ?
+			xml.WriteElementString ("timestamp", ((long)(date - new DateTime (1970, 1, 1)).TotalSeconds * 1000).ToString (), PicasaNamespaces.GPhoto);
+			//keywords ?
+			xml.WriteElementStringWithAttributes ("category", null,
+					"scheme", "http://schemas.google.com/g/2005#kind";,
+					"term", "http://schemas.google.com/photos/2007#album";);
+
+			return xml.GetDocumentString ();
+		}
+
+		/*
+			"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" +
+			"<rss version=\"2.0\" xmlns:gphoto=\"http://www.temp.com/\";>\n" +
+			"  <channel>\n" +
+			"    <gphoto:user>{0}</gphoto:user>\n" +
+			"    <gphoto:id>{1}</gphoto:id>\n" +
+			"    <gphoto:op>deleteAlbum</gphoto:op>\n" +
+			"  </channel>\n" +
+			"</rss>";
+		*/
+
+//		static string GetXmlForDelete (string user, string aid)
+//		{
+//			XmlUtil xml = new XmlUtil ();
+//			xml.WriteElementString ("user", user, PicasaNamespaces.GPhoto);
+//			xml.WriteElementString ("id", aid, PicasaNamespaces.GPhoto);
+//			xml.WriteElementString ("op", "deleteAlbum", PicasaNamespaces.GPhoto);
+//			return xml.GetDocumentString ();
+//		}
+
+		public void DeleteAlbum (PicasaAlbum album)
+		{
+			if (album == null)
+				throw new ArgumentNullException ("album");
+
+			DeleteAlbum (album.UniqueID);
+		}
+
+		public void DeleteAlbum (string unique_id)
+		{
+	//FIXME: implement this
+			throw new System.NotImplementedException ("but I'll implemented if you say please...");
+//			if (unique_id == null)
+//				throw new ArgumentNullException ("unique_id");
+//
+//			string url = GDataApi.GetPostURL (conn.User);
+//			if (url == null)
+//				throw new UnauthorizedAccessException ("You are not authorized to delete this album.");
+//			string op_string = GetXmlForDelete (conn.User, unique_id);
+//			byte [] op_bytes = Encoding.UTF8.GetBytes (op_string);
+//			MultipartRequest request = new MultipartRequest (conn, url);
+////			request.Request.CookieContainer = conn.Cookies;
+//			request.BeginPart ();
+//			request.AddHeader ("Content-Disposition: form-data; name=\"xml\"\r\n");
+//			request.AddHeader ("Content-Type: text/plain; charset=utf8\r\n", true);
+//			request.WriteContent (op_bytes);
+//			request.EndPart (true);
+//			string received = request.GetResponseAsString ();
+//
+//			XmlDocument doc = new XmlDocument ();
+//			doc.LoadXml (received);
+//			XmlNode node = doc.SelectSingleNode ("/response/result");
+//			if (node == null)
+//				throw new DeleteAlbumException ("Invalid response from server");
+//
+//			if (node.InnerText != "success") {
+//				node = doc.SelectSingleNode ("/response/reason");
+//				if (node == null)
+//					throw new DeleteAlbumException ("Unknown reason");
+//					
+//				throw new DeleteAlbumException (node.InnerText);
+//			}
+		}
+
+		public PicasaAlbumCollection GetAlbums ()
+		{
+			string gallery_link = GDataApi.GetGalleryFeed (user);
+			string received = conn.DownloadString (gallery_link);
+
+			XmlDocument doc = new XmlDocument ();
+			doc.LoadXml (received);
+			XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
+			XmlUtil.AddDefaultNamespaces (nsmgr);
+			XmlNode feed = doc.SelectSingleNode ("atom:feed", nsmgr);
+			PicasaAlbumCollection coll = new PicasaAlbumCollection ();
+			foreach (XmlNode item in feed.SelectNodes ("atom:entry", nsmgr)) {
+				coll.Add (new PicasaAlbum (conn, user, item, nsmgr));
+			}
+			coll.SetReadOnly ();
+			return coll;
+		}
+
+		private void ParseGallery (XmlNode nodeitem, XmlNamespaceManager nsmgr)
+		{
+			XmlNode node = nodeitem.SelectSingleNode ("atom:title", nsmgr);
+			title = node.InnerText;
+			node = nodeitem.SelectSingleNode ("gphoto:user", nsmgr);
+			user = node.InnerText;
+			node = nodeitem.SelectSingleNode ("gphoto:nickname", nsmgr);
+			nickname = node.InnerText;
+			node = nodeitem.SelectSingleNode ("gphoto:quotacurrent", nsmgr);
+			quota_used = (node != null) ? (long) UInt64.Parse (node.InnerText) : -1;
+			node = nodeitem.SelectSingleNode ("gphoto:quotalimit", nsmgr);
+			quota_limit = (node != null) ? (long) UInt64.Parse (node.InnerText) : -1;
+		}
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/UploadPictureException.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/UploadPictureException.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,44 @@
+//
+// Mono.Google.Picasa.UploadPictureException.cs:
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+//
+
+// 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.Runtime.Serialization;
+namespace Mono.Google.Picasa {
+	public class UploadPictureException : Exception {
+		public UploadPictureException (string msg) : base (msg)
+		{
+		}
+
+		protected UploadPictureException (SerializationInfo info, StreamingContext context)
+			: base (info, context)
+		{
+		}
+	}
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/UploadProgressEventArgs.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/UploadProgressEventArgs.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,57 @@
+//
+// Mono.Google.Picasa.UploadProgressEventArgs
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+//
+
+// 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.Google.Picasa {
+	public sealed class UploadProgressEventArgs : EventArgs {
+		string title;
+		long bytes_sent;
+		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/PicasaWebExport/google-sharp/UploadProgressEventHandler.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/UploadProgressEventHandler.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,33 @@
+//
+// Mono.Google.Picasa.UploadProgressEventHandler.cs:
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+//
+
+// 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.Google.Picasa {
+	public delegate void UploadProgressEventHandler (object sender, UploadProgressEventArgs args);
+}
+

Added: trunk/extensions/PicasaWebExport/google-sharp/XmlUtil.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/PicasaWebExport/google-sharp/XmlUtil.cs	Fri Feb  8 15:37:13 2008
@@ -0,0 +1,121 @@
+//
+// Mono.Google.Picasa.XmlUtil.cs:
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//	Stephane Delcroix (stephane delcroix org)
+//
+// (C) Copyright 2006 Novell, Inc. (http://www.novell.com)
+// (C) Copyright 2007 S. Delcroix
+//
+
+// 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.
+//
+// Check Picasa Web Albums Data Api at http://code.google.com/apis/picasaweb/gdata.html
+//
+
+using System;
+using System.IO;
+using System.Text;
+using System.Xml;
+namespace Mono.Google.Picasa {
+	enum PicasaNamespaces {
+		None,
+		Atom,
+		GPhoto,
+		Photo,
+		Media
+	}
+
+	internal class XmlUtil {
+		static string [] URIs = new string [] {
+			null,
+			"http://www.w3.org/2005/Atom";,
+			"http://schemas.google.com/photos/2007";,
+			"http://www.pheed.com/pheed/";,
+			"http://search.yahoo.com/mrss/";
+		};
+
+		StringWriter sr;
+		XmlTextWriter writer;
+
+		public XmlUtil ()
+		{
+			StartDocument ();
+		}
+
+		public void StartDocument ()
+		{
+			sr = new StringWriter ();
+			writer = new XmlTextWriter (sr);
+			writer.Formatting = Formatting.Indented;
+			writer.Indentation = 2;
+			writer.Namespaces = true;
+			writer.WriteStartElement (null, "entry", null);
+			writer.WriteAttributeString ("xmlns", null, URIs [(int) PicasaNamespaces.Atom]);
+			writer.WriteAttributeString ("xmlns", "media", null, URIs [(int) PicasaNamespaces.Media]);
+			writer.WriteAttributeString ("xmlns", "gphoto", null, URIs [(int) PicasaNamespaces.GPhoto]);
+		}
+
+		public void WriteElementString (string name, string val)
+		{
+			writer.WriteElementString (name, val);
+		}
+
+		public void WriteElementString (string name, string val, string uri)
+		{
+			writer.WriteElementString (name, uri, val);
+		}
+
+		public void WriteElementString (string name, string val, PicasaNamespaces ns)
+		{
+			writer.WriteElementString (name, URIs [(int) ns], val);
+		}
+
+		public void WriteStartElement (string elem)
+		{
+			writer.WriteStartElement (elem, null);
+		}
+
+		public void WriteElementStringWithAttributes (string ename, string eval, params string[] attributes)
+		{
+			writer.WriteStartElement (null, ename, null);
+			for (int i = 0; i < attributes.Length; i+=2)
+				writer.WriteAttributeString (attributes[i], attributes[i+1]);
+			writer.WriteRaw (eval);
+			writer.WriteEndElement ();
+		}
+
+		public string GetDocumentString ()
+		{
+			writer.Close ();
+			return sr.ToString ();
+		}
+
+		internal static void AddDefaultNamespaces (XmlNamespaceManager nsmgr) {
+			nsmgr.AddNamespace ("atom", "http://www.w3.org/2005/Atom";);
+			nsmgr.AddNamespace ("photo", "http://www.pheed.com/pheed/";);
+			nsmgr.AddNamespace ("media", "http://search.yahoo.com/mrss/";);
+			nsmgr.AddNamespace ("gphoto", "http://schemas.google.com/photos/2007";);
+			nsmgr.AddNamespace ("batch", "http://schemas.google.com/gdata/batch";);
+		}
+	}
+}
+

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Fri Feb  8 15:37:13 2008
@@ -60,7 +60,6 @@
 src/PhotoVersionCommands.cs
 src/PhotoVersionMenu.cs
 src/PhotoView.cs
-src/PicasaWebExport.cs
 src/Preferences.cs
 src/ProgressDialog.cs
 src/QueryWidget.cs

Modified: trunk/po/POTFILES.skip
==============================================================================
--- trunk/po/POTFILES.skip	(original)
+++ trunk/po/POTFILES.skip	Fri Feb  8 15:37:13 2008
@@ -22,3 +22,6 @@
 extensions/GalleryExport/GalleryExport.cs
 extensions/GalleryExport/GalleryExport.glade
 extensions/GalleryExport/GalleryRemote.cs
+extensions/PicasaWebExport/PicasaWebExport.cs
+extensions/PicasaWebExport/PicasaWebExport.glade
+extensions/PicasaWebExport/PicasaWebRemote.cs

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Fri Feb  8 15:37:13 2008
@@ -188,7 +188,6 @@
 	$(srcdir)/PhotoVersionCommands.cs	\
 	$(srcdir)/PhotoVersionMenu.cs		\
 	$(srcdir)/PhotoView.cs			\
-	$(srcdir)/PicasaWebExport.cs		\
 	$(srcdir)/PixbufLoader.cs		\
 	$(srcdir)/PixbufUtils.cs		\
 	$(srcdir)/PixbufCache.cs		\

Modified: trunk/src/Preferences.cs
==============================================================================
--- trunk/src/Preferences.cs	(original)
+++ trunk/src/Preferences.cs	Fri Feb  8 15:37:13 2008
@@ -50,12 +50,6 @@
 		public const string EXPORT_TOKEN_23HQ = "/apps/f-spot/export/tokens/23hq"; 
 		public const string EXPORT_TOKEN_ZOOOMR = "/apps/f-spot/export/tokens/zooomr"; 
 
-		public const string EXPORT_PICASAWEB_SCALE = "/apps/f-spot/export/picasaweb/scale";
-		public const string EXPORT_PICASAWEB_SIZE = "/apps/f-spot/export/picasaweb/size";
-		public const string EXPORT_PICASAWEB_ROTATE = "/apps/f-spot/export/picasaweb/rotate";
-		public const string EXPORT_PICASAWEB_BROWSER = "/apps/f-spot/export/picasaweb/browser";
-		public const string EXPORT_PICASAWEB_TAG = "/apps/f-spot/export/picasaweb/tag";
-
 		public const string EXPORT_SMUGMUG_SCALE = "/apps/f-spot/export/smugmug/scale";
 		public const string EXPORT_SMUGMUG_SIZE = "/apps/f-spot/export/smugmug/size";
 		public const string EXPORT_SMUGMUG_ROTATE = "/apps/f-spot/export/smugmug/rotate";
@@ -152,10 +146,6 @@
 			case SHOW_DATES:
 			case SHOW_RATINGS:
 			case VIEWER_SHOW_FILENAMES:
-			case EXPORT_PICASAWEB_SCALE:
-			case EXPORT_PICASAWEB_ROTATE:
-			case EXPORT_PICASAWEB_BROWSER:
-			case EXPORT_PICASAWEB_TAG:
 			case EXPORT_SMUGMUG_SCALE:
 			case EXPORT_SMUGMUG_ROTATE:
 			case EXPORT_SMUGMUG_BROWSER:
@@ -165,7 +155,6 @@
 			case DBUS_READ_ONLY:
 				return true;
 			
-			case EXPORT_PICASAWEB_SIZE:
 			case EXPORT_SMUGMUG_SIZE:
 			case EXPORT_FOLDER_SIZE:
 				return 800;

Modified: trunk/src/f-spot.glade
==============================================================================
--- trunk/src/f-spot.glade	(original)
+++ trunk/src/f-spot.glade	Fri Feb  8 15:37:13 2008
@@ -1915,834 +1915,6 @@
       </widget>
     </child>
   </widget>
-  <widget class="GtkDialog" id="google_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_scrolledwindow">
-                        <property name="width_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">&lt;b&gt;Photos&lt;/b&gt;</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="GtkAlignment" id="alignment13">
-                        <property name="visible">True</property>
-                        <property name="left_padding">12</property>
-                        <child>
-                          <widget class="GtkVBox" id="vbox12">
-                            <property name="visible">True</property>
-                            <property name="spacing">6</property>
-                            <child>
-                              <widget class="GtkHBox" id="hbox20">
-                                <property name="visible">True</property>
-                                <property name="spacing">6</property>
-                                <child>
-                                  <widget class="GtkLabel" id="gallery_label">
-                                    <property name="visible">True</property>
-                                    <property name="label" translatable="yes">_Gallery:</property>
-                                    <property name="use_underline">True</property>
-                                    <property name="mnemonic_widget">gallery_optionmenu</property>
-                                  </widget>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <widget class="GtkOptionMenu" id="gallery_optionmenu">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="response_id">0</property>
-                                    <signal name="changed" handler="HandleAccountSelected"/>
-                                  </widget>
-                                  <packing>
-                                    <property name="position">1</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <widget class="GtkButton" id="gallery_button">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="label">gtk-add</property>
-                                    <property name="use_stock">True</property>
-                                    <property name="response_id">0</property>
-                                    <signal name="clicked" handler="HandleAddGallery"/>
-                                  </widget>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="position">2</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <widget class="GtkButton" id="edit_button">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="label">gtk-edit</property>
-                                    <property name="use_stock">True</property>
-                                    <property name="response_id">0</property>
-                                  </widget>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="position">3</property>
-                                  </packing>
-                                </child>
-                              </widget>
-                            </child>
-                            <child>
-                              <widget class="GtkLabel" id="status_label">
-                                <property name="visible">True</property>
-                                <property name="xalign">0</property>
-                                <property name="use_markup">True</property>
-                              </widget>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">False</property>
-                                <property name="position">1</property>
-                              </packing>
-                            </child>
-                          </widget>
-                        </child>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkLabel" id="label44">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">&lt;b&gt;PicasaWeb Export&lt;/b&gt;</property>
-                        <property name="use_markup">True</property>
-                      </widget>
-                      <packing>
-                        <property name="type">label_item</property>
-                      </packing>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkFrame" id="frame10">
-                    <property name="visible">True</property>
-                    <property name="label_xalign">0</property>
-                    <property name="shadow_type">GTK_SHADOW_NONE</property>
-                    <child>
-                      <widget class="GtkAlignment" id="alignment14">
-                        <property name="visible">True</property>
-                        <property name="left_padding">12</property>
-                        <child>
-                          <widget class="GtkVBox" id="vbox13">
-                            <property name="visible">True</property>
-                            <property name="spacing">6</property>
-                            <child>
-                              <widget class="GtkHBox" id="hbox18">
-                                <property name="visible">True</property>
-                                <property name="spacing">6</property>
-                                <child>
-                                  <widget class="GtkLabel" id="album_label">
-                                    <property name="visible">True</property>
-                                    <property name="label" translatable="yes">_Export to Album:</property>
-                                    <property name="use_underline">True</property>
-                                    <property name="mnemonic_widget">album_optionmenu</property>
-                                  </widget>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <widget class="GtkOptionMenu" id="album_optionmenu">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="response_id">0</property>
-                                  </widget>
-                                  <packing>
-                                    <property name="position">1</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <widget class="GtkButton" id="album_button">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="label">gtk-add</property>
-                                    <property name="use_stock">True</property>
-                                    <property name="response_id">0</property>
-                                    <signal name="clicked" handler="HandleAddAlbum"/>
-                                  </widget>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="position">2</property>
-                                  </packing>
-                                </child>
-                              </widget>
-                            </child>
-                            <child>
-                              <widget class="GtkCheckButton" id="browser_check">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="label" translatable="yes">Open _album in browser when done uploading</property>
-                                <property name="use_underline">True</property>
-                                <property name="response_id">0</property>
-                                <property name="active">True</property>
-                                <property name="draw_indicator">True</property>
-                              </widget>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">False</property>
-                                <property name="position">1</property>
-                              </packing>
-                            </child>
-                          </widget>
-                        </child>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkLabel" id="label45">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">&lt;b&gt;Album&lt;/b&gt;</property>
-                        <property name="use_markup">True</property>
-                      </widget>
-                      <packing>
-                        <property name="type">label_item</property>
-                      </packing>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkFrame" id="frame11">
-                    <property name="visible">True</property>
-                    <property name="label_xalign">0</property>
-                    <property name="shadow_type">GTK_SHADOW_NONE</property>
-                    <child>
-                      <widget class="GtkAlignment" id="alignment15">
-                        <property name="visible">True</property>
-                        <property name="left_padding">12</property>
-                        <child>
-                          <widget class="GtkVBox" id="vbox14">
-                            <property name="visible">True</property>
-                            <property name="spacing">6</property>
-                            <child>
-                              <widget class="GtkHBox" id="hbox58">
-                                <property name="visible">True</property>
-                                <child>
-                                  <widget class="GtkCheckButton" id="scale_check">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="label" translatable="yes">_Resize to: </property>
-                                    <property name="use_underline">True</property>
-                                    <property name="response_id">0</property>
-                                    <property name="draw_indicator">True</property>
-                                    <signal name="toggled" handler="HandleSizeActive"/>
-                                  </widget>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <widget class="GtkSpinButton" id="size_spin">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="adjustment">400 0 10000 1 10 10</property>
-                                    <property name="climb_rate">1</property>
-                                  </widget>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="position">1</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <widget class="GtkLabel" id="label153">
-                                    <property name="visible">True</property>
-                                    <property name="label" translatable="yes">pixels</property>
-                                  </widget>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">False</property>
-                                    <property name="position">2</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <placeholder/>
-                                </child>
-                              </widget>
-                            </child>
-                            <child>
-                              <widget class="GtkCheckButton" id="rotate_check">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="label" translatable="yes">_Autorotate</property>
-                                <property name="use_underline">True</property>
-                                <property name="response_id">0</property>
-                                <property name="draw_indicator">True</property>
-                              </widget>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">False</property>
-                                <property name="position">1</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <widget class="GtkCheckButton" id="tag_check">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="label" translatable="yes">_Export tags</property>
-                                <property name="use_underline">True</property>
-                                <property name="response_id">0</property>
-                                <property name="draw_indicator">True</property>
-                              </widget>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">False</property>
-                                <property name="position">2</property>
-                              </packing>
-                            </child>
-                          </widget>
-                        </child>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkLabel" id="label46">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">&lt;b&gt;Style&lt;/b&gt;</property>
-                        <property name="use_markup">True</property>
-                      </widget>
-                      <packing>
-                        <property name="type">label_item</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="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="cancel_button">
-                <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>
-  <widget class="GtkDialog" id="google_add_album_dialog">
-    <property name="visible">True</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-vbox12">
-        <property name="visible">True</property>
-        <child>
-          <widget class="GtkTable" id="table10">
-            <property name="visible">True</property>
-            <property name="border_width">12</property>
-            <property name="n_rows">3</property>
-            <property name="n_columns">2</property>
-            <property name="column_spacing">7</property>
-            <property name="row_spacing">6</property>
-            <child>
-              <placeholder/>
-            </child>
-            <child>
-              <widget class="GtkLabel" id="descroption_label">
-                <property name="visible">True</property>
-                <property name="xalign">1</property>
-                <property name="label" translatable="yes">_Description:</property>
-                <property name="use_underline">True</property>
-                <property name="mnemonic_widget">description_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="description_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="top_attach">1</property>
-                <property name="bottom_attach">2</property>
-                <property name="y_options"></property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkLabel" id="name_label">
-                <property name="visible">True</property>
-                <property name="xalign">1</property>
-                <property name="label" translatable="yes">_Album Title:</property>
-                <property name="use_underline">True</property>
-                <property name="mnemonic_widget">title_entry</property>
-              </widget>
-              <packing>
-                <property name="x_options">GTK_FILL</property>
-                <property name="y_options"></property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkEntry" id="title_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>
-            <child>
-              <widget class="GtkCheckButton" id="public_check">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="label" translatable="yes">Public Album</property>
-                <property name="use_underline">True</property>
-                <property name="response_id">0</property>
-                <property name="draw_indicator">True</property>
-              </widget>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="right_attach">2</property>
-                <property name="top_attach">2</property>
-                <property name="bottom_attach">3</property>
-                <property name="x_options">GTK_FILL</property>
-                <property name="y_options"></property>
-              </packing>
-            </child>
-          </widget>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">GTK_PACK_END</property>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child internal-child="action_area">
-          <widget class="GtkHButtonBox" id="dialog-action_area12">
-            <property name="visible">True</property>
-            <property name="layout_style">GTK_BUTTONBOX_END</property>
-            <child>
-              <widget class="GtkButton" id="cancel_button">
-                <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="add_button">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="has_default">True</property>
-                <property name="label">gtk-add</property>
-                <property name="use_stock">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>
-  <widget class="GtkDialog" id="google_add_dialog">
-    <property name="visible">True</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-vbox12">
-        <property name="visible">True</property>
-        <child>
-          <widget class="GtkVBox" id="vbox63">
-            <property name="visible">True</property>
-            <child>
-              <widget class="GtkHBox" id="status_area">
-                <property name="border_width">12</property>
-                <child>
-                  <widget class="GtkImage" id="image12">
-                    <property name="visible">True</property>
-                    <property name="yalign">0</property>
-                    <property name="stock">gtk-dialog-question</property>
-                    <property name="icon_size">6</property>
-                  </widget>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="padding">2</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkVBox" id="vbox64">
-                    <property name="visible">True</property>
-                    <property name="border_width">6</property>
-                    <child>
-                      <widget class="GtkLabel" id="summary_label">
-                        <property name="visible">True</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes">&lt;span weight='bold' size='larger'&gt;Error Connecting to Gallery&lt;/span&gt;
-</property>
-                        <property name="use_markup">True</property>
-                      </widget>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <widget class="GtkLabel" id="description_label">
-                        <property name="visible">True</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes">Please verify that the settings for this gallery are correct.</property>
-                      </widget>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-              </widget>
-              <packing>
-                <property name="fill">False</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkHBox" id="locked_area">
-                <property name="border_width">12</property>
-                <child>
-                  <widget class="GtkImage" id="image45">
-                    <property name="visible">True</property>
-                    <property name="yalign">0</property>
-                    <property name="stock">gtk-missing-image</property>
-                    <property name="icon_size">6</property>
-                  </widget>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="padding">2</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkVBox" id="vbox84">
-                    <property name="visible">True</property>
-                    <property name="border_width">6</property>
-                    <child>
-                      <widget class="GtkLabel" id="label214">
-                        <property name="visible">True</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes">&lt;span weight='bold' size='larger'&gt;Your Google Account is locked&lt;/span&gt;
-</property>
-                        <property name="use_markup">True</property>
-                      </widget>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <widget class="GtkLabel" id="label215">
-                        <property name="visible">True</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes">Please verify that the settings for this gallery are correct.
-Enter the letters as they are shown in the image in
-the 'Captcha' field. &lt;i&gt;Letters are not case-sensitive&lt;/i&gt;</property>
-                        <property name="use_markup">True</property>
-                      </widget>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-              </widget>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkTable" id="table10">
-                <property name="visible">True</property>
-                <property name="border_width">12</property>
-                <property name="n_rows">3</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>
-                <child>
-                  <widget class="GtkLabel" id="captcha_label">
-                    <property name="xalign">1</property>
-                    <property name="label" translatable="yes">_Captcha:</property>
-                    <property name="use_underline">True</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">2</property>
-                    <property name="bottom_attach">3</property>
-                    <property name="x_options">GTK_FILL</property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkHBox" id="hbox88">
-                    <property name="visible">True</property>
-                    <child>
-                      <widget class="GtkEntry" id="captcha_entry">
-                        <property name="can_focus">True</property>
-                        <property name="invisible_char">*</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkImage" id="captcha_image">
-                        <property name="stock">gtk-missing-image</property>
-                      </widget>
-                      <packing>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">2</property>
-                    <property name="bottom_attach">3</property>
-                    <property name="x_options">GTK_FILL</property>
-                    <property name="y_options">GTK_FILL</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="pack_type">GTK_PACK_END</property>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child internal-child="action_area">
-          <widget class="GtkHButtonBox" id="dialog-action_area12">
-            <property name="visible">True</property>
-            <property name="layout_style">GTK_BUTTONBOX_END</property>
-            <child>
-              <widget class="GtkButton" id="cancel_button">
-                <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="remove_button">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="label">gtk-remove</property>
-                <property name="use_stock">True</property>
-                <property name="response_id">-2</property>
-              </widget>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkButton" id="add_button">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="has_default">True</property>
-                <property name="label">gtk-add</property>
-                <property name="use_stock">True</property>
-                <property name="response_id">-5</property>
-              </widget>
-              <packing>
-                <property name="position">2</property>
-              </packing>
-            </child>
-          </widget>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">GTK_PACK_END</property>
-          </packing>
-        </child>
-      </widget>
-    </child>
-  </widget>
   <widget class="GtkDialog" id="vfs_export_dialog">
     <property name="title" translatable="yes">Export</property>
     <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]