9
9
extern string hmac_sha1(string key, string message);
11
public class FlickrService : Object, Spit.Pluggable, Spit.Publishing.Service {
11
public class FlickrService : UOAPublishingService, Spit.Pluggable, Spit.Publishing.Service {
12
12
private const string ICON_FILENAME = "flickr.png";
14
14
private static Gdk.Pixbuf[] icon_pixbuf_set = null;
16
16
public FlickrService(GLib.File resource_directory) {
17
18
if (icon_pixbuf_set == null)
18
19
icon_pixbuf_set = Resources.load_icon_set(resource_directory.get_child(ICON_FILENAME));
21
public int get_pluggable_interface(int min_host_interface, int max_host_interface) {
22
return Spit.negotiate_interfaces(min_host_interface, max_host_interface,
23
Spit.Publishing.CURRENT_INTERFACE);
26
public unowned string get_id() {
22
public override unowned string get_id() {
27
23
return "org.yorba.shotwell.publishing.flickr";
30
public unowned string get_pluggable_name() {
26
public override unowned string get_pluggable_name() {
34
public void get_info(ref Spit.PluggableInfo info) {
30
public override void get_info(ref Spit.PluggableInfo info) {
35
31
info.authors = "Lucas Beeler";
36
32
info.copyright = _("Copyright 2009-2012 Yorba Foundation");
37
33
info.translators = Resources.TRANSLATORS;
43
39
info.icons = icon_pixbuf_set;
46
public void activation(bool enabled) {
49
public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) {
50
return new Publishing.Flickr.FlickrPublisher(this, host);
42
public override Spit.Publishing.Publisher create_publisher(string? account_name, Spit.Publishing.PluginHost host) {
43
SharingAccount account = find_account(account_name);
44
return new Publishing.Flickr.FlickrPublisher(this, account, host);
53
public Spit.Publishing.Publisher.MediaType get_supported_media() {
47
public override Spit.Publishing.Publisher.MediaType get_supported_media() {
54
48
return (Spit.Publishing.Publisher.MediaType.PHOTO |
55
49
Spit.Publishing.Publisher.MediaType.VIDEO);
58
public bool is_enabled() {
59
SharingAccounts accounts = new SharingAccounts();
60
return accounts.get_account_for_provider("flickr") != null;
64
53
namespace Publishing.Flickr {
112
101
private bool was_started = false;
113
102
private Session session = null;
114
103
private PublishingOptionsPane publishing_options_pane = null;
115
private Signon.AuthSession auth_session = null;
104
private UOAPublisherAuthenticator authenticator = null;
117
106
private PublishingParameters parameters = null;
119
108
public FlickrPublisher(Spit.Publishing.Service service,
109
SharingAccount account,
120
110
Spit.Publishing.PluginHost host) {
121
111
debug("FlickrPublisher instantiated.");
122
112
this.service = service;
123
113
this.host = host;
124
114
this.session = new Session();
115
authenticator = new UOAPublisherAuthenticator(account, host,
116
SERVICE_WELCOME_MESSAGE);
125
117
this.parameters = new PublishingParameters();
127
119
session.authenticated.connect(on_session_authenticated);
120
HashTable<string,Value?> data =
121
authenticator.get_authentication_data();
122
session.set_api_credentials(data.lookup("ConsumerKey").get_string(),
123
data.lookup("ConsumerSecret").get_string());
124
authenticator.authenticated.connect(on_authenticator_authenticated);
130
127
~FlickrPublisher() {
131
128
session.authenticated.disconnect(on_session_authenticated);
134
private void invalidate_persistent_session() {
135
set_persistent_access_phase_token("");
136
set_persistent_access_phase_token_secret("");
137
set_persistent_access_phase_username("");
140
private bool is_persistent_session_valid() {
141
return (get_persistent_access_phase_username() != null &&
142
get_persistent_access_phase_token() != null &&
143
get_persistent_access_phase_token_secret() != null);
146
private string? get_persistent_access_phase_username() {
147
return host.get_config_string("access_phase_username", null);
150
private void set_persistent_access_phase_username(string username) {
151
host.set_config_string("access_phase_username", username);
154
private string? get_persistent_access_phase_token() {
155
return host.get_config_string("access_phase_token", null);
158
private void set_persistent_access_phase_token(string token) {
159
host.set_config_string("access_phase_token", token);
162
private string? get_persistent_access_phase_token_secret() {
163
return host.get_config_string("access_phase_token_secret", null);
166
private void set_persistent_access_phase_token_secret(string secret) {
167
host.set_config_string("access_phase_token_secret", secret);
170
131
private bool get_persistent_strip_metadata() {
171
132
return host.get_config_bool("strip_metadata", false);
175
136
host.set_config_bool("strip_metadata", strip_metadata);
178
private void on_welcome_pane_login_clicked() {
182
debug("EVENT: user clicked 'Login' button in the welcome pane");
184
HashTable<string,Value?> data = null;
185
string mechanism = null;
186
SharingAccounts accounts = new SharingAccounts();
188
SharingAccount? account = accounts.get_account_for_provider("flickr");
189
if (account != null) {
191
auth_session = account.create_auth_session();
192
data = account.get_session_parameters(out mechanism);
193
debug("Got account data");
194
} catch (GLib.Error e) {
195
warning("EVENT: couldn't create session for account: %s",
201
warning ("No account authentication data");
202
host.post_error(new Spit.Publishing.PublishingError.SERVICE_ERROR(
203
"Error while accessing the account"));
207
session.set_api_credentials(data.lookup("ConsumerKey").get_string(),
208
data.lookup("ConsumerSecret").get_string());
210
var windowId = host.get_dialog_xid();
212
data.insert("WindowId", (uint)windowId);
215
auth_session.process(data, mechanism, on_processed);
216
host.set_service_locked(false);
219
public void on_processed(Signon.AuthSession self, owned HashTable<string,Value?> session_data, GLib.Error error){
220
/* TODO: handle errors */
139
public void on_authenticator_authenticated(owned HashTable<string,Value?> session_data) {
222
140
host.set_service_locked(true);
223
141
host.install_account_fetch_wait_pane();
286
199
do_publish(strip_metadata);
289
private void on_publishing_options_pane_logout() {
290
publishing_options_pane.publish.disconnect(on_publishing_options_pane_publish);
291
publishing_options_pane.logout.disconnect(on_publishing_options_pane_logout);
296
debug("EVENT: user clicked the 'Logout' button in the publishing options pane");
301
202
private void on_upload_status_updated(int file_number, double completed_fraction) {
302
203
if (!is_running())
335
236
host.post_error(err);
338
private void do_show_login_welcome_pane() {
339
debug("ACTION: installing login welcome pane");
341
host.set_service_locked(false);
342
host.install_welcome_pane(SERVICE_WELCOME_MESSAGE, on_welcome_pane_login_clicked);
345
239
private void do_fetch_account_info() {
346
240
debug("ACTION: running network transaction to fetch account information");
438
331
publishing_options_pane = new PublishingOptionsPane(this, parameters,
439
332
host.get_publishable_media_type(), builder, get_persistent_strip_metadata());
440
333
publishing_options_pane.publish.connect(on_publishing_options_pane_publish);
441
publishing_options_pane.logout.connect(on_publishing_options_pane_logout);
442
334
host.install_dialog_pane(publishing_options_pane);
514
406
was_started = true;
516
if (is_persistent_session_valid()) {
517
debug("attempt start: a persistent session is available; using it");
519
session.authenticate_from_persistent_credentials(get_persistent_access_phase_token(),
520
get_persistent_access_phase_token_secret(), get_persistent_access_phase_username());
522
debug("attempt start: no persistent session available; showing login welcome pane");
524
do_show_login_welcome_pane();
408
authenticator.authenticate();
528
411
public void start() {
782
665
username != null);
785
public void authenticate_from_persistent_credentials(string token, string secret,
787
this.access_phase_token = token;
788
this.access_phase_token_secret = secret;
789
this.username = username;
794
668
public void deauthenticate() {
795
669
access_phase_token = null;
796
670
access_phase_token_secret = null;
931
800
private Gtk.Label visibility_label = null;
932
801
private Gtk.Label upload_info_label = null;
933
802
private Gtk.Label size_label = null;
934
private Gtk.Button logout_button = null;
935
803
private Gtk.Button publish_button = null;
936
804
private Gtk.ComboBoxText visibility_combo = null;
937
805
private Gtk.ComboBoxText size_combo = null;
943
811
private Spit.Publishing.Publisher.MediaType media_type;
945
813
public signal void publish(bool strip_metadata);
946
public signal void logout();
948
815
public PublishingOptionsPane(FlickrPublisher publisher, PublishingParameters parameters,
949
816
Spit.Publishing.Publisher.MediaType media_type, Gtk.Builder builder, bool strip_metadata) {
955
822
pane_widget = (Gtk.Box) this.builder.get_object("flickr_pane");
956
823
visibility_label = (Gtk.Label) this.builder.get_object("visibility_label");
957
824
upload_info_label = (Gtk.Label) this.builder.get_object("upload_info_label");
958
logout_button = (Gtk.Button) this.builder.get_object("logout_button");
959
825
publish_button = (Gtk.Button) this.builder.get_object("publish_button");
960
826
visibility_combo = (Gtk.ComboBoxText) this.builder.get_object("visibility_combo");
961
827
size_combo = (Gtk.ComboBoxText) this.builder.get_object("size_combo");
1003
869
strip_metadata_check.set_active(strip_metadata);
1005
logout_button.clicked.connect(on_logout_clicked);
1006
871
publish_button.clicked.connect(on_publish_clicked);
1009
private void on_logout_clicked() {
1013
874
private void on_publish_clicked() {
1014
875
parameters.visibility_specification =
1015
876
visibilities[visibility_combo.get_active()].specification;