Merge lp:~mardy/shotwell/uoa-update into lp:~ubuntu-desktop/shotwell/ubuntu

Proposed by Alberto Mardegan
Status: Merged
Merged at revision: 85
Proposed branch: lp:~mardy/shotwell/uoa-update
Merge into: lp:~ubuntu-desktop/shotwell/ubuntu
Diff against target: 2378 lines (+1527/-382)
1 file modified
debian/patches/06_uoa.patch (+1527/-382)
To merge this branch: bzr merge lp:~mardy/shotwell/uoa-update
Reviewer Review Type Date Requested Status
Ubuntu branches Pending
Review via email: mp+124659@code.launchpad.net

Description of the change

Update the UOA patch
* Support multiple accounts per service
* Attempt automatic login
* Remove logout buttons

To post a comment you must log in.
lp:~mardy/shotwell/uoa-update updated
85. By Alberto Mardegan

i18n update

* Allow translating the shotwell.application file
* Add the "Add more accounts..." string for translations.

86. By Alberto Mardegan

Avoid critical warnings

Vala was generating an enumerated type, but all we want is an int.

87. By Alberto Mardegan

Do not make warnings fatal when building plugins

Gtk.Table, which is used all over the place, has been deprecated.

88. By Alberto Mardegan

* New upstream bugfix release
* debian/watch:
  - Watch for stable versions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/patches/06_uoa.patch'
2--- debian/patches/06_uoa.patch 2012-09-20 03:21:36 +0000
3+++ debian/patches/06_uoa.patch 2012-09-24 08:43:19 +0000
4@@ -1,12 +1,12 @@
5 Description: use Ubuntu Online Accounts for Picasa, Facebook and Flickr export plugins
6 Author: Alberto Mardegan <alberto.mardegan@canonical.com>
7
8-=== modified file 'Makefile'
9-Index: shotwell-0.13.0/Makefile
10-===================================================================
11---- shotwell-0.13.0.orig/Makefile 2012-09-20 15:15:16.000000000 +1200
12-+++ shotwell-0.13.0/Makefile 2012-09-20 15:16:00.929921786 +1200
13-@@ -152,6 +152,7 @@
14+---
15+diff --git a/Makefile b/Makefile
16+index 70bdc96..f5ac032 100644
17+--- a/Makefile
18++++ b/Makefile
19+@@ -152,6 +152,7 @@ RESOURCE_FILES = \
20 trash.ui
21
22 SYS_INTEGRATION_FILES = \
23@@ -14,7 +14,7 @@
24 shotwell.desktop.head \
25 shotwell-viewer.desktop.head \
26 org.yorba.shotwell.gschema.xml \
27-@@ -546,6 +547,8 @@
28+@@ -546,6 +547,8 @@ install:
29 $(INSTALL_PROGRAM) $(PROGRAM) $(DESTDIR)$(PREFIX)/bin
30 $(INSTALL_PROGRAM) $(THUMBNAILER_BIN) $(DESTDIR)$(PREFIX)/bin
31 $(INSTALL_PROGRAM) $(MIGRATOR_BIN) $(DESTDIR)$(PREFIX)/bin
32@@ -23,51 +23,36 @@
33 mkdir -p $(DESTDIR)$(PREFIX)/share/shotwell/icons
34 $(INSTALL_DATA) icons/* $(DESTDIR)$(PREFIX)/share/shotwell/icons
35 mkdir -p $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps
36-Index: shotwell-0.13.0/misc/org.yorba.shotwell.gschema.xml
37-===================================================================
38---- shotwell-0.13.0.orig/misc/org.yorba.shotwell.gschema.xml 2012-09-20 07:08:59.000000000 +1200
39-+++ shotwell-0.13.0/misc/org.yorba.shotwell.gschema.xml 2012-09-20 15:16:00.929921786 +1200
40-@@ -310,6 +310,12 @@
41- <description>Facebook user i.d. for the currently logged in user, if any</description>
42- </key>
43-
44-+ <key name="auth-method" type="s">
45-+ <default>""</default>
46-+ <summary>auth method</summary>
47-+ <description>The authorization method for the currently logged in Picasa Web Albums user, if any</description>
48-+ </key>
49-+
50- <key name="user-name" type="s">
51- <default>""</default>
52- <summary>user name</summary>
53-Index: shotwell-0.13.0/misc/shotwell.application
54-===================================================================
55---- /dev/null 1970-01-01 00:00:00.000000000 +0000
56-+++ shotwell-0.13.0/misc/shotwell.application 2012-09-20 15:16:00.929921786 +1200
57-@@ -0,0 +1,18 @@
58+diff --git a/misc/shotwell.application b/misc/shotwell.application
59+new file mode 100644
60+index 0000000..815345f
61+--- /dev/null
62++++ b/misc/shotwell.application
63+@@ -0,0 +1,19 @@
64 +<?xml version="1.0" encoding="UTF-8" ?>
65 +<application id="shotwell">
66 + <description>Shotwell</description>
67-+ <desktop-entry>shotwell.desktop</desktop-entry>
68++ <desktop-entry>shotwell.desktop</desktop-entry>
69++ <translations>shotwell</translations>
70 +
71 + <services>
72-+ <service id="picasa">
73-+ <description>Publish your pictures to Picasa</description>
74-+ </service>
75-+ <service id="facebook-sharing">
76-+ <description>Publish your pictures to Facebook</description>
77-+ </service>
78-+ <service id="flickr-sharing">
79-+ <description>Publish your pictures to Flickr</description>
80-+ </service>
81++ <service id="picasa">
82++ <description>Publish your pictures to Picasa</description>
83++ </service>
84++ <service id="facebook-sharing">
85++ <description>Publish your pictures to Facebook</description>
86++ </service>
87++ <service id="flickr-sharing">
88++ <description>Publish your pictures to Flickr</description>
89++ </service>
90 + </services>
91 +
92 +</application>
93-Index: shotwell-0.13.0/plugins/Makefile
94-===================================================================
95---- shotwell-0.13.0.orig/plugins/Makefile 2012-09-20 07:08:59.000000000 +1200
96-+++ shotwell-0.13.0/plugins/Makefile 2012-09-20 15:16:00.929921786 +1200
97-@@ -4,7 +4,10 @@
98+diff --git a/plugins/Makefile b/plugins/Makefile
99+index c622063..255e9cc 100644
100+--- a/plugins/Makefile
101++++ b/plugins/Makefile
102+@@ -4,7 +4,10 @@ include plugins.mk
103 DIST_FILES := \
104 Makefile \
105 Makefile.plugin.mk \
106@@ -79,11 +64,11 @@
107
108 .PHONY: all
109 all: $(ALL_PLUGINS)
110-Index: shotwell-0.13.0/plugins/Makefile.plugin.mk
111-===================================================================
112---- shotwell-0.13.0.orig/plugins/Makefile.plugin.mk 2012-09-20 07:08:59.000000000 +1200
113-+++ shotwell-0.13.0/plugins/Makefile.plugin.mk 2012-09-20 15:16:00.929921786 +1200
114-@@ -27,6 +27,8 @@
115+diff --git a/plugins/Makefile.plugin.mk b/plugins/Makefile.plugin.mk
116+index d76433b..211c02a 100644
117+--- a/plugins/Makefile.plugin.mk
118++++ b/plugins/Makefile.plugin.mk
119+@@ -27,6 +27,8 @@ PKGS := $(shell sed ':a;N;$$!ba;s/\n/ /g' ../shotwell-plugin-dev-1.0.deps) $(PKG
120 # automatically include the shotwell-plugin-dev-1.0 package as a local dependency
121 EXT_PKGS := $(PKGS)
122 PKGS := shotwell-plugin-dev-1.0 $(PKGS) $(PLUGIN_PKGS)
123@@ -92,11 +77,11 @@
124
125 # automatically include the Resources.vala common file
126 SRC_FILES := ../common/Resources.vala $(SRC_FILES)
127-Index: shotwell-0.13.0/plugins/common/RESTSupport.vala
128-===================================================================
129---- shotwell-0.13.0.orig/plugins/common/RESTSupport.vala 2012-09-20 07:08:59.000000000 +1200
130-+++ shotwell-0.13.0/plugins/common/RESTSupport.vala 2012-09-20 15:16:00.929921786 +1200
131-@@ -314,7 +314,7 @@
132+diff --git a/plugins/common/RESTSupport.vala b/plugins/common/RESTSupport.vala
133+index 3f5ed21..3e90828 100644
134+--- a/plugins/common/RESTSupport.vala
135++++ b/plugins/common/RESTSupport.vala
136+@@ -314,7 +314,7 @@ public class Transaction {
137 old_url = message.get_uri().to_string(false);
138 url_with_query = get_endpoint_url() + "?" + formdata_string;
139 message.set_uri(new Soup.URI(url_with_query));
140@@ -105,22 +90,23 @@
141 message.set_request("application/x-www-form-urlencoded", Soup.MemoryUse.COPY,
142 formdata_string.data);
143 }
144-Index: shotwell-0.13.0/plugins/common/accounts.vala
145-===================================================================
146---- /dev/null 1970-01-01 00:00:00.000000000 +0000
147-+++ shotwell-0.13.0/plugins/common/accounts.vala 2012-09-20 15:16:00.929921786 +1200
148-@@ -0,0 +1,54 @@
149+diff --git a/plugins/common/accounts.vala b/plugins/common/accounts.vala
150+new file mode 100644
151+index 0000000..ee2d9da
152+--- /dev/null
153++++ b/plugins/common/accounts.vala
154+@@ -0,0 +1,226 @@
155 +/* Copyright 2009-2011 Yorba Foundation
156 + *
157 + * This software is licensed under the GNU Lesser General Public License
158-+ * (version 2.1 or later). See the COPYING file in this distribution.
159++ * (version 2.1 or later). See the COPYING file in this distribution.
160 + */
161 +
162 +namespace Publishing.Accounts {
163 +
164 +public class SharingAccount {
165 + private Ag.AccountService account_service = null;
166-+
167++
168 + public SharingAccount(Ag.AccountService account_service) {
169 + this.account_service = account_service;
170 + }
171@@ -142,54 +128,297 @@
172 +}
173 +
174 +public class SharingAccounts {
175-+ private Ag.Manager manager = null;
176-+
177-+ public SharingAccounts() {
178-+ manager = new Ag.Manager.for_service_type("sharing");
179-+ }
180-+
181-+ public SharingAccount? get_account_for_provider(string provider) {
182++ private static Ag.Manager manager = null;
183++ private string provider_name;
184++ private Ag.AccountService[] all_accounts;
185++
186++ public SharingAccounts(string provider_name) {
187++ if (manager == null) {
188++ manager = new Ag.Manager.for_service_type("sharing");
189++ }
190++ manager.enabled_event.connect(on_account_enabled);
191++
192++ this.provider_name = provider_name;
193++ all_accounts = get_accounts();
194++ }
195++
196++ private void on_account_enabled(uint account_id) {
197++ /* To keep the implementation simple, just rebuild the account
198++ * list from scratch */
199++ all_accounts = get_accounts();
200++ }
201++
202++ private Ag.AccountService[] get_accounts() {
203 + GLib.List<Ag.AccountService> accounts =
204 + manager.get_enabled_account_services();
205 +
206++ Ag.AccountService[] list = {};
207++
208 + foreach (Ag.AccountService account_service in accounts) {
209 + Ag.Account account = account_service.get_account();
210-+ if (account.get_provider_name() == provider) {
211++ if (account.get_provider_name() == provider_name) {
212++ list += account_service;
213++ }
214++ }
215++ return list;
216++ }
217++
218++ public bool has_enabled_accounts() {
219++ return all_accounts.length > 0;
220++ }
221++
222++ public string[] list_account_names() {
223++ string[] names = {};
224++ foreach (Ag.AccountService account_service in all_accounts) {
225++ names += account_service.get_account().get_display_name();
226++ }
227++ return names;
228++ }
229++
230++ public SharingAccount? find_account(string? account_name) {
231++ foreach (Ag.AccountService account_service in all_accounts)
232++ if (account_service.get_account().get_display_name() == account_name) {
233 + return new SharingAccount(account_service);
234 + }
235-+ }
236++
237 + return null;
238 + }
239 +}
240 +
241-+}
242-+
243-Index: shotwell-0.13.0/plugins/shotwell-publishing/FacebookPublishing.vala
244-===================================================================
245---- shotwell-0.13.0.orig/plugins/shotwell-publishing/FacebookPublishing.vala 2012-09-20 07:08:59.000000000 +1200
246-+++ shotwell-0.13.0/plugins/shotwell-publishing/FacebookPublishing.vala 2012-09-20 15:16:00.933921786 +1200
247-@@ -4,6 +4,8 @@
248++public abstract class UOAPublishingService : Object, Spit.Pluggable, Spit.Publishing.Service {
249++ private SharingAccounts account_manager;
250++
251++ public UOAPublishingService(string provider_name) {
252++ account_manager = new SharingAccounts(provider_name);
253++ }
254++
255++ public virtual int get_pluggable_interface(int min_host_interface, int max_host_interface) {
256++ return Spit.negotiate_interfaces(min_host_interface, max_host_interface,
257++ Spit.Publishing.CURRENT_INTERFACE);
258++ }
259++
260++ public abstract unowned string get_id();
261++
262++ public abstract unowned string get_pluggable_name();
263++
264++ public abstract void get_info(ref Spit.PluggableInfo info);
265++
266++ public virtual void activation(bool enabled) {
267++ }
268++
269++ public abstract Spit.Publishing.Publisher create_publisher(string? account_name, Spit.Publishing.PluginHost host);
270++
271++ public abstract Spit.Publishing.Publisher.MediaType get_supported_media();
272++
273++ public SharingAccount? find_account(string? account_name) {
274++ return account_manager.find_account(account_name);
275++ }
276++
277++ public bool is_enabled() {
278++ return account_manager.has_enabled_accounts();
279++ }
280++
281++ public string[] list_account_names() {
282++ return account_manager.list_account_names();
283++ }
284++}
285++
286++public class UOAPublisherAuthenticator : Object {
287++ private weak Spit.Publishing.PluginHost host = null;
288++ private Signon.AuthSession auth_session = null;
289++ private SharingAccount account = null;
290++ private bool firstLoginAttempt = true;
291++ private string welcome_message = null;
292++
293++ public UOAPublisherAuthenticator(SharingAccount account,
294++ Spit.Publishing.PluginHost host,
295++ string welcome_message)
296++ {
297++ this.host = host;
298++ this.account = account;
299++ this.welcome_message = welcome_message;
300++ }
301++
302++ public signal void authenticated(owned HashTable<string,Value?> session_data);
303++
304++ public void authenticate() {
305++ debug("ACTION: authentication requested.");
306++
307++ do_authentication();
308++ }
309++
310++ public HashTable<string,Value?>? get_authentication_data() {
311++ if (account == null) return null;
312++ string mechanism = null;
313++ return account.get_session_parameters(out mechanism);
314++ }
315++
316++ private void do_authentication() {
317++ debug("ACTION: authenticating.");
318++
319++ HashTable<string,Value?> data = null;
320++ string mechanism = null;
321++
322++ if (account != null) {
323++ try {
324++ auth_session = account.create_auth_session();
325++ data = account.get_session_parameters(out mechanism);
326++ debug("Got account data");
327++ } catch (GLib.Error e) {
328++ warning("EVENT: couldn't create session for account: %s",
329++ e.message);
330++ }
331++ }
332++
333++ if (data == null) {
334++ warning ("No account authentication data");
335++ host.post_error(new Spit.Publishing.PublishingError.SERVICE_ERROR(
336++ "Error while accessing the account"));
337++ return;
338++ }
339++
340++ if (firstLoginAttempt) {
341++ firstLoginAttempt = false;
342++ data.insert("UiPolicy", (int)Signon.SessionDataUiPolicy.NO_USER_INTERACTION);
343++ } else {
344++ var windowId = host.get_dialog_xid();
345++ if (windowId != 0) {
346++ data.insert("WindowId", (uint)windowId);
347++ }
348++ }
349++
350++ auth_session.process(data, mechanism, on_processed);
351++ host.set_service_locked(true);
352++ }
353++
354++ private void on_processed(Signon.AuthSession self, owned HashTable<string,Value?>? session_data, GLib.Error error){
355++ host.set_service_locked(false);
356++ if (error != null) {
357++ debug("got error: %s", error.message);
358++ if (error is Signon.Error.USER_INTERACTION) {
359++ debug("User interaction!");
360++ do_show_service_welcome_pane();
361++ } else {
362++ host.post_error(new Spit.Publishing.PublishingError.SERVICE_ERROR("Authentication failed"));
363++ }
364++ return;
365++ }
366++
367++ authenticated(session_data);
368++ }
369++
370++ private void do_show_service_welcome_pane() {
371++ debug("ACTION: showing service welcome pane.");
372++
373++ host.install_welcome_pane(welcome_message, on_service_welcome_login);
374++ }
375++
376++ private void on_service_welcome_login() {
377++ debug("EVENT: user clicked 'Login' in welcome pane.");
378++
379++ do_authentication();
380++ }
381++}
382++
383++}
384++
385+diff --git a/plugins/shotwell-publishing-extras/TumblrPublishing.vala b/plugins/shotwell-publishing-extras/TumblrPublishing.vala
386+index c65e19a..e3cfb79 100644
387+--- a/plugins/shotwell-publishing-extras/TumblrPublishing.vala
388++++ b/plugins/shotwell-publishing-extras/TumblrPublishing.vala
389+@@ -48,7 +48,7 @@ public class TumblrService : Object, Spit.Pluggable, Spit.Publishing.Service {
390+ public void activation(bool enabled) {
391+ }
392+
393+- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
394++ public Spit.Publishing.Publisher create_publisher(string? account, Spit.Publishing.PluginHost host) {
395+ return new Publishing.Tumblr.TumblrPublisher(this, host);
396+ }
397+
398+diff --git a/plugins/shotwell-publishing-extras/YandexPublishing.vala b/plugins/shotwell-publishing-extras/YandexPublishing.vala
399+index 1370690..760a8f3 100644
400+--- a/plugins/shotwell-publishing-extras/YandexPublishing.vala
401++++ b/plugins/shotwell-publishing-extras/YandexPublishing.vala
402+@@ -30,7 +30,7 @@ public class YandexService : Object, Spit.Pluggable, Spit.Publishing.Service {
403+ info.license = Resources.LICENSE;
404+ }
405+
406+- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
407++ public Spit.Publishing.Publisher create_publisher(string? account, Spit.Publishing.PluginHost host) {
408+ return new Publishing.Yandex.YandexPublisher(this, host);
409+ }
410+
411+diff --git a/plugins/shotwell-publishing/FacebookPublishing.vala b/plugins/shotwell-publishing/FacebookPublishing.vala
412+index fa9d8f2..bd3cd08 100644
413+--- a/plugins/shotwell-publishing/FacebookPublishing.vala
414++++ b/plugins/shotwell-publishing/FacebookPublishing.vala
415+@@ -4,30 +4,28 @@
416 * (version 2.1 or later). See the COPYING file in this distribution.
417 */
418
419+-public class FacebookService : Object, Spit.Pluggable, Spit.Publishing.Service {
420 +using Publishing.Accounts;
421 +
422- public class FacebookService : Object, Spit.Pluggable, Spit.Publishing.Service {
423++public class FacebookService : UOAPublishingService, Spit.Pluggable, Spit.Publishing.Service {
424 private const string ICON_FILENAME = "facebook.png";
425
426-@@ -50,6 +52,11 @@
427+ private static Gdk.Pixbuf[] icon_pixbuf_set = null;
428+
429+ public FacebookService(GLib.File resource_directory) {
430++ base("facebook");
431+ if (icon_pixbuf_set == null)
432+ icon_pixbuf_set = Resources.load_icon_set(resource_directory.get_child(ICON_FILENAME));
433+ }
434+
435+- public int get_pluggable_interface(int min_host_interface, int max_host_interface) {
436+- return Spit.negotiate_interfaces(min_host_interface, max_host_interface,
437+- Spit.Publishing.CURRENT_INTERFACE);
438+- }
439+-
440+- public unowned string get_id() {
441++ public override unowned string get_id() {
442+ return "org.yorba.shotwell.publishing.facebook";
443+ }
444+
445+- public unowned string get_pluggable_name() {
446++ public override unowned string get_pluggable_name() {
447+ return "Facebook";
448+ }
449+
450+- public void get_info(ref Spit.PluggableInfo info) {
451++ public override void get_info(ref Spit.PluggableInfo info) {
452+ info.authors = "Lucas Beeler";
453+ info.copyright = _("Copyright 2009-2012 Yorba Foundation");
454+ info.translators = Resources.TRANSLATORS;
455+@@ -39,14 +37,12 @@ public class FacebookService : Object, Spit.Pluggable, Spit.Publishing.Service {
456+ info.icons = icon_pixbuf_set;
457+ }
458+
459+- public void activation(bool enabled) {
460++ public override Spit.Publishing.Publisher create_publisher(string? account_name, Spit.Publishing.PluginHost host) {
461++ SharingAccount account = find_account(account_name);
462++ return new Publishing.Facebook.FacebookPublisher(this, account, host);
463+ }
464+
465+- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
466+- return new Publishing.Facebook.FacebookPublisher(this, host);
467+- }
468+-
469+- public Spit.Publishing.Publisher.MediaType get_supported_media() {
470++ public override Spit.Publishing.Publisher.MediaType get_supported_media() {
471 return (Spit.Publishing.Publisher.MediaType.PHOTO |
472 Spit.Publishing.Publisher.MediaType.VIDEO);
473 }
474-+
475-+ public bool is_enabled() {
476-+ SharingAccounts accounts = new SharingAccounts();
477-+ return accounts.get_account_for_provider("facebook") != null;
478-+ }
479- }
480-
481- namespace Publishing.Facebook {
482-@@ -163,11 +170,11 @@
483+@@ -66,8 +62,6 @@ internal const string PHOTO_ENDPOINT_URL = "https://api.facebook.com/restserver.
484+ internal const string VIDEO_ENDPOINT_URL = "https://api-video.facebook.com/restserver.php";
485+ internal const string SERVICE_WELCOME_MESSAGE =
486+ _("You are not currently logged into Facebook.\n\nIf you don't yet have a Facebook account, you can create one during the login process. During login, Shotwell Connect may ask you for permission to upload photos and publish to your feed. These permissions are required for Shotwell Connect to function.");
487+-internal const string RESTART_ERROR_MESSAGE =
488+- _("You have already logged in and out of Facebook during this Shotwell session.\nTo continue publishing to Facebook, quit and restart Shotwell, then try publishing again.");
489+ // as of mid-November 2010, the privacy the simple string "SELF" is no longer a valid
490+ // privacy value; "SELF" must be simulated by a "CUSTOM" setting; see the discussion
491+ // http://forum.developers.facebook.net/viewtopic.php?pid=289287
492+@@ -163,19 +157,23 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
493 private int publish_to_album = NO_ALBUM;
494 private weak Spit.Publishing.PluginHost host = null;
495 private FacebookRESTSession session = null;
496@@ -198,51 +427,153 @@
497 private weak Spit.Publishing.Service service = null;
498 private bool strip_metadata = false;
499 private bool running = false;
500-+ private Signon.AuthSession auth_session = null;
501++ private UOAPublisherAuthenticator authenticator = null;
502
503 private Resolution target_resolution = Resolution.HIGH;
504
505-@@ -402,37 +409,56 @@
506+ public FacebookPublisher(Spit.Publishing.Service service,
507++ SharingAccount account,
508+ Spit.Publishing.PluginHost host) {
509+ debug("FacebookPublisher instantiated.");
510+ this.service = service;
511+ this.host = host;
512++ authenticator = new UOAPublisherAuthenticator(account, host,
513++ SERVICE_WELCOME_MESSAGE);
514++ authenticator.authenticated.connect(on_authenticator_authenticated);
515+ }
516+
517+ private bool is_running() {
518+@@ -190,49 +188,10 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
519+ return NO_ALBUM;
520+ }
521+
522+- private bool is_persistent_session_valid() {
523+- string? access_token = get_persistent_access_token();
524+- string? uid = get_persistent_uid();
525+- string? user_name = get_persistent_user_name();
526+-
527+- bool valid = ((access_token != null) && (uid != null) && (user_name != null));
528+-
529+- if (valid)
530+- debug("existing Facebook session for user = '%s' found in configuration database; using it.", user_name);
531+- else
532+- debug("no persisted Facebook session exists.");
533+-
534+- return valid;
535+- }
536+-
537+- private string? get_persistent_access_token() {
538+- return host.get_config_string("access_token", null);
539+- }
540+-
541+- private string? get_persistent_uid() {
542+- return host.get_config_string("uid", null);
543+- }
544+-
545+- private string? get_persistent_user_name() {
546+- return host.get_config_string("user_name", null);
547+- }
548+-
549+ private bool get_persistent_strip_metadata() {
550+ return host.get_config_bool("strip_metadata", false);
551+ }
552+
553+- private void set_persistent_access_token(string access_token) {
554+- host.set_config_string("access_token", access_token);
555+- }
556+-
557+- private void set_persistent_uid(string uid) {
558+- host.set_config_string("uid", uid);
559+- }
560+-
561+- private void set_persistent_user_name(string user_name) {
562+- host.set_config_string("user_name", user_name);
563+- }
564+-
565+ private void set_persistent_strip_metadata(bool strip_metadata) {
566+ host.set_config_bool("strip_metadata", strip_metadata);
567+ }
568+@@ -247,39 +206,6 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
569+ host.set_config_int("default_size", size);
570+ }
571+
572+- private void invalidate_persistent_session() {
573+- debug("invalidating persisted Facebook session.");
574+-
575+- set_persistent_access_token("");
576+- set_persistent_uid("");
577+- set_persistent_user_name("");
578+- }
579+-
580+- private void do_show_service_welcome_pane() {
581+- debug("ACTION: showing service welcome pane.");
582+-
583+- host.install_welcome_pane(SERVICE_WELCOME_MESSAGE, on_login_clicked);
584+- host.set_service_locked(false);
585+- }
586+-
587+- private void do_test_connection_to_endpoint() {
588+- debug("ACTION: testing connection to Facebook endpoint.");
589+- host.set_service_locked(true);
590+-
591+- host.install_static_message_pane(_("Testing connection to Facebook..."));
592+-
593+- FacebookEndpointTestTransaction txn = new FacebookEndpointTestTransaction(session);
594+- txn.completed.connect(on_endpoint_test_completed);
595+- txn.network_error.connect(on_endpoint_test_error);
596+-
597+- try {
598+- txn.execute();
599+- } catch (Spit.Publishing.PublishingError err) {
600+- if (is_running())
601+- host.post_error(err);
602+- }
603+- }
604+-
605+ private void do_fetch_album_descriptions() {
606+ debug("ACTION: fetching album descriptions from remote endpoint.");
607+
608+@@ -387,7 +313,6 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
609+ PublishingOptionsPane publishing_options_pane = new PublishingOptionsPane(
610+ session.get_user_name(), albums, host.get_publishable_media_type(), this, builder,
611+ get_persistent_strip_metadata());
612+- publishing_options_pane.logout.connect(on_publishing_options_pane_logout);
613+ publishing_options_pane.publish.connect(on_publishing_options_pane_publish);
614+ host.install_dialog_pane(publishing_options_pane,
615+ Spit.Publishing.PluginHost.ButtonMode.CANCEL);
616+@@ -396,51 +321,20 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
617+ private void do_logout() {
618+ debug("ACTION: clearing persistent session information and restaring interaction.");
619+
620+- invalidate_persistent_session();
621+-
622+ running = false;
623 start();
624 }
625
626 - private void do_hosted_web_authentication() {
627 - debug("ACTION: doing hosted web authentication.");
628-+ public void on_processed(Signon.AuthSession self, owned HashTable<string,Value?> session_data, GLib.Error error){
629-+ /* TODO: handle errors */
630-
631+-
632 - host.set_service_locked(false);
633-+ host.set_service_locked(true);
634-+ host.install_account_fetch_wait_pane();
635-
636+-
637 - web_auth_pane = new WebAuthenticationPane();
638 - web_auth_pane.login_succeeded.connect(on_web_auth_pane_login_succeeded);
639 - web_auth_pane.login_failed.connect(on_web_auth_pane_login_failed);
640-+ session.authenticated.connect(on_session_authenticated);
641-+ session.authentication_failed.connect(on_session_authentication_failed);
642-
643+-
644 - host.install_dialog_pane(web_auth_pane,
645 - Spit.Publishing.PluginHost.ButtonMode.CANCEL);
646-+ string token = session_data.lookup("AccessToken").get_string();
647-+ debug("Access Token: %s", token);
648-+ session.authenticate_with_parameters(token, null, null);
649- }
650-
651+- }
652+-
653 - private void do_authenticate_session(string success_url) {
654 - debug("ACTION: preparing to extract session information encoded in url = '%s'",
655 - success_url);
656-+ private void do_hosted_web_authentication() {
657-+ debug("ACTION: doing hosted web authentication.");
658-
659-- host.set_service_locked(true);
660-- host.install_account_fetch_wait_pane();
661-+ HashTable<string,Value?> data = null;
662-+ string mechanism = "user_agent";
663-
664-- session.authenticated.connect(on_session_authenticated);
665-- session.authentication_failed.connect(on_session_authentication_failed);
666-+ SharingAccounts accounts =
667-+ new SharingAccounts();
668+-
669++ public void on_authenticator_authenticated(owned HashTable<string,Value?> session_data) {
670+ host.set_service_locked(true);
671+ host.install_account_fetch_wait_pane();
672+
673+ session.authenticated.connect(on_session_authenticated);
674+ session.authentication_failed.connect(on_session_authentication_failed);
675
676 - try {
677 - session.authenticate_from_uri(success_url);
678@@ -251,40 +582,59 @@
679 - // another error has already posted and caused us to stop
680 - if (is_running())
681 - host.post_error(err);
682-+ SharingAccount? account = accounts.get_account_for_provider("facebook");
683-+ if (account != null) {
684-+ try {
685-+ auth_session = account.create_auth_session();
686-+ data = account.get_session_parameters(out mechanism);
687-+ debug("Got account data");
688-+ } catch (GLib.Error e) {
689-+ warning("EVENT: couldn't create session for account: %s",
690-+ e.message);
691-+ return;
692-+ }
693- }
694-+
695-+ if (data == null) {
696-+ warning ("No account authentication data");
697-+ host.post_error(new Spit.Publishing.PublishingError.SERVICE_ERROR(
698-+ "Error while accessing the account"));
699-+ return;
700-+ }
701-+
702-+ var windowId = host.get_dialog_xid();
703-+ if (windowId != 0) {
704-+ data.insert("WindowId", (uint)windowId);
705-+ }
706-+
707-+ auth_session.process(data, mechanism, on_processed);
708-+ host.set_service_locked(false);
709- }
710-
711- private void do_save_session_information() {
712-@@ -562,30 +588,6 @@
713- host.post_error(err);
714- }
715-
716+- }
717+- }
718+-
719+- private void do_save_session_information() {
720+- debug("ACTION: saving session information to configuration system.");
721+-
722+- set_persistent_access_token(session.get_access_token());
723+- set_persistent_uid(session.get_user_id());
724+- set_persistent_user_name(session.get_user_name());
725++ string token = session_data.lookup("AccessToken").get_string();
726++ debug("Access Token: %s", token);
727++ session.authenticate_with_parameters(token, null, null);
728+ }
729+
730+ private void do_upload(bool strip_metadata) {
731+@@ -528,64 +422,6 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
732+ host.install_success_pane();
733+ }
734+
735+- private void on_login_clicked() {
736+- if (!is_running())
737+- return;
738+-
739+- debug("EVENT: user clicked 'Login' on welcome pane.");
740+-
741+- do_test_connection_to_endpoint();
742+- }
743+-
744+- private void on_endpoint_test_completed(FacebookRESTTransaction txn) {
745+- txn.completed.disconnect(on_endpoint_test_completed);
746+- txn.network_error.disconnect(on_endpoint_test_error);
747+-
748+- if (!is_running())
749+- return;
750+-
751+- debug("EVENT: endpoint test transaction detected that the Facebook endpoint is alive.");
752+-
753+- do_hosted_web_authentication();
754+- }
755+-
756+- private void on_endpoint_test_error(FacebookRESTTransaction bad_txn,
757+- Spit.Publishing.PublishingError err) {
758+- bad_txn.completed.disconnect(on_endpoint_test_completed);
759+- bad_txn.network_error.disconnect(on_endpoint_test_error);
760+-
761+- if (!is_running())
762+- return;
763+-
764+- debug("EVENT: endpoint test transaction failed to detect a connection to the Facebook endpoint");
765+-
766+- host.post_error(err);
767+- }
768+-
769 - private void on_web_auth_pane_login_succeeded(string success_url) {
770 - if (!is_running())
771 - return;
772@@ -312,10 +662,45 @@
773 private void on_session_authenticated() {
774 if (!is_running())
775 return;
776-@@ -773,14 +775,8 @@
777- get_persistent_uid(), get_persistent_user_name());
778- on_session_authenticated();
779- } else {
780+@@ -593,7 +429,6 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
781+ assert(session.is_authenticated());
782+ debug("EVENT: an authenticated session has become available.");
783+
784+- do_save_session_information();
785+ do_fetch_album_descriptions();
786+ }
787+
788+@@ -638,15 +473,6 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
789+ do_show_publishing_options_pane();
790+ }
791+
792+- public void on_publishing_options_pane_logout() {
793+- if (!is_running())
794+- return;
795+-
796+- debug("EVENT: user clicked 'Logout' in publishing options pane.");
797+-
798+- do_logout();
799+- }
800+-
801+ public void on_publishing_options_pane_publish(string? target_album, string privacy_setting,
802+ Resolution target_resolution, bool strip_metadata) {
803+ if (!is_running())
804+@@ -762,26 +588,8 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
805+ albums = null;
806+ publish_to_album = NO_ALBUM;
807+
808+- // determine whether a user is logged in; if so, then show the publishing options pane
809+- // for that user; otherwise, show the welcome pane
810+- if (is_persistent_session_valid()) {
811+- // if valid session information has been saved in the configuration system, build
812+- // a Session object and pre-authenticate it with the saved information, then simulate an
813+- // on_session_authenticated event to drive the rest of the interaction
814+- session = new FacebookRESTSession(PHOTO_ENDPOINT_URL, USER_AGENT);
815+- session.authenticate_with_parameters(get_persistent_access_token(),
816+- get_persistent_uid(), get_persistent_user_name());
817+- on_session_authenticated();
818+- } else {
819 - if (WebAuthenticationPane.is_cache_dirty()) {
820 - host.set_service_locked(false);
821 - host.install_static_message_pane(RESTART_ERROR_MESSAGE,
822@@ -324,12 +709,13 @@
823 - session = new FacebookRESTSession(PHOTO_ENDPOINT_URL, USER_AGENT);
824 - do_show_service_welcome_pane();
825 - }
826-+ session = new FacebookRESTSession(PHOTO_ENDPOINT_URL, USER_AGENT);
827-+ do_show_service_welcome_pane();
828- }
829+- }
830++ session = new FacebookRESTSession(PHOTO_ENDPOINT_URL, USER_AGENT);
831++ authenticator.authenticate();
832 }
833
834-@@ -909,39 +905,14 @@
835+ public void stop() {
836+@@ -909,39 +717,14 @@ internal class FacebookRESTSession {
837 return (access_token != null && uid != null && user_name != null);
838 }
839
840@@ -376,7 +762,7 @@
841 }
842
843 public string get_endpoint_url() {
844-@@ -1335,190 +1306,6 @@
845+@@ -1335,190 +1118,6 @@ internal class FacebookCreateAlbumTransaction : FacebookRESTTransaction {
846 }
847 }
848
849@@ -567,11 +953,80 @@
850 internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
851 private Gtk.Builder builder;
852 private Gtk.Box pane_widget = null;
853-Index: shotwell-0.13.0/plugins/shotwell-publishing/FlickrPublishing.vala
854-===================================================================
855---- shotwell-0.13.0.orig/plugins/shotwell-publishing/FlickrPublishing.vala 2012-09-20 07:08:59.000000000 +1200
856-+++ shotwell-0.13.0/plugins/shotwell-publishing/FlickrPublishing.vala 2012-09-20 15:16:00.933921786 +1200
857-@@ -4,6 +4,8 @@
858+@@ -1529,7 +1128,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
859+ private Gtk.Entry new_album_entry = null;
860+ private Gtk.CheckButton strip_metadata_check = null;
861+ private Gtk.Button publish_button = null;
862+- private Gtk.Button logout_button = null;
863+ private Gtk.Label how_to_label = null;
864+ private FacebookAlbum[] albums = null;
865+ private FacebookPublisher publisher = null;
866+@@ -1546,7 +1144,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
867+ private const int CONTENT_GROUP_SPACING = 32;
868+ private const int STANDARD_ACTION_BUTTON_WIDTH = 128;
869+
870+- public signal void logout();
871+ public signal void publish(string? target_album, string privacy_setting, Resolution target_resolution, bool strip_metadata);
872+
873+ private class PrivacyDescription {
874+@@ -1586,7 +1183,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
875+ existing_albums_combo = (Gtk.ComboBoxText) this.builder.get_object("existing_albums_combo");
876+ visibility_combo = (Gtk.ComboBoxText) this.builder.get_object("visibility_combo");
877+ publish_button = (Gtk.Button) this.builder.get_object("publish_button");
878+- logout_button = (Gtk.Button) this.builder.get_object("logout_button");
879+ new_album_entry = (Gtk.Entry) this.builder.get_object("new_album_entry");
880+ resolution_combo = (Gtk.ComboBoxText) this.builder.get_object("resolution_combo");
881+ how_to_label = (Gtk.Label) this.builder.get_object("how_to_label");
882+@@ -1605,7 +1201,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
883+ visibility_combo.set_active(0);
884+
885+ publish_button.clicked.connect(on_publish_button_clicked);
886+- logout_button.clicked.connect(on_logout_button_clicked);
887+
888+ // Ticket #2916 - if the user is uploading photographs, allow
889+ // them to choose what resolution they should be uploaded at.
890+@@ -1669,10 +1264,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
891+ publisher.set_persistent_default_size(resolution_combo.get_active());
892+ }
893+
894+- private void on_logout_button_clicked() {
895+- logout();
896+- }
897+-
898+ private void on_publish_button_clicked() {
899+ string album_name;
900+ string privacy_setting = privacy_descriptions[visibility_combo.get_active()].privacy_setting;
901+@@ -1747,10 +1338,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
902+ publish_button.grab_focus();
903+ }
904+
905+- private void notify_logout() {
906+- logout();
907+- }
908+-
909+ private void notify_publish(string? target_album, string privacy_setting, Resolution target_resolution) {
910+ publish(target_album, privacy_setting, target_resolution, strip_metadata_check.get_active());
911+ }
912+@@ -1764,14 +1351,12 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
913+ }
914+
915+ public void on_pane_installed() {
916+- logout.connect(notify_logout);
917+ publish.connect(notify_publish);
918+
919+ installed();
920+ }
921+
922+ public void on_pane_uninstalled() {
923+- logout.disconnect(notify_logout);
924+ publish.disconnect(notify_publish);
925+ }
926+ }
927+diff --git a/plugins/shotwell-publishing/FlickrPublishing.vala b/plugins/shotwell-publishing/FlickrPublishing.vala
928+index a6f8b45..abaf0b2 100644
929+--- a/plugins/shotwell-publishing/FlickrPublishing.vala
930++++ b/plugins/shotwell-publishing/FlickrPublishing.vala
931+@@ -4,32 +4,30 @@
932 * (version 2.1 or later). See the COPYING file in this distribution.
933 */
934
935@@ -579,31 +1034,137 @@
936 +
937 extern string hmac_sha1(string key, string message);
938
939- public class FlickrService : Object, Spit.Pluggable, Spit.Publishing.Service {
940-@@ -52,6 +54,11 @@
941+-public class FlickrService : Object, Spit.Pluggable, Spit.Publishing.Service {
942++public class FlickrService : UOAPublishingService, Spit.Pluggable, Spit.Publishing.Service {
943+ private const string ICON_FILENAME = "flickr.png";
944+
945+ private static Gdk.Pixbuf[] icon_pixbuf_set = null;
946+
947+ public FlickrService(GLib.File resource_directory) {
948++ base("flickr");
949+ if (icon_pixbuf_set == null)
950+ icon_pixbuf_set = Resources.load_icon_set(resource_directory.get_child(ICON_FILENAME));
951+ }
952+
953+- public int get_pluggable_interface(int min_host_interface, int max_host_interface) {
954+- return Spit.negotiate_interfaces(min_host_interface, max_host_interface,
955+- Spit.Publishing.CURRENT_INTERFACE);
956+- }
957+-
958+- public unowned string get_id() {
959++ public override unowned string get_id() {
960+ return "org.yorba.shotwell.publishing.flickr";
961+ }
962+
963+- public unowned string get_pluggable_name() {
964++ public override unowned string get_pluggable_name() {
965+ return "Flickr";
966+ }
967+
968+- public void get_info(ref Spit.PluggableInfo info) {
969++ public override void get_info(ref Spit.PluggableInfo info) {
970+ info.authors = "Lucas Beeler";
971+ info.copyright = _("Copyright 2009-2012 Yorba Foundation");
972+ info.translators = Resources.TRANSLATORS;
973+@@ -41,14 +39,12 @@ public class FlickrService : Object, Spit.Pluggable, Spit.Publishing.Service {
974+ info.icons = icon_pixbuf_set;
975+ }
976+
977+- public void activation(bool enabled) {
978+- }
979+-
980+- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
981+- return new Publishing.Flickr.FlickrPublisher(this, host);
982++ public override Spit.Publishing.Publisher create_publisher(string? account_name, Spit.Publishing.PluginHost host) {
983++ SharingAccount account = find_account(account_name);
984++ return new Publishing.Flickr.FlickrPublisher(this, account, host);
985+ }
986+
987+- public Spit.Publishing.Publisher.MediaType get_supported_media() {
988++ public override Spit.Publishing.Publisher.MediaType get_supported_media() {
989 return (Spit.Publishing.Publisher.MediaType.PHOTO |
990 Spit.Publishing.Publisher.MediaType.VIDEO);
991 }
992-+
993-+ public bool is_enabled() {
994-+ SharingAccounts accounts = new SharingAccounts();
995-+ return accounts.get_account_for_provider("flickr") != null;
996-+ }
997- }
998-
999- namespace Publishing.Flickr {
1000-@@ -105,6 +112,7 @@
1001+@@ -105,60 +101,33 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object {
1002 private bool was_started = false;
1003 private Session session = null;
1004 private PublishingOptionsPane publishing_options_pane = null;
1005-+ private Signon.AuthSession auth_session = null;
1006++ private UOAPublisherAuthenticator authenticator = null;
1007
1008 private PublishingParameters parameters = null;
1009
1010-@@ -173,88 +181,54 @@
1011-
1012- debug("EVENT: user clicked 'Login' button in the welcome pane");
1013+ public FlickrPublisher(Spit.Publishing.Service service,
1014++ SharingAccount account,
1015+ Spit.Publishing.PluginHost host) {
1016+ debug("FlickrPublisher instantiated.");
1017+ this.service = service;
1018+ this.host = host;
1019+ this.session = new Session();
1020++ authenticator = new UOAPublisherAuthenticator(account, host,
1021++ SERVICE_WELCOME_MESSAGE);
1022+ this.parameters = new PublishingParameters();
1023
1024+ session.authenticated.connect(on_session_authenticated);
1025++ HashTable<string,Value?> data =
1026++ authenticator.get_authentication_data();
1027++ session.set_api_credentials(data.lookup("ConsumerKey").get_string(),
1028++ data.lookup("ConsumerSecret").get_string());
1029++ authenticator.authenticated.connect(on_authenticator_authenticated);
1030+ }
1031+
1032+ ~FlickrPublisher() {
1033+ session.authenticated.disconnect(on_session_authenticated);
1034+ }
1035+
1036+- private void invalidate_persistent_session() {
1037+- set_persistent_access_phase_token("");
1038+- set_persistent_access_phase_token_secret("");
1039+- set_persistent_access_phase_username("");
1040+- }
1041+-
1042+- private bool is_persistent_session_valid() {
1043+- return (get_persistent_access_phase_username() != null &&
1044+- get_persistent_access_phase_token() != null &&
1045+- get_persistent_access_phase_token_secret() != null);
1046+- }
1047+-
1048+- private string? get_persistent_access_phase_username() {
1049+- return host.get_config_string("access_phase_username", null);
1050+- }
1051+-
1052+- private void set_persistent_access_phase_username(string username) {
1053+- host.set_config_string("access_phase_username", username);
1054+- }
1055+-
1056+- private string? get_persistent_access_phase_token() {
1057+- return host.get_config_string("access_phase_token", null);
1058+- }
1059+-
1060+- private void set_persistent_access_phase_token(string token) {
1061+- host.set_config_string("access_phase_token", token);
1062+- }
1063+-
1064+- private string? get_persistent_access_phase_token_secret() {
1065+- return host.get_config_string("access_phase_token_secret", null);
1066+- }
1067+-
1068+- private void set_persistent_access_phase_token_secret(string secret) {
1069+- host.set_config_string("access_phase_token_secret", secret);
1070+- }
1071+-
1072+ private bool get_persistent_strip_metadata() {
1073+ return host.get_config_bool("strip_metadata", false);
1074+ }
1075+@@ -167,94 +136,17 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object {
1076+ host.set_config_bool("strip_metadata", strip_metadata);
1077+ }
1078+
1079+- private void on_welcome_pane_login_clicked() {
1080+- if (!running)
1081+- return;
1082+-
1083+- debug("EVENT: user clicked 'Login' button in the welcome pane");
1084+-
1085 - do_run_authentication_request_transaction();
1086 - }
1087 -
1088@@ -624,30 +1185,10 @@
1089 - Spit.Publishing.PublishingError err) {
1090 - txn.completed.disconnect(on_auth_request_txn_completed);
1091 - txn.network_error.disconnect(on_auth_request_txn_error);
1092-+ HashTable<string,Value?> data = null;
1093-+ string mechanism = null;
1094-+ SharingAccounts accounts = new SharingAccounts();
1095-+
1096-+ SharingAccount? account = accounts.get_account_for_provider("flickr");
1097-+ if (account != null) {
1098-+ try {
1099-+ auth_session = account.create_auth_session();
1100-+ data = account.get_session_parameters(out mechanism);
1101-+ debug("Got account data");
1102-+ } catch (GLib.Error e) {
1103-+ warning("EVENT: couldn't create session for account: %s",
1104-+ e.message);
1105-+ }
1106-+ }
1107-
1108+-
1109 - if (!is_running())
1110-+ if (data == null) {
1111-+ warning ("No account authentication data");
1112-+ host.post_error(new Spit.Publishing.PublishingError.SERVICE_ERROR(
1113-+ "Error while accessing the account"));
1114- return;
1115-+ }
1116-
1117+- return;
1118+-
1119 - debug("EVENT: OAuth authentication request transaction caused a network error");
1120 - host.post_error(err);
1121 - }
1122@@ -655,24 +1196,16 @@
1123 - private void on_authentication_token_available(string token, string token_secret) {
1124 - debug("EVENT: OAuth authentication token (%s) and token secret (%s) available",
1125 - token, token_secret);
1126-+ session.set_api_credentials(data.lookup("ConsumerKey").get_string(),
1127-+ data.lookup("ConsumerSecret").get_string());
1128-
1129+-
1130 - session.set_request_phase_credentials(token, token_secret);
1131-+ var windowId = host.get_dialog_xid();
1132-+ if (windowId != 0) {
1133-+ data.insert("WindowId", (uint)windowId);
1134-+ }
1135-
1136+-
1137 - do_launch_system_browser(token);
1138-+ auth_session.process(data, mechanism, on_processed);
1139-+ host.set_service_locked(false);
1140- }
1141+- }
1142 -
1143 - private void on_system_browser_launched() {
1144 - if (!is_running())
1145 - return;
1146-
1147+-
1148 - debug("EVENT: system browser launched.");
1149 -
1150 - do_show_pin_entry_pane();
1151@@ -683,13 +1216,12 @@
1152 -
1153 - if (!is_running())
1154 - return;
1155-+ public void on_processed(Signon.AuthSession self, owned HashTable<string,Value?> session_data, GLib.Error error){
1156-+ /* TODO: handle errors */
1157-
1158+-
1159 - debug("EVENT: user clicked 'Continue' in PIN entry pane.");
1160 -
1161 - do_verify_pin(pin);
1162 - }
1163++ public void on_authenticator_authenticated(owned HashTable<string,Value?> session_data) {
1164 + host.set_service_locked(true);
1165 + host.install_account_fetch_wait_pane();
1166
1167@@ -726,10 +1258,55 @@
1168 private void on_session_authenticated() {
1169 if (!is_running())
1170 return;
1171-@@ -368,141 +342,6 @@
1172- host.install_welcome_pane(SERVICE_WELCOME_MESSAGE, on_welcome_pane_login_clicked);
1173- }
1174-
1175+@@ -263,10 +155,6 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object {
1176+
1177+ parameters.username = session.get_username();
1178+
1179+- set_persistent_access_phase_token(session.get_access_phase_token());
1180+- set_persistent_access_phase_token_secret(session.get_access_phase_token_secret());
1181+- set_persistent_access_phase_username(session.get_username());
1182+-
1183+ do_fetch_account_info();
1184+ }
1185+
1186+@@ -303,7 +191,6 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object {
1187+
1188+ private void on_publishing_options_pane_publish(bool strip_metadata) {
1189+ publishing_options_pane.publish.disconnect(on_publishing_options_pane_publish);
1190+- publishing_options_pane.logout.disconnect(on_publishing_options_pane_logout);
1191+
1192+ if (!is_running())
1193+ return;
1194+@@ -312,18 +199,6 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object {
1195+ do_publish(strip_metadata);
1196+ }
1197+
1198+- private void on_publishing_options_pane_logout() {
1199+- publishing_options_pane.publish.disconnect(on_publishing_options_pane_publish);
1200+- publishing_options_pane.logout.disconnect(on_publishing_options_pane_logout);
1201+-
1202+- if (!is_running())
1203+- return;
1204+-
1205+- debug("EVENT: user clicked the 'Logout' button in the publishing options pane");
1206+-
1207+- do_logout();
1208+- }
1209+-
1210+ private void on_upload_status_updated(int file_number, double completed_fraction) {
1211+ if (!is_running())
1212+ return;
1213+@@ -361,148 +236,6 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object {
1214+ host.post_error(err);
1215+ }
1216+
1217+- private void do_show_login_welcome_pane() {
1218+- debug("ACTION: installing login welcome pane");
1219+-
1220+- host.set_service_locked(false);
1221+- host.install_welcome_pane(SERVICE_WELCOME_MESSAGE, on_welcome_pane_login_clicked);
1222+- }
1223+-
1224 - private void do_run_authentication_request_transaction() {
1225 - debug("ACTION: running authentication request transaction");
1226 -
1227@@ -868,7 +1445,41 @@
1228 private void do_fetch_account_info() {
1229 debug("ACTION: running network transaction to fetch account information");
1230
1231-@@ -772,7 +611,7 @@
1232+@@ -568,7 +301,6 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object {
1233+ debug("ACTION: logging user out, deauthenticating session, and erasing stored credentials");
1234+
1235+ session.deauthenticate();
1236+- invalidate_persistent_session();
1237+
1238+ running = false;
1239+
1240+@@ -599,7 +331,6 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object {
1241+ publishing_options_pane = new PublishingOptionsPane(this, parameters,
1242+ host.get_publishable_media_type(), builder, get_persistent_strip_metadata());
1243+ publishing_options_pane.publish.connect(on_publishing_options_pane_publish);
1244+- publishing_options_pane.logout.connect(on_publishing_options_pane_logout);
1245+ host.install_dialog_pane(publishing_options_pane);
1246+ }
1247+
1248+@@ -674,16 +405,7 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object {
1249+ running = true;
1250+ was_started = true;
1251+
1252+- if (is_persistent_session_valid()) {
1253+- debug("attempt start: a persistent session is available; using it");
1254+-
1255+- session.authenticate_from_persistent_credentials(get_persistent_access_phase_token(),
1256+- get_persistent_access_phase_token_secret(), get_persistent_access_phase_username());
1257+- } else {
1258+- debug("attempt start: no persistent session available; showing login welcome pane");
1259+-
1260+- do_show_login_welcome_pane();
1261+- }
1262++ authenticator.authenticate();
1263+ }
1264+
1265+ public void start() {
1266+@@ -772,7 +494,7 @@ internal class Transaction : Publishing.RESTSupport.Transaction {
1267 add_argument("oauth_version", "1.0");
1268 add_argument("oauth_callback", "oob");
1269 add_argument("oauth_timestamp", session.get_oauth_timestamp());
1270@@ -877,7 +1488,7 @@
1271 }
1272
1273 public Transaction.with_uri(Session session, string uri,
1274-@@ -784,7 +623,7 @@
1275+@@ -784,7 +506,7 @@ internal class Transaction : Publishing.RESTSupport.Transaction {
1276 add_argument("oauth_version", "1.0");
1277 add_argument("oauth_callback", "oob");
1278 add_argument("oauth_timestamp", session.get_oauth_timestamp());
1279@@ -886,7 +1497,7 @@
1280 }
1281
1282 public override void execute() throws Spit.Publishing.PublishingError {
1283-@@ -842,22 +681,6 @@
1284+@@ -842,22 +564,6 @@ internal class Transaction : Publishing.RESTSupport.Transaction {
1285 }
1286 }
1287
1288@@ -909,7 +1520,7 @@
1289 internal class AccountInfoFetchTransaction : Transaction {
1290 public AccountInfoFetchTransaction(Session session) {
1291 base(session, Publishing.RESTSupport.HttpMethod.GET);
1292-@@ -884,7 +707,7 @@
1293+@@ -884,7 +590,7 @@ private class UploadTransaction : Publishing.RESTSupport.UploadTransaction {
1294 add_authorization_header_field("oauth_version", "1.0");
1295 add_authorization_header_field("oauth_callback", "oob");
1296 add_authorization_header_field("oauth_timestamp", session.get_oauth_timestamp());
1297@@ -918,7 +1529,7 @@
1298 add_authorization_header_field("oauth_token", session.get_access_phase_token());
1299
1300 add_argument("is_public", ("%d".printf(parameters.visibility_specification.everyone_level)));
1301-@@ -944,11 +767,11 @@
1302+@@ -944,11 +650,11 @@ private class UploadTransaction : Publishing.RESTSupport.UploadTransaction {
1303 }
1304
1305 internal class Session : Publishing.RESTSupport.Session {
1306@@ -932,7 +1543,23 @@
1307
1308 public Session() {
1309 base(ENDPOINT_URL);
1310-@@ -1008,16 +831,12 @@
1311+@@ -959,15 +665,6 @@ internal class Session : Publishing.RESTSupport.Session {
1312+ username != null);
1313+ }
1314+
1315+- public void authenticate_from_persistent_credentials(string token, string secret,
1316+- string username) {
1317+- this.access_phase_token = token;
1318+- this.access_phase_token_secret = secret;
1319+- this.username = username;
1320+-
1321+- authenticated();
1322+- }
1323+-
1324+ public void deauthenticate() {
1325+ access_phase_token = null;
1326+ access_phase_token_secret = null;
1327+@@ -1008,16 +705,12 @@ internal class Session : Publishing.RESTSupport.Session {
1328 if (access_phase_token_secret != null) {
1329 debug("access phase token secret available; using it as signing key");
1330
1331@@ -952,7 +1579,7 @@
1332 }
1333
1334 string signature_base_string = http_method + "&" + Soup.URI.encode(
1335-@@ -1040,11 +859,11 @@
1336+@@ -1040,11 +733,11 @@ internal class Session : Publishing.RESTSupport.Session {
1337 txn.add_argument("oauth_signature", signature);
1338 }
1339
1340@@ -968,7 +1595,7 @@
1341 public void set_access_phase_credentials(string token, string secret, string username) {
1342 this.access_phase_token = token;
1343 this.access_phase_token_secret = secret;
1344-@@ -1065,11 +884,11 @@
1345+@@ -1065,21 +758,16 @@ internal class Session : Publishing.RESTSupport.Session {
1346 return GLib.get_real_time().to_string().substring(0, 10);
1347 }
1348
1349@@ -984,11 +1611,84 @@
1350 public string get_access_phase_token() {
1351 assert(access_phase_token != null);
1352 return access_phase_token;
1353-Index: shotwell-0.13.0/plugins/shotwell-publishing/Makefile
1354-===================================================================
1355---- shotwell-0.13.0.orig/plugins/shotwell-publishing/Makefile 2012-09-20 07:08:59.000000000 +1200
1356-+++ shotwell-0.13.0/plugins/shotwell-publishing/Makefile 2012-09-20 15:16:00.933921786 +1200
1357-@@ -18,6 +18,7 @@
1358+ }
1359+
1360+- public string get_access_phase_token_secret() {
1361+- assert(access_phase_token_secret != null);
1362+- return access_phase_token_secret;
1363+- }
1364+-
1365+ public string get_username() {
1366+ assert(is_authenticated());
1367+ return username;
1368+@@ -1112,7 +800,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
1369+ private Gtk.Label visibility_label = null;
1370+ private Gtk.Label upload_info_label = null;
1371+ private Gtk.Label size_label = null;
1372+- private Gtk.Button logout_button = null;
1373+ private Gtk.Button publish_button = null;
1374+ private Gtk.ComboBoxText visibility_combo = null;
1375+ private Gtk.ComboBoxText size_combo = null;
1376+@@ -1124,7 +811,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
1377+ private Spit.Publishing.Publisher.MediaType media_type;
1378+
1379+ public signal void publish(bool strip_metadata);
1380+- public signal void logout();
1381+
1382+ public PublishingOptionsPane(FlickrPublisher publisher, PublishingParameters parameters,
1383+ Spit.Publishing.Publisher.MediaType media_type, Gtk.Builder builder, bool strip_metadata) {
1384+@@ -1136,7 +822,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
1385+ pane_widget = (Gtk.Box) this.builder.get_object("flickr_pane");
1386+ visibility_label = (Gtk.Label) this.builder.get_object("visibility_label");
1387+ upload_info_label = (Gtk.Label) this.builder.get_object("upload_info_label");
1388+- logout_button = (Gtk.Button) this.builder.get_object("logout_button");
1389+ publish_button = (Gtk.Button) this.builder.get_object("publish_button");
1390+ visibility_combo = (Gtk.ComboBoxText) this.builder.get_object("visibility_combo");
1391+ size_combo = (Gtk.ComboBoxText) this.builder.get_object("size_combo");
1392+@@ -1183,14 +868,9 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
1393+
1394+ strip_metadata_check.set_active(strip_metadata);
1395+
1396+- logout_button.clicked.connect(on_logout_clicked);
1397+ publish_button.clicked.connect(on_publish_clicked);
1398+ }
1399+
1400+- private void on_logout_clicked() {
1401+- logout();
1402+- }
1403+-
1404+ private void on_publish_clicked() {
1405+ parameters.visibility_specification =
1406+ visibilities[visibility_combo.get_active()].specification;
1407+@@ -1257,10 +937,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
1408+ publish(strip_metadata_check.get_active());
1409+ }
1410+
1411+- protected void notify_logout() {
1412+- logout();
1413+- }
1414+-
1415+ public Gtk.Widget get_widget() {
1416+ return pane_widget;
1417+ }
1418+@@ -1271,12 +947,10 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
1419+
1420+ public void on_pane_installed() {
1421+ publish.connect(notify_publish);
1422+- logout.connect(notify_logout);
1423+ }
1424+
1425+ public void on_pane_uninstalled() {
1426+ publish.disconnect(notify_publish);
1427+- logout.disconnect(notify_logout);
1428+ }
1429+ }
1430+
1431+diff --git a/plugins/shotwell-publishing/Makefile b/plugins/shotwell-publishing/Makefile
1432+index e939a77..bacfff4 100644
1433+--- a/plugins/shotwell-publishing/Makefile
1434++++ b/plugins/shotwell-publishing/Makefile
1435+@@ -18,6 +18,7 @@ SRC_FILES := \
1436 FlickrPublishing.vala \
1437 YouTubePublishing.vala \
1438 PiwigoPublishing.vala \
1439@@ -996,40 +1696,87 @@
1440 ../../src/util/string.vala \
1441 ../common/RESTSupport.vala \
1442 ../common/ui.vala
1443-Index: shotwell-0.13.0/plugins/shotwell-publishing/PicasaPublishing.vala
1444-===================================================================
1445---- shotwell-0.13.0.orig/plugins/shotwell-publishing/PicasaPublishing.vala 2012-09-20 07:08:59.000000000 +1200
1446-+++ shotwell-0.13.0/plugins/shotwell-publishing/PicasaPublishing.vala 2012-09-20 15:16:00.933921786 +1200
1447-@@ -4,6 +4,8 @@
1448+diff --git a/plugins/shotwell-publishing/PicasaPublishing.vala b/plugins/shotwell-publishing/PicasaPublishing.vala
1449+index 397503d..a428a30 100644
1450+--- a/plugins/shotwell-publishing/PicasaPublishing.vala
1451++++ b/plugins/shotwell-publishing/PicasaPublishing.vala
1452+@@ -4,30 +4,28 @@
1453 * (version 2.1 or later). See the COPYING file in this distribution.
1454 */
1455
1456+-public class PicasaService : Object, Spit.Pluggable, Spit.Publishing.Service {
1457 +using Publishing.Accounts;
1458 +
1459- public class PicasaService : Object, Spit.Pluggable, Spit.Publishing.Service {
1460++public class PicasaService : UOAPublishingService, Spit.Pluggable, Spit.Publishing.Service {
1461 private const string ICON_FILENAME = "picasa.png";
1462
1463-@@ -50,6 +52,11 @@
1464-
1465- public void activation(bool enabled) {
1466- }
1467-+
1468-+ public bool is_enabled() {
1469-+ SharingAccounts accounts = new SharingAccounts();
1470-+ return accounts.get_account_for_provider("google") != null;
1471-+ }
1472+ private static Gdk.Pixbuf[] icon_pixbuf_set = null;
1473+
1474+ public PicasaService(GLib.File resource_directory) {
1475++ base("google");
1476+ if (icon_pixbuf_set == null)
1477+ icon_pixbuf_set = Resources.load_icon_set(resource_directory.get_child(ICON_FILENAME));
1478+ }
1479+
1480+- public int get_pluggable_interface(int min_host_interface, int max_host_interface) {
1481+- return Spit.negotiate_interfaces(min_host_interface, max_host_interface,
1482+- Spit.Publishing.CURRENT_INTERFACE);
1483+- }
1484+-
1485+- public unowned string get_id() {
1486++ public override unowned string get_id() {
1487+ return "org.yorba.shotwell.publishing.picasa";
1488+ }
1489+
1490+- public unowned string get_pluggable_name() {
1491++ public override unowned string get_pluggable_name() {
1492+ return "Picasa Web Albums";
1493+ }
1494+
1495+- public void get_info(ref Spit.PluggableInfo info) {
1496++ public override void get_info(ref Spit.PluggableInfo info) {
1497+ info.authors = "Lucas Beeler";
1498+ info.copyright = _("Copyright 2009-2012 Yorba Foundation");
1499+ info.translators = Resources.TRANSLATORS;
1500+@@ -39,17 +37,15 @@ public class PicasaService : Object, Spit.Pluggable, Spit.Publishing.Service {
1501+ info.icons = icon_pixbuf_set;
1502+ }
1503+
1504+- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
1505+- return new Publishing.Picasa.PicasaPublisher(this, host);
1506++ public override Spit.Publishing.Publisher create_publisher(string? account_name, Spit.Publishing.PluginHost host) {
1507++ SharingAccount account = find_account(account_name);
1508++ return new Publishing.Picasa.PicasaPublisher(this, account, host);
1509+ }
1510+
1511+- public Spit.Publishing.Publisher.MediaType get_supported_media() {
1512++ public override Spit.Publishing.Publisher.MediaType get_supported_media() {
1513+ return (Spit.Publishing.Publisher.MediaType.PHOTO |
1514+ Spit.Publishing.Publisher.MediaType.VIDEO);
1515+ }
1516+-
1517+- public void activation(bool enabled) {
1518+- }
1519 }
1520
1521 namespace Publishing.Picasa {
1522-@@ -72,6 +79,7 @@
1523+@@ -72,29 +68,22 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object {
1524 private PublishingParameters parameters = null;
1525 private Spit.Publishing.Publisher.MediaType media_type =
1526 Spit.Publishing.Publisher.MediaType.NONE;
1527-+ private Signon.AuthSession auth_session = null;
1528++ private UOAPublisherAuthenticator authenticator = null;
1529
1530 public PicasaPublisher(Spit.Publishing.Service service,
1531++ SharingAccount account,
1532 Spit.Publishing.PluginHost host) {
1533-@@ -83,18 +91,6 @@
1534+ this.service = service;
1535+ this.host = host;
1536+ this.session = new Session();
1537++ authenticator = new UOAPublisherAuthenticator(account, host,
1538++ SERVICE_WELCOME_MESSAGE);
1539++ authenticator.authenticated.connect(on_authenticator_authenticated);
1540+
1541+ foreach(Spit.Publishing.Publishable p in host.get_publishables())
1542 media_type |= p.get_media_type();
1543 }
1544
1545@@ -1048,7 +1795,7 @@
1546 private Album[] extract_albums(Xml.Node* document_root) throws Spit.Publishing.PublishingError {
1547 Album[] result = new Album[0];
1548
1549-@@ -133,14 +129,6 @@
1550+@@ -133,14 +122,6 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object {
1551 return result;
1552 }
1553
1554@@ -1063,7 +1810,7 @@
1555 internal bool get_persistent_strip_metadata() {
1556 return host.get_config_bool("strip_metadata", false);
1557 }
1558-@@ -149,16 +137,6 @@
1559+@@ -149,16 +130,6 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object {
1560 host.set_config_bool("strip_metadata", strip_metadata);
1561 }
1562
1563@@ -1080,14 +1827,19 @@
1564 public bool is_running() {
1565 return running;
1566 }
1567-@@ -173,92 +151,69 @@
1568-
1569- debug("EVENT: user clicked 'Login' in welcome pane.");
1570+@@ -167,98 +138,22 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object {
1571+ return service;
1572+ }
1573
1574+- private void on_service_welcome_login() {
1575+- if (!is_running())
1576+- return;
1577+-
1578+- debug("EVENT: user clicked 'Login' in welcome pane.");
1579+-
1580 - do_launch_browser_for_authorization();
1581-+ do_hosted_web_authentication();
1582- }
1583-
1584+- }
1585+-
1586 - private void on_auth_code_entry_pane_proceed(AuthCodeEntryPane sender, string code) {
1587 - debug("EVENT: user clicked 'Continue' in authorization code entry pane.");
1588 -
1589@@ -1105,18 +1857,10 @@
1590 - private void on_get_access_tokens_completed(Publishing.RESTSupport.Transaction txn) {
1591 - txn.completed.disconnect(on_get_access_tokens_completed);
1592 - txn.network_error.disconnect(on_get_access_tokens_error);
1593-+ public void on_processed(Signon.AuthSession self, owned HashTable<string,Value?>? session_data, GLib.Error error){
1594-+ if (error != null) {
1595-+ debug("got error: %s", error.message);
1596-+ /* TODO: handle errors */
1597-+ return;
1598-+ }
1599-
1600+-
1601 - debug("EVENT: network transaction to exchange authorization code for access tokens " +
1602 - "completed successfully.");
1603-+ host.set_service_locked(true);
1604-+ host.install_account_fetch_wait_pane();
1605-
1606+-
1607 - do_extract_tokens(txn.get_response());
1608 - }
1609 -
1610@@ -1124,8 +1868,7 @@
1611 - Spit.Publishing.PublishingError err) {
1612 - txn.completed.disconnect(on_get_access_tokens_completed);
1613 - txn.network_error.disconnect(on_get_access_tokens_error);
1614-+ session.authenticated.connect(on_session_authenticated);
1615-
1616+-
1617 - debug("EVENT: network transaction to exchange authorization code for access tokens " +
1618 - "failed; response = '%s'", txn.get_response());
1619 - }
1620@@ -1148,6 +1891,41 @@
1621 - sender.proceed.disconnect(on_not_set_up_pane_proceed);
1622 -
1623 - do_launch_browser_for_authorization();
1624+- }
1625+-
1626+- private void on_refresh_access_token_transaction_completed(Publishing.RESTSupport.Transaction
1627+- txn) {
1628+- txn.completed.disconnect(on_refresh_access_token_transaction_completed);
1629+- txn.network_error.disconnect(on_refresh_access_token_transaction_error);
1630+-
1631+- if (!is_running())
1632+- return;
1633+-
1634+- if (session.is_authenticated()) // ignore these events if the session is already auth'd
1635+- return;
1636+-
1637+- debug("EVENT: refresh access token transaction completed successfully.");
1638+-
1639+- do_extract_tokens(txn.get_response());
1640+- }
1641+-
1642+- private void on_refresh_access_token_transaction_error(Publishing.RESTSupport.Transaction txn,
1643+- Spit.Publishing.PublishingError err) {
1644+- txn.completed.disconnect(on_refresh_access_token_transaction_completed);
1645+- txn.network_error.disconnect(on_refresh_access_token_transaction_error);
1646+-
1647+- if (!is_running())
1648+- return;
1649++ public void on_authenticator_authenticated(owned HashTable<string,Value?> session_data) {
1650++ host.install_account_fetch_wait_pane();
1651+
1652+- if (session.is_authenticated()) // ignore these events if the session is already auth'd
1653+- return;
1654++ session.authenticated.connect(on_session_authenticated);
1655+
1656+- debug("EVENT: refresh access token transaction caused a network error.");
1657+-
1658+- host.post_error(err);
1659 + if (session_data.lookup("AccessToken") != null) {
1660 + string token = session_data.lookup("AccessToken").get_string();
1661 + debug("OAuth Access Token: %s", token);
1662@@ -1160,72 +1938,9 @@
1663 + debug("Access token not present!");
1664 + }
1665 }
1666--
1667-- private void on_refresh_access_token_transaction_completed(Publishing.RESTSupport.Transaction
1668-- txn) {
1669-- txn.completed.disconnect(on_refresh_access_token_transaction_completed);
1670-- txn.network_error.disconnect(on_refresh_access_token_transaction_error);
1671--
1672-- if (!is_running())
1673-- return;
1674-
1675-- if (session.is_authenticated()) // ignore these events if the session is already auth'd
1676-- return;
1677-+ private void do_hosted_web_authentication() {
1678-+ debug("ACTION: doing hosted web authentication.");
1679-
1680-- debug("EVENT: refresh access token transaction completed successfully.");
1681--
1682-- do_extract_tokens(txn.get_response());
1683-- }
1684--
1685-- private void on_refresh_access_token_transaction_error(Publishing.RESTSupport.Transaction txn,
1686-- Spit.Publishing.PublishingError err) {
1687-- txn.completed.disconnect(on_refresh_access_token_transaction_completed);
1688-- txn.network_error.disconnect(on_refresh_access_token_transaction_error);
1689--
1690-- if (!is_running())
1691-- return;
1692-+ HashTable<string,Value?> data = null;
1693-+ string mechanism = "user_agent";
1694-+
1695-+ SharingAccounts accounts =
1696-+ new SharingAccounts();
1697-
1698-- if (session.is_authenticated()) // ignore these events if the session is already auth'd
1699-+ SharingAccount? account = accounts.get_account_for_provider("google");
1700-+ if (account != null) {
1701-+ try {
1702-+ auth_session = account.create_auth_session();
1703-+ data = account.get_session_parameters(out mechanism);
1704-+ debug("Got account data");
1705-+ } catch (GLib.Error e) {
1706-+ warning("EVENT: couldn't create session for account: %s",
1707-+ e.message);
1708-+ }
1709-+ }
1710-+
1711-+ if (data == null) {
1712-+ warning ("No account authentication data");
1713-+ host.post_error(new Spit.Publishing.PublishingError.SERVICE_ERROR(
1714-+ "Error while accessing the account"));
1715- return;
1716-+ }
1717-
1718-- debug("EVENT: refresh access token transaction caused a network error.");
1719--
1720-- host.post_error(err);
1721-+ var windowId = host.get_dialog_xid();
1722-+ if (windowId != 0) {
1723-+ data.insert("WindowId", (uint)windowId);
1724-+ }
1725-+
1726-+ auth_session.process(data, mechanism, on_processed);
1727-+ host.set_service_locked(false);
1728- }
1729
1730 private void on_session_authenticated() {
1731-@@ -313,19 +268,7 @@
1732+@@ -313,31 +208,7 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object {
1733 debug("EVENT: fetching account and album information failed; response = '%s'.",
1734 bad_txn.get_response());
1735
1736@@ -1242,22 +1957,32 @@
1737 - // If we get any other kind of error, we can't recover, so just post it to the user
1738 - host.post_error(err);
1739 - }
1740+- }
1741+-
1742+- private void on_publishing_options_logout() {
1743+- if (!is_running())
1744+- return;
1745+-
1746+- debug("EVENT: user clicked 'Logout' in the publishing options pane.");
1747+-
1748+- session.deauthenticate();
1749+- invalidate_persistent_session();
1750+-
1751+- do_show_service_welcome_pane();
1752 + host.post_error(err);
1753 }
1754
1755- private void on_publishing_options_logout() {
1756-@@ -335,7 +278,6 @@
1757- debug("EVENT: user clicked 'Logout' in the publishing options pane.");
1758-
1759- session.deauthenticate();
1760-- invalidate_persistent_session();
1761-
1762- do_show_service_welcome_pane();
1763- }
1764-@@ -453,94 +395,6 @@
1765- host.install_welcome_pane(SERVICE_WELCOME_MESSAGE, on_service_welcome_login);
1766- }
1767-
1768+ private void on_publishing_options_publish(PublishingParameters parameters,
1769+@@ -447,100 +318,6 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object {
1770+ host.post_error(err);
1771+ }
1772+
1773+- private void do_show_service_welcome_pane() {
1774+- debug("ACTION: showing service welcome pane.");
1775+-
1776+- host.install_welcome_pane(SERVICE_WELCOME_MESSAGE, on_service_welcome_login);
1777+- }
1778+-
1779 - private void do_launch_browser_for_authorization() {
1780 - string auth_url = get_user_authorization_url();
1781 -
1782@@ -1349,7 +2074,7 @@
1783 private void do_extract_username(string response_body) {
1784 debug("ACTION: extracting username from body of server response");
1785
1786-@@ -562,66 +416,8 @@
1787+@@ -562,66 +339,8 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object {
1788 if (username != "")
1789 this.username = username;
1790 }
1791@@ -1416,20 +2141,29 @@
1792 private void do_fetch_username() {
1793 debug("ACTION: running network transaction to fetch username.");
1794
1795-@@ -771,11 +567,7 @@
1796+@@ -701,7 +420,6 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object {
1797+ PublishingOptionsPane opts_pane = new PublishingOptionsPane(host, username, albums, media_type, builder,
1798+ get_persistent_strip_metadata());
1799+ opts_pane.publish.connect(on_publishing_options_publish);
1800+- opts_pane.logout.connect(on_publishing_options_logout);
1801+ host.install_dialog_pane(opts_pane);
1802+
1803+ host.set_service_locked(false);
1804+@@ -770,12 +488,7 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object {
1805+ debug("PicasaPublisher: starting interaction.");
1806
1807 running = true;
1808-
1809+-
1810 - if (is_persistent_session_available()) {
1811 - do_refresh_session(get_persistent_refresh_token());
1812 - } else {
1813 - do_show_service_welcome_pane();
1814 - }
1815-+ do_show_service_welcome_pane();
1816++ authenticator.authenticate();
1817 }
1818
1819 public void stop() {
1820-@@ -801,6 +593,7 @@
1821+@@ -801,6 +514,7 @@ internal class Album {
1822
1823 internal class Session : Publishing.RESTSupport.Session {
1824 private string? auth_token = null;
1825@@ -1437,7 +2171,7 @@
1826
1827 public Session() {
1828 }
1829-@@ -809,45 +602,24 @@
1830+@@ -809,45 +523,19 @@ internal class Session : Publishing.RESTSupport.Session {
1831 return (auth_token != null);
1832 }
1833
1834@@ -1449,11 +2183,10 @@
1835 notify_authenticated();
1836 }
1837
1838- public void deauthenticate() {
1839- auth_token = null;
1840-+ auth_method = null;
1841- }
1842-
1843+- public void deauthenticate() {
1844+- auth_token = null;
1845+- }
1846+-
1847 public string? get_auth_token() {
1848 return auth_token;
1849 }
1850@@ -1488,7 +2221,7 @@
1851 }
1852 }
1853
1854-@@ -862,7 +634,13 @@
1855+@@ -862,7 +550,13 @@ internal class AuthenticatedTransaction : Publishing.RESTSupport.Transaction {
1856 base.with_endpoint_url(session, endpoint_url, method);
1857 assert(session.is_authenticated());
1858
1859@@ -1503,7 +2236,7 @@
1860 }
1861 }
1862
1863-@@ -875,7 +653,7 @@
1864+@@ -875,7 +569,7 @@ internal class UsernameFetchTransaction : AuthenticatedTransaction {
1865 }
1866
1867 internal class AlbumDirectoryTransaction : AuthenticatedTransaction {
1868@@ -1512,7 +2245,7 @@
1869 "default";
1870
1871 public AlbumDirectoryTransaction(Session session) {
1872-@@ -892,7 +670,7 @@
1873+@@ -892,7 +586,7 @@ internal class AlbumDirectoryTransaction : AuthenticatedTransaction {
1874 }
1875
1876 private class AlbumCreationTransaction : AuthenticatedTransaction {
1877@@ -1521,7 +2254,7 @@
1878 "default";
1879 private const string ALBUM_ENTRY_TEMPLATE = "<?xml version='1.0' encoding='utf-8'?><entry xmlns='http://www.w3.org/2005/Atom' xmlns:gphoto='http://schemas.google.com/photos/2007'><title type='text'>%s</title><gphoto:access>%s</gphoto:access><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/photos/2007#album'></category></entry>";
1880
1881-@@ -971,9 +749,14 @@
1882+@@ -971,9 +665,14 @@ internal class UploadTransaction : AuthenticatedTransaction {
1883 // that we've been building up
1884 Soup.Message outbound_message =
1885 soup_form_request_new_from_multipart(get_endpoint_url(), message_parts);
1886@@ -1538,7 +2271,7 @@
1887
1888 // send the message and get its response
1889 set_is_executed(true);
1890-@@ -981,95 +764,6 @@
1891+@@ -981,95 +680,6 @@ internal class UploadTransaction : AuthenticatedTransaction {
1892 }
1893 }
1894
1895@@ -1634,11 +2367,284 @@
1896 internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
1897 private class SizeDescription {
1898 public string name;
1899-Index: shotwell-0.13.0/src/plugins/PublishingInterfaces.vala
1900-===================================================================
1901---- shotwell-0.13.0.orig/src/plugins/PublishingInterfaces.vala 2012-09-20 07:08:59.000000000 +1200
1902-+++ shotwell-0.13.0/src/plugins/PublishingInterfaces.vala 2012-09-20 15:16:00.933921786 +1200
1903-@@ -494,6 +494,7 @@
1904+@@ -1097,7 +707,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
1905+ private Gtk.ComboBoxText size_combo = null;
1906+ private Gtk.CheckButton strip_metadata_check = null;
1907+ private Gtk.Button publish_button = null;
1908+- private Gtk.Button logout_button = null;
1909+
1910+ private Album[] albums;
1911+ private SizeDescription[] size_descriptions;
1912+@@ -1105,7 +714,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
1913+ private weak Spit.Publishing.PluginHost host;
1914+
1915+ public signal void publish(PublishingParameters parameters, bool strip_metadata);
1916+- public signal void logout();
1917+
1918+ public PublishingOptionsPane(Spit.Publishing.PluginHost host, string username,
1919+ Album[] albums, Spit.Publishing.Publisher.MediaType media_type, Gtk.Builder builder,
1920+@@ -1131,7 +739,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
1921+ size_combo = (Gtk.ComboBoxText) builder.get_object("size_combo");
1922+ strip_metadata_check = (Gtk.CheckButton) this.builder.get_object("strip_metadata_check");
1923+ publish_button = (Gtk.Button) builder.get_object("publish_button");
1924+- logout_button = (Gtk.Button) builder.get_object("logout_button");
1925+
1926+ // populate any widgets whose contents are programmatically-generated.
1927+ login_identity_label.set_label(_("You are logged into Picasa Web Albums as %s.").printf(username));
1928+@@ -1157,7 +764,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
1929+ use_existing_radio.clicked.connect(on_use_existing_radio_clicked);
1930+ create_new_radio.clicked.connect(on_create_new_radio_clicked);
1931+ new_album_entry.changed.connect(on_new_album_entry_changed);
1932+- logout_button.clicked.connect(on_logout_clicked);
1933+ publish_button.clicked.connect(on_publish_clicked);
1934+ }
1935+
1936+@@ -1200,10 +806,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
1937+ public_check.set_sensitive(true);
1938+ }
1939+
1940+- private void on_logout_clicked() {
1941+- logout();
1942+- }
1943+-
1944+ private void update_publish_button_sensitivity() {
1945+ string album_name = new_album_entry.get_text();
1946+ publish_button.set_sensitive(!(album_name.strip() == "" &&
1947+@@ -1263,10 +865,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
1948+ publish(parameters, strip_metadata_check.get_active());
1949+ }
1950+
1951+- protected void notify_logout() {
1952+- logout();
1953+- }
1954+-
1955+ public Gtk.Widget get_widget() {
1956+ return pane_widget;
1957+ }
1958+@@ -1279,12 +877,10 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
1959+ installed();
1960+
1961+ publish.connect(notify_publish);
1962+- logout.connect(notify_logout);
1963+ }
1964+
1965+ public void on_pane_uninstalled() {
1966+ publish.disconnect(notify_publish);
1967+- logout.disconnect(notify_logout);
1968+ }
1969+ }
1970+
1971+diff --git a/plugins/shotwell-publishing/PiwigoPublishing.vala b/plugins/shotwell-publishing/PiwigoPublishing.vala
1972+index d75b922..0fdf800 100644
1973+--- a/plugins/shotwell-publishing/PiwigoPublishing.vala
1974++++ b/plugins/shotwell-publishing/PiwigoPublishing.vala
1975+@@ -42,7 +42,7 @@ public class PiwigoService : Object, Spit.Pluggable, Spit.Publishing.Service {
1976+ public void activation(bool enabled) {
1977+ }
1978+
1979+- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
1980++ public Spit.Publishing.Publisher create_publisher(string? account, Spit.Publishing.PluginHost host) {
1981+ return new Publishing.Piwigo.PiwigoPublisher(this, host);
1982+ }
1983+
1984+diff --git a/plugins/shotwell-publishing/YouTubePublishing.vala b/plugins/shotwell-publishing/YouTubePublishing.vala
1985+index 9319eb9..fc03fe7 100644
1986+--- a/plugins/shotwell-publishing/YouTubePublishing.vala
1987++++ b/plugins/shotwell-publishing/YouTubePublishing.vala
1988+@@ -39,7 +39,7 @@ public class YouTubeService : Object, Spit.Pluggable, Spit.Publishing.Service {
1989+ info.icons = icon_pixbuf_set;
1990+ }
1991+
1992+- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
1993++ public Spit.Publishing.Publisher create_publisher(string? account, Spit.Publishing.PluginHost host) {
1994+ return new Publishing.YouTube.YouTubePublisher(this, host);
1995+ }
1996+
1997+diff --git a/plugins/shotwell-publishing/facebook_publishing_options_pane.glade b/plugins/shotwell-publishing/facebook_publishing_options_pane.glade
1998+index 0ba57ad..567b8c8 100644
1999+--- a/plugins/shotwell-publishing/facebook_publishing_options_pane.glade
2000++++ b/plugins/shotwell-publishing/facebook_publishing_options_pane.glade
2001+@@ -196,29 +196,14 @@ anything put into this field won't display)</property>
2002+ <object class="GtkBox" id="box2">
2003+ <property name="visible">True</property>
2004+ <property name="can_focus">False</property>
2005++ <property name="halign">center</property>
2006+ <property name="spacing">32</property>
2007+ <property name="homogeneous">True</property>
2008+ <child>
2009+- <object class="GtkButton" id="logout_button">
2010+- <property name="label" translatable="yes">_Logout</property>
2011+- <property name="use_action_appearance">False</property>
2012+- <property name="visible">True</property>
2013+- <property name="can_focus">True</property>
2014+- <property name="receives_default">True</property>
2015+- <property name="use_action_appearance">False</property>
2016+- <property name="use_underline">True</property>
2017+- </object>
2018+- <packing>
2019+- <property name="expand">False</property>
2020+- <property name="fill">True</property>
2021+- <property name="padding">80</property>
2022+- <property name="position">0</property>
2023+- </packing>
2024+- </child>
2025+- <child>
2026+ <object class="GtkButton" id="publish_button">
2027+ <property name="label" translatable="yes">_Publish</property>
2028+ <property name="use_action_appearance">False</property>
2029++ <property name="width_request">96</property>
2030+ <property name="visible">True</property>
2031+ <property name="can_focus">True</property>
2032+ <property name="receives_default">True</property>
2033+@@ -229,13 +214,13 @@ anything put into this field won't display)</property>
2034+ <property name="expand">False</property>
2035+ <property name="fill">True</property>
2036+ <property name="padding">80</property>
2037+- <property name="position">1</property>
2038++ <property name="position">0</property>
2039+ </packing>
2040+ </child>
2041+ </object>
2042+ <packing>
2043+ <property name="expand">False</property>
2044+- <property name="fill">True</property>
2045++ <property name="fill">False</property>
2046+ <property name="padding">2</property>
2047+ <property name="position">3</property>
2048+ </packing>
2049+diff --git a/plugins/shotwell-publishing/flickr_publishing_options_pane.glade b/plugins/shotwell-publishing/flickr_publishing_options_pane.glade
2050+index e39a52e..b9edd04 100644
2051+--- a/plugins/shotwell-publishing/flickr_publishing_options_pane.glade
2052++++ b/plugins/shotwell-publishing/flickr_publishing_options_pane.glade
2053+@@ -135,24 +135,6 @@ so changes made here will not display)</property>
2054+ <property name="spacing">64</property>
2055+ <property name="homogeneous">True</property>
2056+ <child>
2057+- <object class="GtkButton" id="logout_button">
2058+- <property name="label" translatable="yes">_Logout</property>
2059+- <property name="use_action_appearance">False</property>
2060+- <property name="width_request">96</property>
2061+- <property name="visible">True</property>
2062+- <property name="can_focus">True</property>
2063+- <property name="receives_default">True</property>
2064+- <property name="use_action_appearance">False</property>
2065+- <property name="use_underline">True</property>
2066+- </object>
2067+- <packing>
2068+- <property name="expand">False</property>
2069+- <property name="fill">True</property>
2070+- <property name="padding">24</property>
2071+- <property name="position">0</property>
2072+- </packing>
2073+- </child>
2074+- <child>
2075+ <object class="GtkButton" id="publish_button">
2076+ <property name="label" translatable="yes">_Publish</property>
2077+ <property name="use_action_appearance">False</property>
2078+@@ -167,7 +149,7 @@ so changes made here will not display)</property>
2079+ <property name="expand">False</property>
2080+ <property name="fill">True</property>
2081+ <property name="padding">24</property>
2082+- <property name="position">1</property>
2083++ <property name="position">0</property>
2084+ </packing>
2085+ </child>
2086+ </object>
2087+diff --git a/plugins/shotwell-publishing/picasa_publishing_options_pane.glade b/plugins/shotwell-publishing/picasa_publishing_options_pane.glade
2088+index 07af67d..4d2cfb4 100644
2089+--- a/plugins/shotwell-publishing/picasa_publishing_options_pane.glade
2090++++ b/plugins/shotwell-publishing/picasa_publishing_options_pane.glade
2091+@@ -226,32 +226,16 @@
2092+ <object class="GtkBox" id="button_area_box">
2093+ <property name="visible">True</property>
2094+ <property name="can_focus">False</property>
2095+- <property name="margin_left">112</property>
2096+- <property name="margin_right">112</property>
2097++ <property name="halign">center</property>
2098+ <property name="margin_top">48</property>
2099+ <property name="margin_bottom">24</property>
2100+ <property name="spacing">128</property>
2101+ <property name="homogeneous">True</property>
2102+ <child>
2103+- <object class="GtkButton" id="logout_button">
2104+- <property name="label" translatable="yes">_Logout</property>
2105+- <property name="use_action_appearance">False</property>
2106+- <property name="visible">True</property>
2107+- <property name="can_focus">True</property>
2108+- <property name="receives_default">True</property>
2109+- <property name="use_action_appearance">False</property>
2110+- <property name="use_underline">True</property>
2111+- </object>
2112+- <packing>
2113+- <property name="expand">False</property>
2114+- <property name="fill">True</property>
2115+- <property name="position">0</property>
2116+- </packing>
2117+- </child>
2118+- <child>
2119+ <object class="GtkButton" id="publish_button">
2120+ <property name="label" translatable="yes">_Publish</property>
2121+ <property name="use_action_appearance">False</property>
2122++ <property name="width_request">96</property>
2123+ <property name="visible">True</property>
2124+ <property name="can_focus">True</property>
2125+ <property name="receives_default">True</property>
2126+@@ -261,13 +245,13 @@
2127+ <packing>
2128+ <property name="expand">False</property>
2129+ <property name="fill">True</property>
2130+- <property name="position">1</property>
2131++ <property name="position">0</property>
2132+ </packing>
2133+ </child>
2134+ </object>
2135+ <packing>
2136+ <property name="expand">False</property>
2137+- <property name="fill">True</property>
2138++ <property name="fill">False</property>
2139+ <property name="position">4</property>
2140+ </packing>
2141+ </child>
2142+diff --git a/po/shotwell-core/shotwell.pot b/po/shotwell-core/shotwell.pot
2143+index df41958..cee8286 100644
2144+--- a/po/shotwell-core/shotwell.pot
2145++++ b/po/shotwell-core/shotwell.pot
2146+@@ -2326,6 +2326,10 @@ msgstr ""
2147+ msgid "Publish photos and videos _to"
2148+ msgstr ""
2149+
2150++#: src/publishing/PublishingUI.vala:238
2151++msgid "Add more accounts..."
2152++msgstr ""
2153++
2154+ #: src/publishing/PublishingUI.vala:354
2155+ msgid "Unable to publish"
2156+ msgstr ""
2157+@@ -3932,3 +3936,19 @@ msgstr ""
2158+ #: ui/shotwell.glade:995
2159+ msgid "Plugins"
2160+ msgstr ""
2161++
2162++#: misc/shotwell.application:2
2163++msgid "Shotwell"
2164++msgstr ""
2165++
2166++#: misc/shotwell.application:9
2167++msgid "Publish your pictures to Picasa"
2168++msgstr ""
2169++
2170++#: misc/shotwell.application:12
2171++msgid "Publish your pictures to Facebook"
2172++msgstr ""
2173++
2174++#: misc/shotwell.application:15
2175++msgid "Publish your pictures to Flickr"
2176++msgstr ""
2177+diff --git a/src/plugins/PublishingInterfaces.vala b/src/plugins/PublishingInterfaces.vala
2178+index 339cc9d..4ed2bec 100644
2179+--- a/src/plugins/PublishingInterfaces.vala
2180++++ b/src/plugins/PublishingInterfaces.vala
2181+@@ -494,6 +494,7 @@ public interface PluginHost : GLib.Object, Spit.HostInterface {
2182 */
2183 public abstract Spit.Publishing.Publisher.MediaType get_publishable_media_type();
2184
2185@@ -1646,7 +2652,15 @@
2186 //
2187 // For future expansion.
2188 //
2189-@@ -586,10 +587,14 @@
2190+@@ -579,18 +580,26 @@ public interface Service : Object, Spit.Pluggable {
2191+ * A factory method that instantiates and returns a new {@link Publisher} object that
2192+ * encapsulates a connection to the remote publishing service that this Service describes.
2193+ */
2194+- public abstract Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host);
2195++ public abstract Spit.Publishing.Publisher create_publisher(string? account, Spit.Publishing.PluginHost host);
2196+
2197+ /**
2198+ * Returns the kinds of media that this service can work with.
2199 */
2200 public abstract Spit.Publishing.Publisher.MediaType get_supported_media();
2201
2202@@ -1655,18 +2669,43 @@
2203 + */
2204 + public virtual bool is_enabled() { return true; }
2205 +
2206++ /**
2207++ * List the accounts available for this service.
2208++ */
2209++ public virtual string[] list_account_names() { return {}; }
2210++
2211 //
2212 // For future expansion.
2213 //
2214 - protected virtual void reserved0() {}
2215- protected virtual void reserved1() {}
2216+- protected virtual void reserved1() {}
2217 protected virtual void reserved2() {}
2218 protected virtual void reserved3() {}
2219-Index: shotwell-0.13.0/src/publishing/PublishingPluginHost.vala
2220-===================================================================
2221---- shotwell-0.13.0.orig/src/publishing/PublishingPluginHost.vala 2012-09-20 07:08:59.000000000 +1200
2222-+++ shotwell-0.13.0/src/publishing/PublishingPluginHost.vala 2012-09-20 15:16:00.933921786 +1200
2223-@@ -232,6 +232,13 @@
2224+ protected virtual void reserved4() {}
2225+diff --git a/src/publishing/PublishingPluginHost.vala b/src/publishing/PublishingPluginHost.vala
2226+index 7be7bed..c0417f8 100644
2227+--- a/src/publishing/PublishingPluginHost.vala
2228++++ b/src/publishing/PublishingPluginHost.vala
2229+@@ -21,7 +21,8 @@ public class ConcretePublishingHost : Plugins.StandardHostInterface,
2230+ private Spit.Publishing.Publisher.MediaType media_type =
2231+ Spit.Publishing.Publisher.MediaType.NONE;
2232+
2233+- public ConcretePublishingHost(Service service, PublishingUI.PublishingDialog dialog,
2234++ public ConcretePublishingHost(Service service, string? account,
2235++ PublishingUI.PublishingDialog dialog,
2236+ Publishable[] publishables) {
2237+ base(service, "sharing");
2238+ this.dialog = dialog;
2239+@@ -30,7 +31,7 @@ public class ConcretePublishingHost : Plugins.StandardHostInterface,
2240+ foreach (Publishable curr_publishable in publishables)
2241+ this.media_type |= curr_publishable.get_media_type();
2242+
2243+- this.active_publisher = service.create_publisher(this);
2244++ this.active_publisher = service.create_publisher(account, this);
2245+ }
2246+
2247+ private void on_login_clicked() {
2248+@@ -232,6 +233,13 @@ public class ConcretePublishingHost : Plugins.StandardHostInterface,
2249
2250 return report_plugin_upload_progress;
2251 }
2252@@ -1680,11 +2719,72 @@
2253 }
2254
2255 }
2256-Index: shotwell-0.13.0/src/publishing/PublishingUI.vala
2257-===================================================================
2258---- shotwell-0.13.0.orig/src/publishing/PublishingUI.vala 2012-09-20 07:08:59.000000000 +1200
2259-+++ shotwell-0.13.0/src/publishing/PublishingUI.vala 2012-09-20 15:16:00.937921786 +1200
2260-@@ -296,6 +296,7 @@
2261+diff --git a/src/publishing/PublishingUI.vala b/src/publishing/PublishingUI.vala
2262+index b7f7f75..a3d404c 100644
2263+--- a/src/publishing/PublishingUI.vala
2264++++ b/src/publishing/PublishingUI.vala
2265+@@ -130,6 +130,11 @@ public class LoginWaitPane : StaticMessagePane {
2266+ }
2267+
2268+ public class PublishingDialog : Gtk.Dialog {
2269++ private struct AccountService {
2270++ Spit.Publishing.Service service;
2271++ string? account;
2272++ }
2273++
2274+ private const int LARGE_WINDOW_WIDTH = 860;
2275+ private const int LARGE_WINDOW_HEIGHT = 688;
2276+ private const int COLOSSAL_WINDOW_WIDTH = 1024;
2277+@@ -151,6 +156,8 @@ public class PublishingDialog : Gtk.Dialog {
2278+ private Spit.Publishing.DialogPane active_pane;
2279+ private Spit.Publishing.Publishable[] publishables;
2280+ private Spit.Publishing.ConcretePublishingHost host;
2281++ private Gee.HashMap<string,AccountService?> services;
2282++ private int service_selector_add_accounts_index;
2283+
2284+ protected PublishingDialog(Gee.Collection<MediaSource> to_publish) {
2285+ assert(to_publish.size > 0);
2286+@@ -158,6 +165,8 @@ public class PublishingDialog : Gtk.Dialog {
2287+ resizable = false;
2288+ delete_event.connect(on_window_close);
2289+
2290++ services = new Gee.HashMap<string,AccountService?>();
2291++
2292+ publishables = new Spit.Publishing.Publishable[0];
2293+ bool has_photos = false;
2294+ bool has_videos = false;
2295+@@ -206,9 +215,28 @@ public class PublishingDialog : Gtk.Dialog {
2296+ if (last_used_service != null && last_used_service == curr_service_id)
2297+ last_used_index = ticker;
2298+
2299+- service_selector_box.append_text(service.get_pluggable_name());
2300+- ticker++;
2301++ var account_names = service.list_account_names();
2302++ if (account_names.length == 0) {
2303++ account_names += null;
2304++ }
2305++
2306++ foreach (string? account_name in account_names) {
2307++ string service_name = service.get_pluggable_name();
2308++ if (account_name != null) {
2309++ service_name += " (%s)".printf(account_name);
2310++ }
2311++
2312++ AccountService account_service = {
2313++ service: service,
2314++ account: account_name
2315++ };
2316++ services.set(service_name, account_service);
2317++ service_selector_box.append_text(service_name);
2318++ ticker++;
2319++ }
2320+ }
2321++ service_selector_box.append_text(_("Add more accounts..."));
2322++ service_selector_add_accounts_index = ticker;
2323+ if (last_used_index >= 0)
2324+ service_selector_box.set_active(last_used_index);
2325+ else
2326+@@ -296,6 +324,7 @@ public class PublishingDialog : Gtk.Dialog {
2327 Spit.Publishing.Service[] all_services = load_all_services();
2328
2329 foreach (Spit.Publishing.Service service in all_services) {
2330@@ -1692,3 +2792,48 @@
2331
2332 if (has_photos && !has_videos) {
2333 if ((service.get_supported_media() & Spit.Publishing.Publisher.MediaType.PHOTO) != 0)
2334+@@ -384,21 +413,34 @@ public class PublishingDialog : Gtk.Dialog {
2335+ }
2336+
2337+ private void on_service_changed() {
2338+- string service_name = service_selector_box.get_active_text();
2339+-
2340+- Spit.Publishing.Service? selected_service = null;
2341+- Spit.Publishing.Service[] services = load_all_services();
2342+- foreach (Spit.Publishing.Service service in services) {
2343+- if (service.get_pluggable_name() == service_name) {
2344+- selected_service = service;
2345+- break;
2346++ if (service_selector_box.get_active() ==
2347++ service_selector_add_accounts_index) {
2348++ debug("Starting Online Accounts...");
2349++ try
2350++ {
2351++ DesktopAppInfo app_info =
2352++ new DesktopAppInfo ("gnome-credentials-panel.desktop");
2353++ GLib.Process.spawn_command_line_async(app_info.get_commandline() + " application=shotwell");
2354++ }
2355++ catch (Error e)
2356++ {
2357++ warning ("Error launching Online Accounts: %s", e.message);
2358+ }
2359++
2360++ on_close_cancel_clicked();
2361++ return;
2362+ }
2363+- assert(selected_service != null);
2364++
2365++ string service_name = service_selector_box.get_active_text();
2366++
2367++ AccountService account_service = services.get(service_name);
2368++ Spit.Publishing.Service? selected_service = account_service.service;
2369+
2370+ Config.Facade.get_instance().set_last_used_service(selected_service.get_id());
2371+
2372+- host = new Spit.Publishing.ConcretePublishingHost(selected_service, this, publishables);
2373++ host = new Spit.Publishing.ConcretePublishingHost(selected_service,
2374++ account_service.account,
2375++ this, publishables);
2376+ host.start_publishing();
2377+ }
2378+

Subscribers

People subscribed via source and target branches