Merge lp:~elementary-os/pantheon-photos/remove-format-string into lp:~elementary-os/pantheon-photos/deb-packaging

Proposed by Danielle Foré
Status: Merged
Approved by: Cody Garver
Approved revision: 8
Merged at revision: 6
Proposed branch: lp:~elementary-os/pantheon-photos/remove-format-string
Merge into: lp:~elementary-os/pantheon-photos/deb-packaging
Diff against target: 2498 lines (+1/-2481)
3 files modified
debian/patches/06_uoa.patch (+0/-2462)
debian/patches/format_string.patch (+0/-16)
debian/patches/series (+1/-3)
To merge this branch: bzr merge lp:~elementary-os/pantheon-photos/remove-format-string
Reviewer Review Type Date Requested Status
elementary OS team Pending
Review via email: mp+220888@code.launchpad.net

Commit message

Remove format string and UOA patches

Description of the change

kills the format string patch

To post a comment you must log in.
7. By Danielle Foré

remove ref in series file

8. By Danielle Foré

also kill uoa patch

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed file 'debian/patches/06_uoa.patch'
2--- debian/patches/06_uoa.patch 2014-01-29 07:10:35 +0000
3+++ debian/patches/06_uoa.patch 1970-01-01 00:00:00 +0000
4@@ -1,2462 +0,0 @@
5-Description: use Ubuntu Online Accounts for Picasa, Facebook and Flickr export plugins
6-Author: Alberto Mardegan <alberto.mardegan@canonical.com>
7-
8----
9-Index: shotwell-0.15.0/Makefile
10-===================================================================
11---- shotwell-0.15.0.orig/Makefile 2013-10-11 12:44:22.142929509 +0200
12-+++ shotwell-0.15.0/Makefile 2013-10-11 12:44:22.122929508 +0200
13-@@ -168,7 +168,11 @@
14-
15- SYS_INTEGRATION_FILES = \
16- shotwell.appdata.xml \
17-+ shotwell.application \
18- shotwell.desktop.head \
19-+ shotwell-sharing-facebook.service \
20-+ shotwell-sharing-flickr.service \
21-+ shotwell-sharing-picasa.service \
22- shotwell-viewer.desktop.head \
23- org.yorba.shotwell.gschema.xml \
24- org.yorba.shotwell-extras.gschema.xml \
25-@@ -306,6 +310,7 @@
26- EXT_PKGS = \
27- atk \
28- gdk-3.0 \
29-+ gdk-x11-3.0 \
30- gee-0.8 \
31- gexiv2 \
32- gio-unix-2.0 \
33-@@ -561,6 +566,12 @@
34- mkdir -p $(DESTDIR)$(LIBEXECDIR)
35- $(INSTALL_PROGRAM) $(THUMBNAILER_BIN) $(DESTDIR)$(LIBEXECDIR)
36- $(INSTALL_PROGRAM) $(MIGRATOR_BIN) $(DESTDIR)$(LIBEXECDIR)
37-+ mkdir -p $(DESTDIR)$(PREFIX)/share/accounts/applications
38-+ $(INSTALL_DATA) misc/shotwell.application $(DESTDIR)$(PREFIX)/share/accounts/applications
39-+ mkdir -p $(DESTDIR)$(PREFIX)/share/accounts/services
40-+ $(INSTALL_DATA) misc/shotwell-sharing-facebook.service $(DESTDIR)$(PREFIX)/share/accounts/services
41-+ $(INSTALL_DATA) misc/shotwell-sharing-flickr.service $(DESTDIR)$(PREFIX)/share/accounts/services
42-+ $(INSTALL_DATA) misc/shotwell-sharing-picasa.service $(DESTDIR)$(PREFIX)/share/accounts/services
43- mkdir -p $(DESTDIR)$(PREFIX)/share/shotwell/icons
44- $(INSTALL_DATA) icons/* $(DESTDIR)$(PREFIX)/share/shotwell/icons
45- mkdir -p $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps
46-Index: shotwell-0.15.0/misc/shotwell.application
47-===================================================================
48---- /dev/null 1970-01-01 00:00:00.000000000 +0000
49-+++ shotwell-0.15.0/misc/shotwell.application 2013-10-11 12:44:22.122929508 +0200
50-@@ -0,0 +1,19 @@
51-+<?xml version="1.0" encoding="UTF-8" ?>
52-+<application id="shotwell">
53-+ <description>Shotwell</description>
54-+ <desktop-entry>shotwell.desktop</desktop-entry>
55-+ <translations>shotwell</translations>
56-+
57-+ <services>
58-+ <service id="shotwell-sharing-picasa">
59-+ <description>Publish your pictures to Picasa</description>
60-+ </service>
61-+ <service id="shotwell-sharing-facebook">
62-+ <description>Publish your pictures to Facebook</description>
63-+ </service>
64-+ <service id="shotwell-sharing-flickr">
65-+ <description>Publish your pictures to Flickr</description>
66-+ </service>
67-+ </services>
68-+
69-+</application>
70-Index: shotwell-0.15.0/plugins/Makefile
71-===================================================================
72---- shotwell-0.15.0.orig/plugins/Makefile 2013-10-11 12:44:22.142929509 +0200
73-+++ shotwell-0.15.0/plugins/Makefile 2013-10-11 12:44:22.122929508 +0200
74-@@ -4,7 +4,10 @@
75- DIST_FILES := \
76- Makefile \
77- Makefile.plugin.mk \
78-- plugins.mk
79-+ plugins.mk \
80-+ Accounts.vapi \
81-+ Accounts.deps \
82-+ Signon.vapi
83-
84- .PHONY: all
85- all: $(ALL_PLUGINS)
86-Index: shotwell-0.15.0/plugins/Makefile.plugin.mk
87-===================================================================
88---- shotwell-0.15.0.orig/plugins/Makefile.plugin.mk 2013-10-11 12:44:22.142929509 +0200
89-+++ shotwell-0.15.0/plugins/Makefile.plugin.mk 2013-10-11 12:44:22.122929508 +0200
90-@@ -27,6 +27,8 @@
91- # automatically include the shotwell-plugin-dev-1.0 package as a local dependency
92- EXT_PKGS := $(PKGS)
93- PKGS := shotwell-plugin-dev-1.0 $(PKGS) $(PLUGIN_PKGS)
94-+EXT_PKGS := libsignon-glib libaccounts-glib $(EXT_PKGS)
95-+PKGS := signon libaccounts-glib $(PKGS)
96-
97- # automatically include the Resources.vala common file
98- SRC_FILES := ../common/Resources.vala $(SRC_FILES)
99-@@ -41,7 +43,7 @@
100- all: $(PLUGIN).so
101-
102- .stamp: $(SRC_FILES) $(MAKE_FILES) $(HEADER_FILES)
103-- $(VALAC) --target-glib=$(MIN_GLIB_VERSION) -g --enable-checking --fatal-warnings --save-temps --compile --enable-deprecated \
104-+ $(VALAC) --target-glib=$(MIN_GLIB_VERSION) -g --enable-checking --save-temps --compile --enable-deprecated \
105- --vapidir=../ $(foreach pkg,$(PKGS),--pkg=$(pkg)) $(foreach pkg,$(CUSTOM_VAPI_PKGS),--pkg=$(pkg)) \
106- -X -I../.. -X -fPIC \
107- $(foreach dfn,$(DEFINES),-X $(dfn)) \
108-Index: shotwell-0.15.0/plugins/common/RESTSupport.vala
109-===================================================================
110---- shotwell-0.15.0.orig/plugins/common/RESTSupport.vala 2013-10-11 12:44:22.142929509 +0200
111-+++ shotwell-0.15.0/plugins/common/RESTSupport.vala 2013-10-11 12:44:22.122929508 +0200
112-@@ -311,7 +311,7 @@
113- old_url = message.get_uri().to_string(false);
114- url_with_query = get_endpoint_url() + "?" + formdata_string;
115- message.set_uri(new Soup.URI(url_with_query));
116-- } else {
117-+ } else if (get_method() == HttpMethod.POST) {
118- message.set_request("application/x-www-form-urlencoded", Soup.MemoryUse.COPY,
119- formdata_string.data);
120- }
121-@@ -868,6 +868,20 @@
122- do_get_access_tokens(auth_code);
123- }
124-
125-+ protected void on_authenticator_authenticated(owned HashTable<string,Value?> session_data) {
126-+ host.install_account_fetch_wait_pane();
127-+
128-+ if (session_data.lookup("AccessToken") != null) {
129-+ string token = session_data.lookup("AccessToken").get_string();
130-+ debug("OAuth Access Token: %s", token);
131-+ session.access_token = token;
132-+
133-+ do_fetch_username();
134-+ } else {
135-+ debug("Access token not present!");
136-+ }
137-+ }
138-+
139- private void on_get_access_tokens_complete(Publishing.RESTSupport.Transaction txn) {
140- txn.completed.disconnect(on_get_access_tokens_complete);
141- txn.network_error.disconnect(on_get_access_tokens_error);
142-Index: shotwell-0.15.0/plugins/common/accounts.vala
143-===================================================================
144---- /dev/null 1970-01-01 00:00:00.000000000 +0000
145-+++ shotwell-0.15.0/plugins/common/accounts.vala 2013-10-11 12:44:22.126929508 +0200
146-@@ -0,0 +1,226 @@
147-+/* Copyright 2009-2011 Yorba Foundation
148-+ *
149-+ * This software is licensed under the GNU Lesser General Public License
150-+ * (version 2.1 or later). See the COPYING file in this distribution.
151-+ */
152-+
153-+namespace Publishing.Accounts {
154-+
155-+public class SharingAccount {
156-+ private Ag.AccountService account_service = null;
157-+
158-+ public SharingAccount(Ag.AccountService account_service) {
159-+ this.account_service = account_service;
160-+ }
161-+
162-+ public Signon.AuthSession create_auth_session() throws GLib.Error {
163-+ var auth_data = account_service.get_auth_data();
164-+
165-+ debug("Signon-id: %u", auth_data.get_credentials_id());
166-+
167-+ return new Signon.AuthSession(auth_data.get_credentials_id(),
168-+ auth_data.get_method());
169-+ }
170-+
171-+ public HashTable<string,Value?> get_session_parameters(out string mechanism) {
172-+ var auth_data = account_service.get_auth_data();
173-+ mechanism = auth_data.get_mechanism();
174-+ return auth_data.get_parameters();
175-+ }
176-+}
177-+
178-+public class SharingAccounts {
179-+ private static Ag.Manager manager = null;
180-+ private string provider_name;
181-+ private Ag.AccountService[] all_accounts;
182-+
183-+ public SharingAccounts(string provider_name) {
184-+ if (manager == null) {
185-+ manager = new Ag.Manager.for_service_type("shotwell-sharing");
186-+ }
187-+ manager.enabled_event.connect(on_account_enabled);
188-+
189-+ this.provider_name = provider_name;
190-+ all_accounts = get_accounts();
191-+ }
192-+
193-+ private void on_account_enabled(uint account_id) {
194-+ /* To keep the implementation simple, just rebuild the account
195-+ * list from scratch */
196-+ all_accounts = get_accounts();
197-+ }
198-+
199-+ private Ag.AccountService[] get_accounts() {
200-+ GLib.List<Ag.AccountService> accounts =
201-+ manager.get_enabled_account_services();
202-+
203-+ Ag.AccountService[] list = {};
204-+
205-+ foreach (Ag.AccountService account_service in accounts) {
206-+ Ag.Account account = account_service.get_account();
207-+ if (account.get_provider_name() == provider_name) {
208-+ list += account_service;
209-+ }
210-+ }
211-+ return list;
212-+ }
213-+
214-+ public bool has_enabled_accounts() {
215-+ return all_accounts.length > 0;
216-+ }
217-+
218-+ public string[] list_account_names() {
219-+ string[] names = {};
220-+ foreach (Ag.AccountService account_service in all_accounts) {
221-+ names += account_service.get_account().get_display_name();
222-+ }
223-+ return names;
224-+ }
225-+
226-+ public SharingAccount? find_account(string? account_name) {
227-+ foreach (Ag.AccountService account_service in all_accounts)
228-+ if (account_service.get_account().get_display_name() == account_name) {
229-+ return new SharingAccount(account_service);
230-+ }
231-+
232-+ return null;
233-+ }
234-+}
235-+
236-+public abstract class UOAPublishingService : Object, Spit.Pluggable, Spit.Publishing.Service {
237-+ private SharingAccounts account_manager;
238-+
239-+ public UOAPublishingService(string provider_name) {
240-+ account_manager = new SharingAccounts(provider_name);
241-+ }
242-+
243-+ public virtual int get_pluggable_interface(int min_host_interface, int max_host_interface) {
244-+ return Spit.negotiate_interfaces(min_host_interface, max_host_interface,
245-+ Spit.Publishing.CURRENT_INTERFACE);
246-+ }
247-+
248-+ public abstract unowned string get_id();
249-+
250-+ public abstract unowned string get_pluggable_name();
251-+
252-+ public abstract void get_info(ref Spit.PluggableInfo info);
253-+
254-+ public virtual void activation(bool enabled) {
255-+ }
256-+
257-+ public abstract Spit.Publishing.Publisher create_publisher(string? account_name, Spit.Publishing.PluginHost host);
258-+
259-+ public abstract Spit.Publishing.Publisher.MediaType get_supported_media();
260-+
261-+ public SharingAccount? find_account(string? account_name) {
262-+ return account_manager.find_account(account_name);
263-+ }
264-+
265-+ public bool is_enabled() {
266-+ return account_manager.has_enabled_accounts();
267-+ }
268-+
269-+ public string[] list_account_names() {
270-+ return account_manager.list_account_names();
271-+ }
272-+}
273-+
274-+public class UOAPublisherAuthenticator : Object {
275-+ private weak Spit.Publishing.PluginHost host = null;
276-+ private Signon.AuthSession auth_session = null;
277-+ private SharingAccount account = null;
278-+ private bool firstLoginAttempt = true;
279-+ private string welcome_message = null;
280-+
281-+ public UOAPublisherAuthenticator(SharingAccount account,
282-+ Spit.Publishing.PluginHost host,
283-+ string welcome_message)
284-+ {
285-+ this.host = host;
286-+ this.account = account;
287-+ this.welcome_message = welcome_message;
288-+ }
289-+
290-+ public signal void authenticated(owned HashTable<string,Value?> session_data);
291-+
292-+ public void authenticate() {
293-+ debug("ACTION: authentication requested.");
294-+
295-+ do_authentication();
296-+ }
297-+
298-+ public HashTable<string,Value?>? get_authentication_data() {
299-+ if (account == null) return null;
300-+ string mechanism = null;
301-+ return account.get_session_parameters(out mechanism);
302-+ }
303-+
304-+ private void do_authentication() {
305-+ debug("ACTION: authenticating.");
306-+
307-+ HashTable<string,Value?> data = null;
308-+ string mechanism = null;
309-+
310-+ if (account != null) {
311-+ try {
312-+ auth_session = account.create_auth_session();
313-+ data = account.get_session_parameters(out mechanism);
314-+ debug("Got account data");
315-+ } catch (GLib.Error e) {
316-+ warning("EVENT: couldn't create session for account: %s",
317-+ e.message);
318-+ }
319-+ }
320-+
321-+ if (data == null) {
322-+ warning ("No account authentication data");
323-+ host.post_error(new Spit.Publishing.PublishingError.SERVICE_ERROR(
324-+ "Error while accessing the account"));
325-+ return;
326-+ }
327-+
328-+ if (firstLoginAttempt) {
329-+ firstLoginAttempt = false;
330-+ data.insert("UiPolicy", (int)Signon.SessionDataUiPolicy.NO_USER_INTERACTION);
331-+ } else {
332-+ var windowId = host.get_dialog_xid();
333-+ if (windowId != 0) {
334-+ data.insert("WindowId", (uint)windowId);
335-+ }
336-+ }
337-+
338-+ auth_session.process(data, mechanism, on_processed);
339-+ host.set_service_locked(true);
340-+ }
341-+
342-+ private void on_processed(Signon.AuthSession self, owned HashTable<string,Value?>? session_data, GLib.Error error){
343-+ host.set_service_locked(false);
344-+ if (error != null) {
345-+ debug("got error: %s", error.message);
346-+ if (error is Signon.Error.USER_INTERACTION) {
347-+ debug("User interaction!");
348-+ do_show_service_welcome_pane();
349-+ } else {
350-+ host.post_error(new Spit.Publishing.PublishingError.SERVICE_ERROR("Authentication failed"));
351-+ }
352-+ return;
353-+ }
354-+
355-+ authenticated(session_data);
356-+ }
357-+
358-+ private void do_show_service_welcome_pane() {
359-+ debug("ACTION: showing service welcome pane.");
360-+
361-+ host.install_welcome_pane(welcome_message, on_service_welcome_login);
362-+ }
363-+
364-+ private void on_service_welcome_login() {
365-+ debug("EVENT: user clicked 'Login' in welcome pane.");
366-+
367-+ do_authentication();
368-+ }
369-+}
370-+
371-+}
372-+
373-Index: shotwell-0.15.0/plugins/shotwell-publishing-extras/TumblrPublishing.vala
374-===================================================================
375---- shotwell-0.15.0.orig/plugins/shotwell-publishing-extras/TumblrPublishing.vala 2013-10-11 12:44:22.142929509 +0200
376-+++ shotwell-0.15.0/plugins/shotwell-publishing-extras/TumblrPublishing.vala 2013-10-11 12:44:22.126929508 +0200
377-@@ -48,7 +48,7 @@
378- public void activation(bool enabled) {
379- }
380-
381-- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
382-+ public Spit.Publishing.Publisher create_publisher(string? account, Spit.Publishing.PluginHost host) {
383- return new Publishing.Tumblr.TumblrPublisher(this, host);
384- }
385-
386-Index: shotwell-0.15.0/plugins/shotwell-publishing-extras/YandexPublishing.vala
387-===================================================================
388---- shotwell-0.15.0.orig/plugins/shotwell-publishing-extras/YandexPublishing.vala 2013-10-11 12:44:22.142929509 +0200
389-+++ shotwell-0.15.0/plugins/shotwell-publishing-extras/YandexPublishing.vala 2013-10-11 12:44:22.126929508 +0200
390-@@ -30,7 +30,7 @@
391- info.license = Resources.LICENSE;
392- }
393-
394-- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
395-+ public Spit.Publishing.Publisher create_publisher(string? account, Spit.Publishing.PluginHost host) {
396- return new Publishing.Yandex.YandexPublisher(this, host);
397- }
398-
399-Index: shotwell-0.15.0/plugins/shotwell-publishing/FacebookPublishing.vala
400-===================================================================
401---- shotwell-0.15.0.orig/plugins/shotwell-publishing/FacebookPublishing.vala 2013-10-11 12:44:22.142929509 +0200
402-+++ shotwell-0.15.0/plugins/shotwell-publishing/FacebookPublishing.vala 2013-10-11 12:44:22.130929509 +0200
403-@@ -4,30 +4,28 @@
404- * (version 2.1 or later). See the COPYING file in this distribution.
405- */
406-
407--public class FacebookService : Object, Spit.Pluggable, Spit.Publishing.Service {
408-+using Publishing.Accounts;
409-+
410-+public class FacebookService : UOAPublishingService, Spit.Pluggable, Spit.Publishing.Service {
411- private const string ICON_FILENAME = "facebook.png";
412-
413- private static Gdk.Pixbuf[] icon_pixbuf_set = null;
414-
415- public FacebookService(GLib.File resource_directory) {
416-+ base("facebook");
417- if (icon_pixbuf_set == null)
418- icon_pixbuf_set = Resources.load_icon_set(resource_directory.get_child(ICON_FILENAME));
419- }
420-
421-- public int get_pluggable_interface(int min_host_interface, int max_host_interface) {
422-- return Spit.negotiate_interfaces(min_host_interface, max_host_interface,
423-- Spit.Publishing.CURRENT_INTERFACE);
424-- }
425--
426-- public unowned string get_id() {
427-+ public override unowned string get_id() {
428- return "org.yorba.shotwell.publishing.facebook";
429- }
430-
431-- public unowned string get_pluggable_name() {
432-+ public override unowned string get_pluggable_name() {
433- return "Facebook";
434- }
435-
436-- public void get_info(ref Spit.PluggableInfo info) {
437-+ public override void get_info(ref Spit.PluggableInfo info) {
438- info.authors = "Lucas Beeler";
439- info.copyright = _("Copyright 2009-2013 Yorba Foundation");
440- info.translators = Resources.TRANSLATORS;
441-@@ -39,14 +37,12 @@
442- info.icons = icon_pixbuf_set;
443- }
444-
445-- public void activation(bool enabled) {
446-- }
447--
448-- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
449-- return new Publishing.Facebook.FacebookPublisher(this, host);
450-+ public override Spit.Publishing.Publisher create_publisher(string? account_name, Spit.Publishing.PluginHost host) {
451-+ SharingAccount account = find_account(account_name);
452-+ return new Publishing.Facebook.FacebookPublisher(this, account, host);
453- }
454-
455-- public Spit.Publishing.Publisher.MediaType get_supported_media() {
456-+ public override Spit.Publishing.Publisher.MediaType get_supported_media() {
457- return (Spit.Publishing.Publisher.MediaType.PHOTO |
458- Spit.Publishing.Publisher.MediaType.VIDEO);
459- }
460-@@ -57,12 +53,9 @@
461- // truly, deep-down know what you're doing)
462- public const string SERVICE_NAME = "facebook";
463- internal const string USER_VISIBLE_NAME = "Facebook";
464--internal const string APPLICATION_ID = "162702932093";
465- internal const string DEFAULT_ALBUM_NAME = _("Shotwell Connect");
466- internal const string SERVICE_WELCOME_MESSAGE =
467- _("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.");
468--internal const string RESTART_ERROR_MESSAGE =
469-- _("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.");
470- internal const string USER_AGENT = "Java/1.6.0_16";
471- internal const int EXPIRED_SESSION_STATUS_CODE = 400;
472-
473-@@ -173,7 +166,6 @@
474- public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
475- private PublishingParameters publishing_params;
476- private weak Spit.Publishing.PluginHost host = null;
477-- private WebAuthenticationPane web_auth_pane = null;
478- private Spit.Publishing.ProgressCallback progress_reporter = null;
479- private weak Spit.Publishing.Service service = null;
480- private bool running = false;
481-@@ -182,8 +174,10 @@
482- private Uploader? uploader = null;
483- private string? uid = null;
484- private string? username = null;
485-+ private UOAPublisherAuthenticator authenticator = null;
486-
487- public FacebookPublisher(Spit.Publishing.Service service,
488-+ SharingAccount account,
489- Spit.Publishing.PluginHost host) {
490- debug("FacebookPublisher instantiated.");
491-
492-@@ -194,32 +188,16 @@
493-
494- this.graph_session = new GraphSession();
495- graph_session.authenticated.connect(on_session_authenticated);
496-- }
497--
498-- private bool is_persistent_session_valid() {
499-- string? token = get_persistent_access_token();
500-
501-- if (token != null)
502-- debug("existing Facebook session found in configuration database (access_token = %s).",
503-- token);
504-- else
505-- debug("no existing Facebook session available.");
506--
507-- return token != null;
508-+ authenticator = new UOAPublisherAuthenticator(account, host,
509-+ SERVICE_WELCOME_MESSAGE);
510-+ authenticator.authenticated.connect(on_authenticator_authenticated);
511- }
512-
513-- private string? get_persistent_access_token() {
514-- return host.get_config_string("access_token", null);
515-- }
516--
517- private bool get_persistent_strip_metadata() {
518- return host.get_config_bool("strip_metadata", false);
519- }
520-
521-- private void set_persistent_access_token(string access_token) {
522-- host.set_config_string("access_token", access_token);
523-- }
524--
525- private void set_persistent_strip_metadata(bool strip_metadata) {
526- host.set_config_bool("strip_metadata", strip_metadata);
527- }
528-@@ -234,32 +212,6 @@
529- host.set_config_int("default_size", size);
530- }
531-
532-- private void invalidate_persistent_session() {
533-- debug("invalidating saved Facebook session.");
534--
535-- set_persistent_access_token("");
536-- }
537--
538-- private void do_show_service_welcome_pane() {
539-- debug("ACTION: showing service welcome pane.");
540--
541-- host.install_welcome_pane(SERVICE_WELCOME_MESSAGE, on_login_clicked);
542-- host.set_service_locked(false);
543-- }
544--
545-- private void do_test_connection_to_endpoint() {
546-- debug("ACTION: testing connection to Facebook endpoint.");
547-- host.set_service_locked(true);
548--
549-- host.install_static_message_pane(_("Testing connection to Facebook..."));
550--
551-- GraphMessage endpoint_test_message = graph_session.new_endpoint_test();
552-- endpoint_test_message.completed.connect(on_endpoint_test_completed);
553-- endpoint_test_message.failed.connect(on_endpoint_test_error);
554--
555-- graph_session.send_message(endpoint_test_message);
556-- }
557--
558- private void do_fetch_user_info() {
559- debug("ACTION: fetching user information.");
560-
561-@@ -377,7 +329,6 @@
562-
563- publishing_options_pane = new PublishingOptionsPane(username, publishing_params.albums,
564- host.get_publishable_media_type(), this, builder, get_persistent_strip_metadata());
565-- publishing_options_pane.logout.connect(on_publishing_options_pane_logout);
566- publishing_options_pane.publish.connect(on_publishing_options_pane_publish);
567- host.install_dialog_pane(publishing_options_pane,
568- Spit.Publishing.PluginHost.ButtonMode.CANCEL);
569-@@ -386,8 +337,6 @@
570- private void do_logout() {
571- debug("ACTION: clearing persistent session information and restaring interaction.");
572-
573-- invalidate_persistent_session();
574--
575- running = false;
576- start();
577- }
578-@@ -411,60 +360,13 @@
579- do_upload();
580- }
581-
582-- private void do_hosted_web_authentication() {
583-- debug("ACTION: doing hosted web authentication.");
584--
585-- host.set_service_locked(false);
586--
587-- web_auth_pane = new WebAuthenticationPane();
588-- web_auth_pane.login_succeeded.connect(on_web_auth_pane_login_succeeded);
589-- web_auth_pane.login_failed.connect(on_web_auth_pane_login_failed);
590--
591-- host.install_dialog_pane(web_auth_pane,
592-- Spit.Publishing.PluginHost.ButtonMode.CANCEL);
593--
594-- }
595--
596-- private void do_authenticate_session(string good_login_uri) {
597-- debug("ACTION: preparing to extract session information encoded in uri = '%s'",
598-- good_login_uri);
599--
600-- // the raw uri is percent-encoded, so decode it
601-- string decoded_uri = Soup.URI.decode(good_login_uri);
602--
603-- // locate the access token within the URI
604-- string? access_token = null;
605-- int index = decoded_uri.index_of("#access_token=");
606-- if (index >= 0)
607-- access_token = decoded_uri[index:decoded_uri.length];
608-- if (access_token == null) {
609-- host.post_error(new Spit.Publishing.PublishingError.MALFORMED_RESPONSE(
610-- "Server redirect URL contained no access token"));
611-- return;
612-- }
613--
614-- // remove any trailing parameters from the session description string
615-- string? trailing_params = null;
616-- index = access_token.index_of_char('&');
617-- if (index >= 0)
618-- trailing_params = access_token[index:access_token.length];
619-- if (trailing_params != null)
620-- access_token = access_token.replace(trailing_params, "");
621--
622-- // remove the key from the session description string
623-- access_token = access_token.replace("#access_token=", "");
624--
625-- // we've got an access token!
626-+ public void on_authenticator_authenticated(owned HashTable<string,Value?> session_data) {
627- graph_session.authenticated.connect(on_session_authenticated);
628-+ string access_token = session_data.lookup("AccessToken").get_string();
629-+ debug("Access Token: %s", access_token);
630- graph_session.authenticate(access_token);
631- }
632-
633-- private void do_save_session_information() {
634-- debug("ACTION: saving session information to configuration system.");
635--
636-- set_persistent_access_token(graph_session.get_access_token());
637-- }
638--
639- private void do_upload() {
640- debug("ACTION: uploading photos to album '%s'",
641- publishing_params.target_album == PublishingParameters.UNKNOWN_ALBUM ? "(none)" :
642-@@ -505,67 +407,6 @@
643- host.post_error(error);
644- }
645-
646-- private void on_login_clicked() {
647-- if (!is_running())
648-- return;
649--
650-- debug("EVENT: user clicked 'Login' on welcome pane.");
651--
652-- do_test_connection_to_endpoint();
653-- }
654--
655-- private void on_endpoint_test_completed(GraphMessage message) {
656-- message.completed.disconnect(on_endpoint_test_completed);
657-- message.failed.disconnect(on_endpoint_test_error);
658--
659-- if (!is_running())
660-- return;
661--
662-- debug("EVENT: endpoint test transaction detected that the Facebook endpoint is alive.");
663--
664-- do_hosted_web_authentication();
665-- }
666--
667-- private void on_endpoint_test_error(GraphMessage message,
668-- Spit.Publishing.PublishingError error) {
669-- message.completed.disconnect(on_endpoint_test_completed);
670-- message.failed.disconnect(on_endpoint_test_error);
671--
672-- if (!is_running())
673-- return;
674--
675-- debug("EVENT: endpoint test transaction failed to detect a connection to the Facebook " +
676-- "endpoint");
677--
678-- on_generic_error(error);
679-- }
680--
681-- private void on_web_auth_pane_login_succeeded(string success_url) {
682-- if (!is_running())
683-- return;
684--
685-- debug("EVENT: hosted web login succeeded.");
686--
687-- do_authenticate_session(success_url);
688-- }
689--
690--
691--
692-- private void on_web_auth_pane_login_failed() {
693-- if (!is_running())
694-- return;
695--
696-- debug("EVENT: hosted web login failed.");
697--
698-- // In this case, "failed" doesn't mean that the user didn't enter the right username and
699-- // password -- Facebook handles that case inside the Facebook Connect web control. Instead,
700-- // it means that no session was initiated in response to our login request. The only
701-- // way this happens is if the user clicks the "Cancel" button that appears inside
702-- // the web control. In this case, the correct behavior is to return the user to the
703-- // service welcome pane so that they can start the web interaction again.
704-- do_show_service_welcome_pane();
705-- }
706--
707- private void on_session_authenticated() {
708- graph_session.authenticated.disconnect(on_session_authenticated);
709-
710-@@ -575,7 +416,6 @@
711- assert(graph_session.is_authenticated());
712- debug("EVENT: an authenticated session has become available.");
713-
714-- do_save_session_information();
715- do_fetch_user_info();
716- }
717-
718-@@ -649,22 +489,9 @@
719- do_show_publishing_options_pane();
720- }
721-
722-- private void on_publishing_options_pane_logout() {
723-- publishing_options_pane.publish.disconnect(on_publishing_options_pane_publish);
724-- publishing_options_pane.logout.disconnect(on_publishing_options_pane_logout);
725--
726-- if (!is_running())
727-- return;
728--
729-- debug("EVENT: user clicked 'Logout' in publishing options pane.");
730--
731-- do_logout();
732-- }
733--
734- private void on_publishing_options_pane_publish(string? target_album, string privacy_setting,
735- Resolution resolution, bool strip_metadata) {
736- publishing_options_pane.publish.disconnect(on_publishing_options_pane_publish);
737-- publishing_options_pane.logout.disconnect(on_publishing_options_pane_logout);
738-
739- if (!is_running())
740- return;
741-@@ -780,20 +607,7 @@
742- // actually a restart
743- publishing_params = new PublishingParameters();
744-
745-- // Do we have saved user credentials? If so, go ahead and authenticate the session
746-- // with the saved credentials and proceed with the publishing interaction. Otherwise, show
747-- // the Welcome pane
748-- if (is_persistent_session_valid()) {
749-- graph_session.authenticate(get_persistent_access_token());
750-- } else {
751-- if (WebAuthenticationPane.is_cache_dirty()) {
752-- host.set_service_locked(false);
753-- host.install_static_message_pane(RESTART_ERROR_MESSAGE,
754-- Spit.Publishing.PluginHost.ButtonMode.CANCEL);
755-- } else {
756-- do_show_service_welcome_pane();
757-- }
758-- }
759-+ authenticator.authenticate();
760- }
761-
762- public void stop() {
763-@@ -811,190 +625,6 @@
764- }
765- }
766-
767--internal class WebAuthenticationPane : Spit.Publishing.DialogPane, Object {
768-- private WebKit.WebView webview = null;
769-- private Gtk.Box pane_widget = null;
770-- private Gtk.ScrolledWindow webview_frame = null;
771-- private static bool cache_dirty = false;
772--
773-- public signal void login_succeeded(string success_url);
774-- public signal void login_failed();
775--
776-- public WebAuthenticationPane() {
777-- pane_widget = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
778--
779-- webview_frame = new Gtk.ScrolledWindow(null, null);
780-- webview_frame.set_shadow_type(Gtk.ShadowType.ETCHED_IN);
781-- webview_frame.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
782--
783-- webview = new WebKit.WebView();
784-- webview.get_settings().enable_plugins = false;
785-- webview.get_settings().enable_default_context_menu = false;
786--
787-- webview.load_finished.connect(on_page_load);
788-- webview.load_started.connect(on_load_started);
789--
790-- webview_frame.add(webview);
791-- pane_widget.pack_start(webview_frame, true, true, 0);
792-- }
793--
794-- private class LocaleLookup {
795-- public string prefix;
796-- public string translation;
797-- public string? exception_code;
798-- public string? exception_translation;
799-- public string? exception_code_2;
800-- public string? exception_translation_2;
801--
802-- public LocaleLookup(string prefix, string translation, string? exception_code = null,
803-- string? exception_translation = null, string? exception_code_2 = null,
804-- string? exception_translation_2 = null) {
805-- this.prefix = prefix;
806-- this.translation = translation;
807-- this.exception_code = exception_code;
808-- this.exception_translation = exception_translation;
809-- this.exception_code_2 = exception_code_2;
810-- this.exception_translation_2 = exception_translation_2;
811-- }
812--
813-- }
814--
815-- private LocaleLookup[] locale_lookup_table = {
816-- new LocaleLookup( "es", "es-la", "ES", "es-es" ),
817-- new LocaleLookup( "en", "en-gb", "US", "en-us" ),
818-- new LocaleLookup( "fr", "fr-fr", "CA", "fr-ca" ),
819-- new LocaleLookup( "pt", "pt-br", "PT", "pt-pt" ),
820-- new LocaleLookup( "zh", "zh-cn", "HK", "zh-hk", "TW", "zh-tw" ),
821-- new LocaleLookup( "af", "af-za" ),
822-- new LocaleLookup( "ar", "ar-ar" ),
823-- new LocaleLookup( "nb", "nb-no" ),
824-- new LocaleLookup( "no", "nb-no" ),
825-- new LocaleLookup( "id", "id-id" ),
826-- new LocaleLookup( "ms", "ms-my" ),
827-- new LocaleLookup( "ca", "ca-es" ),
828-- new LocaleLookup( "cs", "cs-cz" ),
829-- new LocaleLookup( "cy", "cy-gb" ),
830-- new LocaleLookup( "da", "da-dk" ),
831-- new LocaleLookup( "de", "de-de" ),
832-- new LocaleLookup( "tl", "tl-ph" ),
833-- new LocaleLookup( "ko", "ko-kr" ),
834-- new LocaleLookup( "hr", "hr-hr" ),
835-- new LocaleLookup( "it", "it-it" ),
836-- new LocaleLookup( "lt", "lt-lt" ),
837-- new LocaleLookup( "hu", "hu-hu" ),
838-- new LocaleLookup( "nl", "nl-nl" ),
839-- new LocaleLookup( "ja", "ja-jp" ),
840-- new LocaleLookup( "nb", "nb-no" ),
841-- new LocaleLookup( "no", "nb-no" ),
842-- new LocaleLookup( "pl", "pl-pl" ),
843-- new LocaleLookup( "ro", "ro-ro" ),
844-- new LocaleLookup( "ru", "ru-ru" ),
845-- new LocaleLookup( "sk", "sk-sk" ),
846-- new LocaleLookup( "sl", "sl-si" ),
847-- new LocaleLookup( "sv", "sv-se" ),
848-- new LocaleLookup( "th", "th-th" ),
849-- new LocaleLookup( "vi", "vi-vn" ),
850-- new LocaleLookup( "tr", "tr-tr" ),
851-- new LocaleLookup( "el", "el-gr" ),
852-- new LocaleLookup( "bg", "bg-bg" ),
853-- new LocaleLookup( "sr", "sr-rs" ),
854-- new LocaleLookup( "he", "he-il" ),
855-- new LocaleLookup( "hi", "hi-in" ),
856-- new LocaleLookup( "bn", "bn-in" ),
857-- new LocaleLookup( "pa", "pa-in" ),
858-- new LocaleLookup( "ta", "ta-in" ),
859-- new LocaleLookup( "te", "te-in" ),
860-- new LocaleLookup( "ml", "ml-in" )
861-- };
862--
863-- private string get_system_locale_as_facebook_locale() {
864-- unowned string? raw_system_locale = Intl.setlocale(LocaleCategory.ALL, "");
865-- if (raw_system_locale == null || raw_system_locale == "")
866-- return "www";
867--
868-- string system_locale = raw_system_locale.split(".")[0];
869--
870-- foreach (LocaleLookup locale_lookup in locale_lookup_table) {
871-- if (!system_locale.has_prefix(locale_lookup.prefix))
872-- continue;
873--
874-- if (locale_lookup.exception_code != null) {
875-- assert(locale_lookup.exception_translation != null);
876--
877-- if (system_locale.contains(locale_lookup.exception_code))
878-- return locale_lookup.exception_translation;
879-- }
880--
881-- if (locale_lookup.exception_code_2 != null) {
882-- assert(locale_lookup.exception_translation_2 != null);
883--
884-- if (system_locale.contains(locale_lookup.exception_code_2))
885-- return locale_lookup.exception_translation_2;
886-- }
887--
888-- return locale_lookup.translation;
889-- }
890--
891-- // default
892-- return "www";
893-- }
894--
895-- private string get_login_url() {
896-- string facebook_locale = get_system_locale_as_facebook_locale();
897--
898-- return "https://%s.facebook.com/dialog/oauth?client_id=%s&redirect_uri=https://www.facebook.com/connect/login_success.html&scope=publish_actions,user_photos,user_videos&response_type=token".printf(facebook_locale, APPLICATION_ID);
899-- }
900--
901-- private void on_page_load(WebKit.WebFrame origin_frame) {
902-- pane_widget.get_window().set_cursor(new Gdk.Cursor(Gdk.CursorType.LEFT_PTR));
903--
904-- string loaded_url = origin_frame.get_uri().dup();
905--
906-- // strip parameters from the loaded url
907-- if (loaded_url.contains("?")) {
908-- int index = loaded_url.index_of_char('?');
909-- string params = loaded_url[index:loaded_url.length];
910-- loaded_url = loaded_url.replace(params, "");
911-- }
912--
913-- // were we redirected to the facebook login success page?
914-- if (loaded_url.contains("login_success")) {
915-- cache_dirty = true;
916-- login_succeeded(origin_frame.get_uri());
917-- return;
918-- }
919--
920-- // were we redirected to the login total failure page?
921-- if (loaded_url.contains("login_failure")) {
922-- login_failed();
923-- return;
924-- }
925-- }
926--
927-- private void on_load_started(WebKit.WebFrame frame) {
928-- pane_widget.get_window().set_cursor(new Gdk.Cursor(Gdk.CursorType.WATCH));
929-- }
930--
931-- public static bool is_cache_dirty() {
932-- return cache_dirty;
933-- }
934--
935-- public Gtk.Widget get_widget() {
936-- return pane_widget;
937-- }
938--
939-- public Spit.Publishing.DialogPane.GeometryOptions get_preferred_geometry() {
940-- return Spit.Publishing.DialogPane.GeometryOptions.NONE;
941-- }
942--
943-- public void on_pane_installed() {
944-- webview.open(get_login_url());
945-- }
946--
947-- public void on_pane_uninstalled() {
948-- }
949--}
950--
951- internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
952- private Gtk.Builder builder;
953- private Gtk.Box pane_widget = null;
954-@@ -1005,7 +635,6 @@
955- private Gtk.Entry new_album_entry = null;
956- private Gtk.CheckButton strip_metadata_check = null;
957- private Gtk.Button publish_button = null;
958-- private Gtk.Button logout_button = null;
959- private Gtk.Label how_to_label = null;
960- private Album[] albums = null;
961- private FacebookPublisher publisher = null;
962-@@ -1022,7 +651,6 @@
963- private const int CONTENT_GROUP_SPACING = 32;
964- private const int STANDARD_ACTION_BUTTON_WIDTH = 128;
965-
966-- public signal void logout();
967- public signal void publish(string? target_album, string privacy_setting,
968- Resolution target_resolution, bool strip_metadata);
969-
970-@@ -1061,7 +689,6 @@
971- existing_albums_combo = (Gtk.ComboBoxText) this.builder.get_object("existing_albums_combo");
972- visibility_combo = (Gtk.ComboBoxText) this.builder.get_object("visibility_combo");
973- publish_button = (Gtk.Button) this.builder.get_object("publish_button");
974-- logout_button = (Gtk.Button) this.builder.get_object("logout_button");
975- new_album_entry = (Gtk.Entry) this.builder.get_object("new_album_entry");
976- resolution_combo = (Gtk.ComboBoxText) this.builder.get_object("resolution_combo");
977- how_to_label = (Gtk.Label) this.builder.get_object("how_to_label");
978-@@ -1080,7 +707,6 @@
979- visibility_combo.set_active(0);
980-
981- publish_button.clicked.connect(on_publish_button_clicked);
982-- logout_button.clicked.connect(on_logout_button_clicked);
983-
984- setup_resolution_combo();
985- resolution_combo.set_active(publisher.get_persistent_default_size());
986-@@ -1149,10 +775,6 @@
987- publisher.set_persistent_default_size(resolution_combo.get_active());
988- }
989-
990-- private void on_logout_button_clicked() {
991-- logout();
992-- }
993--
994- private void on_publish_button_clicked() {
995- string album_name;
996- string privacy_setting = privacy_descriptions[visibility_combo.get_active()].privacy_setting;
997-@@ -1226,10 +848,6 @@
998- publish_button.grab_focus();
999- }
1000-
1001-- private void notify_logout() {
1002-- logout();
1003-- }
1004--
1005- private void notify_publish(string? target_album, string privacy_setting, Resolution target_resolution) {
1006- publish(target_album, privacy_setting, target_resolution, strip_metadata_check.get_active());
1007- }
1008-@@ -1243,14 +861,12 @@
1009- }
1010-
1011- public void on_pane_installed() {
1012-- logout.connect(notify_logout);
1013- publish.connect(notify_publish);
1014-
1015- installed();
1016- }
1017-
1018- public void on_pane_uninstalled() {
1019-- logout.disconnect(notify_logout);
1020- publish.disconnect(notify_publish);
1021- }
1022- }
1023-@@ -1545,15 +1161,6 @@
1024- return access_token != null;
1025- }
1026-
1027-- public string get_access_token() {
1028-- assert(is_authenticated());
1029-- return access_token;
1030-- }
1031--
1032-- public GraphMessage new_endpoint_test() {
1033-- return new GraphEndpointProbeMessage(this);
1034-- }
1035--
1036- public GraphMessage new_query(string resource_path) {
1037- return new GraphQueryMessage(this, resource_path, access_token);
1038- }
1039-Index: shotwell-0.15.0/plugins/shotwell-publishing/FlickrPublishing.vala
1040-===================================================================
1041---- shotwell-0.15.0.orig/plugins/shotwell-publishing/FlickrPublishing.vala 2013-10-11 12:44:22.142929509 +0200
1042-+++ shotwell-0.15.0/plugins/shotwell-publishing/FlickrPublishing.vala 2013-10-11 12:44:22.130929509 +0200
1043-@@ -4,32 +4,30 @@
1044- * (version 2.1 or later). See the COPYING file in this distribution.
1045- */
1046-
1047-+using Publishing.Accounts;
1048-+
1049- extern string hmac_sha1(string key, string message);
1050-
1051--public class FlickrService : Object, Spit.Pluggable, Spit.Publishing.Service {
1052-+public class FlickrService : UOAPublishingService, Spit.Pluggable, Spit.Publishing.Service {
1053- private const string ICON_FILENAME = "flickr.png";
1054-
1055- private static Gdk.Pixbuf[] icon_pixbuf_set = null;
1056-
1057- public FlickrService(GLib.File resource_directory) {
1058-+ base("flickr");
1059- if (icon_pixbuf_set == null)
1060- icon_pixbuf_set = Resources.load_icon_set(resource_directory.get_child(ICON_FILENAME));
1061- }
1062-
1063-- public int get_pluggable_interface(int min_host_interface, int max_host_interface) {
1064-- return Spit.negotiate_interfaces(min_host_interface, max_host_interface,
1065-- Spit.Publishing.CURRENT_INTERFACE);
1066-- }
1067--
1068-- public unowned string get_id() {
1069-+ public override unowned string get_id() {
1070- return "org.yorba.shotwell.publishing.flickr";
1071- }
1072-
1073-- public unowned string get_pluggable_name() {
1074-+ public override unowned string get_pluggable_name() {
1075- return "Flickr";
1076- }
1077-
1078-- public void get_info(ref Spit.PluggableInfo info) {
1079-+ public override void get_info(ref Spit.PluggableInfo info) {
1080- info.authors = "Lucas Beeler";
1081- info.copyright = _("Copyright 2009-2013 Yorba Foundation");
1082- info.translators = Resources.TRANSLATORS;
1083-@@ -41,14 +39,12 @@
1084- info.icons = icon_pixbuf_set;
1085- }
1086-
1087-- public void activation(bool enabled) {
1088-- }
1089--
1090-- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
1091-- return new Publishing.Flickr.FlickrPublisher(this, host);
1092-+ public override Spit.Publishing.Publisher create_publisher(string? account_name, Spit.Publishing.PluginHost host) {
1093-+ SharingAccount account = find_account(account_name);
1094-+ return new Publishing.Flickr.FlickrPublisher(this, account, host);
1095- }
1096-
1097-- public Spit.Publishing.Publisher.MediaType get_supported_media() {
1098-+ public override Spit.Publishing.Publisher.MediaType get_supported_media() {
1099- return (Spit.Publishing.Publisher.MediaType.PHOTO |
1100- Spit.Publishing.Publisher.MediaType.VIDEO);
1101- }
1102-@@ -62,8 +58,6 @@
1103- internal const string RESTART_ERROR_MESSAGE =
1104- _("You have already logged in and out of Flickr during this Shotwell session.\nTo continue publishing to Flickr, quit and restart Shotwell, then try publishing again.");
1105- internal const string ENDPOINT_URL = "http://api.flickr.com/services/rest";
1106--internal const string API_KEY = "60dd96d4a2ad04888b09c9e18d82c26f";
1107--internal const string API_SECRET = "d0960565e03547c1";
1108- internal const int ORIGINAL_SIZE = -1;
1109- internal const string EXPIRED_SESSION_ERROR_CODE = "98";
1110- internal const string ENCODE_RFC_3986_EXTRA = "!*'();:@&=+$,/?%#[] \\";
1111-@@ -105,60 +99,33 @@
1112- private bool was_started = false;
1113- private Session session = null;
1114- private PublishingOptionsPane publishing_options_pane = null;
1115-+ private UOAPublisherAuthenticator authenticator = null;
1116-
1117- private PublishingParameters parameters = null;
1118-
1119- public FlickrPublisher(Spit.Publishing.Service service,
1120-+ SharingAccount account,
1121- Spit.Publishing.PluginHost host) {
1122- debug("FlickrPublisher instantiated.");
1123- this.service = service;
1124- this.host = host;
1125- this.session = new Session();
1126-+ authenticator = new UOAPublisherAuthenticator(account, host,
1127-+ SERVICE_WELCOME_MESSAGE);
1128- this.parameters = new PublishingParameters();
1129-
1130- session.authenticated.connect(on_session_authenticated);
1131-+ HashTable<string,Value?> data =
1132-+ authenticator.get_authentication_data();
1133-+ session.set_api_credentials(data.lookup("ConsumerKey").get_string(),
1134-+ data.lookup("ConsumerSecret").get_string());
1135-+ authenticator.authenticated.connect(on_authenticator_authenticated);
1136- }
1137-
1138- ~FlickrPublisher() {
1139- session.authenticated.disconnect(on_session_authenticated);
1140- }
1141-
1142-- private void invalidate_persistent_session() {
1143-- set_persistent_access_phase_token("");
1144-- set_persistent_access_phase_token_secret("");
1145-- set_persistent_access_phase_username("");
1146-- }
1147--
1148-- private bool is_persistent_session_valid() {
1149-- return (get_persistent_access_phase_username() != null &&
1150-- get_persistent_access_phase_token() != null &&
1151-- get_persistent_access_phase_token_secret() != null);
1152-- }
1153--
1154-- private string? get_persistent_access_phase_username() {
1155-- return host.get_config_string("access_phase_username", null);
1156-- }
1157--
1158-- private void set_persistent_access_phase_username(string username) {
1159-- host.set_config_string("access_phase_username", username);
1160-- }
1161--
1162-- private string? get_persistent_access_phase_token() {
1163-- return host.get_config_string("access_phase_token", null);
1164-- }
1165--
1166-- private void set_persistent_access_phase_token(string token) {
1167-- host.set_config_string("access_phase_token", token);
1168-- }
1169--
1170-- private string? get_persistent_access_phase_token_secret() {
1171-- return host.get_config_string("access_phase_token_secret", null);
1172-- }
1173--
1174-- private void set_persistent_access_phase_token_secret(string secret) {
1175-- host.set_config_string("access_phase_token_secret", secret);
1176-- }
1177--
1178- private bool get_persistent_strip_metadata() {
1179- return host.get_config_bool("strip_metadata", false);
1180- }
1181-@@ -167,94 +134,17 @@
1182- host.set_config_bool("strip_metadata", strip_metadata);
1183- }
1184-
1185-- private void on_welcome_pane_login_clicked() {
1186-- if (!running)
1187-- return;
1188--
1189-- debug("EVENT: user clicked 'Login' button in the welcome pane");
1190--
1191-- do_run_authentication_request_transaction();
1192-- }
1193--
1194-- private void on_auth_request_txn_completed(Publishing.RESTSupport.Transaction txn) {
1195-- txn.completed.disconnect(on_auth_request_txn_completed);
1196-- txn.network_error.disconnect(on_auth_request_txn_error);
1197--
1198-- if (!is_running())
1199-- return;
1200--
1201-- debug("EVENT: OAuth authentication request transaction completed; response = '%s'",
1202-- txn.get_response());
1203--
1204-- do_parse_token_info_from_auth_request(txn.get_response());
1205-- }
1206--
1207-- private void on_auth_request_txn_error(Publishing.RESTSupport.Transaction txn,
1208-- Spit.Publishing.PublishingError err) {
1209-- txn.completed.disconnect(on_auth_request_txn_completed);
1210-- txn.network_error.disconnect(on_auth_request_txn_error);
1211--
1212-- if (!is_running())
1213-- return;
1214--
1215-- debug("EVENT: OAuth authentication request transaction caused a network error");
1216-- host.post_error(err);
1217-- }
1218--
1219-- private void on_authentication_token_available(string token, string token_secret) {
1220-- debug("EVENT: OAuth authentication token (%s) and token secret (%s) available",
1221-- token, token_secret);
1222--
1223-- session.set_request_phase_credentials(token, token_secret);
1224--
1225-- do_launch_system_browser(token);
1226-- }
1227--
1228-- private void on_system_browser_launched() {
1229-- if (!is_running())
1230-- return;
1231--
1232-- debug("EVENT: system browser launched.");
1233--
1234-- do_show_pin_entry_pane();
1235-- }
1236--
1237-- private void on_pin_entry_proceed(PinEntryPane sender, string pin) {
1238-- sender.proceed.disconnect(on_pin_entry_proceed);
1239--
1240-- if (!is_running())
1241-- return;
1242--
1243-- debug("EVENT: user clicked 'Continue' in PIN entry pane.");
1244--
1245-- do_verify_pin(pin);
1246-- }
1247-+ public void on_authenticator_authenticated(owned HashTable<string,Value?> session_data) {
1248-+ host.set_service_locked(true);
1249-+ host.install_account_fetch_wait_pane();
1250-
1251-- private void on_access_token_fetch_txn_completed(Publishing.RESTSupport.Transaction txn) {
1252-- txn.completed.disconnect(on_access_token_fetch_txn_completed);
1253-- txn.network_error.disconnect(on_access_token_fetch_error);
1254--
1255-- if (!is_running())
1256-- return;
1257--
1258-- debug("EVENT: fetching OAuth access token over the network succeeded");
1259--
1260-- do_extract_access_phase_credentials_from_reponse(txn.get_response());
1261-+ string token = session_data.lookup("AccessToken").get_string();
1262-+ string token_secret = session_data.lookup("TokenSecret").get_string();
1263-+ string username = session_data.lookup("username").get_string();
1264-+ debug("Access Token: %s, %s, %s", token, token_secret, username);
1265-+ session.set_access_phase_credentials(token, token_secret, username);
1266- }
1267-
1268-- private void on_access_token_fetch_error(Publishing.RESTSupport.Transaction txn,
1269-- Spit.Publishing.PublishingError err) {
1270-- txn.completed.disconnect(on_access_token_fetch_txn_completed);
1271-- txn.network_error.disconnect(on_access_token_fetch_error);
1272--
1273-- if (!is_running())
1274-- return;
1275--
1276-- debug("EVENT: fetching OAuth access token over the network caused an error.");
1277--
1278-- host.post_error(err);
1279-- }
1280--
1281- private void on_session_authenticated() {
1282- if (!is_running())
1283- return;
1284-@@ -263,10 +153,6 @@
1285-
1286- parameters.username = session.get_username();
1287-
1288-- set_persistent_access_phase_token(session.get_access_phase_token());
1289-- set_persistent_access_phase_token_secret(session.get_access_phase_token_secret());
1290-- set_persistent_access_phase_username(session.get_username());
1291--
1292- do_fetch_account_info();
1293- }
1294-
1295-@@ -303,7 +189,6 @@
1296-
1297- private void on_publishing_options_pane_publish(bool strip_metadata) {
1298- publishing_options_pane.publish.disconnect(on_publishing_options_pane_publish);
1299-- publishing_options_pane.logout.disconnect(on_publishing_options_pane_logout);
1300-
1301- if (!is_running())
1302- return;
1303-@@ -312,18 +197,6 @@
1304- do_publish(strip_metadata);
1305- }
1306-
1307-- private void on_publishing_options_pane_logout() {
1308-- publishing_options_pane.publish.disconnect(on_publishing_options_pane_publish);
1309-- publishing_options_pane.logout.disconnect(on_publishing_options_pane_logout);
1310--
1311-- if (!is_running())
1312-- return;
1313--
1314-- debug("EVENT: user clicked the 'Logout' button in the publishing options pane");
1315--
1316-- do_logout();
1317-- }
1318--
1319- private void on_upload_status_updated(int file_number, double completed_fraction) {
1320- if (!is_running())
1321- return;
1322-@@ -361,148 +234,6 @@
1323- host.post_error(err);
1324- }
1325-
1326-- private void do_show_login_welcome_pane() {
1327-- debug("ACTION: installing login welcome pane");
1328--
1329-- host.set_service_locked(false);
1330-- host.install_welcome_pane(SERVICE_WELCOME_MESSAGE, on_welcome_pane_login_clicked);
1331-- }
1332--
1333-- private void do_run_authentication_request_transaction() {
1334-- debug("ACTION: running authentication request transaction");
1335--
1336-- host.set_service_locked(true);
1337-- host.install_static_message_pane(_("Preparing for login..."));
1338--
1339-- AuthenticationRequestTransaction txn = new AuthenticationRequestTransaction(session);
1340-- txn.completed.connect(on_auth_request_txn_completed);
1341-- txn.network_error.connect(on_auth_request_txn_error);
1342--
1343-- try {
1344-- txn.execute();
1345-- } catch (Spit.Publishing.PublishingError err) {
1346-- host.post_error(err);
1347-- }
1348-- }
1349--
1350-- private void do_parse_token_info_from_auth_request(string response) {
1351-- debug("ACTION: parsing authorization request response '%s' into token and secret", response);
1352--
1353-- string? oauth_token = null;
1354-- string? oauth_token_secret = null;
1355--
1356-- string[] key_value_pairs = response.split("&");
1357-- foreach (string pair in key_value_pairs) {
1358-- string[] split_pair = pair.split("=");
1359--
1360-- if (split_pair.length != 2)
1361-- host.post_error(new Spit.Publishing.PublishingError.MALFORMED_RESPONSE(
1362-- "'%s' isn't a valid response to an OAuth authentication request"));
1363--
1364-- if (split_pair[0] == "oauth_token")
1365-- oauth_token = split_pair[1];
1366-- else if (split_pair[0] == "oauth_token_secret")
1367-- oauth_token_secret = split_pair[1];
1368-- }
1369--
1370-- if (oauth_token == null || oauth_token_secret == null)
1371-- host.post_error(new Spit.Publishing.PublishingError.MALFORMED_RESPONSE(
1372-- "'%s' isn't a valid response to an OAuth authentication request"));
1373--
1374--
1375-- on_authentication_token_available(oauth_token, oauth_token_secret);
1376-- }
1377--
1378-- private void do_launch_system_browser(string token) {
1379-- string login_uri = "http://www.flickr.com/services/oauth/authorize?oauth_token=" + token +
1380-- "&perms=write";
1381--
1382-- debug("ACTION: launching system browser with uri = '%s'", login_uri);
1383--
1384-- try {
1385-- Process.spawn_command_line_async("xdg-open " + login_uri);
1386-- } catch (SpawnError e) {
1387-- host.post_error(new Spit.Publishing.PublishingError.LOCAL_FILE_ERROR(
1388-- "couldn't launch system web browser to complete Flickr login"));
1389-- return;
1390-- }
1391--
1392-- on_system_browser_launched();
1393-- }
1394--
1395-- private void do_show_pin_entry_pane() {
1396-- debug("ACTION: showing PIN entry pane");
1397--
1398-- Gtk.Builder builder = new Gtk.Builder();
1399--
1400-- try {
1401-- builder.add_from_file(host.get_module_file().get_parent().get_child("flickr_pin_entry_pane.glade").get_path());
1402-- } catch (Error e) {
1403-- warning("Could not parse UI file! Error: %s.", e.message);
1404-- host.post_error(
1405-- new Spit.Publishing.PublishingError.LOCAL_FILE_ERROR(
1406-- _("A file required for publishing is unavailable. Publishing to Flickr can't continue.")));
1407-- return;
1408-- }
1409--
1410-- PinEntryPane pin_entry_pane = new PinEntryPane(builder);
1411-- pin_entry_pane.proceed.connect(on_pin_entry_proceed);
1412-- host.install_dialog_pane(pin_entry_pane);
1413-- }
1414--
1415-- private void do_verify_pin(string pin) {
1416-- debug("ACTION: validating authorization PIN %s", pin);
1417--
1418-- host.set_service_locked(true);
1419-- host.install_static_message_pane(_("Verifying authorization..."));
1420--
1421-- AccessTokenFetchTransaction txn = new AccessTokenFetchTransaction(session, pin);
1422-- txn.completed.connect(on_access_token_fetch_txn_completed);
1423-- txn.network_error.connect(on_access_token_fetch_error);
1424--
1425-- try {
1426-- txn.execute();
1427-- } catch (Spit.Publishing.PublishingError err) {
1428-- host.post_error(err);
1429-- }
1430-- }
1431--
1432-- private void do_extract_access_phase_credentials_from_reponse(string response) {
1433-- debug("ACTION: extracting access phase credentials from '%s'", response);
1434--
1435-- string[] key_value_pairs = response.split("&");
1436--
1437-- string? token = null;
1438-- string? token_secret = null;
1439-- string? username = null;
1440-- foreach (string key_value_pair in key_value_pairs) {
1441-- string[] split_pair = key_value_pair.split("=");
1442--
1443-- if (split_pair.length != 2)
1444-- continue;
1445--
1446-- string key = split_pair[0];
1447-- string value = split_pair[1];
1448--
1449-- if (key == "oauth_token")
1450-- token = value;
1451-- else if (key == "oauth_token_secret")
1452-- token_secret = value;
1453-- else if (key == "username")
1454-- username = value;
1455-- }
1456--
1457-- debug("access phase credentials: { token = '%s'; token_secret = '%s'; username = '%s' }",
1458-- token, token_secret, username);
1459--
1460-- if (token == null || token_secret == null || username == null)
1461-- host.post_error(new Spit.Publishing.PublishingError.MALFORMED_RESPONSE("expected " +
1462-- "access phase credentials to contain token, token secret, and username but at " +
1463-- "least one of these is absent"));
1464--
1465-- session.set_access_phase_credentials(token, token_secret, username);
1466-- }
1467--
1468- private void do_fetch_account_info() {
1469- debug("ACTION: running network transaction to fetch account information");
1470-
1471-@@ -568,7 +299,6 @@
1472- debug("ACTION: logging user out, deauthenticating session, and erasing stored credentials");
1473-
1474- session.deauthenticate();
1475-- invalidate_persistent_session();
1476-
1477- running = false;
1478-
1479-@@ -599,7 +329,6 @@
1480- publishing_options_pane = new PublishingOptionsPane(this, parameters,
1481- host.get_publishable_media_type(), builder, get_persistent_strip_metadata());
1482- publishing_options_pane.publish.connect(on_publishing_options_pane_publish);
1483-- publishing_options_pane.logout.connect(on_publishing_options_pane_logout);
1484- host.install_dialog_pane(publishing_options_pane);
1485- }
1486-
1487-@@ -674,16 +403,7 @@
1488- running = true;
1489- was_started = true;
1490-
1491-- if (is_persistent_session_valid()) {
1492-- debug("attempt start: a persistent session is available; using it");
1493--
1494-- session.authenticate_from_persistent_credentials(get_persistent_access_phase_token(),
1495-- get_persistent_access_phase_token_secret(), get_persistent_access_phase_username());
1496-- } else {
1497-- debug("attempt start: no persistent session available; showing login welcome pane");
1498--
1499-- do_show_login_welcome_pane();
1500-- }
1501-+ authenticator.authenticate();
1502- }
1503-
1504- public void start() {
1505-@@ -772,7 +492,7 @@
1506- add_argument("oauth_version", "1.0");
1507- add_argument("oauth_callback", "oob");
1508- add_argument("oauth_timestamp", session.get_oauth_timestamp());
1509-- add_argument("oauth_consumer_key", API_KEY);
1510-+ add_argument("oauth_consumer_key", session.get_api_key());
1511- }
1512-
1513- public Transaction.with_uri(Session session, string uri,
1514-@@ -784,7 +504,7 @@
1515- add_argument("oauth_version", "1.0");
1516- add_argument("oauth_callback", "oob");
1517- add_argument("oauth_timestamp", session.get_oauth_timestamp());
1518-- add_argument("oauth_consumer_key", API_KEY);
1519-+ add_argument("oauth_consumer_key", session.get_api_key());
1520- }
1521-
1522- public override void execute() throws Spit.Publishing.PublishingError {
1523-@@ -842,22 +562,6 @@
1524- }
1525- }
1526-
1527--internal class AuthenticationRequestTransaction : Transaction {
1528-- public AuthenticationRequestTransaction(Session session) {
1529-- base.with_uri(session, "http://www.flickr.com/services/oauth/request_token",
1530-- Publishing.RESTSupport.HttpMethod.GET);
1531-- }
1532--}
1533--
1534--internal class AccessTokenFetchTransaction : Transaction {
1535-- public AccessTokenFetchTransaction(Session session, string user_verifier) {
1536-- base.with_uri(session, "http://www.flickr.com/services/oauth/access_token",
1537-- Publishing.RESTSupport.HttpMethod.GET);
1538-- add_argument("oauth_verifier", user_verifier);
1539-- add_argument("oauth_token", session.get_request_phase_token());
1540-- }
1541--}
1542--
1543- internal class AccountInfoFetchTransaction : Transaction {
1544- public AccountInfoFetchTransaction(Session session) {
1545- base(session, Publishing.RESTSupport.HttpMethod.GET);
1546-@@ -884,7 +588,7 @@
1547- add_authorization_header_field("oauth_version", "1.0");
1548- add_authorization_header_field("oauth_callback", "oob");
1549- add_authorization_header_field("oauth_timestamp", session.get_oauth_timestamp());
1550-- add_authorization_header_field("oauth_consumer_key", API_KEY);
1551-+ add_authorization_header_field("oauth_consumer_key", session.get_api_key());
1552- add_authorization_header_field("oauth_token", session.get_access_phase_token());
1553-
1554- add_argument("is_public", ("%d".printf(parameters.visibility_specification.everyone_level)));
1555-@@ -944,11 +648,11 @@
1556- }
1557-
1558- internal class Session : Publishing.RESTSupport.Session {
1559-- private string? request_phase_token = null;
1560-- private string? request_phase_token_secret = null;
1561- private string? access_phase_token = null;
1562- private string? access_phase_token_secret = null;
1563- private string? username = null;
1564-+ private string? api_key = null;
1565-+ private string? api_secret = null;
1566-
1567- public Session() {
1568- base(ENDPOINT_URL);
1569-@@ -959,15 +663,6 @@
1570- username != null);
1571- }
1572-
1573-- public void authenticate_from_persistent_credentials(string token, string secret,
1574-- string username) {
1575-- this.access_phase_token = token;
1576-- this.access_phase_token_secret = secret;
1577-- this.username = username;
1578--
1579-- authenticated();
1580-- }
1581--
1582- public void deauthenticate() {
1583- access_phase_token = null;
1584- access_phase_token_secret = null;
1585-@@ -1008,16 +703,12 @@
1586- if (access_phase_token_secret != null) {
1587- debug("access phase token secret available; using it as signing key");
1588-
1589-- signing_key = API_SECRET + "&" + access_phase_token_secret;
1590-- } else if (request_phase_token_secret != null) {
1591-- debug("request phase token secret available; using it as signing key");
1592--
1593-- signing_key = API_SECRET + "&" + request_phase_token_secret;
1594-+ signing_key = api_secret + "&" + access_phase_token_secret;
1595- } else {
1596-- debug("neither access phase nor request phase token secrets available; using API " +
1597-+ debug("access token secret not available; using API " +
1598- "key as signing key");
1599-
1600-- signing_key = API_SECRET + "&";
1601-+ signing_key = api_secret + "&";
1602- }
1603-
1604- string signature_base_string = http_method + "&" + Soup.URI.encode(
1605-@@ -1040,11 +731,11 @@
1606- txn.add_argument("oauth_signature", signature);
1607- }
1608-
1609-- public void set_request_phase_credentials(string token, string secret) {
1610-- this.request_phase_token = token;
1611-- this.request_phase_token_secret = secret;
1612-+ public void set_api_credentials(string api_key, string api_secret) {
1613-+ this.api_key = api_key;
1614-+ this.api_secret = api_secret;
1615- }
1616--
1617-+
1618- public void set_access_phase_credentials(string token, string secret, string username) {
1619- this.access_phase_token = token;
1620- this.access_phase_token_secret = secret;
1621-@@ -1065,21 +756,16 @@
1622- return GLib.get_real_time().to_string().substring(0, 10);
1623- }
1624-
1625-- public string get_request_phase_token() {
1626-- assert(request_phase_token != null);
1627-- return request_phase_token;
1628-+ public string get_api_key() {
1629-+ assert(api_key != null);
1630-+ return api_key;
1631- }
1632--
1633-+
1634- public string get_access_phase_token() {
1635- assert(access_phase_token != null);
1636- return access_phase_token;
1637- }
1638-
1639-- public string get_access_phase_token_secret() {
1640-- assert(access_phase_token_secret != null);
1641-- return access_phase_token_secret;
1642-- }
1643--
1644- public string get_username() {
1645- assert(is_authenticated());
1646- return username;
1647-@@ -1112,7 +798,6 @@
1648- private Gtk.Label visibility_label = null;
1649- private Gtk.Label upload_info_label = null;
1650- private Gtk.Label size_label = null;
1651-- private Gtk.Button logout_button = null;
1652- private Gtk.Button publish_button = null;
1653- private Gtk.ComboBoxText visibility_combo = null;
1654- private Gtk.ComboBoxText size_combo = null;
1655-@@ -1124,7 +809,6 @@
1656- private Spit.Publishing.Publisher.MediaType media_type;
1657-
1658- public signal void publish(bool strip_metadata);
1659-- public signal void logout();
1660-
1661- public PublishingOptionsPane(FlickrPublisher publisher, PublishingParameters parameters,
1662- Spit.Publishing.Publisher.MediaType media_type, Gtk.Builder builder, bool strip_metadata) {
1663-@@ -1136,7 +820,6 @@
1664- pane_widget = (Gtk.Box) this.builder.get_object("flickr_pane");
1665- visibility_label = (Gtk.Label) this.builder.get_object("visibility_label");
1666- upload_info_label = (Gtk.Label) this.builder.get_object("upload_info_label");
1667-- logout_button = (Gtk.Button) this.builder.get_object("logout_button");
1668- publish_button = (Gtk.Button) this.builder.get_object("publish_button");
1669- visibility_combo = (Gtk.ComboBoxText) this.builder.get_object("visibility_combo");
1670- size_combo = (Gtk.ComboBoxText) this.builder.get_object("size_combo");
1671-@@ -1183,14 +866,9 @@
1672-
1673- strip_metadata_check.set_active(strip_metadata);
1674-
1675-- logout_button.clicked.connect(on_logout_clicked);
1676- publish_button.clicked.connect(on_publish_clicked);
1677- }
1678-
1679-- private void on_logout_clicked() {
1680-- logout();
1681-- }
1682--
1683- private void on_publish_clicked() {
1684- parameters.visibility_specification =
1685- visibilities[visibility_combo.get_active()].specification;
1686-@@ -1257,10 +935,6 @@
1687- publish(strip_metadata_check.get_active());
1688- }
1689-
1690-- protected void notify_logout() {
1691-- logout();
1692-- }
1693--
1694- public Gtk.Widget get_widget() {
1695- return pane_widget;
1696- }
1697-@@ -1271,12 +945,10 @@
1698-
1699- public void on_pane_installed() {
1700- publish.connect(notify_publish);
1701-- logout.connect(notify_logout);
1702- }
1703-
1704- public void on_pane_uninstalled() {
1705- publish.disconnect(notify_publish);
1706-- logout.disconnect(notify_logout);
1707- }
1708- }
1709-
1710-Index: shotwell-0.15.0/plugins/shotwell-publishing/Makefile
1711-===================================================================
1712---- shotwell-0.15.0.orig/plugins/shotwell-publishing/Makefile 2013-10-11 12:44:22.142929509 +0200
1713-+++ shotwell-0.15.0/plugins/shotwell-publishing/Makefile 2013-10-11 12:44:22.130929509 +0200
1714-@@ -18,6 +18,7 @@
1715- FlickrPublishing.vala \
1716- YouTubePublishing.vala \
1717- PiwigoPublishing.vala \
1718-+ ../common/accounts.vala \
1719- ../../src/util/string.vala \
1720- ../common/RESTSupport.vala
1721-
1722-Index: shotwell-0.15.0/plugins/shotwell-publishing/PicasaPublishing.vala
1723-===================================================================
1724---- shotwell-0.15.0.orig/plugins/shotwell-publishing/PicasaPublishing.vala 2013-10-11 12:44:22.142929509 +0200
1725-+++ shotwell-0.15.0/plugins/shotwell-publishing/PicasaPublishing.vala 2013-10-11 12:44:22.134929509 +0200
1726-@@ -4,30 +4,28 @@
1727- * (version 2.1 or later). See the COPYING file in this distribution.
1728- */
1729-
1730--public class PicasaService : Object, Spit.Pluggable, Spit.Publishing.Service {
1731-+using Publishing.Accounts;
1732-+
1733-+public class PicasaService : UOAPublishingService, Spit.Pluggable, Spit.Publishing.Service {
1734- private const string ICON_FILENAME = "picasa.png";
1735-
1736- private static Gdk.Pixbuf[] icon_pixbuf_set = null;
1737-
1738- public PicasaService(GLib.File resource_directory) {
1739-+ base("google");
1740- if (icon_pixbuf_set == null)
1741- icon_pixbuf_set = Resources.load_icon_set(resource_directory.get_child(ICON_FILENAME));
1742- }
1743-
1744-- public int get_pluggable_interface(int min_host_interface, int max_host_interface) {
1745-- return Spit.negotiate_interfaces(min_host_interface, max_host_interface,
1746-- Spit.Publishing.CURRENT_INTERFACE);
1747-- }
1748--
1749-- public unowned string get_id() {
1750-+ public override unowned string get_id() {
1751- return "org.yorba.shotwell.publishing.picasa";
1752- }
1753-
1754-- public unowned string get_pluggable_name() {
1755-+ public override unowned string get_pluggable_name() {
1756- return "Picasa Web Albums";
1757- }
1758-
1759-- public void get_info(ref Spit.PluggableInfo info) {
1760-+ public override void get_info(ref Spit.PluggableInfo info) {
1761- info.authors = "Lucas Beeler";
1762- info.copyright = _("Copyright 2009-2013 Yorba Foundation");
1763- info.translators = Resources.TRANSLATORS;
1764-@@ -39,17 +37,15 @@
1765- info.icons = icon_pixbuf_set;
1766- }
1767-
1768-- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
1769-- return new Publishing.Picasa.PicasaPublisher(this, host);
1770-+ public override Spit.Publishing.Publisher create_publisher(string? account_name, Spit.Publishing.PluginHost host) {
1771-+ SharingAccount account = find_account(account_name);
1772-+ return new Publishing.Picasa.PicasaPublisher(this, account, host);
1773- }
1774-
1775-- public Spit.Publishing.Publisher.MediaType get_supported_media() {
1776-+ public override Spit.Publishing.Publisher.MediaType get_supported_media() {
1777- return (Spit.Publishing.Publisher.MediaType.PHOTO |
1778- Spit.Publishing.Publisher.MediaType.VIDEO);
1779- }
1780--
1781-- public void activation(bool enabled) {
1782-- }
1783- }
1784-
1785- namespace Publishing.Picasa {
1786-@@ -62,21 +58,25 @@
1787- private bool running;
1788- private Spit.Publishing.ProgressCallback progress_reporter;
1789- private PublishingParameters publishing_parameters;
1790-- private string? refresh_token;
1791-+ private UOAPublisherAuthenticator authenticator = null;
1792-
1793- public PicasaPublisher(Spit.Publishing.Service service,
1794-+ SharingAccount account,
1795- Spit.Publishing.PluginHost host) {
1796- base(service, host, "http://picasaweb.google.com/data/");
1797-
1798- this.publishing_parameters = new PublishingParameters();
1799- load_parameters_from_configuration_system(publishing_parameters);
1800-
1801-+ authenticator = new UOAPublisherAuthenticator(account, host,
1802-+ SERVICE_WELCOME_MESSAGE);
1803-+ authenticator.authenticated.connect(on_authenticator_authenticated);
1804-+
1805- Spit.Publishing.Publisher.MediaType media_type = Spit.Publishing.Publisher.MediaType.NONE;
1806- foreach(Spit.Publishing.Publishable p in host.get_publishables())
1807- media_type |= p.get_media_type();
1808- publishing_parameters.set_media_type(media_type);
1809-
1810-- this.refresh_token = host.get_config_string("refresh_token", null);
1811- this.progress_reporter = null;
1812- }
1813-
1814-@@ -131,20 +131,9 @@
1815- get_host().set_config_string("last-album", parameters.get_target_album_name());
1816- }
1817-
1818-- private void on_service_welcome_login() {
1819-- debug("EVENT: user clicked 'Login' in welcome pane.");
1820--
1821-- if (!is_running())
1822-- return;
1823--
1824-- start_oauth_flow(refresh_token);
1825-- }
1826--
1827- protected override void on_login_flow_complete() {
1828- debug("EVENT: OAuth login flow complete.");
1829-
1830-- get_host().set_config_string("refresh_token", get_session().get_refresh_token());
1831--
1832- publishing_parameters.set_user_name(get_session().get_user_name());
1833-
1834- do_fetch_account_information();
1835-@@ -173,21 +162,7 @@
1836- debug("EVENT: fetching account and album information failed; response = '%s'.",
1837- bad_txn.get_response());
1838-
1839-- if (bad_txn.get_status_code() == 403 || bad_txn.get_status_code() == 404) {
1840-- do_logout();
1841-- } else {
1842-- // If we get any other kind of error, we can't recover, so just post it to the user
1843-- get_host().post_error(err);
1844-- }
1845-- }
1846--
1847-- private void on_publishing_options_logout() {
1848-- if (!is_running())
1849-- return;
1850--
1851-- debug("EVENT: user clicked 'Logout' in the publishing options pane.");
1852--
1853-- do_logout();
1854-+ get_host().post_error(err);
1855- }
1856-
1857- private void on_publishing_options_publish() {
1858-@@ -295,12 +270,6 @@
1859- get_host().post_error(err);
1860- }
1861-
1862-- private void do_show_service_welcome_pane() {
1863-- debug("ACTION: showing service welcome pane.");
1864--
1865-- get_host().install_welcome_pane(SERVICE_WELCOME_MESSAGE, on_service_welcome_login);
1866-- }
1867--
1868- private void do_fetch_account_information() {
1869- debug("ACTION: fetching account and album information.");
1870-
1871-@@ -364,7 +333,6 @@
1872-
1873- PublishingOptionsPane opts_pane = new PublishingOptionsPane(builder, publishing_parameters);
1874- opts_pane.publish.connect(on_publishing_options_publish);
1875-- opts_pane.logout.connect(on_publishing_options_logout);
1876- get_host().install_dialog_pane(opts_pane);
1877-
1878- get_host().set_service_locked(false);
1879-@@ -425,13 +393,6 @@
1880-
1881- protected override void do_logout() {
1882- debug("ACTION: logging out user.");
1883--
1884-- get_session().deauthenticate();
1885-- refresh_token = null;
1886-- get_host().unset_config_key("refresh_token");
1887--
1888--
1889-- do_show_service_welcome_pane();
1890- }
1891-
1892- public override bool is_running() {
1893-@@ -446,10 +407,7 @@
1894-
1895- running = true;
1896-
1897-- if (refresh_token == null)
1898-- do_show_service_welcome_pane();
1899-- else
1900-- start_oauth_flow(refresh_token);
1901-+ authenticator.authenticate();
1902- }
1903-
1904- public override void stop() {
1905-@@ -625,7 +583,6 @@
1906- private Gtk.ComboBoxText size_combo = null;
1907- private Gtk.CheckButton strip_metadata_check = null;
1908- private Gtk.Button publish_button = null;
1909-- private Gtk.Button logout_button = null;
1910- private SizeDescription[] size_descriptions;
1911- private PublishingParameters parameters;
1912-
1913-@@ -653,7 +610,6 @@
1914- size_combo = (Gtk.ComboBoxText) builder.get_object("size_combo");
1915- strip_metadata_check = (Gtk.CheckButton) this.builder.get_object("strip_metadata_check");
1916- publish_button = (Gtk.Button) builder.get_object("publish_button");
1917-- logout_button = (Gtk.Button) builder.get_object("logout_button");
1918-
1919- // populate any widgets whose contents are programmatically-generated.
1920- login_identity_label.set_label(_("You are logged into Picasa Web Albums as %s.").printf(
1921-@@ -680,7 +636,6 @@
1922- use_existing_radio.clicked.connect(on_use_existing_radio_clicked);
1923- create_new_radio.clicked.connect(on_create_new_radio_clicked);
1924- new_album_entry.changed.connect(on_new_album_entry_changed);
1925-- logout_button.clicked.connect(on_logout_clicked);
1926- publish_button.clicked.connect(on_publish_clicked);
1927- }
1928-
1929-@@ -726,10 +681,6 @@
1930- public_check.set_sensitive(true);
1931- }
1932-
1933-- private void on_logout_clicked() {
1934-- logout();
1935-- }
1936--
1937- private void update_publish_button_sensitivity() {
1938- string album_name = new_album_entry.get_text();
1939- publish_button.set_sensitive(!(album_name.strip() == "" &&
1940-Index: shotwell-0.15.0/plugins/shotwell-publishing/PiwigoPublishing.vala
1941-===================================================================
1942---- shotwell-0.15.0.orig/plugins/shotwell-publishing/PiwigoPublishing.vala 2013-10-11 12:44:22.142929509 +0200
1943-+++ shotwell-0.15.0/plugins/shotwell-publishing/PiwigoPublishing.vala 2013-10-11 12:44:22.134929509 +0200
1944-@@ -42,7 +42,7 @@
1945- public void activation(bool enabled) {
1946- }
1947-
1948-- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
1949-+ public Spit.Publishing.Publisher create_publisher(string? account, Spit.Publishing.PluginHost host) {
1950- return new Publishing.Piwigo.PiwigoPublisher(this, host);
1951- }
1952-
1953-Index: shotwell-0.15.0/plugins/shotwell-publishing/YouTubePublishing.vala
1954-===================================================================
1955---- shotwell-0.15.0.orig/plugins/shotwell-publishing/YouTubePublishing.vala 2013-10-11 12:44:22.142929509 +0200
1956-+++ shotwell-0.15.0/plugins/shotwell-publishing/YouTubePublishing.vala 2013-10-11 12:44:22.134929509 +0200
1957-@@ -39,7 +39,7 @@
1958- info.icons = icon_pixbuf_set;
1959- }
1960-
1961-- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
1962-+ public Spit.Publishing.Publisher create_publisher(string? account, Spit.Publishing.PluginHost host) {
1963- return new Publishing.YouTube.YouTubePublisher(this, host);
1964- }
1965-
1966-Index: shotwell-0.15.0/plugins/shotwell-publishing/facebook_publishing_options_pane.glade
1967-===================================================================
1968---- shotwell-0.15.0.orig/plugins/shotwell-publishing/facebook_publishing_options_pane.glade 2013-10-11 12:44:22.142929509 +0200
1969-+++ shotwell-0.15.0/plugins/shotwell-publishing/facebook_publishing_options_pane.glade 2013-10-11 12:44:22.134929509 +0200
1970-@@ -190,42 +190,29 @@
1971- <object class="GtkBox" id="box2">
1972- <property name="visible">True</property>
1973- <property name="can_focus">False</property>
1974-+ <property name="halign">center</property>
1975- <property name="spacing">32</property>
1976- <property name="homogeneous">True</property>
1977- <child>
1978-- <object class="GtkButton" id="logout_button">
1979-- <property name="label" translatable="yes">_Logout</property>
1980-- <property name="visible">True</property>
1981-- <property name="can_focus">True</property>
1982-- <property name="receives_default">True</property>
1983-- <property name="use_underline">True</property>
1984-- </object>
1985-- <packing>
1986-- <property name="expand">False</property>
1987-- <property name="fill">True</property>
1988-- <property name="padding">80</property>
1989-- <property name="position">0</property>
1990-- </packing>
1991-- </child>
1992-- <child>
1993- <object class="GtkButton" id="publish_button">
1994- <property name="label" translatable="yes">_Publish</property>
1995- <property name="visible">True</property>
1996- <property name="can_focus">True</property>
1997- <property name="receives_default">True</property>
1998- <property name="use_underline">True</property>
1999-+ <property name="width_request">96</property>
2000- </object>
2001- <packing>
2002- <property name="expand">False</property>
2003- <property name="fill">True</property>
2004- <property name="padding">80</property>
2005-- <property name="position">1</property>
2006-+ <property name="position">0</property>
2007- </packing>
2008- </child>
2009- </object>
2010- <packing>
2011- <property name="expand">False</property>
2012-- <property name="fill">True</property>
2013-+ <property name="fill">False</property>
2014- <property name="padding">2</property>
2015- <property name="position">3</property>
2016- </packing>
2017-Index: shotwell-0.15.0/plugins/shotwell-publishing/picasa_publishing_options_pane.glade
2018-===================================================================
2019---- shotwell-0.15.0.orig/plugins/shotwell-publishing/picasa_publishing_options_pane.glade 2013-10-11 12:44:22.142929509 +0200
2020-+++ shotwell-0.15.0/plugins/shotwell-publishing/picasa_publishing_options_pane.glade 2013-10-11 12:44:22.134929509 +0200
2021-@@ -218,28 +218,14 @@
2022- <object class="GtkBox" id="button_area_box">
2023- <property name="visible">True</property>
2024- <property name="can_focus">False</property>
2025-- <property name="margin_left">112</property>
2026-- <property name="margin_right">112</property>
2027-+ <property name="halign">center</property>
2028- <property name="margin_top">48</property>
2029- <property name="margin_bottom">24</property>
2030- <property name="spacing">128</property>
2031- <property name="homogeneous">True</property>
2032- <child>
2033-- <object class="GtkButton" id="logout_button">
2034-- <property name="label" translatable="yes">_Logout</property>
2035-- <property name="visible">True</property>
2036-- <property name="can_focus">True</property>
2037-- <property name="receives_default">True</property>
2038-- <property name="use_underline">True</property>
2039-- </object>
2040-- <packing>
2041-- <property name="expand">False</property>
2042-- <property name="fill">True</property>
2043-- <property name="position">0</property>
2044-- </packing>
2045-- </child>
2046-- <child>
2047- <object class="GtkButton" id="publish_button">
2048-+ <property name="width_request">96</property>
2049- <property name="label" translatable="yes">_Publish</property>
2050- <property name="visible">True</property>
2051- <property name="can_focus">True</property>
2052-@@ -249,13 +235,13 @@
2053- <packing>
2054- <property name="expand">False</property>
2055- <property name="fill">True</property>
2056-- <property name="position">1</property>
2057-+ <property name="position">0</property>
2058- </packing>
2059- </child>
2060- </object>
2061- <packing>
2062- <property name="expand">False</property>
2063-- <property name="fill">True</property>
2064-+ <property name="fill">False</property>
2065- <property name="position">4</property>
2066- </packing>
2067- </child>
2068-Index: shotwell-0.15.0/po/shotwell-core/shotwell.pot
2069-===================================================================
2070---- shotwell-0.15.0.orig/po/shotwell-core/shotwell.pot 2013-10-11 12:44:22.142929509 +0200
2071-+++ shotwell-0.15.0/po/shotwell-core/shotwell.pot 2013-10-11 12:44:22.134929509 +0200
2072-@@ -1805,6 +1805,7 @@
2073- msgstr ""
2074-
2075- #: src/photos/RawSupport.vala:297 src/MediaPage.vala:420
2076-+#: misc/shotwell.application:2
2077- msgid "Shotwell"
2078- msgstr ""
2079-
2080-@@ -3466,6 +3467,10 @@
2081- msgid "Publish photos and videos _to"
2082- msgstr ""
2083-
2084-+#: src/publishing/PublishingUI.vala:238
2085-+msgid "Add more accounts..."
2086-+msgstr ""
2087-+
2088- #: src/publishing/PublishingUI.vala:383
2089- msgid "Unable to publish"
2090- msgstr ""
2091-@@ -4267,3 +4272,15 @@
2092- #: plugins/shotwell-publishing/youtube_publishing_options_pane.glade:55
2093- msgid "Video privacy _setting:"
2094- msgstr ""
2095-+
2096-+#: misc/shotwell.application:9
2097-+msgid "Publish your pictures to Picasa"
2098-+msgstr ""
2099-+
2100-+#: misc/shotwell.application:12
2101-+msgid "Publish your pictures to Facebook"
2102-+msgstr ""
2103-+
2104-+#: misc/shotwell.application:15
2105-+msgid "Publish your pictures to Flickr"
2106-+msgstr ""
2107-Index: shotwell-0.15.0/src/plugins/PublishingInterfaces.vala
2108-===================================================================
2109---- shotwell-0.15.0.orig/src/plugins/PublishingInterfaces.vala 2013-10-11 12:44:22.142929509 +0200
2110-+++ shotwell-0.15.0/src/plugins/PublishingInterfaces.vala 2013-10-11 12:44:22.134929509 +0200
2111-@@ -494,6 +494,7 @@
2112- */
2113- public abstract Spit.Publishing.Publisher.MediaType get_publishable_media_type();
2114-
2115-+ public abstract ulong get_dialog_xid();
2116- //
2117- // For future expansion.
2118- //
2119-@@ -581,18 +582,26 @@
2120- * A factory method that instantiates and returns a new {@link Publisher} object that
2121- * encapsulates a connection to the remote publishing service that this Service describes.
2122- */
2123-- public abstract Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host);
2124-+ public abstract Spit.Publishing.Publisher create_publisher(string? account, Spit.Publishing.PluginHost host);
2125-
2126- /**
2127- * Returns the kinds of media that this service can work with.
2128- */
2129- public abstract Spit.Publishing.Publisher.MediaType get_supported_media();
2130-
2131-+ /**
2132-+ * Checks whether the service is enabled.
2133-+ */
2134-+ public virtual bool is_enabled() { return true; }
2135-+
2136-+ /**
2137-+ * List the accounts available for this service.
2138-+ */
2139-+ public virtual string[] list_account_names() { return {}; }
2140-+
2141- //
2142- // For future expansion.
2143- //
2144-- protected virtual void reserved0() {}
2145-- protected virtual void reserved1() {}
2146- protected virtual void reserved2() {}
2147- protected virtual void reserved3() {}
2148- protected virtual void reserved4() {}
2149-Index: shotwell-0.15.0/src/publishing/PublishingPluginHost.vala
2150-===================================================================
2151---- shotwell-0.15.0.orig/src/publishing/PublishingPluginHost.vala 2013-10-11 12:44:22.142929509 +0200
2152-+++ shotwell-0.15.0/src/publishing/PublishingPluginHost.vala 2013-10-11 12:44:22.134929509 +0200
2153-@@ -21,7 +21,8 @@
2154- private Spit.Publishing.Publisher.MediaType media_type =
2155- Spit.Publishing.Publisher.MediaType.NONE;
2156-
2157-- public ConcretePublishingHost(Service service, PublishingUI.PublishingDialog dialog,
2158-+ public ConcretePublishingHost(Service service, string? account,
2159-+ PublishingUI.PublishingDialog dialog,
2160- Publishable[] publishables) {
2161- base(service, "sharing");
2162- this.dialog = dialog;
2163-@@ -30,7 +31,7 @@
2164- foreach (Publishable curr_publishable in publishables)
2165- this.media_type |= curr_publishable.get_media_type();
2166-
2167-- this.active_publisher = service.create_publisher(this);
2168-+ this.active_publisher = service.create_publisher(account, this);
2169- }
2170-
2171- private void on_login_clicked() {
2172-@@ -232,6 +233,13 @@
2173-
2174- return report_plugin_upload_progress;
2175- }
2176-+
2177-+ public ulong get_dialog_xid() {
2178-+ if (dialog == null) return 0;
2179-+
2180-+ Gdk.Window window = dialog.get_window();
2181-+ return Gdk.X11Window.get_xid(window);
2182-+ }
2183- }
2184-
2185- }
2186-Index: shotwell-0.15.0/src/publishing/PublishingUI.vala
2187-===================================================================
2188---- shotwell-0.15.0.orig/src/publishing/PublishingUI.vala 2013-10-11 12:44:22.142929509 +0200
2189-+++ shotwell-0.15.0/src/publishing/PublishingUI.vala 2013-10-11 12:44:22.138929509 +0200
2190-@@ -130,6 +130,11 @@
2191- }
2192-
2193- public class PublishingDialog : Gtk.Dialog {
2194-+ private struct AccountService {
2195-+ Spit.Publishing.Service service;
2196-+ string? account;
2197-+ }
2198-+
2199- private const int LARGE_WINDOW_WIDTH = 860;
2200- private const int LARGE_WINDOW_HEIGHT = 688;
2201- private const int COLOSSAL_WINDOW_WIDTH = 1024;
2202-@@ -153,6 +158,7 @@
2203- private Spit.Publishing.Publishable[] publishables;
2204- private Spit.Publishing.ConcretePublishingHost host;
2205- private Spit.PluggableInfo info;
2206-+ private Gee.HashMap<string,AccountService?> services;
2207-
2208- protected PublishingDialog(Gee.Collection<MediaSource> to_publish) {
2209- assert(to_publish.size > 0);
2210-@@ -160,6 +166,8 @@
2211- resizable = false;
2212- delete_event.connect(on_window_close);
2213-
2214-+ services = new Gee.HashMap<string,AccountService?>();
2215-+
2216- publishables = new Spit.Publishing.Publishable[0];
2217- bool has_photos = false;
2218- bool has_videos = false;
2219-@@ -211,38 +219,61 @@
2220- // get the name of the service the user last used
2221- string? last_used_service = Config.Facade.get_instance().get_last_used_service();
2222-
2223-- Spit.Publishing.Service[] loaded_services = load_services(has_photos, has_videos);
2224-+ Spit.Publishing.Service[] loaded_services = load_services(has_photos, has_videos, null);
2225-
2226- Gtk.TreeIter iter;
2227-
2228- foreach (Spit.Publishing.Service service in loaded_services) {
2229-- service_selector_box_model.append(out iter);
2230--
2231- string curr_service_id = service.get_id();
2232-
2233- service.get_info(ref info);
2234-
2235-- if (null != info.icons && 0 < info.icons.length) {
2236-- // check if the icons object is set -- if set use that icon
2237-- service_selector_box_model.set(iter, 0, info.icons[0], 1,
2238-- service.get_pluggable_name());
2239--
2240-- // in case the icons object is not set on the next iteration
2241-- info.icons[0] = Resources.get_icon(Resources.ICON_GENERIC_PLUGIN);
2242-- } else {
2243-- // if icons object is null or zero length use a generic icon
2244-- service_selector_box_model.set(iter, 0, Resources.get_icon(
2245-- Resources.ICON_GENERIC_PLUGIN), 1, service.get_pluggable_name());
2246-+ var account_names = service.list_account_names();
2247-+ if (account_names.length == 0) {
2248-+ account_names += null;
2249- }
2250-+
2251-+ foreach (string? account_name in account_names) {
2252-+ service_selector_box_model.append(out iter);
2253-+
2254-+ string service_name = service.get_pluggable_name();
2255-+ if (account_name != null) {
2256-+ service_name += " (%s)".printf(account_name);
2257-+ }
2258-+
2259-+ AccountService account_service = {
2260-+ service: service,
2261-+ account: account_name
2262-+ };
2263-+ services.set(service_name, account_service);
2264-+
2265-+ if (null != info.icons && 0 < info.icons.length) {
2266-+ // check if the icons object is set -- if set use that icon
2267-+ service_selector_box_model.set(iter, 0, info.icons[0], 1,
2268-+ service_name);
2269-+
2270-+ // in case the icons object is not set on the next iteration
2271-+ info.icons[0] = Resources.get_icon(Resources.ICON_GENERIC_PLUGIN);
2272-+ } else {
2273-+ // if icons object is null or zero length use a generic icon
2274-+ service_selector_box_model.set(iter, 0, Resources.get_icon(
2275-+ Resources.ICON_GENERIC_PLUGIN), 1, service_name);
2276-+ }
2277-
2278-- if (last_used_service == null) {
2279-- service_selector_box.set_active_iter(iter);
2280-- last_used_service = service.get_id();
2281-- } else if (last_used_service == curr_service_id) {
2282-- service_selector_box.set_active_iter(iter);
2283-+ if (last_used_service == null) {
2284-+ service_selector_box.set_active_iter(iter);
2285-+ last_used_service = service.get_id();
2286-+ } else if (last_used_service == curr_service_id) {
2287-+ service_selector_box.set_active_iter(iter);
2288-+ }
2289- }
2290- }
2291-
2292-+ service_selector_box_model.append(out iter);
2293-+ service_selector_box_model.set(iter,
2294-+ 0, Resources.get_icon(Resources.ICON_GENERIC_PLUGIN),
2295-+ 1, _("Add more accounts..."));
2296-+
2297- service_selector_box.changed.connect(on_service_changed);
2298-
2299- /* the wrapper is not an extraneous widget -- it's necessary to prevent the service
2300-@@ -318,24 +349,35 @@
2301- return loaded_services;
2302- }
2303-
2304-- private static Spit.Publishing.Service[] load_services(bool has_photos, bool has_videos) {
2305-+ private static Spit.Publishing.Service[] load_services(bool has_photos, bool has_videos,
2306-+ out bool has_disabled_services) {
2307- assert (has_photos || has_videos);
2308-
2309- Spit.Publishing.Service[] filtered_services = new Spit.Publishing.Service[0];
2310- Spit.Publishing.Service[] all_services = load_all_services();
2311-
2312-+ has_disabled_services = false;
2313- foreach (Spit.Publishing.Service service in all_services) {
2314-+ bool supports_media = false;
2315-
2316- if (has_photos && !has_videos) {
2317- if ((service.get_supported_media() & Spit.Publishing.Publisher.MediaType.PHOTO) != 0)
2318-- filtered_services += service;
2319-+ supports_media = true;
2320- } else if (!has_photos && has_videos) {
2321- if ((service.get_supported_media() & Spit.Publishing.Publisher.MediaType.VIDEO) != 0)
2322-- filtered_services += service;
2323-+ supports_media = true;
2324- } else {
2325- if (((service.get_supported_media() & Spit.Publishing.Publisher.MediaType.PHOTO) != 0) &&
2326- ((service.get_supported_media() & Spit.Publishing.Publisher.MediaType.VIDEO) != 0))
2327-+ supports_media = true;
2328-+ }
2329-+
2330-+ if (supports_media) {
2331-+ if (service.is_enabled()) {
2332- filtered_services += service;
2333-+ } else {
2334-+ has_disabled_services = true;
2335-+ }
2336- }
2337- }
2338-
2339-@@ -374,15 +416,26 @@
2340- Gee.ArrayList<Video> videos = new Gee.ArrayList<Video>();
2341- MediaSourceCollection.filter_media(to_publish, photos, videos);
2342-
2343-+ bool has_disabled_services = false;
2344- Spit.Publishing.Service[] avail_services =
2345-- load_services((photos.size > 0), (videos.size > 0));
2346-+ load_services((photos.size > 0), (videos.size > 0), out has_disabled_services);
2347-
2348- if (avail_services.length == 0) {
2349-- // There are no enabled publishing services that accept this media type,
2350-- // warn the user.
2351-- AppWindow.error_message_with_title(_("Unable to publish"),
2352-- _("Shotwell cannot publish the selected items because you do not have a compatible publishing plugin enabled. To correct this, choose <b>Edit %s Preferences</b> and enable one or more of the publishing plugins on the <b>Plugins</b> tab.").printf("▸"),
2353-- null, false);
2354-+ if (has_disabled_services) {
2355-+ try {
2356-+ DesktopAppInfo app_info =
2357-+ new DesktopAppInfo ("gnome-credentials-panel.desktop");
2358-+ GLib.Process.spawn_command_line_async(app_info.get_commandline() + " application=shotwell");
2359-+ } catch (Error e) {
2360-+ warning ("Error launching Online Accounts: %s", e.message);
2361-+ }
2362-+ } else {
2363-+ // There are no enabled publishing services that accept this media type,
2364-+ // warn the user.
2365-+ AppWindow.error_message_with_title(_("Unable to publish"),
2366-+ _("Shotwell cannot publish the selected items because you do not have a compatible publishing plugin enabled. To correct this, choose <b>Edit %s Preferences</b> and enable one or more of the publishing plugins on the <b>Plugins</b> tab.").printf("▸"),
2367-+ null, false);
2368-+ }
2369-
2370- return;
2371- }
2372-@@ -431,19 +484,29 @@
2373-
2374- string service_name = (string) service_name_val;
2375-
2376-- Spit.Publishing.Service? selected_service = null;
2377-- Spit.Publishing.Service[] services = load_all_services();
2378-- foreach (Spit.Publishing.Service service in services) {
2379-- if (service.get_pluggable_name() == service_name) {
2380-- selected_service = service;
2381-- break;
2382-+ if (!services.has_key(service_name)) {
2383-+ debug("Starting Online Accounts...");
2384-+ try {
2385-+ DesktopAppInfo app_info =
2386-+ new DesktopAppInfo ("gnome-credentials-panel.desktop");
2387-+ GLib.Process.spawn_command_line_async(app_info.get_commandline() + " application=shotwell");
2388-+ } catch (Error e) {
2389-+ warning ("Error launching Online Accounts: %s", e.message);
2390- }
2391-+
2392-+ on_close_cancel_clicked();
2393-+ return;
2394-+
2395- }
2396-- assert(selected_service != null);
2397-+
2398-+ AccountService account_service = services.get(service_name);
2399-+ Spit.Publishing.Service? selected_service = account_service.service;
2400-
2401- Config.Facade.get_instance().set_last_used_service(selected_service.get_id());
2402-
2403-- host = new Spit.Publishing.ConcretePublishingHost(selected_service, this, publishables);
2404-+ host = new Spit.Publishing.ConcretePublishingHost(selected_service,
2405-+ account_service.account,
2406-+ this, publishables);
2407- host.start_publishing();
2408- }
2409-
2410-Index: shotwell-0.15.0/misc/shotwell-sharing-facebook.service
2411-===================================================================
2412---- /dev/null 1970-01-01 00:00:00.000000000 +0000
2413-+++ shotwell-0.15.0/misc/shotwell-sharing-facebook.service 2013-10-11 12:44:22.138929509 +0200
2414-@@ -0,0 +1,13 @@
2415-+<?xml version="1.0" encoding="UTF-8"?>
2416-+<service id="shotwell-sharing-facebook">
2417-+ <type>shotwell-sharing</type>
2418-+ <name>Facebook</name>
2419-+ <icon>facebook</icon>
2420-+ <provider>facebook</provider>
2421-+ <template>
2422-+ <group name="auth/oauth2/user_agent">
2423-+ <setting type="as" name="Scope">['publish_actions','user_photos','user_videos']</setting>
2424-+ <setting name="ClientId">162702932093</setting>
2425-+ </group>
2426-+ </template>
2427-+</service>
2428-Index: shotwell-0.15.0/misc/shotwell-sharing-flickr.service
2429-===================================================================
2430---- /dev/null 1970-01-01 00:00:00.000000000 +0000
2431-+++ shotwell-0.15.0/misc/shotwell-sharing-flickr.service 2013-10-11 12:44:22.138929509 +0200
2432-@@ -0,0 +1,7 @@
2433-+<?xml version="1.0" encoding="UTF-8"?>
2434-+<service id="shotwell-sharing-flickr">
2435-+ <type>shotwell-sharing</type>
2436-+ <name>Flickr</name>
2437-+ <icon>flickr</icon>
2438-+ <provider>flickr</provider>
2439-+</service>
2440-Index: shotwell-0.15.0/misc/shotwell-sharing-picasa.service
2441-===================================================================
2442---- /dev/null 1970-01-01 00:00:00.000000000 +0000
2443-+++ shotwell-0.15.0/misc/shotwell-sharing-picasa.service 2013-10-11 12:44:22.138929509 +0200
2444-@@ -0,0 +1,22 @@
2445-+<?xml version="1.0" encoding="UTF-8"?>
2446-+<service id="shotwell-sharing-picasa">
2447-+ <type>shotwell-sharing</type>
2448-+ <name>Picasa</name>
2449-+ <icon>icon_picasa</icon>
2450-+ <provider>google</provider>
2451-+ <template>
2452-+ <group name="auth/oauth2">
2453-+ <group name="user_agent">
2454-+ <setting type="as" name="Scope">['http://picasaweb.google.com/data/','https://picasaweb.google.com/data/','https://www.googleapis.com/auth/userinfo.profile']</setting>
2455-+ <setting name="ClientId">1073902228337-nv1s75sfvrt75lfcq4pg3pn7gee8e1d5.apps.googleusercontent.com</setting>
2456-+ <setting name="RedirectUri">https://wiki.ubuntu.com/</setting>
2457-+ </group>
2458-+ <group name="web_server">
2459-+ <setting type="as" name="Scope">['http://picasaweb.google.com/data/','https://picasaweb.google.com/data/','https://www.googleapis.com/auth/userinfo.profile']</setting>
2460-+ <setting name="ClientId">1073902228337-nv1s75sfvrt75lfcq4pg3pn7gee8e1d5.apps.googleusercontent.com</setting>
2461-+ <setting name="ClientSecret">jWoGL5PDGk55ZfpBYNOgG43g</setting>
2462-+ <setting name="RedirectUri">https://wiki.ubuntu.com/</setting>
2463-+ </group>
2464-+ </group>
2465-+ </template>
2466-+</service>
2467
2468=== removed file 'debian/patches/format_string.patch'
2469--- debian/patches/format_string.patch 2014-01-29 07:10:35 +0000
2470+++ debian/patches/format_string.patch 1970-01-01 00:00:00 +0000
2471@@ -1,16 +0,0 @@
2472-Description: Fix FTBFS with missing format string parameter
2473-Author: Luca Falavigna <dktrkranz@debian.org>
2474-
2475-Index: shotwell-0.12.2/src/Dialogs.vala
2476-===================================================================
2477---- shotwell-0.12.2.orig/src/Dialogs.vala 2012-04-11 20:18:19.000000000 +0200
2478-+++ shotwell-0.12.2/src/Dialogs.vala 2012-05-06 19:47:46.625600885 +0200
2479-@@ -31,7 +31,7 @@
2480-
2481- public bool confirm_warn_developer_changed(int number) {
2482- Gtk.MessageDialog dialog = new Gtk.MessageDialog.with_markup(AppWindow.get_instance(),
2483-- Gtk.DialogFlags.MODAL, Gtk.MessageType.WARNING, Gtk.ButtonsType.NONE,
2484-+ Gtk.DialogFlags.MODAL, Gtk.MessageType.WARNING, Gtk.ButtonsType.NONE, "%s",
2485- "<span weight=\"bold\" size=\"larger\">%s</span>".printf(ngettext("Switching developers will undo all changes you have made to this photo in Shotwell",
2486- "Switching developers will undo all changes you have made to these photos in Shotwell", number)));
2487-
2488
2489=== modified file 'debian/patches/series'
2490--- debian/patches/series 2014-01-29 07:10:35 +0000
2491+++ debian/patches/series 2014-05-25 21:30:43 +0000
2492@@ -1,4 +1,2 @@
2493-format_string.patch
2494 hardening.patch
2495-02_desktop_translations.patch
2496-06_uoa.patch
2497+02_desktop_translations.patch
2498\ No newline at end of file

Subscribers

People subscribed via source and target branches