[gthumb: 6/11] [flicker] implemented the flickr uploader



commit f90899da206f6a3233e964f0dd1583018a53a5a3
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Wed Mar 10 17:48:23 2010 +0100

    [flicker] implemented the flickr uploader

 extensions/catalogs/gth-catalog.c                  |   41 ++-
 extensions/flicker/data/ui/Makefile.am             |    3 +-
 extensions/flicker/data/ui/export-to-flickr.ui     |  150 +++++-
 .../flicker/data/ui/flicker-export-completed.ui    |   70 +++
 extensions/flicker/dlg-export-to-flickr.c          |  247 +++++++--
 extensions/flicker/flickr-photoset.c               |   12 +
 extensions/flicker/flickr-photoset.h               |    3 +
 extensions/flicker/flickr-service.c                |  542 ++++++++++++++------
 extensions/flicker/flickr-service.h                |   31 +-
 extensions/picasaweb/dlg-export-to-picasaweb.c     |    2 +-
 10 files changed, 880 insertions(+), 221 deletions(-)
---
diff --git a/extensions/catalogs/gth-catalog.c b/extensions/catalogs/gth-catalog.c
index 7985028..143d9e1 100644
--- a/extensions/catalogs/gth-catalog.c
+++ b/extensions/catalogs/gth-catalog.c
@@ -691,6 +691,28 @@ get_display_name (GFile       *file,
 }
 
 
+static char *
+get_edit_name (GFile       *file,
+	       const char  *name,
+	       GthDateTime *date_time)
+{
+	GString *display_name;
+	char    *basename;
+
+	display_name = g_string_new ("");
+	basename = g_file_get_basename (file);
+	if ((basename == NULL) || (strcmp (basename, "/") == 0)) {
+		 g_string_append (display_name, _("Catalogs"));
+	}
+	else {
+		if (name != NULL)
+			g_string_append (display_name, name);
+	}
+
+	return g_string_free (display_name, FALSE);
+}
+
+
 static void
 update_standard_attributes (GFile       *file,
 			    GFileInfo   *info,
@@ -698,6 +720,7 @@ update_standard_attributes (GFile       *file,
 			    GthDateTime *date_time)
 {
 	char *display_name;
+	char *edit_name;
 
 	if (gth_datetime_valid (date_time)) {
 		char *sort_order_s;
@@ -711,8 +734,16 @@ update_standard_attributes (GFile       *file,
 		g_file_info_set_sort_order (info, 99999999);
 
 	display_name = get_display_name (file, name, date_time);
-	if (display_name != NULL)
+	if (display_name != NULL) {
 		g_file_info_set_display_name (info, display_name);
+		g_free (display_name);
+	}
+
+	edit_name = get_edit_name (file, name, date_time);
+	if (edit_name != NULL) {
+		g_file_info_set_edit_name (info, edit_name);
+		g_free (edit_name);
+	}
 }
 
 
@@ -973,6 +1004,7 @@ gth_catalog_update_standard_attributes (GFile     *file,
 				        GFileInfo *info)
 {
 	char *display_name = NULL;
+	char *edit_name = NULL;
 	char *basename;
 
 	basename = g_file_get_basename (file);
@@ -1015,12 +1047,17 @@ gth_catalog_update_standard_attributes (GFile     *file,
 		gth_datetime_free (date_time);
 		g_free (name);
 	}
-	else
+	else {
 		display_name = g_strdup (_("Catalogs"));
+		edit_name = g_strdup (_("Catalogs"));
+	}
 
 	if (display_name != NULL)
 		g_file_info_set_display_name (info, display_name);
+	if (edit_name != NULL)
+		g_file_info_set_edit_name (info, edit_name);
 
+	g_free (edit_name);
 	g_free (display_name);
 	g_free (basename);
 }
diff --git a/extensions/flicker/data/ui/Makefile.am b/extensions/flicker/data/ui/Makefile.am
index d8e958c..d53d82d 100644
--- a/extensions/flicker/data/ui/Makefile.am
+++ b/extensions/flicker/data/ui/Makefile.am
@@ -4,7 +4,8 @@ ui_DATA = 					\
 	flicker-account-chooser.ui		\
 	flicker-account-manager.ui		\
 	flicker-ask-authorization.ui		\
-	flicker-complete-authorization.ui
+	flicker-complete-authorization.ui	\
+	flicker-export-completed.ui
 
 EXTRA_DIST = $(ui_DATA)
 
diff --git a/extensions/flicker/data/ui/export-to-flickr.ui b/extensions/flicker/data/ui/export-to-flickr.ui
index 89ecb18..c7cf053 100644
--- a/extensions/flicker/data/ui/export-to-flickr.ui
+++ b/extensions/flicker/data/ui/export-to-flickr.ui
@@ -48,7 +48,7 @@
                 <child>
                   <object class="GtkTable" id="table2">
                     <property name="visible">True</property>
-                    <property name="n_rows">2</property>
+                    <property name="n_rows">5</property>
                     <property name="n_columns">2</property>
                     <property name="column_spacing">6</property>
                     <property name="row_spacing">5</property>
@@ -61,8 +61,9 @@
                             <property name="visible">True</property>
                             <property name="xalign">0</property>
                             <property name="yalign">0</property>
-                            <property name="label" translatable="yes">A_ccount:</property>
+                            <property name="label" translatable="yes">_Account:</property>
                             <property name="use_underline">True</property>
+                            <property name="mnemonic_widget">account_combobox</property>
                           </object>
                         </child>
                       </object>
@@ -100,6 +101,7 @@
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
                                 <property name="receives_default">True</property>
+                                <property name="tooltip_text" translatable="yes">Edit accounts</property>
                                 <child>
                                   <object class="GtkImage" id="image2">
                                     <property name="visible">True</property>
@@ -162,8 +164,9 @@
                       <object class="GtkLabel" id="label1">
                         <property name="visible">True</property>
                         <property name="xalign">0</property>
-                        <property name="label" translatable="yes">_Album:</property>
+                        <property name="label" translatable="yes">Ph_otoset:</property>
                         <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">photoset_comboboxentry</property>
                       </object>
                       <packing>
                         <property name="top_attach">1</property>
@@ -177,23 +180,98 @@
                         <property name="model">photoset_liststore</property>
                         <property name="text_column">2</property>
                         <child>
-                          <object class="GtkCellRendererPixbuf" id="cellrenderertext1"/>
+                          <object class="GtkCellRendererText" id="cellrenderertext2"/>
                           <attributes>
-                            <attribute name="icon-name">1</attribute>
+                            <attribute name="text">3</attribute>
                           </attributes>
                         </child>
+                      </object>
+                      <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>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label5">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">_Privacy:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">privacy_combobox</property>
+                      </object>
+                      <packing>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="x_options">GTK_FILL</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="privacy_combobox">
+                        <property name="visible">True</property>
+                        <property name="model">privacy_liststore</property>
+                        <property name="active">0</property>
                         <child>
-                          <object class="GtkCellRendererText" id="cellrenderertext2"/>
+                          <object class="GtkCellRendererText" id="cellrenderertext5"/>
                           <attributes>
-                            <attribute name="text">2</attribute>
+                            <attribute name="text">1</attribute>
                           </attributes>
                         </child>
                       </object>
                       <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="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="hidden_checkbutton">
+                        <property name="label" translatable="yes">Hi_de from public searches</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">4</property>
+                        <property name="bottom_attach">5</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label2">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">_Safety:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">safety_combobox</property>
+                      </object>
+                      <packing>
+                        <property name="top_attach">3</property>
+                        <property name="bottom_attach">4</property>
+                        <property name="x_options">GTK_FILL</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="safety_combobox">
+                        <property name="visible">True</property>
+                        <property name="model">safety_liststore</property>
+                        <property name="active">0</property>
+                        <child>
+                          <object class="GtkCellRendererText" id="cellrenderertext3"/>
+                          <attributes>
+                            <attribute name="text">1</attribute>
+                          </attributes>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">3</property>
+                        <property name="bottom_attach">4</property>
                       </packing>
                     </child>
                   </object>
@@ -288,6 +366,58 @@
       <column type="gchararray"/>
     </columns>
   </object>
+  <object class="GtkListStore" id="safety_liststore">
+    <columns>
+      <!-- column-name value -->
+      <column type="gint"/>
+      <!-- column-name name -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0">0</col>
+        <col id="1" translatable="yes">Safe content</col>
+      </row>
+      <row>
+        <col id="0">1</col>
+        <col id="1" translatable="yes">Moderate content</col>
+      </row>
+      <row>
+        <col id="0">2</col>
+        <col id="1" translatable="yes">Restricted content</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="privacy_liststore">
+    <columns>
+      <!-- column-name value -->
+      <column type="gint"/>
+      <!-- column-name name -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0">0</col>
+        <col id="1" translatable="yes">Public photos</col>
+      </row>
+      <row>
+        <col id="0">1</col>
+        <col id="1" translatable="yes">Private photos, visible to family and friends</col>
+      </row>
+      <row>
+        <col id="0">2</col>
+        <col id="1" translatable="yes">Private photos, visible to friends</col>
+      </row>
+      <row>
+        <col id="0">3</col>
+        <col id="1" translatable="yes">Private photos, visible to family</col>
+      </row>
+      <row>
+        <col id="0">4</col>
+        <col id="1" translatable="yes">Private photos</col>
+      </row>
+    </data>
+  </object>
   <object class="GtkListStore" id="photoset_liststore">
     <columns>
       <!-- column-name data -->
@@ -296,6 +426,8 @@
       <column type="gchararray"/>
       <!-- column-name title -->
       <column type="gchararray"/>
+      <!-- column-name n_photos -->
+      <column type="gchararray"/>
     </columns>
   </object>
 </interface>
diff --git a/extensions/flicker/data/ui/flicker-export-completed.ui b/extensions/flicker/data/ui/flicker-export-completed.ui
new file mode 100644
index 0000000..8341986
--- /dev/null
+++ b/extensions/flicker/data/ui/flicker-export-completed.ui
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkMessageDialog" id="completed_messagedialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Upload to Flickr</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="type_hint">normal</property>
+    <property name="skip_taskbar_hint">True</property>
+    <property name="text" translatable="yes">Files successfully uploaded to the server.</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label" translatable="yes">_Open in the Browser</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="image">icon_image</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button2">
+                <property name="label">gtk-close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="1">button1</action-widget>
+      <action-widget response="-7">button2</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkImage" id="icon_image">
+    <property name="visible">True</property>
+    <property name="yalign">0</property>
+    <property name="stock">gtk-jump-to</property>
+  </object>
+</interface>
diff --git a/extensions/flicker/dlg-export-to-flickr.c b/extensions/flicker/dlg-export-to-flickr.c
index 0c48d00..28f62ac 100644
--- a/extensions/flicker/dlg-export-to-flickr.c
+++ b/extensions/flicker/dlg-export-to-flickr.c
@@ -32,6 +32,7 @@
 
 
 #define GET_WIDGET(x) (_gtk_builder_get_widget (data->builder, (x)))
+#define _OPEN_IN_BROWSER_RESPONSE 1
 
 
 enum {
@@ -59,8 +60,10 @@ typedef struct {
 	FlickrAccount    *account;
 	FlickrUser       *user;
 	GList            *photosets;
+	FlickrPhotoset   *photoset;
 	FlickrConnection *conn;
 	FlickrService    *service;
+	GList            *photos_ids;
 	GCancellable     *cancellable;
 } DialogData;
 
@@ -78,6 +81,8 @@ export_dialog_destroy_cb (GtkWidget  *widget,
 	_g_object_unref (data->account);
 	_g_object_unref (data->user);
 	_g_object_list_unref (data->photosets);
+	_g_object_unref (data->photoset);
+	_g_string_list_free (data->photos_ids);
 	_g_object_unref (data->builder);
 	_g_object_list_unref (data->file_list);
 	_g_object_unref (data->location);
@@ -85,9 +90,135 @@ export_dialog_destroy_cb (GtkWidget  *widget,
 }
 
 
-#if 0
+static void
+completed_messagedialog_response_cb (GtkDialog *dialog,
+				     int        response_id,
+				     gpointer   user_data)
+{
+	DialogData *data = user_data;
+
+	switch (response_id) {
+	case GTK_RESPONSE_DELETE_EVENT:
+	case GTK_RESPONSE_CLOSE:
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+		gtk_widget_destroy (data->dialog);
+		break;
+
+	case _OPEN_IN_BROWSER_RESPONSE:
+		{
+			char   *url = NULL;
+			GError *error = NULL;
+
+			gtk_widget_destroy (GTK_WIDGET (dialog));
+
+			if (data->photoset == NULL) {
+				GString *ids;
+				GList   *scan;
+
+				ids = g_string_new ("");
+				for (scan = data->photos_ids; scan; scan = scan->next) {
+					if (scan != data->photos_ids)
+						g_string_append (ids, ",");
+					g_string_append (ids, (char *) scan->data);
+				}
+				url = g_strconcat ("http://www.flickr.com/photos/upload/edit/?ids=";, ids->str, NULL);
+
+				g_string_free (ids, TRUE);
+			}
+			else if (data->photoset->url != NULL)
+				url = g_strdup (data->photoset->url);
+			else if (data->photoset->id != NULL)
+				url = g_strconcat ("http://www.flickr.com/photos/";, data->user->id, "/sets/", data->photoset->id, NULL);
+
+			if ((url != NULL) && ! gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (dialog)), url, 0, &error))
+				_gtk_error_dialog_from_gerror_run (GTK_WINDOW (data->browser), _("Could not connect to the server"), &error);
+			gtk_widget_destroy (data->dialog);
+
+			g_free (url);
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+
+static void
+export_completed_with_success (DialogData *data)
+{
+	GtkBuilder *builder;
+	GtkWidget  *dialog;
+
+	gth_task_dialog (GTH_TASK (data->conn), TRUE);
+
+	builder = _gtk_builder_new_from_file ("flicker-export-completed.ui", "flicker");
+	dialog = _gtk_builder_get_widget (builder, "completed_messagedialog");
+	g_object_set_data_full (G_OBJECT (dialog), "builder", builder, g_object_unref);
+	g_signal_connect (dialog,
+			  "response",
+			  G_CALLBACK (completed_messagedialog_response_cb),
+			  data);
+
+	gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (data->browser));
+	gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+	gtk_window_present (GTK_WINDOW (dialog));
+}
+
+
+static void
+add_photos_to_photoset_ready_cb (GObject      *source_object,
+				 GAsyncResult *result,
+				 gpointer      user_data)
+{
+	DialogData *data = user_data;
+	GError     *error = NULL;
+
+	if (! flickr_service_add_photos_to_set_finish (FLICKR_SERVICE (source_object), result, &error)) {
+		_gtk_error_dialog_from_gerror_show (GTK_WINDOW (data->browser), _("Could not create the album"), &error);
+		gtk_widget_destroy (data->dialog);
+		return;
+	}
 
-static void get_photoset_list (DialogData *data);
+	export_completed_with_success (data);
+}
+
+
+static void
+add_photos_to_photoset (DialogData *data)
+{
+	flickr_service_add_photos_to_set (data->service,
+					  data->photoset,
+					  data->photos_ids,
+					  data->cancellable,
+					  add_photos_to_photoset_ready_cb,
+					  data);
+}
+
+
+static void
+create_photoset_ready_cb (GObject      *source_object,
+			  GAsyncResult *result,
+			  gpointer      user_data)
+{
+	DialogData *data = user_data;
+	GError     *error = NULL;
+	char       *primary;
+
+	primary = g_strdup (data->photoset->primary);
+	g_object_unref (data->photoset);
+	data->photoset = flickr_service_create_photoset_finish (FLICKR_SERVICE (source_object), result, &error);
+	if (error != NULL) {
+		_gtk_error_dialog_from_gerror_show (GTK_WINDOW (data->browser), _("Could not create the album"), &error);
+		gtk_widget_destroy (data->dialog);
+	}
+	else {
+		flickr_photoset_set_primary (data->photoset, primary);
+		add_photos_to_photoset (data);
+	}
+
+	g_free (primary);
+}
 
 
 static void
@@ -98,19 +229,42 @@ post_photos_ready_cb (GObject      *source_object,
 	DialogData *data = user_data;
 	GError     *error = NULL;
 
-	gth_task_dialog (GTH_TASK (data->conn), TRUE);
-
-	if (! flickr_service_post_photos_finish (FLICKR_SERVICE (source_object), result, &error)) {
+	data->photos_ids = flickr_service_post_photos_finish (FLICKR_SERVICE (source_object), result, &error);
+	if (error != NULL) {
 		_gtk_error_dialog_from_gerror_show (GTK_WINDOW (data->browser), _("Could not upload the files"), &error);
+		gtk_widget_destroy (data->dialog);
 		return;
 	}
 
-	/* FIXME */
+	if (data->photoset == NULL) {
+		export_completed_with_success (data);
+		return;
+	}
 
-	get_photoset_list (data);
+	/* create the photoset if it doesn't exists */
+
+	if (data->photoset->id == NULL) {
+		char *first_id;
+
+		first_id = data->photos_ids->data;
+		flickr_photoset_set_primary (data->photoset, first_id);
+		flickr_service_create_photoset (data->service,
+						data->photoset,
+						data->cancellable,
+						create_photoset_ready_cb,
+						data);
+	}
+	else
+		add_photos_to_photoset (data);
 }
 
-#endif
+
+static int
+find_photoset_by_title (FlickrPhotoset *photoset,
+		        const char     *name)
+{
+	return g_strcmp0 (photoset->title, name);
+}
 
 
 static void
@@ -133,34 +287,39 @@ export_dialog_response_cb (GtkDialog *dialog,
 
 	case GTK_RESPONSE_OK:
 		{
-			/* FIXME
-			GtkTreeModel   *tree_model;
-			GtkTreeIter     iter;
-			PicasaWebAlbum *album;
-			GList          *file_list;
-
-			if (! gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (GET_WIDGET ("albums_treeview"))), &tree_model, &iter)) {
-				gtk_widget_set_sensitive (GET_WIDGET ("upload_button"), FALSE);
-				return;
-			}
-
-			gtk_tree_model_get (tree_model, &iter,
-					    ALBUM_DATA_COLUMN, &album,
-					    -1);
+			char  *photoset_title;
+			GList *file_list;
 
+			gtk_widget_hide (data->dialog);
 			gth_task_dialog (GTH_TASK (data->conn), FALSE);
 
+			data->photoset = NULL;
+			photoset_title = gtk_combo_box_get_active_text (GTK_COMBO_BOX (GET_WIDGET ("photoset_comboboxentry")));
+			if ((photoset_title != NULL) && (g_strcmp0 (photoset_title, "") != 0)) {
+				GList *link;
+
+				link = g_list_find_custom (data->photosets, photoset_title, (GCompareFunc) find_photoset_by_title);
+				if (link != NULL)
+					data->photoset = g_object_ref (link->data);
+
+				if (data->photoset == NULL) {
+					data->photoset = flickr_photoset_new ();
+					flickr_photoset_set_title (data->photoset, photoset_title);
+				}
+			}
+
 			file_list = gth_file_data_list_to_file_list (data->file_list);
-			flickr_service_post_photos (data->picasaweb,
-						    album,
+			flickr_service_post_photos (data->service,
+						    gtk_combo_box_get_active (GTK_COMBO_BOX (GET_WIDGET ("privacy_combobox"))),
+						    gtk_combo_box_get_active (GTK_COMBO_BOX (GET_WIDGET ("safety_combobox"))),
+						    gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("hidden_checkbutton"))),
 						    file_list,
 						    data->cancellable,
 						    post_photos_ready_cb,
 						    data);
 
 			_g_object_list_unref (file_list);
-			g_object_unref (album);
-			*/
+			g_free (photoset_title);
 		}
 		break;
 
@@ -224,7 +383,7 @@ photoset_list_ready_cb (GObject      *source_object,
 		char           *n_photos;
 		GtkTreeIter     iter;
 
-		n_photos = g_strdup_printf ("%d", photoset->n_photos);
+		n_photos = g_strdup_printf ("(%d)", photoset->n_photos);
 
 		gtk_list_store_append (GTK_LIST_STORE (GET_WIDGET ("photoset_liststore")), &iter);
 		gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("photoset_liststore")), &iter,
@@ -626,14 +785,13 @@ void
 dlg_export_to_flickr (GthBrowser *browser,
 		      GList      *file_list)
 {
-	DialogData       *data;
-	GList            *scan;
-	int               n_total;
-	goffset           total_size;
-	char             *total_size_formatted;
-	char             *text;
-	GtkWidget        *list_view;
-	/*GtkTreeSelection *selection;*/
+	DialogData *data;
+	GList      *scan;
+	int         n_total;
+	goffset     total_size;
+	char       *total_size_formatted;
+	char       *text;
+	GtkWidget  *list_view;
 
 	data = g_new0 (DialogData, 1);
 	data->browser = browser;
@@ -664,6 +822,7 @@ dlg_export_to_flickr (GthBrowser *browser,
 			data->file_list = g_list_prepend (data->file_list, new_file_data);
 		}
 	}
+	data->file_list = g_list_reverse (data->file_list);
 
 	if (data->file_list == NULL) {
 		GError *error;
@@ -671,6 +830,7 @@ dlg_export_to_flickr (GthBrowser *browser,
 		error = g_error_new_literal (GTH_ERROR, GTH_ERROR_GENERIC, _("No valid file selected."));
 		_gtk_error_dialog_from_gerror_show (GTK_WINDOW (browser), _("Could not export the files"), &error);
 		gtk_widget_destroy (data->dialog);
+
 		return;
 	}
 
@@ -692,6 +852,7 @@ dlg_export_to_flickr (GthBrowser *browser,
 	gtk_box_pack_start (GTK_BOX (GET_WIDGET ("images_box")), list_view, TRUE, TRUE, 0);
 	gth_file_list_set_files (GTH_FILE_LIST (list_view), data->file_list);
 
+	gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (GET_WIDGET ("photoset_comboboxentry")))), g_file_info_get_edit_name (data->location->info));
 	gtk_widget_set_sensitive (GET_WIDGET ("upload_button"), FALSE);
 
 	/* Set the signals handlers. */
@@ -700,7 +861,6 @@ dlg_export_to_flickr (GthBrowser *browser,
 			  "destroy",
 			  G_CALLBACK (export_dialog_destroy_cb),
 			  data);
-
 	g_signal_connect (data->dialog,
 			  "response",
 			  G_CALLBACK (export_dialog_response_cb),
@@ -714,19 +874,10 @@ dlg_export_to_flickr (GthBrowser *browser,
 			  G_CALLBACK (account_combobox_changed_cb),
 			  data);
 
-	/* FIXME
-	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (GET_WIDGET ("albums_treeview")));
-	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
-	g_signal_connect (selection,
-			  "changed",
-			  G_CALLBACK (albums_treeview_selection_changed_cb),
-			  data);
-
-	data->accounts = flickr_accounts_load_from_file (&data->username);
-	auto_select_account (data);
-	*/
-
 	data->conn = flickr_connection_new ();
+	data->progress_dialog = gth_progress_dialog_new (GTK_WINDOW (data->browser));
+	gth_progress_dialog_add_task (GTH_PROGRESS_DIALOG (data->progress_dialog), GTH_TASK (data->conn));
+
 	data->accounts = flickr_accounts_load_from_file ();
 	data->account = flickr_accounts_find_default (data->accounts);
 	auto_select_account (data);
diff --git a/extensions/flicker/flickr-photoset.c b/extensions/flicker/flickr-photoset.c
index 7975e78..e9f9244 100644
--- a/extensions/flicker/flickr-photoset.c
+++ b/extensions/flicker/flickr-photoset.c
@@ -110,6 +110,7 @@ flickr_photoset_load_from_element (DomDomizable *base,
 	flickr_photoset_set_secret (self, dom_element_get_attribute (element, "secret"));
 	flickr_photoset_set_server (self, dom_element_get_attribute (element, "server"));
 	flickr_photoset_set_farm (self, dom_element_get_attribute (element, "farm"));
+	flickr_photoset_set_url (self, dom_element_get_attribute (element, "url"));
 
 	for (node = element->first_child; node; node = node->next_sibling) {
 		if (g_strcmp0 (node->tag_name, "title") == 0) {
@@ -264,3 +265,14 @@ flickr_photoset_set_farm (FlickrPhotoset *self,
 	if (value != NULL)
 		self->farm = g_strdup (value);
 }
+
+
+void
+flickr_photoset_set_url (FlickrPhotoset *self,
+			 const char     *value)
+{
+	g_free (self->url);
+	self->url = NULL;
+	if (value != NULL)
+		self->url = g_strdup (value);
+}
diff --git a/extensions/flicker/flickr-photoset.h b/extensions/flicker/flickr-photoset.h
index bc0c3bb..3450128 100644
--- a/extensions/flicker/flickr-photoset.h
+++ b/extensions/flicker/flickr-photoset.h
@@ -51,6 +51,7 @@ struct _FlickrPhotoset {
 	char *secret;
 	char *server;
 	char *farm;
+	char *url;
 };
 
 struct _FlickrPhotosetClass {
@@ -75,6 +76,8 @@ void              flickr_photoset_set_server        (FlickrPhotoset *self,
 						     const char     *value);
 void              flickr_photoset_set_farm          (FlickrPhotoset *self,
 						     const char     *value);
+void              flickr_photoset_set_url           (FlickrPhotoset *self,
+						     const char     *value);
 
 G_END_DECLS
 
diff --git a/extensions/flicker/flickr-service.c b/extensions/flicker/flickr-service.c
index f557902..d167f7a 100644
--- a/extensions/flicker/flickr-service.c
+++ b/extensions/flicker/flickr-service.c
@@ -32,7 +32,9 @@
 
 
 typedef struct {
-	FlickrPhotoset      *album;
+	FlickrPrivacyType    privacy_level;
+	FlickrSafetyType     safety_level;
+	gboolean             hidden;
 	GList               *file_list;
 	GCancellable        *cancellable;
         GAsyncReadyCallback  callback;
@@ -42,6 +44,7 @@ typedef struct {
 	goffset              uploaded_size;
 	int                  n_files;
 	int                  uploaded_files;
+	GList               *ids;
 } PostPhotosData;
 
 
@@ -50,18 +53,43 @@ post_photos_data_free (PostPhotosData *post_photos)
 {
 	if (post_photos == NULL)
 		return;
+	_g_string_list_free (post_photos->ids);
 	_g_object_unref (post_photos->cancellable);
 	_g_object_list_unref (post_photos->file_list);
-	g_object_unref (post_photos->album);
 	g_free (post_photos);
 }
 
 
+typedef struct {
+	FlickrPhotoset      *photoset;
+	GList               *photo_ids;
+	GCancellable        *cancellable;
+        GAsyncReadyCallback  callback;
+        gpointer             user_data;
+        int                  n_files;
+        GList               *current;
+        int                  n_current;
+} AddPhotosData;
+
+
+static void
+add_photos_data_free (AddPhotosData *add_photos)
+{
+	if (add_photos == NULL)
+		return;
+	_g_object_unref (add_photos->photoset);
+	_g_string_list_free (add_photos->photo_ids);
+	_g_object_unref (add_photos->cancellable);
+	g_free (add_photos);
+}
+
+
 struct _FlickrServicePrivate
 {
 	FlickrConnection *conn;
 	FlickrUser       *user;
 	PostPhotosData   *post_photos;
+	AddPhotosData    *add_photos;
 };
 
 
@@ -78,6 +106,7 @@ flickr_service_finalize (GObject *object)
 	_g_object_unref (self->priv->conn);
 	_g_object_unref (self->priv->user);
 	post_photos_data_free (self->priv->post_photos);
+	add_photos_data_free (self->priv->add_photos);
 
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -349,24 +378,23 @@ flickr_service_list_photosets_finish (FlickrService  *service,
 }
 
 
-#if 0
-/* -- flickr_service_create_album -- */
+/* -- flickr_service_create_photoset_finish -- */
 
 
 static void
-create_album_ready_cb (SoupSession *session,
-		       SoupMessage *msg,
-		       gpointer     user_data)
+create_photoset_ready_cb (SoupSession *session,
+			  SoupMessage *msg,
+			  gpointer     user_data)
 {
 	FlickrService      *self = user_data;
 	GSimpleAsyncResult *result;
 	SoupBuffer         *body;
-	DomDocument        *doc;
+	DomDocument        *doc = NULL;
 	GError             *error = NULL;
 
-	result = google_connection_get_result (self->priv->conn);
+	result = flickr_connection_get_result (self->priv->conn);
 
-	if (msg->status_code != 201) {
+	if (msg->status_code != 200) {
 		g_simple_async_result_set_error (result,
 						 SOUP_HTTP_ERROR,
 						 msg->status_code,
@@ -377,72 +405,74 @@ create_album_ready_cb (SoupSession *session,
 	}
 
 	body = soup_message_body_flatten (msg->response_body);
-	doc = dom_document_new ();
-	if (dom_document_load (doc, body->data, body->length, &error)) {
-		FlickrPhotoset *album;
+	if (flickr_utils_parse_response (body, &doc, &error)) {
+		DomElement     *response;
+		DomElement     *node;
+		FlickrPhotoset *photoset = NULL;
+
+		response = DOM_ELEMENT (doc)->first_child;
+		for (node = response->first_child; node; node = node->next_sibling) {
+			if (g_strcmp0 (node->tag_name, "photoset") == 0) {
+				photoset = flickr_photoset_new ();
+				dom_domizable_load_from_element (DOM_DOMIZABLE (photoset), node);
+				g_simple_async_result_set_op_res_gpointer (result, photoset, (GDestroyNotify) g_object_unref);
+			}
+		}
+
+		if (photoset == NULL) {
+			error = g_error_new_literal (FLICKR_CONNECTION_ERROR, 0, _("Unknown error"));
+			g_simple_async_result_set_from_error (result, error);
+		}
 
-		album = flickr_album_new ();
-		dom_domizable_load_from_element (DOM_DOMIZABLE (album), DOM_ELEMENT (doc)->first_child);
-		g_simple_async_result_set_op_res_gpointer (result, album, (GDestroyNotify) g_object_unref);
+		g_object_unref (doc);
 	}
-	else {
+	else
 		g_simple_async_result_set_from_error (result, error);
-		g_error_free (error);
-	}
+
 	g_simple_async_result_complete_in_idle (result);
 
-	g_object_unref (doc);
 	soup_buffer_free (body);
 }
 
 
 void
-flickr_service_create_album (FlickrService        *self,
-			     FlickrPhotoset       *album,
-			     GCancellable         *cancellable,
-			     GAsyncReadyCallback   callback,
-			     gpointer              user_data)
+flickr_service_create_photoset (FlickrService       *self,
+				FlickrPhotoset      *photoset,
+				GCancellable        *cancellable,
+				GAsyncReadyCallback  callback,
+				gpointer             user_data)
 {
-	DomDocument *doc;
-	DomElement  *entry;
-	char        *buffer;
-	gsize        len;
-	char        *url;
+	GHashTable  *data_set;
 	SoupMessage *msg;
 
-	g_return_if_fail (self->priv->user != NULL);
+	g_return_if_fail (photoset != NULL);
+	g_return_if_fail (photoset->primary != NULL);
 
 	gth_task_progress (GTH_TASK (self->priv->conn), _("Creating the new album"), NULL, TRUE, 0.0);
 
-	doc = dom_document_new ();
-	entry = dom_domizable_create_element (DOM_DOMIZABLE (album), doc);
-	dom_element_set_attribute (entry, "xmlns", "http://www.w3.org/2005/Atom";);
-	dom_element_set_attribute (entry, "xmlns:media", "http://search.yahoo.com/mrss/";);
-	dom_element_set_attribute (entry, "xmlns:gphoto", "http://schemas.google.com/photos/2007";);
-	dom_element_append_child (DOM_ELEMENT (doc), entry);
-	buffer = dom_document_dump (doc, &len);
-
-	url = g_strconcat ("http://picasaweb.google.com/data/feed/api/user/";, self->priv->user->id, NULL);
-	msg = soup_message_new ("POST", url);
-	soup_message_set_request (msg, ATOM_ENTRY_MIME_TYPE, SOUP_MEMORY_TAKE, buffer, len);
-	google_connection_send_message (self->priv->conn,
+	data_set = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (data_set, "method", "flickr.photosets.create");
+	g_hash_table_insert (data_set, "title", photoset->title);
+	g_hash_table_insert (data_set, "primary_photo_id", photoset->primary);
+	flickr_connection_add_api_sig (self->priv->conn, data_set);
+	msg = soup_form_request_new_from_hash ("GET", "http://api.flickr.com/services/rest";, data_set);
+	flickr_connection_send_message (self->priv->conn,
 					msg,
 					cancellable,
 					callback,
 					user_data,
-					flickr_service_create_album,
-					create_album_ready_cb,
+					flickr_service_create_photoset,
+					create_photoset_ready_cb,
 					self);
 
-	g_free (url);
-	g_object_unref (doc);
+	g_hash_table_destroy (data_set);
 }
 
 
 FlickrPhotoset *
-flickr_service_create_album_finish (FlickrService  *service,
-				    GAsyncResult   *result,
-				    GError        **error)
+flickr_service_create_photoset_finish (FlickrService  *self,
+				       GAsyncResult   *result,
+				       GError        **error)
 {
 	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
 		return NULL;
@@ -451,6 +481,154 @@ flickr_service_create_album_finish (FlickrService  *service,
 }
 
 
+/* -- flickr_service_add_photos_to_set -- */
+
+
+static void
+add_photos_to_set_done (FlickrService *self,
+			GError        *error)
+{
+	GSimpleAsyncResult *result;
+
+	result = flickr_connection_get_result (self->priv->conn);
+	if (error == NULL)
+		g_simple_async_result_set_op_res_gboolean (result, TRUE);
+	else
+		g_simple_async_result_set_from_error (result, error);
+
+	g_simple_async_result_complete_in_idle (result);
+}
+
+
+static void add_current_photo_to_set (FlickrService *self);
+
+
+static void
+add_next_photo_to_set (FlickrService *self)
+{
+	self->priv->add_photos->current = self->priv->add_photos->current->next;
+	self->priv->add_photos->n_current += 1;
+	add_current_photo_to_set (self);
+}
+
+
+static void
+add_current_photo_to_set_ready_cb (SoupSession *session,
+				   SoupMessage *msg,
+				   gpointer     user_data)
+{
+	FlickrService      *self = user_data;
+	GSimpleAsyncResult *result;
+	SoupBuffer         *body;
+	DomDocument        *doc = NULL;
+	GError             *error = NULL;
+
+	result = flickr_connection_get_result (self->priv->conn);
+
+	if (msg->status_code != 200) {
+		g_simple_async_result_set_error (result,
+						 SOUP_HTTP_ERROR,
+						 msg->status_code,
+						 "%s",
+						 soup_status_get_phrase (msg->status_code));
+		g_simple_async_result_complete_in_idle (result);
+		return;
+	}
+
+	body = soup_message_body_flatten (msg->response_body);
+	if (! flickr_utils_parse_response (body, &doc, &error)) {
+		soup_buffer_free (body);
+		add_photos_to_set_done (self, error);
+		return;
+	}
+
+	g_object_unref (doc);
+	soup_buffer_free (body);
+
+	add_next_photo_to_set (self);
+}
+
+
+static void
+add_current_photo_to_set (FlickrService *self)
+{
+	char        *photo_id;
+	GHashTable  *data_set;
+	SoupMessage *msg;
+
+	if (self->priv->add_photos->current == NULL) {
+		add_photos_to_set_done (self, NULL);
+		return;
+	}
+
+	gth_task_progress (GTH_TASK (self->priv->conn),
+			   _("Creating the new album"),
+			   "",
+			   FALSE,
+			   (double) self->priv->add_photos->n_current / (self->priv->add_photos->n_files + 1));
+
+	photo_id = self->priv->add_photos->current->data;
+	if (g_strcmp0 (photo_id, self->priv->add_photos->photoset->primary) == 0) {
+		add_next_photo_to_set (self);
+		return;
+	}
+
+	data_set = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (data_set, "method", "flickr.photosets.addPhoto");
+	g_hash_table_insert (data_set, "photoset_id", self->priv->add_photos->photoset->id);
+	g_hash_table_insert (data_set, "photo_id", photo_id);
+	flickr_connection_add_api_sig (self->priv->conn, data_set);
+	msg = soup_form_request_new_from_hash ("POST", "http://api.flickr.com/services/rest";, data_set);
+	flickr_connection_send_message (self->priv->conn,
+					msg,
+					self->priv->add_photos->cancellable,
+					self->priv->add_photos->callback,
+					self->priv->add_photos->user_data,
+					flickr_service_add_photos_to_set,
+					add_current_photo_to_set_ready_cb,
+					self);
+
+	g_hash_table_destroy (data_set);
+}
+
+
+void
+flickr_service_add_photos_to_set (FlickrService        *self,
+				  FlickrPhotoset       *photoset,
+				  GList                *photo_ids,
+				  GCancellable         *cancellable,
+				  GAsyncReadyCallback   callback,
+				  gpointer              user_data)
+{
+	gth_task_progress (GTH_TASK (self->priv->conn), _("Creating the new album"), NULL, TRUE, 0.0);
+
+	add_photos_data_free (self->priv->add_photos);
+	self->priv->add_photos = g_new0 (AddPhotosData, 1);
+	self->priv->add_photos->photoset = _g_object_ref (photoset);
+	self->priv->add_photos->photo_ids = _g_string_list_dup (photo_ids);
+	self->priv->add_photos->cancellable = _g_object_ref (cancellable);
+	self->priv->add_photos->callback = callback;
+	self->priv->add_photos->user_data = user_data;
+	self->priv->add_photos->n_files = g_list_length (self->priv->add_photos->photo_ids);
+	self->priv->add_photos->current = self->priv->add_photos->photo_ids;
+	self->priv->add_photos->n_current = 1;
+
+	add_current_photo_to_set (self);
+}
+
+
+gboolean
+flickr_service_add_photos_to_set_finish (FlickrService  *self,
+					 GAsyncResult   *result,
+					 GError        **error)
+{
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+	else
+		return TRUE;
+}
+
+
 /* -- flickr_service_post_photos -- */
 
 
@@ -460,16 +638,20 @@ post_photos_done (FlickrService *self,
 {
 	GSimpleAsyncResult *result;
 
-	result = google_connection_get_result (self->priv->conn);
-	if (error == NULL)
-		g_simple_async_result_set_op_res_gboolean (result, TRUE);
+	result = flickr_connection_get_result (self->priv->conn);
+	if (error == NULL) {
+		self->priv->post_photos->ids = g_list_reverse (self->priv->post_photos->ids);
+		g_simple_async_result_set_op_res_gpointer (result, self->priv->post_photos->ids, (GDestroyNotify) _g_string_list_free);
+		self->priv->post_photos->ids = NULL;
+	}
 	else
 		g_simple_async_result_set_from_error (result, error);
+
 	g_simple_async_result_complete_in_idle (result);
 }
 
 
-static void picasa_wev_service_post_current_file (FlickrService *self);
+static void flickr_service_post_current_file (FlickrService *self);
 
 
 static void
@@ -478,8 +660,12 @@ post_photo_ready_cb (SoupSession *session,
 		     gpointer     user_data)
 {
 	FlickrService *self = user_data;
+	SoupBuffer    *body;
+	DomDocument   *doc = NULL;
+	GError        *error = NULL;
+	GthFileData   *file_data;
 
-	if (msg->status_code != 201) {
+	if (msg->status_code != 200) {
 		GError *error;
 
 		error = g_error_new (SOUP_HTTP_ERROR, msg->status_code, "%s", soup_status_get_phrase (msg->status_code));
@@ -489,8 +675,60 @@ post_photo_ready_cb (SoupSession *session,
 		return;
 	}
 
+	body = soup_message_body_flatten (msg->response_body);
+	if (flickr_utils_parse_response (body, &doc, &error)) {
+		DomElement *response;
+		DomElement *node;
+
+		/* save the file id */
+
+		response = DOM_ELEMENT (doc)->first_child;
+		for (node = response->first_child; node; node = node->next_sibling) {
+			if (g_strcmp0 (node->tag_name, "photoid") == 0) {
+				const char *id;
+
+				id = dom_element_get_inner_text (node);
+				self->priv->post_photos->ids = g_list_prepend (self->priv->post_photos->ids, g_strdup (id));
+			}
+		}
+
+		g_object_unref (doc);
+	}
+	else {
+		soup_buffer_free (body);
+		post_photos_done (self, error);
+		return;
+	}
+
+	soup_buffer_free (body);
+
+	file_data = self->priv->post_photos->current->data;
+	self->priv->post_photos->uploaded_size += g_file_info_get_size (file_data->info);
 	self->priv->post_photos->current = self->priv->post_photos->current->next;
-	picasa_wev_service_post_current_file (self);
+	flickr_service_post_current_file (self);
+}
+
+
+static char *
+get_safety_value (FlickrSafetyType safety_level)
+{
+	char *value = NULL;
+
+	switch (safety_level) {
+	case FLICKR_SAFETY_SAFE:
+		value = "1";
+		break;
+
+	case FLICKR_SAFETY_MODERATE:
+		value = "2";
+		break;
+
+	case FLICKR_SAFETY_RESTRICTED:
+		value = "3";
+		break;
+	}
+
+	return value;
 }
 
 
@@ -500,21 +738,12 @@ post_photo_file_buffer_ready_cb (void     **buffer,
 				 GError    *error,
 				 gpointer   user_data)
 {
-	FlickrService   *self = user_data;
-	GthFileData        *file_data;
-	SoupMultipart      *multipart;
-	const char         *filename;
-	char               *value;
-	GObject            *metadata;
-	DomDocument        *doc;
-	DomElement         *entry;
-	char               *entry_buffer;
-	gsize               entry_len;
-	SoupMessageHeaders *headers;
-	SoupBuffer         *body;
-	char               *details;
-	char               *url;
-	SoupMessage        *msg;
+	FlickrService *self = user_data;
+	GthFileData   *file_data;
+	SoupMultipart *multipart;
+	char          *uri;
+	SoupBuffer    *body;
+	SoupMessage   *msg;
 
 	if (error != NULL) {
 		post_photos_done (self, error);
@@ -522,88 +751,84 @@ post_photo_file_buffer_ready_cb (void     **buffer,
 	}
 
 	file_data = self->priv->post_photos->current->data;
-	multipart = soup_multipart_new ("multipart/related");
+	multipart = soup_multipart_new ("multipart/form-data");
 
 	/* the metadata part */
 
-	doc = dom_document_new ();
-	entry = dom_document_create_element (doc, "entry",
-					     "xmlns", "http://www.w3.org/2005/Atom";,
-					     "xmlns:gphoto", "http://schemas.google.com/photos/2007";,
-					     "xmlns:media", "http://search.yahoo.com/mrss/";,
-					     NULL);
-
-	filename = g_file_info_get_display_name (file_data->info);
-	dom_element_append_child (entry,
-				  dom_document_create_element_with_text (doc, filename, "title", NULL));
-
-	value = gth_file_data_get_attribute_as_string (file_data, "general::description");
-	if (value == NULL)
-		value = gth_file_data_get_attribute_as_string (file_data, "general::title");
-	dom_element_append_child (entry,
-				  dom_document_create_element_with_text (doc, value, "summary", NULL));
-
-	value = gth_file_data_get_attribute_as_string (file_data, "general::location");
-	if (value != NULL)
-		dom_element_append_child (entry,
-					  dom_document_create_element_with_text (doc, value, "gphoto:location", NULL));
-
-	metadata = g_file_info_get_attribute_object (file_data->info, "general::tags");
-	if ((metadata != NULL) && GTH_IS_STRING_LIST (metadata))
-		value = gth_string_list_join (GTH_STRING_LIST (metadata), ", ");
-	if (value != NULL) {
-		DomElement *group;
-
-		group = dom_document_create_element (doc, "media:group", NULL);
-		dom_element_append_child (group,
-					  dom_document_create_element_with_text (doc, value, "media:keywords", NULL));
-		dom_element_append_child (entry, group);
-
-		g_free (value);
-	}
-
-	dom_element_append_child (entry,
-				  dom_document_create_element (doc, "category",
-							       "scheme", "http://schemas.google.com/g/2005#kind";,
-							       "term", "http://schemas.google.com/photos/2007#photo";,
-							       NULL));
-	dom_element_append_child (DOM_ELEMENT (doc), entry);
-	entry_buffer = dom_document_dump (doc, &entry_len);
-
-	headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
-	soup_message_headers_append (headers, "Content-Type", "application/atom+xml");
-	body = soup_buffer_new (SOUP_MEMORY_TAKE, entry_buffer, entry_len);
-	soup_multipart_append_part (multipart, headers, body);
+	{
+		GHashTable *data_set;
+		char       *title;
+		char       *description;
+		char       *tags;
+		GObject    *metadata;
+		GList      *keys;
+		GList      *scan;
+
+		data_set = g_hash_table_new (g_str_hash, g_str_equal);
+
+		title = gth_file_data_get_attribute_as_string (file_data, "general::title");
+		if (title != NULL)
+			g_hash_table_insert (data_set, "title", title);
+
+		description = gth_file_data_get_attribute_as_string (file_data, "general::description");
+		if (description != NULL)
+			g_hash_table_insert (data_set, "description", description);
+
+		tags = NULL;
+		metadata = g_file_info_get_attribute_object (file_data->info, "general::tags");
+		if ((metadata != NULL) && GTH_IS_STRING_LIST (metadata))
+			tags = gth_string_list_join (GTH_STRING_LIST (metadata), " ");
+		if (tags != NULL)
+			g_hash_table_insert (data_set, "tags", tags);
+
+		g_hash_table_insert (data_set, "is_public", (self->priv->post_photos->privacy_level == FLICKR_PRIVACY_PUBLIC) ? "1" : "0");
+		g_hash_table_insert (data_set, "is_friend", ((self->priv->post_photos->privacy_level == FLICKR_PRIVACY_FRIENDS) || (self->priv->post_photos->privacy_level == FLICKR_PRIVACY_FRIENDS_FAMILY)) ? "1" : "0");
+		g_hash_table_insert (data_set, "is_family", ((self->priv->post_photos->privacy_level == FLICKR_PRIVACY_FAMILY) || (self->priv->post_photos->privacy_level == FLICKR_PRIVACY_FRIENDS_FAMILY)) ? "1" : "0");
+		g_hash_table_insert (data_set, "safety_level", get_safety_value (self->priv->post_photos->safety_level));
+		g_hash_table_insert (data_set, "hidden", self->priv->post_photos->hidden ? "2" : "1");
+		flickr_connection_add_api_sig (self->priv->conn, data_set);
+
+		keys = g_hash_table_get_keys (data_set);
+		for (scan = keys; scan; scan = scan->next) {
+			char *key = scan->data;
+			soup_multipart_append_form_string (multipart, key, g_hash_table_lookup (data_set, key));
+		}
 
-	soup_buffer_free (body);
-	soup_message_headers_free (headers);
-	g_object_unref (doc);
+		g_free (tags);
+		g_list_free (keys);
+		g_hash_table_unref (data_set);
+	}
 
 	/* the file part */
 
+	uri = g_file_get_uri (file_data->file);
 	body = soup_buffer_new (SOUP_MEMORY_TEMPORARY, *buffer, count);
 	soup_multipart_append_form_file (multipart,
-					 "file",
-					 NULL,
+					 "photo",
+					 uri,
 					 gth_file_data_get_mime_type (file_data),
 					 body);
 
 	soup_buffer_free (body);
+	g_free (uri);
 
 	/* send the file */
 
-	/* Translators: %s is a filename */
-	details = g_strdup_printf (_("Uploading '%s'"), filename);
-	gth_task_progress (GTH_TASK (self->priv->conn), NULL, details, TRUE, 0.0);
-	g_free (details);
+	{
+		char *details;
 
-	url = g_strconcat ("http://picasaweb.google.com/data/feed/api/user/";,
-			   self->priv->user->id,
-			   "/albumid/",
-			   self->priv->post_photos->album->id,
-			   NULL);
-	msg = soup_form_request_new_from_multipart (url, multipart);
-	google_connection_send_message (self->priv->conn,
+		/* Translators: %s is a filename */
+		details = g_strdup_printf (_("Uploading '%s'"), g_file_info_get_display_name (file_data->info));
+		gth_task_progress (GTH_TASK (self->priv->conn),
+				   NULL, details,
+				   FALSE,
+				   (double) (self->priv->post_photos->uploaded_size + (g_file_info_get_size (file_data->info) / 2.0)) / self->priv->post_photos->total_size);
+
+		g_free (details);
+	}
+
+	msg = soup_form_request_new_from_multipart ("http://api.flickr.com/services/upload/";, multipart);
+	flickr_connection_send_message (self->priv->conn,
 					msg,
 					self->priv->post_photos->cancellable,
 					self->priv->post_photos->callback,
@@ -612,13 +837,12 @@ post_photo_file_buffer_ready_cb (void     **buffer,
 					post_photo_ready_cb,
 					self);
 
-	g_free (url);
 	soup_multipart_free (multipart);
 }
 
 
 static void
-picasa_wev_service_post_current_file (FlickrService *self)
+flickr_service_post_current_file (FlickrService *self)
 {
 	GthFileData *file_data;
 
@@ -642,6 +866,7 @@ post_photos_info_ready_cb (GList    *files,
 		           gpointer  user_data)
 {
 	FlickrService *self = user_data;
+	GList         *scan;
 
 	if (error != NULL) {
 		post_photos_done (self, error);
@@ -649,39 +874,40 @@ post_photos_info_ready_cb (GList    *files,
 	}
 
 	self->priv->post_photos->file_list = _g_object_list_ref (files);
+	for (scan = self->priv->post_photos->file_list; scan; scan = scan->next) {
+		GthFileData *file_data = scan->data;
+
+		self->priv->post_photos->total_size += g_file_info_get_size (file_data->info);
+		self->priv->post_photos->n_files += 1;
+	}
+
 	self->priv->post_photos->current = self->priv->post_photos->file_list;
-	picasa_wev_service_post_current_file (self);
+	flickr_service_post_current_file (self);
 }
 
 
 void
 flickr_service_post_photos (FlickrService       *self,
-			    FlickrPhotoset      *album,
+			    FlickrPrivacyType    privacy_level,
+			    FlickrSafetyType     safety_level,
+			    gboolean             hidden,
 			    GList               *file_list, /* GFile list */
 			    GCancellable        *cancellable,
 			    GAsyncReadyCallback  callback,
 			    gpointer             user_data)
 {
-	GList *scan;
-
-	g_return_if_fail (album != NULL);
-	g_return_if_fail (self->priv->post_photos == NULL);
-
 	gth_task_progress (GTH_TASK (self->priv->conn), _("Uploading the files to the server"), NULL, TRUE, 0.0);
 
+	post_photos_data_free (self->priv->post_photos);
 	self->priv->post_photos = g_new0 (PostPhotosData, 1);
-	self->priv->post_photos->album = g_object_ref (album);
+	self->priv->post_photos->privacy_level = privacy_level;
+	self->priv->post_photos->safety_level = safety_level;
+	self->priv->post_photos->hidden = hidden;
 	self->priv->post_photos->cancellable = _g_object_ref (cancellable);
 	self->priv->post_photos->callback = callback;
 	self->priv->post_photos->user_data = user_data;
 	self->priv->post_photos->total_size = 0;
 	self->priv->post_photos->n_files = 0;
-	for (scan = self->priv->post_photos->file_list; scan; scan = scan->next) {
-		GthFileData *file_data = scan->data;
-
-		self->priv->post_photos->total_size += g_file_info_get_size (file_data->info);
-		self->priv->post_photos->n_files += 1;
-	}
 
 	_g_query_all_metadata_async (file_list,
 				     FALSE,
@@ -693,18 +919,20 @@ flickr_service_post_photos (FlickrService       *self,
 }
 
 
-gboolean
+GList *
 flickr_service_post_photos_finish (FlickrService  *self,
 				   GAsyncResult   *result,
 				   GError        **error)
 {
 	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
-		return FALSE;
+		return NULL;
 	else
-		return TRUE;
+		return _g_string_list_dup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)));
 }
 
 
+#if 0
+
 /* -- flickr_service_list_photos -- */
 
 
diff --git a/extensions/flicker/flickr-service.h b/extensions/flicker/flickr-service.h
index 8966ceb..90db608 100644
--- a/extensions/flicker/flickr-service.h
+++ b/extensions/flicker/flickr-service.h
@@ -29,6 +29,20 @@
 #include "flickr-photoset.h"
 #include "flickr-user.h"
 
+typedef enum {
+	FLICKR_PRIVACY_PUBLIC,
+	FLICKR_PRIVACY_FRIENDS_FAMILY,
+	FLICKR_PRIVACY_FRIENDS,
+	FLICKR_PRIVACY_FAMILY,
+	FLICKR_PRIVACY_PRIVATE
+} FlickrPrivacyType;
+
+typedef enum {
+	FLICKR_SAFETY_SAFE,
+	FLICKR_SAFETY_MODERATE,
+	FLICKR_SAFETY_RESTRICTED
+} FlickrSafetyType;
+
 #define FLICKR_TYPE_SERVICE         (flickr_service_get_type ())
 #define FLICKR_SERVICE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), FLICKR_TYPE_SERVICE, FlickrService))
 #define FLICKR_SERVICE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), FLICKR_TYPE_SERVICE, FlickrServiceClass))
@@ -68,7 +82,6 @@ void              flickr_service_list_photosets           (FlickrService
 GList *           flickr_service_list_photosets_finish    (FlickrService        *self,
 						           GAsyncResult         *result,
 						           GError              **error);
-#if 0
 void              flickr_service_create_photoset          (FlickrService        *self,
 						           FlickrPhotoset       *photoset,
 						           GCancellable         *cancellable,
@@ -77,15 +90,27 @@ void              flickr_service_create_photoset          (FlickrService
 FlickrPhotoset *  flickr_service_create_photoset_finish   (FlickrService        *self,
 						           GAsyncResult         *result,
 						           GError              **error);
+void              flickr_service_add_photos_to_set        (FlickrService        *self,
+						           FlickrPhotoset       *photoset,
+						           GList                *photo_ids,
+						           GCancellable         *cancellable,
+						           GAsyncReadyCallback   callback,
+						           gpointer              user_data);
+gboolean          flickr_service_add_photos_to_set_finish (FlickrService        *self,
+						           GAsyncResult         *result,
+						           GError              **error);
 void              flickr_service_post_photos              (FlickrService        *self,
-							   FlickrPhotoset       *photoset,
+							   FlickrPrivacyType     privacy_level,
+							   FlickrSafetyType      safety_level,
+							   gboolean              hidden,
 						           GList                *file_list, /* GFile list */
 						           GCancellable         *cancellable,
 						           GAsyncReadyCallback   callback,
 						           gpointer              user_data);
-gboolean          flickr_service_post_photos_finish       (FlickrService        *self,
+GList *           flickr_service_post_photos_finish       (FlickrService        *self,
 						           GAsyncResult         *result,
 						           GError              **error);
+#if 0
 void              flickr_service_list_photos              (FlickrService        *self,
 							   FlickrPhotoset       *photoset,
 						           GCancellable         *cancellable,
diff --git a/extensions/picasaweb/dlg-export-to-picasaweb.c b/extensions/picasaweb/dlg-export-to-picasaweb.c
index 413e255..229c51a 100644
--- a/extensions/picasaweb/dlg-export-to-picasaweb.c
+++ b/extensions/picasaweb/dlg-export-to-picasaweb.c
@@ -634,7 +634,7 @@ add_album_button_clicked_cb (GtkButton *button,
 	DialogData *data = user_data;
 	GtkWidget  *dialog;
 
-	dialog = picasa_album_properties_dialog_new (g_file_info_get_display_name (data->location->info),
+	dialog = picasa_album_properties_dialog_new (g_file_info_get_edit_name (data->location->info),
 						     NULL,
 						     PICASA_WEB_ACCESS_PUBLIC);
 	g_signal_connect (dialog,



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