Merge lp:~mardy/shotwell/uoa-update into lp:ubuntu/quantal/shotwell
- uoa-update
- Merge into quantal
Status: | Superseded |
---|---|
Proposed branch: | lp:~mardy/shotwell/uoa-update |
Merge into: | lp:ubuntu/quantal/shotwell |
Diff against target: |
3935 lines (+3831/-0) (has conflicts) 20 files modified
.bzr-builddeb/default.conf (+3/-0) debian/changelog (+424/-0) debian/compat (+1/-0) debian/control (+47/-0) debian/copyright (+435/-0) debian/docs (+2/-0) debian/manpages (+2/-0) debian/menu (+2/-0) debian/patches/02_desktop_translations.patch (+25/-0) debian/patches/03_appmenu_no_stubs.patch (+9/-0) debian/patches/04_no_resize_grip.patch (+26/-0) debian/patches/05-gomp-linking.patch (+16/-0) debian/patches/06_uoa.patch (+2790/-0) debian/patches/series (+6/-0) debian/rules (+10/-0) debian/shotwell-video-thumbnailer.1 (+13/-0) debian/shotwell.1 (+14/-0) debian/shotwell.lintian-overrides (+2/-0) debian/source/format (+1/-0) debian/watch (+3/-0) Conflict adding file debian. Moved existing file to debian.moved. |
To merge this branch: | bzr merge lp:~mardy/shotwell/uoa-update |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu branches | Pending | ||
Review via email: mp+124638@code.launchpad.net |
Commit message
Description of the change
Update the UOA patch
* Support multiple accounts per service
* Attempt automatic login
* Remove logout buttons
- 85. By Alberto Mardegan
-
i18n update
* Allow translating the shotwell.
application file
* Add the "Add more accounts..." string for translations. - 86. By Alberto Mardegan
-
Avoid critical warnings
Vala was generating an enumerated type, but all we want is an int.
- 87. By Alberto Mardegan
-
Do not make warnings fatal when building plugins
Gtk.Table, which is used all over the place, has been deprecated.
- 88. By Alberto Mardegan
-
* New upstream bugfix release
* debian/watch:
- Watch for stable versions
Unmerged revisions
- 88. By Alberto Mardegan
-
* New upstream bugfix release
* debian/watch:
- Watch for stable versions - 87. By Alberto Mardegan
-
Do not make warnings fatal when building plugins
Gtk.Table, which is used all over the place, has been deprecated.
- 86. By Alberto Mardegan
-
Avoid critical warnings
Vala was generating an enumerated type, but all we want is an int.
- 85. By Alberto Mardegan
-
i18n update
* Allow translating the shotwell.
application file
* Add the "Add more accounts..." string for translations. - 84. By Alberto Mardegan
-
Update UOA patch
* Support multiple accounts per service
* Remove login/logout buttons - 83. By Alberto Mardegan
-
UOA: handle multiple accounts per service
- 82. By Sebastien Bacher
-
releasing version 0.12.90-0ubuntu1
- 81. By Sebastien Bacher
-
[ Alberto Mardegan ]
* debian/patches/ 06_uoa. patch:
- updated for the new version - 80. By Robert Ancell
-
New upstream release (LP: #1041011)
- 79. By Robert Ancell
-
* New upstream release
* debian/watch:
- Watch for unstable versions
- Releases now in .xz format
Preview Diff
1 | === added directory '.bzr-builddeb' |
2 | === added file '.bzr-builddeb/default.conf' |
3 | --- .bzr-builddeb/default.conf 1970-01-01 00:00:00 +0000 |
4 | +++ .bzr-builddeb/default.conf 2012-09-17 10:22:22 +0000 |
5 | @@ -0,0 +1,3 @@ |
6 | +[BUILDDEB] |
7 | +merge = True |
8 | +ignore-unknowns = True |
9 | |
10 | === added directory 'debian' |
11 | === renamed directory 'debian' => 'debian.moved' |
12 | === added file 'debian/changelog' |
13 | --- debian/changelog 1970-01-01 00:00:00 +0000 |
14 | +++ debian/changelog 2012-09-17 10:22:22 +0000 |
15 | @@ -0,0 +1,424 @@ |
16 | +shotwell (0.12.90-0ubuntu1) quantal; urgency=low |
17 | + |
18 | + [ Robert Ancell ] |
19 | + * New upstream release (LP: #1041011) |
20 | + * debian/watch: |
21 | + - Watch for unstable versions |
22 | + - Releases now in .xz format |
23 | + |
24 | + [ Alberto Mardegan ] |
25 | + * debian/patches/06_uoa.patch: |
26 | + - updated for the new version |
27 | + |
28 | + -- Sebastien Bacher <seb128@ubuntu.com> Tue, 28 Aug 2012 16:57:19 +0200 |
29 | + |
30 | +shotwell (0.12.3-0ubuntu2) quantal; urgency=low |
31 | + |
32 | + * debian/patches/06_uoa.patch |
33 | + - Added UOA support |
34 | + * debian/control |
35 | + - added build depends libsignon-glib-dev and libaccounts-glib-dev |
36 | + |
37 | + -- Ken VanDine <ken.vandine@canonical.com> Tue, 21 Aug 2012 15:40:58 -0400 |
38 | + |
39 | +shotwell (0.12.3-0ubuntu1) quantal; urgency=low |
40 | + |
41 | + * New upstream version, fixes: |
42 | + - Shotwell deletes tags at random (lp: #999108) |
43 | + - shotwell's unity progress bar hangs halfway across (lp: #987046) |
44 | + - Shotwell will not detect mts moviefiles on memory card (lp: #990725) |
45 | + |
46 | + -- Sebastien Bacher <seb128@ubuntu.com> Wed, 16 May 2012 15:18:16 +0200 |
47 | + |
48 | +shotwell (0.12.2-0ubuntu3) quantal; urgency=low |
49 | + |
50 | + * debian/control: |
51 | + - Use standards version 3.9.3 |
52 | + - Drop dependency on liblaunchpad-integration-3.0-dev |
53 | + * debian/patches/01_lpi.patch: |
54 | + - Dropped, we no longer do Launchpad integration |
55 | + |
56 | + -- Robert Ancell <robert.ancell@canonical.com> Mon, 14 May 2012 16:14:15 +1200 |
57 | + |
58 | +shotwell (0.12.2-0ubuntu2) precise; urgency=low |
59 | + |
60 | + * debian/control: |
61 | + - Add build-depends on libunity-dev |
62 | + * debian/rules: |
63 | + - Build with --unity-support (LP: #980532) |
64 | + |
65 | + -- Robert Ancell <robert.ancell@canonical.com> Fri, 13 Apr 2012 09:11:15 +1000 |
66 | + |
67 | +shotwell (0.12.2-0ubuntu1) precise; urgency=low |
68 | + |
69 | + * New upstream release: |
70 | + - Corrects an issue where graphical corruption of the UI could |
71 | + occur if the user navigated away from a camera page while camera |
72 | + previews were being generated. |
73 | + - Adds enhanced support for the Unity desktop environment. |
74 | + - Clarified several strings. |
75 | + - The application now recovers gracefully from corrupted tag data. |
76 | + |
77 | + -- Robert Ancell <robert.ancell@canonical.com> Thu, 12 Apr 2012 10:44:07 +1000 |
78 | + |
79 | +shotwell (0.12.1-0ubuntu2) precise; urgency=low |
80 | + |
81 | + * debian/control: |
82 | + - build with current gexiv2 to pick the current soname (lp: #971468) |
83 | + |
84 | + -- Sebastien Bacher <seb128@ubuntu.com> Mon, 02 Apr 2012 15:35:03 +0200 |
85 | + |
86 | +shotwell (0.12.1-0ubuntu1) precise-proposed; urgency=low |
87 | + |
88 | + * New upstream release: |
89 | + - Corrects a critical issue where the application could not be started in |
90 | + direct-edit mode. |
91 | + |
92 | + -- Robert Ancell <robert.ancell@canonical.com> Thu, 29 Mar 2012 11:37:01 +1100 |
93 | + |
94 | +shotwell (0.12.0-0ubuntu1) precise-proposed; urgency=low |
95 | + |
96 | + * New upstream release: |
97 | + (Changes since 0.11.6) |
98 | + - Adds straighten tool |
99 | + - Ported from GTK 2 to GTK 3 |
100 | + - Better handling of importing from Android devices |
101 | + - Facebook and Flickr login now use OAuth authentication |
102 | + - Numerous enhancements to the plugin subsystem |
103 | + - The F-Spot importer is now implemented as a plugin |
104 | + - Many, many bugfixes and stability enhancements |
105 | + * debian/control: |
106 | + - Bump build-depends on gexiv2 |
107 | + |
108 | + -- Robert Ancell <robert.ancell@canonical.com> Wed, 28 Mar 2012 11:59:51 +1100 |
109 | + |
110 | +shotwell (0.11.93-0ubuntu2) precise; urgency=low |
111 | + |
112 | + * debian/control: build-depends on librest-dev, the publishing makefile |
113 | + requires it |
114 | + |
115 | + -- Sebastien Bacher <seb128@ubuntu.com> Wed, 07 Mar 2012 16:08:00 +0100 |
116 | + |
117 | +shotwell (0.11.93-0ubuntu1) precise; urgency=low |
118 | + |
119 | + * New upstream release |
120 | + |
121 | + -- Robert Ancell <robert.ancell@canonical.com> Wed, 07 Mar 2012 10:27:48 +1100 |
122 | + |
123 | +shotwell (0.11.92-0ubuntu1) precise; urgency=low |
124 | + |
125 | + * New upstream release |
126 | + |
127 | + -- Robert Ancell <robert.ancell@canonical.com> Tue, 21 Feb 2012 13:52:58 +1100 |
128 | + |
129 | +shotwell (0.11.91-0ubuntu2) precise; urgency=low |
130 | + |
131 | + * debian/control: use the correct liblaunchpad-integration version |
132 | + |
133 | + -- Sebastien Bacher <seb128@ubuntu.com> Thu, 12 Jan 2012 11:58:24 +0100 |
134 | + |
135 | +shotwell (0.11.91-0ubuntu1) precise; urgency=low |
136 | + |
137 | + * New upstream version using GTK3 (lp: #871034), |
138 | + should fix lp: #800459, #881896, #887357, #888363, #898028 |
139 | + * Refreshed patches for the new version |
140 | + * debian/control: |
141 | + - updated build-dependencies for GTK3 |
142 | + * debian/patches/99git_libraw_api.patch: |
143 | + - dropped, the patch is in the new version |
144 | + |
145 | + -- Sebastien Bacher <seb128@ubuntu.com> Wed, 11 Jan 2012 15:59:04 +0100 |
146 | + |
147 | +shotwell (0.11.6-0ubuntu2) precise; urgency=low |
148 | + |
149 | + * debian/patches/99git_libraw_api.patch: cherry-pick changes from git to work |
150 | + with libraw 0.14.0. |
151 | + * debian/patches/05-gomp-linking.patch: we also need to link shotwell against |
152 | + GOMP now, apparently, so add -fopenmp to the Makefile's relevant rule. |
153 | + * debian/shotwell-video-thumbnailer.1: added, it was missing from the previous |
154 | + upload and referred to by debian/manpages. |
155 | + |
156 | + -- Mathieu Trudel-Lapierre <mathieu-tl@ubuntu.com> Fri, 25 Nov 2011 12:31:19 -0500 |
157 | + |
158 | +shotwell (0.11.6-0ubuntu1) precise; urgency=low |
159 | + |
160 | + * New upstream version |
161 | + * Resynchronize on Debian |
162 | + * debian/control.in: |
163 | + - build-depends on python-scour, liblaunchpad-integration-dev |
164 | + - don't build-depends on locales-all |
165 | + * debian/rules: |
166 | + - use configure option --disable-icon-update and dh option --with-scour |
167 | + |
168 | + -- Sebastien Bacher <seb128@ubuntu.com> Wed, 23 Nov 2011 21:19:35 +0100 |
169 | + |
170 | +shotwell (0.11.5-1) unstable; urgency=low |
171 | + |
172 | + * New upstream release (Closes: 645942). |
173 | + * Show translations in GNOME menu, thanks to Hideki Yamane |
174 | + <henrich@debian.or.jp> for this (Closes: 644905). |
175 | + |
176 | + [ Luca Falavigna ] |
177 | + * Enable DM upload. |
178 | + |
179 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Sun, 23 Oct 2011 01:39:38 +0200 |
180 | + |
181 | +shotwell (0.11.2-1) unstable; urgency=low |
182 | + |
183 | + * Team upload. |
184 | + * New upstream bugfix release. |
185 | + * debian/rules: |
186 | + - Do not compile GConf schema (Closes: #641677). |
187 | + |
188 | + -- Luca Falavigna <dktrkranz@debian.org> Sat, 24 Sep 2011 14:27:33 +0200 |
189 | + |
190 | +shotwell (0.11.1-1) unstable; urgency=low |
191 | + |
192 | + * Team upload. |
193 | + * New upstream bugfix release. |
194 | + * debian/patches/sidebar-bg-color.patch: |
195 | + - Refresh for new upstream release. |
196 | + |
197 | + -- Luca Falavigna <dktrkranz@debian.org> Tue, 13 Sep 2011 20:53:25 +0200 |
198 | + |
199 | +shotwell (0.11.0-1) unstable; urgency=low |
200 | + |
201 | + * Team upload. |
202 | + * New upstream release (Closes: #639863). |
203 | + * debian/patches/sidebar-bg-color.patch: |
204 | + - Refresh for new upstream release. |
205 | + * debian/control: |
206 | + - Build-depend on libgstreamer-plugins-base0.10-dev. |
207 | + |
208 | + -- Luca Falavigna <dktrkranz@debian.org> Thu, 01 Sep 2011 19:59:07 +0200 |
209 | + |
210 | +shotwell (0.10.1-1) unstable; urgency=low |
211 | + |
212 | + * Team upload |
213 | + * New upstream release (Closes: #629311). |
214 | + * debian/patches/non-linux-fixes.patch: |
215 | + - Removed, waiting for proper upstream porting efforts. |
216 | + * debian/patches/sidebar-bg-color.patch: |
217 | + - Refresh for new upstream release. |
218 | + * debian/control: |
219 | + - Add Debian Shotwell Maintainers to Maintainers. |
220 | + - Move Devid to Uploaders. |
221 | + - libwebkitgtk-dev transition (Closes: #635426). |
222 | + - Set Architecture to linux-any, shotwell is currently unsupported |
223 | + outside of Linux platform, and require some porting. |
224 | + * debian/shotwell-video-thumbnailer.1: |
225 | + - Provide a minimal man page for shotwell-video-thumbnailer |
226 | + |
227 | + -- Luca Falavigna <dktrkranz@debian.org> Sun, 21 Aug 2011 15:38:31 +0200 |
228 | + |
229 | +shotwell (0.9.3-1) unstable; urgency=low |
230 | + |
231 | + * New upstream release (Closes: #622705). |
232 | + * Update debian/patches/non-linux-fixes.patch patch. |
233 | + * Bump Standards-Version to 3.9.2. |
234 | + |
235 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Sun, 01 May 2011 13:09:48 +0200 |
236 | + |
237 | +shotwell (0.9.1-1) unstable; urgency=low |
238 | + |
239 | + * Upload to unstable. |
240 | + * New upstream release (Closes: #620765). |
241 | + * debian/control: modify libgexiv2-dev (>= 0.3.1) to libgexiv2-dev |
242 | + (>= 0.2.2-4) in Build-Depends field. |
243 | + * Update debian/patches/non-linux-fixes.patch patch. |
244 | + |
245 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Fri, 08 Apr 2011 23:28:01 +0200 |
246 | + |
247 | +shotwell (0.9.0-1) experimental; urgency=low |
248 | + |
249 | + * New upstream release (Closes: #614730, #593660, #619478). |
250 | + * debian/control: modify valac-0.10 (>= 0.10.4) to valac-0.12 (>= 0.11.7) |
251 | + in Build-Depends field. |
252 | + * debian/control: add m4 and libgnomevfs2-dev (>= 2.24.2) to Build-Depends |
253 | + field. |
254 | + * debian/control: modify libgexiv2-dev (>= 0.2.0) to libgexiv2-dev |
255 | + (>= 0.3.1) in Build-Depends field. |
256 | + * Remove debian/patches/vala-0_10_4.patch patch, fixed upstream. |
257 | + * Update debian/patches/non-linux-fixes.patch patch. |
258 | + * Update debian/copyright file. |
259 | + * Override library-not-linked-against-libc lintian warnings. |
260 | + * Override image-file-in-usr-lib lintian warnings. |
261 | + |
262 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Sun, 27 Mar 2011 15:07:13 +0200 |
263 | + |
264 | +shotwell (0.8.1-4) unstable; urgency=low |
265 | + |
266 | + * A patch was reverting some changes introduced in 0.8.1-3, apply them. |
267 | + |
268 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Sun, 27 Mar 2011 12:42:49 +0200 |
269 | + |
270 | +shotwell (0.8.1-3) unstable; urgency=low |
271 | + |
272 | + * Update debian/patches/non-linux-fixes.patch patch (Closes: #619682). |
273 | + * Add debian/patches/vala-0_10_4.patch patch, fix FTBFS caused by |
274 | + valac 0.10.4. |
275 | + * debian/control: modify valac-0.10 (>= 0.9.8) to valac-0.10 (>= 0.10.4) |
276 | + in Build-Depends field. |
277 | + |
278 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Sat, 26 Mar 2011 23:45:32 +0100 |
279 | + |
280 | +shotwell (0.8.1-2) unstable; urgency=low |
281 | + |
282 | + * Upload to unstable (Closes: #614445). |
283 | + * debian/control: modify libjson-glib-dev (>= 0.10.28) to libjson-glib-dev |
284 | + (>= 0.7.6) |
285 | + * debian/control: modify libgstreamer0.10-dev (>= 0.7.6) to |
286 | + libgstreamer0.10-dev (>= 0.10.28) |
287 | + * debian/control: modify libraw-dev to libraw-dev (>= 0.13.1-2). |
288 | + |
289 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Mon, 28 Feb 2011 22:16:51 +0100 |
290 | + |
291 | +shotwell (0.8.1-1) experimental; urgency=low |
292 | + |
293 | + * New upstream release. |
294 | + * debian/control: modify valac-0.10 (>= 0.9.7) to valac-0.10 (>= 0.9.8) in |
295 | + Build-Depends field. |
296 | + * Update debian/copyright. |
297 | + |
298 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Thu, 27 Jan 2011 23:05:40 +0100 |
299 | + |
300 | +shotwell (0.8.0-1) experimental; urgency=low |
301 | + |
302 | + * New upstream release. |
303 | + * debian/control: modify valac (>= 0.9.5) to valac-0.10 (>= 0.9.7) in |
304 | + Build-Depends field. |
305 | + * debian/control: add libjson-glib-dev and libgstreamer0.10-dev to |
306 | + Build-Depends field. |
307 | + * Update debian/patches/sidebar-bg-color.patch patch. |
308 | + * Update debian/patches/non-linux-fixes.patch patch. |
309 | + |
310 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Fri, 07 Jan 2011 15:14:41 +0100 |
311 | + |
312 | +shotwell (0.7.2-1) experimental; urgency=low |
313 | + |
314 | + * New upstream release. |
315 | + * Update debian/patches/sidebar-bg-color.patch patch. |
316 | + |
317 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Wed, 15 Sep 2010 14:56:23 +0200 |
318 | + |
319 | +shotwell (0.7.0-1) experimental; urgency=low |
320 | + |
321 | + * New upstream release. |
322 | + * debian/control: remove Luca Falavigna from Uploaders field. |
323 | + * debian/control: update valac version to >= 0.9.5. |
324 | + * debian/control: update libgexiv2-dev version to >= 0.2.0. |
325 | + * Update debian/patches/non-linux-fixes.patch patch. |
326 | + * debian/patches/sidebar-bg-color.patch: don't set sidebar background color |
327 | + (Closes: #594170). |
328 | + * Bump Standards-Version to 3.9.1. |
329 | + |
330 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Tue, 24 Aug 2010 17:34:23 +0200 |
331 | + |
332 | +shotwell (0.6.1-1) unstable; urgency=low |
333 | + |
334 | + * New upstream release. |
335 | + * debian/control: |
336 | + - Build-depend on libusb-dev. |
337 | + - Bump libgexiv2-dev version to be at least 0.1.0. |
338 | + |
339 | + -- Luca Falavigna <dktrkranz@debian.org> Mon, 05 Jul 2010 20:05:18 +0200 |
340 | + |
341 | +shotwell (0.6.0-1) unstable; urgency=low |
342 | + |
343 | + * New upstream release. |
344 | + * debian/patches/non-linux-fixes.patch: |
345 | + - Refresh for new upstream release. |
346 | + * debian/control: |
347 | + - Bump Standards-Version to 3.9.0, no changes required. |
348 | + |
349 | + -- Luca Falavigna <dktrkranz@debian.org> Wed, 30 Jun 2010 20:48:44 +0200 |
350 | + |
351 | +shotwell (0.5.91-2) experimental; urgency=low |
352 | + |
353 | + * debian/patches/non-linux-fixes.patch: |
354 | + - Let libraw to be available under non-Linux architectures, fix FTBFS |
355 | + on kFreeBSD (Closes: #586634). |
356 | + |
357 | + -- Luca Falavigna <dktrkranz@debian.org> Mon, 21 Jun 2010 23:24:16 +0200 |
358 | + |
359 | +shotwell (0.5.91-1) experimental; urgency=low |
360 | + |
361 | + * New upstream development release. |
362 | + * debian/patches/non-linux-fixes.patch: |
363 | + - Refresh for new upstream release. |
364 | + * debian/control: |
365 | + - Build-depend on libgexiv2-dev and libraw-dev. |
366 | + - No longer build-depend on libhal-dev. |
367 | + - Adjust build-dependencies versioning. |
368 | + * debian/README.source: |
369 | + - Upstream clarified licensing of some icons with their authors, now |
370 | + they are released under CC-BY-SA-3.0, so there is no need to repack |
371 | + upstream tarball anymore, thus removing this file. |
372 | + |
373 | + -- Luca Falavigna <dktrkranz@debian.org> Sun, 20 Jun 2010 16:09:43 +0200 |
374 | + |
375 | +shotwell (0.5.2+dfsg-2) unstable; urgency=low |
376 | + |
377 | + * debian/patches/non-linux-fixes.patch: |
378 | + - Add Hurd bits to allow build on that architecture. |
379 | + |
380 | + -- Luca Falavigna <dktrkranz@debian.org> Mon, 07 Jun 2010 23:41:52 +0200 |
381 | + |
382 | +shotwell (0.5.2+dfsg-1) unstable; urgency=low |
383 | + |
384 | + * New upstream release (Closes: #578903). |
385 | + * Drop vala_0.8.0.patch patch, already applied by upstream. |
386 | + * debian/control: add Luca Falavigna to Uploaders field. |
387 | + * Add debian/patches/non-linux-fixes.patch patch from Peter Green to add |
388 | + support for kfreebsd and hurd (Closes: #581662). |
389 | + * debian/control: replace "libgudev-1.0-dev (>= 145)" with "libgudev-1.0-dev |
390 | + (>= 145) [!kfreebsd-i386 !kfreebsd-amd64 !hurd-i386]" as suggested by |
391 | + Peter Green. |
392 | + |
393 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Sun, 23 May 2010 18:40:49 +0200 |
394 | + |
395 | +shotwell (0.5.0+dfsg-1.1) unstable; urgency=low |
396 | + |
397 | + * Non-maintainer upload. |
398 | + * debian/patches/vala_0.8.0.patch: |
399 | + - Build with vala 0.8.0 (Closes: #577913). |
400 | + * debian/control: |
401 | + - Depend on librsvg2-common and dbus-x11 (Closes: #574112). |
402 | + - Bump minimum valac version to 0.8.0. |
403 | + |
404 | + -- Luca Falavigna <dktrkranz@debian.org> Sun, 18 Apr 2010 23:16:32 +0200 |
405 | + |
406 | +shotwell (0.5.0+dfsg-1) unstable; urgency=low |
407 | + |
408 | + * New upstream release. |
409 | + * Update debian/copyright. |
410 | + * Remove debian/patches directory, patches already applied upstream. |
411 | + * debian/control: add libgudev-1.0-dev (>= 145) to Build-Depends field. |
412 | + * Bump Standards-Version to 3.8.4. |
413 | + |
414 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Mon, 15 Mar 2010 15:59:23 +0100 |
415 | + |
416 | +shotwell (0.4.3+dfsg-1.1) unstable; urgency=low |
417 | + |
418 | + * Non-maintainer upload. |
419 | + * debian/patches/02_vala_0.7.10.patch: |
420 | + - Fix build with vala 0.7.10 (Closes: #569370). |
421 | + * debian/control: |
422 | + - Bump minimum valac version to 0.7.10. |
423 | + |
424 | + -- Luca Falavigna <dktrkranz@debian.org> Sat, 20 Feb 2010 18:03:45 +0100 |
425 | + |
426 | +shotwell (0.4.3+dfsg-1) unstable; urgency=low |
427 | + |
428 | + * New upstream release. |
429 | + * Switch to format 3.0 (quilt). |
430 | + * Add debian/patches/01_GNU-kFreeBSD.diff patch from Cyril Brulebois to fix |
431 | + FTBFS on GNU/kFreeBSD (Closes: #564306). |
432 | + |
433 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Sat, 23 Jan 2010 18:56:33 +0100 |
434 | + |
435 | +shotwell (0.4.2+dfsg-1) unstable; urgency=low |
436 | + |
437 | + * Initial release (Closes: #561788). |
438 | + |
439 | + -- Devid Antonio Filoni <d.filoni@ubuntu.com> Wed, 06 Jan 2010 14:08:43 +0100 |
440 | |
441 | === added file 'debian/compat' |
442 | --- debian/compat 1970-01-01 00:00:00 +0000 |
443 | +++ debian/compat 2012-09-17 10:22:22 +0000 |
444 | @@ -0,0 +1,1 @@ |
445 | +7 |
446 | |
447 | === added file 'debian/control' |
448 | --- debian/control 1970-01-01 00:00:00 +0000 |
449 | +++ debian/control 2012-09-17 10:22:22 +0000 |
450 | @@ -0,0 +1,47 @@ |
451 | +Source: shotwell |
452 | +Section: gnome |
453 | +Priority: optional |
454 | +Maintainer: Ubuntu Desktop Team <ubuntu-desktop@lists.ubuntu.com> |
455 | +XSBC-Original-Maintainer: Debian Shotwell Maintainers <pkg-shotwell-maint@lists.alioth.debian.org> |
456 | +Uploaders: Devid Antonio Filoni <d.filoni@ubuntu.com> |
457 | +Build-Depends: debhelper (>= 7.0.50~), |
458 | + m4, |
459 | + valac-0.18 (>= 0.17.2), |
460 | + libgee-dev (>= 0.5.0), |
461 | + libglib2.0-dev (>= 2.30.0), |
462 | + libgtk-3-dev (>= 3.0.11), |
463 | + libexif-dev (>= 0.6.16), |
464 | + libsqlite3-dev (>= 3.5.9), |
465 | + libgexiv2-dev (>= 0.4.1-1build1), |
466 | + libgnomevfs2-dev (>= 2.24.2), |
467 | + libgphoto2-2-dev (>= 2.4.2), |
468 | + libsoup2.4-dev (>= 2.26.0), |
469 | + libxml2 (>= 2.6.32), |
470 | + libunique-3.0-dev (>= 1.0.0), |
471 | + libwebkitgtk-3.0-dev (>= 1.1.5), |
472 | + libgudev-1.0-dev (>= 145), |
473 | + libdbus-glib-1-dev (>= 0.80), |
474 | + libraw-dev (>= 0.13.2), |
475 | + libusb-dev, |
476 | + libjson-glib-dev (>= 0.7.6), |
477 | + libgstreamer0.10-dev (>= 0.10.28), |
478 | + libgstreamer-plugins-base0.10-dev (>= 0.10.32), |
479 | + python-scour, |
480 | + libunity-dev, |
481 | + librest-dev, |
482 | + libsignon-glib-dev, |
483 | + libaccounts-glib-dev |
484 | +DM-Upload-Allowed: yes |
485 | +Standards-Version: 3.9.3 |
486 | +Homepage: http://yorba.org/shotwell/ |
487 | +Vcs-Bzr: https://code.launchpad.net/~ubuntu-desktop/shotwell/ubuntu |
488 | + |
489 | +Package: shotwell |
490 | +Architecture: linux-any |
491 | +Depends: ${shlibs:Depends}, ${misc:Depends}, librsvg2-common, dbus-x11 |
492 | +Recommends: account-plugin-facebook, account-plugin-google, account-plugin-flickr |
493 | +Description: digital photo organizer |
494 | + Shotwell is a digital photo organizer designed for the GNOME desktop |
495 | + environment. It allows you to import photos from disk or camera, organize |
496 | + them in various ways, view them in full-window or fullscreen mode, and |
497 | + export them to share with others. |
498 | |
499 | === added file 'debian/copyright' |
500 | --- debian/copyright 1970-01-01 00:00:00 +0000 |
501 | +++ debian/copyright 2012-09-17 10:22:22 +0000 |
502 | @@ -0,0 +1,435 @@ |
503 | +This work was packaged for Debian by: |
504 | + |
505 | + Devid Antonio Filoni <d.filoni@ubuntu.com> on Wed, 06 Jan 2010 14:08:43 +0100 |
506 | + |
507 | +It was downloaded from http://yorba.org/download/shotwell/ |
508 | + |
509 | + |
510 | + |
511 | +Upstream Authors: |
512 | + |
513 | + Jim Nelson <jim@yorba.org> |
514 | + Lucas Beeler <lucas@yorba.org> |
515 | + Allison Barlow <allison@yorba.org> |
516 | + |
517 | +Copyright: |
518 | + |
519 | + Copyright © 2009-2011 Yorba Foundation |
520 | + Copyright © 2010 Evgeniy Polyakov |
521 | + Copyright © 2010 Guillaume Viguier-Just |
522 | + Copyright © 2010 Maxim Kartashev |
523 | + |
524 | +License: |
525 | + |
526 | + This package is free software; you can redistribute it and/or |
527 | + modify it under the terms of the GNU Lesser General Public |
528 | + License as published by the Free Software Foundation; either |
529 | + version 2.1 of the License, or (at your option) any later version. |
530 | + |
531 | + This library is distributed in the hope that it will be useful, |
532 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
533 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
534 | + Lesser General Public License for more details. |
535 | + |
536 | + You should have received a copy of the GNU Lesser General Public |
537 | + License along with this package; if not, write to the Free Software |
538 | + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
539 | + |
540 | +On Debian systems, the complete text of the GNU Lesser General |
541 | +Public License can be found in `/usr/share/common-licenses/LGPL-2.1'. |
542 | + |
543 | + |
544 | + |
545 | +The Debian packaging is: |
546 | + |
547 | + Copyright © 2009-2011 Devid Antonio Filoni <d.filoni@ubuntu.com> |
548 | + |
549 | +and is licensed under the GPL version 2, |
550 | +see `/usr/share/common-licenses/GPL-2'. |
551 | + |
552 | + |
553 | + |
554 | +Authors of vapi/ige-mac-integration.vapi: |
555 | + |
556 | + Michael Natterer <mitch@imendio.com> |
557 | + Richard Hult <richard@imendio.com> |
558 | + Mikael Hallendal <micke@imendio.com> |
559 | + John Ralls <jralls@ceridwen.us> |
560 | + |
561 | + |
562 | + |
563 | +icons/pin-toolbar.png, icons/hidden.svg, icons/crop.* and icons/import.* are |
564 | +taken from Breathe Icon Set (https://launchpad.net/breathe-icon-set). |
565 | + |
566 | +icons/import-all.png is a derivate work of icons/import.svg and is licensed |
567 | +under Creative Commons Attribution-ShareAlike 3.0. |
568 | + |
569 | +Upstream Authors of Breathe Icon Set: |
570 | + |
571 | + Sebastian Porta <sebastianporta@gmail.com> |
572 | + Cory Kontros <coryisatm@ubuntu.com> |
573 | + Oliver Scholtz <scholli_tz@yahoo.de> |
574 | + Daniel Planas <daniplanas.a@gmail.com> |
575 | + |
576 | +Copyright of Breathe Icon Set: |
577 | + |
578 | + © 2009, Sebastian Porta <sebastianporta@gmail.com> |
579 | + © 2009, Cory Kontros <coryisatm@ubuntu.com> |
580 | + © 2009, Oliver Scholtz <scholli_tz@yahoo.de> |
581 | + © 2009, Daniel Planas <daniplanas.a@gmail.com> |
582 | + © 2007, David Vignoni <david@icon-king.com> |
583 | + © 2007, Johann Ollivier Lapeyre <johann@oxygen-icons.org> |
584 | + © 2007, Kenneth Wimer <kwwii@bootsplash.org> |
585 | + © 2007, Nuno Fernades Pinheiro <nf.pinheiro@gmail.com> |
586 | + © 2007, Riccardo Iaconelli <riccardo@oxygen-icons.org> |
587 | + © 2007, David Miller <miller@oxygen-icons.org> |
588 | + © 2009, Rosetta Contributors and Canonical Ltd. |
589 | + |
590 | +License of Breathe Icon Set: |
591 | + |
592 | + Creative Commons Attribution-ShareAlike 3.0 |
593 | + |
594 | + THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS |
595 | + CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS |
596 | + PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE |
597 | + WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS |
598 | + PROHIBITED. |
599 | + |
600 | + BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND |
601 | + AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS |
602 | + LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU |
603 | + THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH |
604 | + TERMS AND CONDITIONS. |
605 | + |
606 | + 1. Definitions |
607 | + |
608 | + 1. "Adaptation" means a work based upon the Work, or upon the Work and |
609 | + other pre-existing works, such as a translation, adaptation, derivative |
610 | + work, arrangement of music or other alterations of a literary or artistic |
611 | + work, or phonogram or performance and includes cinematographic adaptations |
612 | + or any other form in which the Work may be recast, transformed, or adapted |
613 | + including in any form recognizably derived from the original, except that a |
614 | + work that constitutes a Collection will not be considered an Adaptation for |
615 | + the purpose of this License. For the avoidance of doubt, where the Work is |
616 | + a musical work, performance or phonogram, the synchronization of the Work |
617 | + in timed-relation with a moving image ("synching") will be considered an |
618 | + Adaptation for the purpose of this License. |
619 | + |
620 | + 2. "Collection" means a collection of literary or artistic works, such as |
621 | + encyclopedias and anthologies, or performances, phonograms or broadcasts, |
622 | + or other works or subject matter other than works listed in Section 1(f) |
623 | + below, which, by reason of the selection and arrangement of their contents, |
624 | + constitute intellectual creations, in which the Work is included in its |
625 | + entirety in unmodified form along with one or more other contributions, |
626 | + each constituting separate and independent works in themselves, which |
627 | + together are assembled into a collective whole. A work that constitutes a |
628 | + Collection will not be considered an Adaptation (as defined above) for the |
629 | + purposes of this License. |
630 | + |
631 | + 3. "Creative Commons Compatible License" means a license that is listed at |
632 | + http://creativecommons.org/compatiblelicenses that has been approved by |
633 | + Creative Commons as being essentially equivalent to this License, including, |
634 | + at a minimum, because that license: (i) contains terms that have the same |
635 | + purpose, meaning and effect as the License Elements of this License; and, |
636 | + (ii) explicitly permits the relicensing of adaptations of works made |
637 | + available under that license under this License or a Creative Commons |
638 | + jurisdiction license with the same License Elements as this License. |
639 | + |
640 | + 4. "Distribute" means to make available to the public the original and |
641 | + copies of the Work or Adaptation, as appropriate, through sale or other |
642 | + transfer of ownership. |
643 | + |
644 | + 5. "License Elements" means the following high-level license attributes |
645 | + as selected by Licensor and indicated in the title of this License: |
646 | + Attribution, ShareAlike. |
647 | + |
648 | + 6. "Licensor" means the individual, individuals, entity or entities that |
649 | + offer(s) the Work under the terms of this License. |
650 | + |
651 | + 7. "Original Author" means, in the case of a literary or artistic work, |
652 | + the individual, individuals, entity or entities who created the Work or |
653 | + if no individual or entity can be identified, the publisher; and in |
654 | + addition (i) in the case of a performance the actors, singers, musicians, |
655 | + dancers, and other persons who act, sing, deliver, declaim, play in, |
656 | + interpret or otherwise perform literary or artistic works or expressions |
657 | + of folklore; (ii) in the case of a phonogram the producer being the person |
658 | + or legal entity who first fixes the sounds of a performance or other |
659 | + sounds; and, (iii) in the case of broadcasts, the organization that |
660 | + transmits the broadcast. |
661 | + |
662 | + 8. "Work" means the literary and/or artistic work offered under the |
663 | + terms of this License including without limitation any production in |
664 | + the literary, scientific and artistic domain, whatever may be the mode |
665 | + or form of its expression including digital form, such as a book, |
666 | + pamphlet and other writing; a lecture, address, sermon or other |
667 | + work of the same nature; a dramatic or dramatico-musical work; a |
668 | + choreographic work or entertainment in dumb show; a musical composition |
669 | + with or without words; a cinematographic work to which are assimilated |
670 | + works expressed by a process analogous to cinematography; a work of |
671 | + drawing, painting, architecture, sculpture, engraving or lithography; a |
672 | + photographic work to which are assimilated works expressed by a |
673 | + process analogous to photography; a work of applied art; an illustration, |
674 | + map, plan, sketch or three-dimensional work relative to geography, |
675 | + topography, architecture or science; a performance; a broadcast; a |
676 | + phonogram; a compilation of data to the extent it is protected as a |
677 | + copyrightable work; or a work performed by a variety or circus performer |
678 | + to the extent it is not otherwise considered a literary or artistic work. |
679 | + |
680 | + 9. "You" means an individual or entity exercising rights under this |
681 | + License who has not previously violated the terms of this License with |
682 | + respect to the Work, or who has received express permission from the |
683 | + Licensor to exercise rights under this License despite a previous |
684 | + violation. |
685 | + |
686 | + 10. "Publicly Perform" means to perform public recitations of the Work |
687 | + and to communicate to the public those public recitations, by any means |
688 | + or process, including by wire or wireless means or public digital |
689 | + performances; to make available to the public Works in such a way that |
690 | + members of the public may access these Works from a place and at a place |
691 | + individually chosen by them; to perform the Work to the public by any |
692 | + means or process and the communication to the public of the performances |
693 | + of the Work, including by public digital performance; to broadcast and |
694 | + rebroadcast the Work by any means including signs, sounds or images. |
695 | + |
696 | + 11. "Reproduce" means to make copies of the Work by any means including |
697 | + without limitation by sound or visual recordings and the right of |
698 | + fixation and reproducing fixations of the Work, including storage of |
699 | + a protected performance or phonogram in digital form or other electronic |
700 | + medium. |
701 | + |
702 | + 2. Fair Dealing Rights. Nothing in this License is intended to reduce, |
703 | + limit, or restrict any uses free from copyright or rights arising from |
704 | + limitations or exceptions that are provided for in connection with the |
705 | + copyright protection under copyright law or other applicable laws. |
706 | + |
707 | + 3. License Grant. Subject to the terms and conditions of this License, |
708 | + Licensor hereby grants You a worldwide, royalty-free, non-exclusive, |
709 | + perpetual (for the duration of the applicable copyright) license to |
710 | + exercise the rights in the Work as stated below: |
711 | + |
712 | + 1. to Reproduce the Work, to incorporate the Work into one or more |
713 | + Collections, and to Reproduce the Work as incorporated in the Collections; |
714 | + 2. to create and Reproduce Adaptations provided that any such Adaptation, |
715 | + including any translation in any medium, takes reasonable steps to |
716 | + clearly label, demarcate or otherwise identify that changes were made to |
717 | + the original Work. For example, a translation could be marked "The |
718 | + original work was translated from English to Spanish," or a modification |
719 | + could indicate "The original work has been modified."; |
720 | + 3. to Distribute and Publicly Perform the Work including as incorporated |
721 | + in Collections; and, |
722 | + 4. to Distribute and Publicly Perform Adaptations. |
723 | + 5. For the avoidance of doubt: |
724 | + 1. Non-waivable Compulsory License Schemes. In those jurisdictions |
725 | + in which the right to collect royalties through any statutory or |
726 | + compulsory licensing scheme cannot be waived, the Licensor reserves |
727 | + the exclusive right to collect such royalties for any exercise by You |
728 | + of the rights granted under this License; |
729 | + 2. Waivable Compulsory License Schemes. In those jurisdictions in |
730 | + which the right to collect royalties through any statutory or compulsory |
731 | + licensing scheme can be waived, the Licensor waives the exclusive right |
732 | + to collect such royalties for any exercise by You of the rights granted |
733 | + under this License; and, |
734 | + 3. Voluntary License Schemes. The Licensor waives the right to |
735 | + collect royalties, whether individually or, in the event that the Licensor |
736 | + is a member of a collecting society that administers voluntary licensing |
737 | + schemes, via that society, from any exercise by You of the rights granted |
738 | + under this License. |
739 | + |
740 | + The above rights may be exercised in all media and formats whether now |
741 | + known or hereafter devised. The above rights include the right to make |
742 | + such modifications as are technically necessary to exercise the rights |
743 | + in other media and formats. Subject to Section 8(f), all rights not |
744 | + expressly granted by Licensor are hereby reserved. |
745 | + |
746 | + 4. Restrictions. The license granted in Section 3 above is expressly |
747 | + made subject to and limited by the following restrictions: |
748 | + |
749 | + 1. You may Distribute or Publicly Perform the Work only under the terms |
750 | + of this License. You must include a copy of, or the Uniform Resource |
751 | + Identifier (URI) for, this License with every copy of the Work You |
752 | + Distribute or Publicly Perform. You may not offer or impose any terms on |
753 | + the Work that restrict the terms of this License or the ability of the |
754 | + recipient of the Work to exercise the rights granted to that recipient |
755 | + under the terms of the License. You may not sublicense the Work. You must |
756 | + keep intact all notices that refer to this License and to the disclaimer of |
757 | + warranties with every copy of the Work You Distribute or Publicly Perform. |
758 | + When You Distribute or Publicly Perform the Work, You may not impose any |
759 | + effective technological measures on the Work that restrict the ability of a |
760 | + recipient of the Work from You to exercise the rights granted to that |
761 | + recipient under the terms of the License. This Section 4(a) applies to the |
762 | + Work as incorporated in a Collection, but this does not require the |
763 | + Collection apart from the Work itself to be made subject to the terms of |
764 | + this License. If You create a Collection, upon notice from any Licensor You |
765 | + must, to the extent practicable, remove from the Collection any credit as |
766 | + required by Section 4(c), as requested. If You create an Adaptation, upon |
767 | + notice from any Licensor You must, to the extent practicable, remove from |
768 | + the Adaptation any credit as required by Section 4(c), as requested. |
769 | + |
770 | + 2. You may Distribute or Publicly Perform an Adaptation only under the |
771 | + terms of: (i) this License; (ii) a later version of this License with the |
772 | + same License Elements as this License; (iii) a Creative Commons |
773 | + jurisdiction license (either this or a later license version) that contains |
774 | + the same License Elements as this License (e.g., Attribution-ShareAlike |
775 | + 3.0 US)); (iv) a Creative Commons Compatible License. If you license the |
776 | + Adaptation under one of the licenses mentioned in (iv), you must comply |
777 | + with the terms of that license. If you license the Adaptation under the |
778 | + terms of any of the licenses mentioned in (i), (ii) or (iii) (the |
779 | + "Applicable License"), you must comply with the terms of the Applicable |
780 | + License generally and the following provisions: (I) You must include a |
781 | + copy of, or the URI for, the Applicable License with every copy of each |
782 | + Adaptation You Distribute or Publicly Perform; (II) You may not offer or |
783 | + impose any terms on the Adaptation that restrict the terms of the |
784 | + Applicable License or the ability of the recipient of the Adaptation to |
785 | + exercise the rights granted to that recipient under the terms of the |
786 | + Applicable License; (III) You must keep intact all notices that refer to |
787 | + the Applicable License and to the disclaimer of warranties with every copy |
788 | + of the Work as included in the Adaptation You Distribute or Publicly |
789 | + Perform; (IV) when You Distribute or Publicly Perform the Adaptation, You |
790 | + may not impose any effective technological measures on the Adaptation that |
791 | + restrict the ability of a recipient of the Adaptation from You to exercise |
792 | + the rights granted to that recipient under the terms of the Applicable |
793 | + License. This Section 4(b) applies to the Adaptation as incorporated in a |
794 | + Collection, but this does not require the Collection apart from the |
795 | + Adaptation itself to be made subject to the terms of the Applicable |
796 | + License. |
797 | + |
798 | + 3. If You Distribute, or Publicly Perform the Work or any Adaptations or |
799 | + Collections, You must, unless a request has been made pursuant to Section |
800 | + 4(a), keep intact all copyright notices for the Work and provide, |
801 | + reasonable to the medium or means You are utilizing: (i) the name of the |
802 | + Original Author (or pseudonym, if applicable) if supplied, and/or if the |
803 | + Original Author and/or Licensor designate another party or parties (e.g., |
804 | + a sponsor institute, publishing entity, journal) for attribution |
805 | + ("Attribution Parties") in Licensor's copyright notice, terms of service |
806 | + or by other reasonable means, the name of such party or parties; (ii) the |
807 | + title of the Work if supplied; (iii) to the extent reasonably practicable, |
808 | + the URI, if any, that Licensor specifies to be associated with the Work, |
809 | + unless such URI does not refer to the copyright notice or licensing |
810 | + information for the Work; and (iv) , consistent with Ssection 3(b), in the |
811 | + case of an Adaptation, a credit identifying the use of the Work in the |
812 | + Adaptation (e.g., "French translation of the Work by Original Author," or |
813 | + "Screenplay based on original Work by Original Author"). The credit |
814 | + required by this Section 4(c) may be implemented in any reasonable manner; |
815 | + provided, however, that in the case of a Adaptation or Collection, at a |
816 | + minimum such credit will appear, if a credit for all contributing authors |
817 | + of the Adaptation or Collection appears, then as part of these credits and |
818 | + in a manner at least as prominent as the credits for the other contributing |
819 | + authors. For the avoidance of doubt, You may only use the credit required by |
820 | + this Section for the purpose of attribution in the manner set out above and, |
821 | + by exercising Your rights under this License, You may not implicitly or |
822 | + explicitly assert or imply any connection with, sponsorship or endorsement |
823 | + by the Original Author, Licensor and/or Attribution Parties, as |
824 | + appropriate, of You or Your use of the Work, without the separate, express |
825 | + prior written permission of the Original Author, Licensor and/or |
826 | + Attribution Parties. |
827 | + |
828 | + 4. Except as otherwise agreed in writing by the Licensor or as may be |
829 | + otherwise permitted by applicable law, if You Reproduce, Distribute or |
830 | + Publicly Perform the Work either by itself or as part of any Adaptations |
831 | + or Collections, You must not distort, mutilate, modify or take other |
832 | + derogatory action in relation to the Work which would be prejudicial to |
833 | + the Original Author's honor or reputation. Licensor agrees that in those |
834 | + jurisdictions (e.g. Japan), in which any exercise of the right granted in |
835 | + Section 3(b) of this License (the right to make Adaptations) would be |
836 | + deemed to be a distortion, mutilation, modification or other derogatory |
837 | + action prejudicial to the Original Author's honor and reputation, the |
838 | + Licensor will waive or not assert, as appropriate, this Section, to the |
839 | + fullest extent permitted by the applicable national law, to enable You to |
840 | + reasonably exercise Your right under Section 3(b) of this License (right |
841 | + to make Adaptations) but not otherwise. |
842 | + |
843 | + 5. Representations, Warranties and Disclaimer |
844 | + |
845 | + UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR |
846 | + OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY |
847 | + KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, |
848 | + INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, |
849 | + FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF |
850 | + LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, |
851 | + WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE |
852 | + EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. |
853 | + |
854 | + 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE |
855 | + LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR |
856 | + ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES |
857 | + ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS |
858 | + BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. |
859 | + |
860 | + 7. Termination |
861 | + |
862 | + 1. This License and the rights granted hereunder will terminate |
863 | + automatically upon any breach by You of the terms of this License. |
864 | + Individuals or entities who have received Adaptations or Collections |
865 | + from You under this License, however, will not have their licenses |
866 | + terminated provided such individuals or entities remain in full |
867 | + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will |
868 | + survive any termination of this License. |
869 | + 2. Subject to the above terms and conditions, the license granted |
870 | + here is perpetual (for the duration of the applicable copyright in |
871 | + the Work). Notwithstanding the above, Licensor reserves the right to |
872 | + release the Work under different license terms or to stop distributing |
873 | + the Work at any time; provided, however that any such election will |
874 | + not serve to withdraw this License (or any other license that has been, |
875 | + or is required to be, granted under the terms of this License), and this |
876 | + License will continue in full force and effect unless terminated as stated |
877 | + above. |
878 | + |
879 | + 8. Miscellaneous |
880 | + |
881 | + 1. Each time You Distribute or Publicly Perform the Work or a Collection, |
882 | + the Licensor offers to the recipient a license to the Work on the same |
883 | + terms and conditions as the license granted to You under this License. |
884 | + 2. Each time You Distribute or Publicly Perform an Adaptation, Licensor |
885 | + offers to the recipient a license to the original Work on the same terms |
886 | + and conditions as the license granted to You under this License. |
887 | + 3. If any provision of this License is invalid or unenforceable under |
888 | + applicable law, it shall not affect the validity or enforceability of |
889 | + the remainder of the terms of this License, and without further action |
890 | + by the parties to this agreement, such provision shall be reformed to |
891 | + the minimum extent necessary to make such provision valid and enforceable. |
892 | + 4. No term or provision of this License shall be deemed waived and no |
893 | + breach consented to unless such waiver or consent shall be in writing |
894 | + and signed by the party to be charged with such waiver or consent. |
895 | + 5. This License constitutes the entire agreement between the parties |
896 | + with respect to the Work licensed here. There are no understandings, |
897 | + agreements or representations with respect to the Work not specified |
898 | + here. Licensor shall not be bound by any additional provisions that |
899 | + may appear in any communication from You. This License may not be |
900 | + modified without the mutual written agreement of the Licensor and You. |
901 | + 6. The rights granted under, and the subject matter referenced, in this |
902 | + License were drafted utilizing the terminology of the Berne Convention |
903 | + for the Protection of Literary and Artistic Works (as amended on |
904 | + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright |
905 | + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 |
906 | + and the Universal Copyright Convention (as revised on July 24, 1971). |
907 | + These rights and subject matter take effect in the relevant jurisdiction |
908 | + in which the License terms are sought to be enforced according to the |
909 | + corresponding provisions of the implementation of those treaty |
910 | + provisions in the applicable national law. If the standard suite of |
911 | + rights granted under applicable copyright law includes additional rights |
912 | + not granted under this License, such additional rights are deemed to be |
913 | + included in the License; this License is not intended to restrict the |
914 | + license of any rights under applicable law. |
915 | + |
916 | + Creative Commons Notice |
917 | + |
918 | + Creative Commons is not a party to this License, and makes no warranty |
919 | + whatsoever in connection with the Work. Creative Commons will not be |
920 | + liable to You or any party on any legal theory for any damages whatsoever, |
921 | + vincluding without limitation any general, special, incidental or |
922 | + consequential damages arising in connection to this license. |
923 | + Notwithstanding the foregoing two (2) sentences, if Creative Commons has |
924 | + expressly identified itself as the Licensor hereunder, it shall have all |
925 | + rights and obligations of Licensor. |
926 | + |
927 | + Except for the limited purpose of indicating to the public that the |
928 | + Work is licensed under the CCPL, Creative Commons does not authorize |
929 | + the use by either party of the trademark "Creative Commons" or any |
930 | + related trademark or logo of Creative Commons without the prior written |
931 | + consent of Creative Commons. Any permitted use will be in compliance |
932 | + with Creative Commons' then-current trademark usage guidelines, as may |
933 | + be published on its website or otherwise made available upon request |
934 | + from time to time. For the avoidance of doubt, this trademark restriction |
935 | + does not form part of this License. |
936 | + |
937 | + Creative Commons may be contacted at http://creativecommons.org/. |
938 | |
939 | === added file 'debian/docs' |
940 | --- debian/docs 1970-01-01 00:00:00 +0000 |
941 | +++ debian/docs 2012-09-17 10:22:22 +0000 |
942 | @@ -0,0 +1,2 @@ |
943 | +README |
944 | +THANKS |
945 | |
946 | === added file 'debian/manpages' |
947 | --- debian/manpages 1970-01-01 00:00:00 +0000 |
948 | +++ debian/manpages 2012-09-17 10:22:22 +0000 |
949 | @@ -0,0 +1,2 @@ |
950 | +debian/shotwell.1 |
951 | +debian/shotwell-video-thumbnailer.1 |
952 | |
953 | === added file 'debian/menu' |
954 | --- debian/menu 1970-01-01 00:00:00 +0000 |
955 | +++ debian/menu 2012-09-17 10:22:22 +0000 |
956 | @@ -0,0 +1,2 @@ |
957 | +?package(shotwell):needs="X11" section="Applications/Viewers"\ |
958 | + title="Shotwell" command="/usr/bin/shotwell" |
959 | |
960 | === added directory 'debian/patches' |
961 | === added file 'debian/patches/02_desktop_translations.patch' |
962 | --- debian/patches/02_desktop_translations.patch 1970-01-01 00:00:00 +0000 |
963 | +++ debian/patches/02_desktop_translations.patch 2012-09-17 10:22:22 +0000 |
964 | @@ -0,0 +1,25 @@ |
965 | +Description: Don't translate the .desktop files, they work with gettext and the build system translates them all into English |
966 | +Bug-Ubuntu: https://bugs.launchpad.net/bugs/760978 |
967 | + |
968 | +Index: shotwell-0.12.90/Makefile |
969 | +=================================================================== |
970 | +--- shotwell-0.12.90.orig/Makefile 2012-08-24 10:38:39.000000000 +1200 |
971 | ++++ shotwell-0.12.90/Makefile 2012-08-24 15:03:05.212013701 +1200 |
972 | +@@ -536,17 +536,6 @@ |
973 | + install: |
974 | + cp misc/shotwell.desktop.head misc/shotwell.desktop |
975 | + cp misc/shotwell-viewer.desktop.head misc/shotwell-viewer.desktop |
976 | +- $(foreach lang,$(CORE_SUPPORTED_LANGUAGES), echo X-GNOME-FullName[$(lang)]=`TEXTDOMAINDIR=locale-langpack \ |
977 | +- LANGUAGE=$(lang) gettext --domain=shotwell $(DESKTOP_APP_FULL_NAME)` \ |
978 | +- >> misc/shotwell.desktop ; \ |
979 | +- echo GenericName[$(lang)]=`TEXTDOMAINDIR=locale-langpack LANGUAGE=$(lang) \ |
980 | +- gettext --domain=shotwell $(DESKTOP_APPLICATION_CLASS)` >> misc/shotwell.desktop ; \ |
981 | +- echo Comment[$(lang)]=`TEXTDOMAINDIR=locale-langpack LANGUAGE=$(lang) gettext \ |
982 | +- --domain=shotwell $(DESKTOP_APPLICATION_COMMENT)` >> misc/shotwell.desktop ; \ |
983 | +- echo X-GNOME-FullName[$(lang)]=`TEXTDOMAINDIR=locale-langpack LANGUAGE=$(lang) gettext \ |
984 | +- --domain=shotwell $(DIRECT_EDIT_DESKTOP_APP_FULL_NAME)` >> misc/shotwell-viewer.desktop ; \ |
985 | +- echo GenericName[$(lang)]=`TEXTDOMAINDIR=locale-langpack LANGUAGE=$(lang) gettext \ |
986 | +- --domain=shotwell $(DIRECT_EDIT_DESKTOP_APPLICATION_CLASS)` >> misc/shotwell-viewer.desktop ;) |
987 | + touch $(LANG_STAMP) |
988 | + mkdir -p $(DESTDIR)$(PREFIX)/bin |
989 | + $(INSTALL_PROGRAM) $(PROGRAM) $(DESTDIR)$(PREFIX)/bin |
990 | |
991 | === added file 'debian/patches/03_appmenu_no_stubs.patch' |
992 | --- debian/patches/03_appmenu_no_stubs.patch 1970-01-01 00:00:00 +0000 |
993 | +++ debian/patches/03_appmenu_no_stubs.patch 2012-09-17 10:22:22 +0000 |
994 | @@ -0,0 +1,9 @@ |
995 | +Index: shotwell-0.11.91/misc/shotwell.desktop.head |
996 | +=================================================================== |
997 | +--- shotwell-0.11.91.orig/misc/shotwell.desktop.head 2012-01-06 02:26:06.000000000 +0100 |
998 | ++++ shotwell-0.11.91/misc/shotwell.desktop.head 2012-01-11 15:11:14.909408671 +0100 |
999 | +@@ -12,3 +12,4 @@ |
1000 | + X-GIO-NoFuse=true |
1001 | + X-GNOME-Gettext-Domain=shotwell |
1002 | + X-GNOME-FullName=Shotwell Photo Manager |
1003 | ++X-Ayatana-Appmenu-Show-Stubs=false |
1004 | |
1005 | === added file 'debian/patches/04_no_resize_grip.patch' |
1006 | --- debian/patches/04_no_resize_grip.patch 1970-01-01 00:00:00 +0000 |
1007 | +++ debian/patches/04_no_resize_grip.patch 2012-09-17 10:22:22 +0000 |
1008 | @@ -0,0 +1,26 @@ |
1009 | +Description: Disable the resize grip, it conflicts with widgets in the bottom corner |
1010 | +Author: Robert Ancell <robert.ancell@canonical.com> |
1011 | +Bug: https://launchpad.net/bugs/740274 |
1012 | + |
1013 | +Index: shotwell-0.12.0/src/AppWindow.vala |
1014 | +=================================================================== |
1015 | +--- shotwell-0.12.0.orig/src/AppWindow.vala 2012-03-28 05:43:09.000000000 +1100 |
1016 | ++++ shotwell-0.12.0/src/AppWindow.vala 2012-03-28 12:05:48.691285125 +1100 |
1017 | +@@ -413,6 +413,8 @@ |
1018 | + |
1019 | + } |
1020 | + |
1021 | ++extern static void gtk_window_set_has_resize_grip (Gtk.Window window, bool has_grip); |
1022 | ++ |
1023 | + // AppWindow is the parent window for most windows in Shotwell (FullscreenWindow is the exception). |
1024 | + // There are multiple types of AppWindows (LibraryWindow, DirectWindow) for different tasks, but only |
1025 | + // one AppWindow may exist per process. Thus, if the user closes an AppWindow, the program exits. |
1026 | +@@ -442,6 +444,8 @@ |
1027 | + assert(instance == null); |
1028 | + instance = this; |
1029 | + |
1030 | ++ gtk_window_set_has_resize_grip (this, false); |
1031 | ++ |
1032 | + title = Resources.APP_TITLE; |
1033 | + |
1034 | + GLib.List<Gdk.Pixbuf> pixbuf_list = new GLib.List<Gdk.Pixbuf>(); |
1035 | |
1036 | === added file 'debian/patches/05-gomp-linking.patch' |
1037 | --- debian/patches/05-gomp-linking.patch 1970-01-01 00:00:00 +0000 |
1038 | +++ debian/patches/05-gomp-linking.patch 2012-09-17 10:22:22 +0000 |
1039 | @@ -0,0 +1,16 @@ |
1040 | +From: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com> |
1041 | +Subject: Link against gomp as well (-lgomp) |
1042 | + |
1043 | +Index: shotwell-0.12.90/Makefile |
1044 | +=================================================================== |
1045 | +--- shotwell-0.12.90.orig/Makefile 2012-08-24 15:03:05.000000000 +1200 |
1046 | ++++ shotwell-0.12.90/Makefile 2012-08-24 15:04:46.356010199 +1200 |
1047 | +@@ -679,7 +679,7 @@ |
1048 | + $(CC) -c $(VALA_CFLAGS) $(CFLAGS) -o $@ $< |
1049 | + |
1050 | + $(PROGRAM): $(EXPANDED_OBJ_FILES) $(RESOURCES) $(LANG_STAMP) $(THUMBNAILER_BIN) |
1051 | +- $(CC) $(EXPANDED_OBJ_FILES) $(CFLAGS) $(LDFLAGS) $(RESOURCES) $(VALA_LDFLAGS) $(EXPORT_FLAGS) -o $@ |
1052 | ++ $(CC) $(EXPANDED_OBJ_FILES) $(CFLAGS) $(LDFLAGS) $(RESOURCES) -fopenmp $(VALA_LDFLAGS) $(EXPORT_FLAGS) -o $@ |
1053 | + glib-compile-schemas misc |
1054 | + |
1055 | + $(THUMBNAILER_BIN): $(EXPANDED_THUMBNAILER_SRC_FILES) |
1056 | |
1057 | === added file 'debian/patches/06_uoa.patch' |
1058 | --- debian/patches/06_uoa.patch 1970-01-01 00:00:00 +0000 |
1059 | +++ debian/patches/06_uoa.patch 2012-09-17 10:22:22 +0000 |
1060 | @@ -0,0 +1,2790 @@ |
1061 | +Description: use Ubuntu Online Accounts for Picasa, Facebook and Flickr export plugins |
1062 | +Author: Alberto Mardegan <alberto.mardegan@canonical.com> |
1063 | + |
1064 | +--- |
1065 | +diff --git a/Makefile b/Makefile |
1066 | +index ff15b71..b848b7f 100644 |
1067 | +--- a/Makefile |
1068 | ++++ b/Makefile |
1069 | +@@ -151,6 +151,7 @@ RESOURCE_FILES = \ |
1070 | + trash.ui |
1071 | + |
1072 | + SYS_INTEGRATION_FILES = \ |
1073 | ++ shotwell.application \ |
1074 | + shotwell.desktop.head \ |
1075 | + shotwell-viewer.desktop.head \ |
1076 | + org.yorba.shotwell.gschema.xml \ |
1077 | +@@ -540,6 +541,8 @@ install: |
1078 | + mkdir -p $(DESTDIR)$(PREFIX)/bin |
1079 | + $(INSTALL_PROGRAM) $(PROGRAM) $(DESTDIR)$(PREFIX)/bin |
1080 | + $(INSTALL_PROGRAM) $(THUMBNAILER_BIN) $(DESTDIR)$(PREFIX)/bin |
1081 | ++ mkdir -p $(DESTDIR)$(PREFIX)/share/accounts/applications |
1082 | ++ $(INSTALL_DATA) misc/shotwell.application $(DESTDIR)$(PREFIX)/share/accounts/applications |
1083 | + mkdir -p $(DESTDIR)$(PREFIX)/share/shotwell/icons |
1084 | + $(INSTALL_DATA) icons/* $(DESTDIR)$(PREFIX)/share/shotwell/icons |
1085 | + mkdir -p $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps |
1086 | +diff --git a/misc/shotwell.application b/misc/shotwell.application |
1087 | +new file mode 100644 |
1088 | +index 0000000..b121198 |
1089 | +--- /dev/null |
1090 | ++++ b/misc/shotwell.application |
1091 | +@@ -0,0 +1,18 @@ |
1092 | ++<?xml version="1.0" encoding="UTF-8" ?> |
1093 | ++<application id="shotwell"> |
1094 | ++ <description>Shotwell</description> |
1095 | ++ <desktop-entry>shotwell.desktop</desktop-entry> |
1096 | ++ |
1097 | ++ <services> |
1098 | ++ <service id="picasa"> |
1099 | ++ <description>Publish your pictures to Picasa</description> |
1100 | ++ </service> |
1101 | ++ <service id="facebook-sharing"> |
1102 | ++ <description>Publish your pictures to Facebook</description> |
1103 | ++ </service> |
1104 | ++ <service id="flickr-sharing"> |
1105 | ++ <description>Publish your pictures to Flickr</description> |
1106 | ++ </service> |
1107 | ++ </services> |
1108 | ++ |
1109 | ++</application> |
1110 | +diff --git a/plugins/Makefile b/plugins/Makefile |
1111 | +index c622063..255e9cc 100644 |
1112 | +--- a/plugins/Makefile |
1113 | ++++ b/plugins/Makefile |
1114 | +@@ -4,7 +4,10 @@ include plugins.mk |
1115 | + DIST_FILES := \ |
1116 | + Makefile \ |
1117 | + Makefile.plugin.mk \ |
1118 | +- plugins.mk |
1119 | ++ plugins.mk \ |
1120 | ++ Accounts.vapi \ |
1121 | ++ Accounts.deps \ |
1122 | ++ Signon.vapi |
1123 | + |
1124 | + .PHONY: all |
1125 | + all: $(ALL_PLUGINS) |
1126 | +diff --git a/plugins/Makefile.plugin.mk b/plugins/Makefile.plugin.mk |
1127 | +index 51a0426..d82cc0f 100644 |
1128 | +--- a/plugins/Makefile.plugin.mk |
1129 | ++++ b/plugins/Makefile.plugin.mk |
1130 | +@@ -27,6 +27,8 @@ PKGS := $(shell sed ':a;N;$$!ba;s/\n/ /g' ../shotwell-plugin-dev-1.0.deps) $(PKG |
1131 | + # automatically include the shotwell-plugin-dev-1.0 package as a local dependency |
1132 | + EXT_PKGS := $(PKGS) |
1133 | + PKGS := shotwell-plugin-dev-1.0 $(PKGS) $(PLUGIN_PKGS) |
1134 | ++EXT_PKGS := libsignon-glib libaccounts-glib $(EXT_PKGS) |
1135 | ++PKGS := signon accounts $(PKGS) |
1136 | + |
1137 | + # automatically include the Resources.vala common file |
1138 | + SRC_FILES := ../common/Resources.vala $(SRC_FILES) |
1139 | +diff --git a/plugins/common/RESTSupport.vala b/plugins/common/RESTSupport.vala |
1140 | +index 12b4180..d4be236 100644 |
1141 | +--- a/plugins/common/RESTSupport.vala |
1142 | ++++ b/plugins/common/RESTSupport.vala |
1143 | +@@ -314,7 +314,7 @@ public class Transaction { |
1144 | + old_url = message.get_uri().to_string(false); |
1145 | + url_with_query = get_endpoint_url() + "?" + formdata_string; |
1146 | + message.set_uri(new Soup.URI(url_with_query)); |
1147 | +- } else { |
1148 | ++ } else if (get_method() == HttpMethod.POST) { |
1149 | + message.set_request("application/x-www-form-urlencoded", Soup.MemoryUse.COPY, |
1150 | + formdata_string.data); |
1151 | + } |
1152 | +diff --git a/plugins/common/accounts.vala b/plugins/common/accounts.vala |
1153 | +new file mode 100644 |
1154 | +index 0000000..d614be6 |
1155 | +--- /dev/null |
1156 | ++++ b/plugins/common/accounts.vala |
1157 | +@@ -0,0 +1,226 @@ |
1158 | ++/* Copyright 2009-2011 Yorba Foundation |
1159 | ++ * |
1160 | ++ * This software is licensed under the GNU Lesser General Public License |
1161 | ++ * (version 2.1 or later). See the COPYING file in this distribution. |
1162 | ++ */ |
1163 | ++ |
1164 | ++namespace Publishing.Accounts { |
1165 | ++ |
1166 | ++public class SharingAccount { |
1167 | ++ private Ag.AccountService account_service = null; |
1168 | ++ |
1169 | ++ public SharingAccount(Ag.AccountService account_service) { |
1170 | ++ this.account_service = account_service; |
1171 | ++ } |
1172 | ++ |
1173 | ++ public Signon.AuthSession create_auth_session() throws GLib.Error { |
1174 | ++ var auth_data = account_service.get_auth_data(); |
1175 | ++ |
1176 | ++ debug("Signon-id: %u", auth_data.get_credentials_id()); |
1177 | ++ |
1178 | ++ return new Signon.AuthSession(auth_data.get_credentials_id(), |
1179 | ++ auth_data.get_method()); |
1180 | ++ } |
1181 | ++ |
1182 | ++ public HashTable<string,Value?> get_session_parameters(out string mechanism) { |
1183 | ++ var auth_data = account_service.get_auth_data(); |
1184 | ++ mechanism = auth_data.get_mechanism(); |
1185 | ++ return auth_data.get_parameters(); |
1186 | ++ } |
1187 | ++} |
1188 | ++ |
1189 | ++public class SharingAccounts { |
1190 | ++ private static Ag.Manager manager = null; |
1191 | ++ private string provider_name; |
1192 | ++ private Ag.AccountService[] all_accounts; |
1193 | ++ |
1194 | ++ public SharingAccounts(string provider_name) { |
1195 | ++ if (manager == null) { |
1196 | ++ manager = new Ag.Manager.for_service_type("sharing"); |
1197 | ++ } |
1198 | ++ manager.enabled_event.connect(on_account_enabled); |
1199 | ++ |
1200 | ++ this.provider_name = provider_name; |
1201 | ++ all_accounts = get_accounts(); |
1202 | ++ } |
1203 | ++ |
1204 | ++ private void on_account_enabled(uint account_id) { |
1205 | ++ /* To keep the implementation simple, just rebuild the account |
1206 | ++ * list from scratch */ |
1207 | ++ all_accounts = get_accounts(); |
1208 | ++ } |
1209 | ++ |
1210 | ++ private Ag.AccountService[] get_accounts() { |
1211 | ++ GLib.List<Ag.AccountService> accounts = |
1212 | ++ manager.get_enabled_account_services(); |
1213 | ++ |
1214 | ++ Ag.AccountService[] list = {}; |
1215 | ++ |
1216 | ++ foreach (Ag.AccountService account_service in accounts) { |
1217 | ++ Ag.Account account = account_service.get_account(); |
1218 | ++ if (account.get_provider_name() == provider_name) { |
1219 | ++ list += account_service; |
1220 | ++ } |
1221 | ++ } |
1222 | ++ return list; |
1223 | ++ } |
1224 | ++ |
1225 | ++ public bool has_enabled_accounts() { |
1226 | ++ return all_accounts.length > 0; |
1227 | ++ } |
1228 | ++ |
1229 | ++ public string[] list_account_names() { |
1230 | ++ string[] names = {}; |
1231 | ++ foreach (Ag.AccountService account_service in all_accounts) { |
1232 | ++ names += account_service.get_account().get_display_name(); |
1233 | ++ } |
1234 | ++ return names; |
1235 | ++ } |
1236 | ++ |
1237 | ++ public SharingAccount? find_account(string? account_name) { |
1238 | ++ foreach (Ag.AccountService account_service in all_accounts) |
1239 | ++ if (account_service.get_account().get_display_name() == account_name) { |
1240 | ++ return new SharingAccount(account_service); |
1241 | ++ } |
1242 | ++ |
1243 | ++ return null; |
1244 | ++ } |
1245 | ++} |
1246 | ++ |
1247 | ++public abstract class UOAPublishingService : Object, Spit.Pluggable, Spit.Publishing.Service { |
1248 | ++ private SharingAccounts account_manager; |
1249 | ++ |
1250 | ++ public UOAPublishingService(string provider_name) { |
1251 | ++ account_manager = new SharingAccounts(provider_name); |
1252 | ++ } |
1253 | ++ |
1254 | ++ public virtual int get_pluggable_interface(int min_host_interface, int max_host_interface) { |
1255 | ++ return Spit.negotiate_interfaces(min_host_interface, max_host_interface, |
1256 | ++ Spit.Publishing.CURRENT_INTERFACE); |
1257 | ++ } |
1258 | ++ |
1259 | ++ public abstract unowned string get_id(); |
1260 | ++ |
1261 | ++ public abstract unowned string get_pluggable_name(); |
1262 | ++ |
1263 | ++ public abstract void get_info(ref Spit.PluggableInfo info); |
1264 | ++ |
1265 | ++ public virtual void activation(bool enabled) { |
1266 | ++ } |
1267 | ++ |
1268 | ++ public abstract Spit.Publishing.Publisher create_publisher(string? account_name, Spit.Publishing.PluginHost host); |
1269 | ++ |
1270 | ++ public abstract Spit.Publishing.Publisher.MediaType get_supported_media(); |
1271 | ++ |
1272 | ++ public SharingAccount? find_account(string? account_name) { |
1273 | ++ return account_manager.find_account(account_name); |
1274 | ++ } |
1275 | ++ |
1276 | ++ public bool is_enabled() { |
1277 | ++ return account_manager.has_enabled_accounts(); |
1278 | ++ } |
1279 | ++ |
1280 | ++ public string[] list_account_names() { |
1281 | ++ return account_manager.list_account_names(); |
1282 | ++ } |
1283 | ++} |
1284 | ++ |
1285 | ++public class UOAPublisherAuthenticator : Object { |
1286 | ++ private weak Spit.Publishing.PluginHost host = null; |
1287 | ++ private Signon.AuthSession auth_session = null; |
1288 | ++ private SharingAccount account = null; |
1289 | ++ private bool firstLoginAttempt = true; |
1290 | ++ private string welcome_message = null; |
1291 | ++ |
1292 | ++ public UOAPublisherAuthenticator(SharingAccount account, |
1293 | ++ Spit.Publishing.PluginHost host, |
1294 | ++ string welcome_message) |
1295 | ++ { |
1296 | ++ this.host = host; |
1297 | ++ this.account = account; |
1298 | ++ this.welcome_message = welcome_message; |
1299 | ++ } |
1300 | ++ |
1301 | ++ public signal void authenticated(owned HashTable<string,Value?> session_data); |
1302 | ++ |
1303 | ++ public void authenticate() { |
1304 | ++ debug("ACTION: authentication requested."); |
1305 | ++ |
1306 | ++ do_authentication(); |
1307 | ++ } |
1308 | ++ |
1309 | ++ public HashTable<string,Value?>? get_authentication_data() { |
1310 | ++ if (account == null) return null; |
1311 | ++ string mechanism = null; |
1312 | ++ return account.get_session_parameters(out mechanism); |
1313 | ++ } |
1314 | ++ |
1315 | ++ private void do_authentication() { |
1316 | ++ debug("ACTION: authenticating."); |
1317 | ++ |
1318 | ++ HashTable<string,Value?> data = null; |
1319 | ++ string mechanism = null; |
1320 | ++ |
1321 | ++ if (account != null) { |
1322 | ++ try { |
1323 | ++ auth_session = account.create_auth_session(); |
1324 | ++ data = account.get_session_parameters(out mechanism); |
1325 | ++ debug("Got account data"); |
1326 | ++ } catch (GLib.Error e) { |
1327 | ++ warning("EVENT: couldn't create session for account: %s", |
1328 | ++ e.message); |
1329 | ++ } |
1330 | ++ } |
1331 | ++ |
1332 | ++ if (data == null) { |
1333 | ++ warning ("No account authentication data"); |
1334 | ++ host.post_error(new Spit.Publishing.PublishingError.SERVICE_ERROR( |
1335 | ++ "Error while accessing the account")); |
1336 | ++ return; |
1337 | ++ } |
1338 | ++ |
1339 | ++ if (firstLoginAttempt) { |
1340 | ++ firstLoginAttempt = false; |
1341 | ++ data.insert("UiPolicy", Signon.SessionDataUiPolicy.NO_USER_INTERACTION); |
1342 | ++ } else { |
1343 | ++ var windowId = host.get_dialog_xid(); |
1344 | ++ if (windowId != 0) { |
1345 | ++ data.insert("WindowId", (uint)windowId); |
1346 | ++ } |
1347 | ++ } |
1348 | ++ |
1349 | ++ auth_session.process(data, mechanism, on_processed); |
1350 | ++ host.set_service_locked(true); |
1351 | ++ } |
1352 | ++ |
1353 | ++ private void on_processed(Signon.AuthSession self, owned HashTable<string,Value?>? session_data, GLib.Error error){ |
1354 | ++ host.set_service_locked(false); |
1355 | ++ if (error != null) { |
1356 | ++ debug("got error: %s", error.message); |
1357 | ++ if (error is Signon.Error.USER_INTERACTION) { |
1358 | ++ debug("User interaction!"); |
1359 | ++ do_show_service_welcome_pane(); |
1360 | ++ } else { |
1361 | ++ host.post_error(new Spit.Publishing.PublishingError.SERVICE_ERROR("Authentication failed")); |
1362 | ++ } |
1363 | ++ return; |
1364 | ++ } |
1365 | ++ |
1366 | ++ authenticated(session_data); |
1367 | ++ } |
1368 | ++ |
1369 | ++ private void do_show_service_welcome_pane() { |
1370 | ++ debug("ACTION: showing service welcome pane."); |
1371 | ++ |
1372 | ++ host.install_welcome_pane(welcome_message, on_service_welcome_login); |
1373 | ++ } |
1374 | ++ |
1375 | ++ private void on_service_welcome_login() { |
1376 | ++ debug("EVENT: user clicked 'Login' in welcome pane."); |
1377 | ++ |
1378 | ++ do_authentication(); |
1379 | ++ } |
1380 | ++} |
1381 | ++ |
1382 | ++} |
1383 | ++ |
1384 | +diff --git a/plugins/shotwell-publishing-extras/YandexPublishing.vala b/plugins/shotwell-publishing-extras/YandexPublishing.vala |
1385 | +index 1370690..760a8f3 100644 |
1386 | +--- a/plugins/shotwell-publishing-extras/YandexPublishing.vala |
1387 | ++++ b/plugins/shotwell-publishing-extras/YandexPublishing.vala |
1388 | +@@ -30,7 +30,7 @@ public class YandexService : Object, Spit.Pluggable, Spit.Publishing.Service { |
1389 | + info.license = Resources.LICENSE; |
1390 | + } |
1391 | + |
1392 | +- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) { |
1393 | ++ public Spit.Publishing.Publisher create_publisher(string? account, Spit.Publishing.PluginHost host) { |
1394 | + return new Publishing.Yandex.YandexPublisher(this, host); |
1395 | + } |
1396 | + |
1397 | +diff --git a/plugins/shotwell-publishing/FacebookPublishing.vala b/plugins/shotwell-publishing/FacebookPublishing.vala |
1398 | +index fa9d8f2..bd3cd08 100644 |
1399 | +--- a/plugins/shotwell-publishing/FacebookPublishing.vala |
1400 | ++++ b/plugins/shotwell-publishing/FacebookPublishing.vala |
1401 | +@@ -4,30 +4,28 @@ |
1402 | + * (version 2.1 or later). See the COPYING file in this distribution. |
1403 | + */ |
1404 | + |
1405 | +-public class FacebookService : Object, Spit.Pluggable, Spit.Publishing.Service { |
1406 | ++using Publishing.Accounts; |
1407 | ++ |
1408 | ++public class FacebookService : UOAPublishingService, Spit.Pluggable, Spit.Publishing.Service { |
1409 | + private const string ICON_FILENAME = "facebook.png"; |
1410 | + |
1411 | + private static Gdk.Pixbuf[] icon_pixbuf_set = null; |
1412 | + |
1413 | + public FacebookService(GLib.File resource_directory) { |
1414 | ++ base("facebook"); |
1415 | + if (icon_pixbuf_set == null) |
1416 | + icon_pixbuf_set = Resources.load_icon_set(resource_directory.get_child(ICON_FILENAME)); |
1417 | + } |
1418 | + |
1419 | +- public int get_pluggable_interface(int min_host_interface, int max_host_interface) { |
1420 | +- return Spit.negotiate_interfaces(min_host_interface, max_host_interface, |
1421 | +- Spit.Publishing.CURRENT_INTERFACE); |
1422 | +- } |
1423 | +- |
1424 | +- public unowned string get_id() { |
1425 | ++ public override unowned string get_id() { |
1426 | + return "org.yorba.shotwell.publishing.facebook"; |
1427 | + } |
1428 | + |
1429 | +- public unowned string get_pluggable_name() { |
1430 | ++ public override unowned string get_pluggable_name() { |
1431 | + return "Facebook"; |
1432 | + } |
1433 | + |
1434 | +- public void get_info(ref Spit.PluggableInfo info) { |
1435 | ++ public override void get_info(ref Spit.PluggableInfo info) { |
1436 | + info.authors = "Lucas Beeler"; |
1437 | + info.copyright = _("Copyright 2009-2012 Yorba Foundation"); |
1438 | + info.translators = Resources.TRANSLATORS; |
1439 | +@@ -39,14 +37,12 @@ public class FacebookService : Object, Spit.Pluggable, Spit.Publishing.Service { |
1440 | + info.icons = icon_pixbuf_set; |
1441 | + } |
1442 | + |
1443 | +- public void activation(bool enabled) { |
1444 | ++ public override Spit.Publishing.Publisher create_publisher(string? account_name, Spit.Publishing.PluginHost host) { |
1445 | ++ SharingAccount account = find_account(account_name); |
1446 | ++ return new Publishing.Facebook.FacebookPublisher(this, account, host); |
1447 | + } |
1448 | + |
1449 | +- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) { |
1450 | +- return new Publishing.Facebook.FacebookPublisher(this, host); |
1451 | +- } |
1452 | +- |
1453 | +- public Spit.Publishing.Publisher.MediaType get_supported_media() { |
1454 | ++ public override Spit.Publishing.Publisher.MediaType get_supported_media() { |
1455 | + return (Spit.Publishing.Publisher.MediaType.PHOTO | |
1456 | + Spit.Publishing.Publisher.MediaType.VIDEO); |
1457 | + } |
1458 | +@@ -66,8 +62,6 @@ internal const string PHOTO_ENDPOINT_URL = "https://api.facebook.com/restserver. |
1459 | + internal const string VIDEO_ENDPOINT_URL = "https://api-video.facebook.com/restserver.php"; |
1460 | + internal const string SERVICE_WELCOME_MESSAGE = |
1461 | + _("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."); |
1462 | +-internal const string RESTART_ERROR_MESSAGE = |
1463 | +- _("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."); |
1464 | + // as of mid-November 2010, the privacy the simple string "SELF" is no longer a valid |
1465 | + // privacy value; "SELF" must be simulated by a "CUSTOM" setting; see the discussion |
1466 | + // http://forum.developers.facebook.net/viewtopic.php?pid=289287 |
1467 | +@@ -163,19 +157,23 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object { |
1468 | + private int publish_to_album = NO_ALBUM; |
1469 | + private weak Spit.Publishing.PluginHost host = null; |
1470 | + private FacebookRESTSession session = null; |
1471 | +- private WebAuthenticationPane web_auth_pane = null; |
1472 | + private Spit.Publishing.ProgressCallback progress_reporter = null; |
1473 | + private weak Spit.Publishing.Service service = null; |
1474 | + private bool strip_metadata = false; |
1475 | + private bool running = false; |
1476 | ++ private UOAPublisherAuthenticator authenticator = null; |
1477 | + |
1478 | + private Resolution target_resolution = Resolution.HIGH; |
1479 | + |
1480 | + public FacebookPublisher(Spit.Publishing.Service service, |
1481 | ++ SharingAccount account, |
1482 | + Spit.Publishing.PluginHost host) { |
1483 | + debug("FacebookPublisher instantiated."); |
1484 | + this.service = service; |
1485 | + this.host = host; |
1486 | ++ authenticator = new UOAPublisherAuthenticator(account, host, |
1487 | ++ SERVICE_WELCOME_MESSAGE); |
1488 | ++ authenticator.authenticated.connect(on_authenticator_authenticated); |
1489 | + } |
1490 | + |
1491 | + private bool is_running() { |
1492 | +@@ -190,49 +188,10 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object { |
1493 | + return NO_ALBUM; |
1494 | + } |
1495 | + |
1496 | +- private bool is_persistent_session_valid() { |
1497 | +- string? access_token = get_persistent_access_token(); |
1498 | +- string? uid = get_persistent_uid(); |
1499 | +- string? user_name = get_persistent_user_name(); |
1500 | +- |
1501 | +- bool valid = ((access_token != null) && (uid != null) && (user_name != null)); |
1502 | +- |
1503 | +- if (valid) |
1504 | +- debug("existing Facebook session for user = '%s' found in configuration database; using it.", user_name); |
1505 | +- else |
1506 | +- debug("no persisted Facebook session exists."); |
1507 | +- |
1508 | +- return valid; |
1509 | +- } |
1510 | +- |
1511 | +- private string? get_persistent_access_token() { |
1512 | +- return host.get_config_string("access_token", null); |
1513 | +- } |
1514 | +- |
1515 | +- private string? get_persistent_uid() { |
1516 | +- return host.get_config_string("uid", null); |
1517 | +- } |
1518 | +- |
1519 | +- private string? get_persistent_user_name() { |
1520 | +- return host.get_config_string("user_name", null); |
1521 | +- } |
1522 | +- |
1523 | + private bool get_persistent_strip_metadata() { |
1524 | + return host.get_config_bool("strip_metadata", false); |
1525 | + } |
1526 | + |
1527 | +- private void set_persistent_access_token(string access_token) { |
1528 | +- host.set_config_string("access_token", access_token); |
1529 | +- } |
1530 | +- |
1531 | +- private void set_persistent_uid(string uid) { |
1532 | +- host.set_config_string("uid", uid); |
1533 | +- } |
1534 | +- |
1535 | +- private void set_persistent_user_name(string user_name) { |
1536 | +- host.set_config_string("user_name", user_name); |
1537 | +- } |
1538 | +- |
1539 | + private void set_persistent_strip_metadata(bool strip_metadata) { |
1540 | + host.set_config_bool("strip_metadata", strip_metadata); |
1541 | + } |
1542 | +@@ -247,39 +206,6 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object { |
1543 | + host.set_config_int("default_size", size); |
1544 | + } |
1545 | + |
1546 | +- private void invalidate_persistent_session() { |
1547 | +- debug("invalidating persisted Facebook session."); |
1548 | +- |
1549 | +- set_persistent_access_token(""); |
1550 | +- set_persistent_uid(""); |
1551 | +- set_persistent_user_name(""); |
1552 | +- } |
1553 | +- |
1554 | +- private void do_show_service_welcome_pane() { |
1555 | +- debug("ACTION: showing service welcome pane."); |
1556 | +- |
1557 | +- host.install_welcome_pane(SERVICE_WELCOME_MESSAGE, on_login_clicked); |
1558 | +- host.set_service_locked(false); |
1559 | +- } |
1560 | +- |
1561 | +- private void do_test_connection_to_endpoint() { |
1562 | +- debug("ACTION: testing connection to Facebook endpoint."); |
1563 | +- host.set_service_locked(true); |
1564 | +- |
1565 | +- host.install_static_message_pane(_("Testing connection to Facebook...")); |
1566 | +- |
1567 | +- FacebookEndpointTestTransaction txn = new FacebookEndpointTestTransaction(session); |
1568 | +- txn.completed.connect(on_endpoint_test_completed); |
1569 | +- txn.network_error.connect(on_endpoint_test_error); |
1570 | +- |
1571 | +- try { |
1572 | +- txn.execute(); |
1573 | +- } catch (Spit.Publishing.PublishingError err) { |
1574 | +- if (is_running()) |
1575 | +- host.post_error(err); |
1576 | +- } |
1577 | +- } |
1578 | +- |
1579 | + private void do_fetch_album_descriptions() { |
1580 | + debug("ACTION: fetching album descriptions from remote endpoint."); |
1581 | + |
1582 | +@@ -387,7 +313,6 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object { |
1583 | + PublishingOptionsPane publishing_options_pane = new PublishingOptionsPane( |
1584 | + session.get_user_name(), albums, host.get_publishable_media_type(), this, builder, |
1585 | + get_persistent_strip_metadata()); |
1586 | +- publishing_options_pane.logout.connect(on_publishing_options_pane_logout); |
1587 | + publishing_options_pane.publish.connect(on_publishing_options_pane_publish); |
1588 | + host.install_dialog_pane(publishing_options_pane, |
1589 | + Spit.Publishing.PluginHost.ButtonMode.CANCEL); |
1590 | +@@ -396,51 +321,20 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object { |
1591 | + private void do_logout() { |
1592 | + debug("ACTION: clearing persistent session information and restaring interaction."); |
1593 | + |
1594 | +- invalidate_persistent_session(); |
1595 | +- |
1596 | + running = false; |
1597 | + start(); |
1598 | + } |
1599 | + |
1600 | +- private void do_hosted_web_authentication() { |
1601 | +- debug("ACTION: doing hosted web authentication."); |
1602 | +- |
1603 | +- host.set_service_locked(false); |
1604 | +- |
1605 | +- web_auth_pane = new WebAuthenticationPane(); |
1606 | +- web_auth_pane.login_succeeded.connect(on_web_auth_pane_login_succeeded); |
1607 | +- web_auth_pane.login_failed.connect(on_web_auth_pane_login_failed); |
1608 | +- |
1609 | +- host.install_dialog_pane(web_auth_pane, |
1610 | +- Spit.Publishing.PluginHost.ButtonMode.CANCEL); |
1611 | +- } |
1612 | +- |
1613 | +- private void do_authenticate_session(string success_url) { |
1614 | +- debug("ACTION: preparing to extract session information encoded in url = '%s'", |
1615 | +- success_url); |
1616 | +- |
1617 | ++ public void on_authenticator_authenticated(owned HashTable<string,Value?> session_data) { |
1618 | + host.set_service_locked(true); |
1619 | + host.install_account_fetch_wait_pane(); |
1620 | + |
1621 | + session.authenticated.connect(on_session_authenticated); |
1622 | + session.authentication_failed.connect(on_session_authentication_failed); |
1623 | + |
1624 | +- try { |
1625 | +- session.authenticate_from_uri(success_url); |
1626 | +- } catch (Spit.Publishing.PublishingError err) { |
1627 | +- // only post an error if we're running; errors tend to come in groups, so it's possible |
1628 | +- // another error has already posted and caused us to stop |
1629 | +- if (is_running()) |
1630 | +- host.post_error(err); |
1631 | +- } |
1632 | +- } |
1633 | +- |
1634 | +- private void do_save_session_information() { |
1635 | +- debug("ACTION: saving session information to configuration system."); |
1636 | +- |
1637 | +- set_persistent_access_token(session.get_access_token()); |
1638 | +- set_persistent_uid(session.get_user_id()); |
1639 | +- set_persistent_user_name(session.get_user_name()); |
1640 | ++ string token = session_data.lookup("AccessToken").get_string(); |
1641 | ++ debug("Access Token: %s", token); |
1642 | ++ session.authenticate_with_parameters(token, null, null); |
1643 | + } |
1644 | + |
1645 | + private void do_upload(bool strip_metadata) { |
1646 | +@@ -528,64 +422,6 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object { |
1647 | + host.install_success_pane(); |
1648 | + } |
1649 | + |
1650 | +- private void on_login_clicked() { |
1651 | +- if (!is_running()) |
1652 | +- return; |
1653 | +- |
1654 | +- debug("EVENT: user clicked 'Login' on welcome pane."); |
1655 | +- |
1656 | +- do_test_connection_to_endpoint(); |
1657 | +- } |
1658 | +- |
1659 | +- private void on_endpoint_test_completed(FacebookRESTTransaction txn) { |
1660 | +- txn.completed.disconnect(on_endpoint_test_completed); |
1661 | +- txn.network_error.disconnect(on_endpoint_test_error); |
1662 | +- |
1663 | +- if (!is_running()) |
1664 | +- return; |
1665 | +- |
1666 | +- debug("EVENT: endpoint test transaction detected that the Facebook endpoint is alive."); |
1667 | +- |
1668 | +- do_hosted_web_authentication(); |
1669 | +- } |
1670 | +- |
1671 | +- private void on_endpoint_test_error(FacebookRESTTransaction bad_txn, |
1672 | +- Spit.Publishing.PublishingError err) { |
1673 | +- bad_txn.completed.disconnect(on_endpoint_test_completed); |
1674 | +- bad_txn.network_error.disconnect(on_endpoint_test_error); |
1675 | +- |
1676 | +- if (!is_running()) |
1677 | +- return; |
1678 | +- |
1679 | +- debug("EVENT: endpoint test transaction failed to detect a connection to the Facebook endpoint"); |
1680 | +- |
1681 | +- host.post_error(err); |
1682 | +- } |
1683 | +- |
1684 | +- private void on_web_auth_pane_login_succeeded(string success_url) { |
1685 | +- if (!is_running()) |
1686 | +- return; |
1687 | +- |
1688 | +- debug("EVENT: hosted web login succeeded."); |
1689 | +- |
1690 | +- do_authenticate_session(success_url); |
1691 | +- } |
1692 | +- |
1693 | +- private void on_web_auth_pane_login_failed() { |
1694 | +- if (!is_running()) |
1695 | +- return; |
1696 | +- |
1697 | +- debug("EVENT: hosted web login failed."); |
1698 | +- |
1699 | +- // In this case, "failed" doesn't mean that the user didn't enter the right username and |
1700 | +- // password -- Facebook handles that case inside the Facebook Connect web control. Instead, |
1701 | +- // it means that no session was initiated in response to our login request. The only |
1702 | +- // way this happens is if the user clicks the "Cancel" button that appears inside |
1703 | +- // the web control. In this case, the correct behavior is to return the user to the |
1704 | +- // service welcome pane so that they can start the web interaction again. |
1705 | +- do_show_service_welcome_pane(); |
1706 | +- } |
1707 | +- |
1708 | + private void on_session_authenticated() { |
1709 | + if (!is_running()) |
1710 | + return; |
1711 | +@@ -593,7 +429,6 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object { |
1712 | + assert(session.is_authenticated()); |
1713 | + debug("EVENT: an authenticated session has become available."); |
1714 | + |
1715 | +- do_save_session_information(); |
1716 | + do_fetch_album_descriptions(); |
1717 | + } |
1718 | + |
1719 | +@@ -638,15 +473,6 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object { |
1720 | + do_show_publishing_options_pane(); |
1721 | + } |
1722 | + |
1723 | +- public void on_publishing_options_pane_logout() { |
1724 | +- if (!is_running()) |
1725 | +- return; |
1726 | +- |
1727 | +- debug("EVENT: user clicked 'Logout' in publishing options pane."); |
1728 | +- |
1729 | +- do_logout(); |
1730 | +- } |
1731 | +- |
1732 | + public void on_publishing_options_pane_publish(string? target_album, string privacy_setting, |
1733 | + Resolution target_resolution, bool strip_metadata) { |
1734 | + if (!is_running()) |
1735 | +@@ -762,26 +588,8 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object { |
1736 | + albums = null; |
1737 | + publish_to_album = NO_ALBUM; |
1738 | + |
1739 | +- // determine whether a user is logged in; if so, then show the publishing options pane |
1740 | +- // for that user; otherwise, show the welcome pane |
1741 | +- if (is_persistent_session_valid()) { |
1742 | +- // if valid session information has been saved in the configuration system, build |
1743 | +- // a Session object and pre-authenticate it with the saved information, then simulate an |
1744 | +- // on_session_authenticated event to drive the rest of the interaction |
1745 | +- session = new FacebookRESTSession(PHOTO_ENDPOINT_URL, USER_AGENT); |
1746 | +- session.authenticate_with_parameters(get_persistent_access_token(), |
1747 | +- get_persistent_uid(), get_persistent_user_name()); |
1748 | +- on_session_authenticated(); |
1749 | +- } else { |
1750 | +- if (WebAuthenticationPane.is_cache_dirty()) { |
1751 | +- host.set_service_locked(false); |
1752 | +- host.install_static_message_pane(RESTART_ERROR_MESSAGE, |
1753 | +- Spit.Publishing.PluginHost.ButtonMode.CANCEL); |
1754 | +- } else { |
1755 | +- session = new FacebookRESTSession(PHOTO_ENDPOINT_URL, USER_AGENT); |
1756 | +- do_show_service_welcome_pane(); |
1757 | +- } |
1758 | +- } |
1759 | ++ session = new FacebookRESTSession(PHOTO_ENDPOINT_URL, USER_AGENT); |
1760 | ++ authenticator.authenticate(); |
1761 | + } |
1762 | + |
1763 | + public void stop() { |
1764 | +@@ -909,39 +717,14 @@ internal class FacebookRESTSession { |
1765 | + return (access_token != null && uid != null && user_name != null); |
1766 | + } |
1767 | + |
1768 | +- public void authenticate_with_parameters(string access_token, string uid, string user_name) { |
1769 | +- this.access_token = access_token; |
1770 | +- this.uid = uid; |
1771 | +- this.user_name = user_name; |
1772 | +- } |
1773 | +- |
1774 | +- public void authenticate_from_uri(string good_login_uri) throws Spit.Publishing.PublishingError { |
1775 | +- // the raw uri is percent-encoded, so decode it |
1776 | +- string decoded_uri = Soup.URI.decode(good_login_uri); |
1777 | +- |
1778 | +- // locate the access token within the URI |
1779 | +- string? access_token = null; |
1780 | +- int index = decoded_uri.index_of("#access_token="); |
1781 | +- if (index >= 0) |
1782 | +- access_token = decoded_uri[index:decoded_uri.length]; |
1783 | +- if (access_token == null) |
1784 | +- throw new Spit.Publishing.PublishingError.MALFORMED_RESPONSE("Server redirect URL contained no access token"); |
1785 | +- |
1786 | +- // remove any trailing parameters from the session description string |
1787 | +- string? trailing_params = null; |
1788 | +- index = access_token.index_of_char('&'); |
1789 | +- if (index >= 0) |
1790 | +- trailing_params = access_token[index:access_token.length]; |
1791 | +- if (trailing_params != null) |
1792 | +- access_token = access_token.replace(trailing_params, ""); |
1793 | +- |
1794 | +- // remove the key from the session description string |
1795 | +- access_token = access_token.replace("#access_token=", ""); |
1796 | +- |
1797 | +- // we've got an access token! |
1798 | ++ public void authenticate_with_parameters(string access_token, string? uid, string? user_name) { |
1799 | + this.access_token = access_token; |
1800 | +- |
1801 | +- do_user_id_fetch_transaction(); |
1802 | ++ if (uid == null) { |
1803 | ++ do_user_id_fetch_transaction(); |
1804 | ++ } else { |
1805 | ++ this.uid = uid; |
1806 | ++ this.user_name = user_name; |
1807 | ++ } |
1808 | + } |
1809 | + |
1810 | + public string get_endpoint_url() { |
1811 | +@@ -1335,190 +1118,6 @@ internal class FacebookCreateAlbumTransaction : FacebookRESTTransaction { |
1812 | + } |
1813 | + } |
1814 | + |
1815 | +-internal class WebAuthenticationPane : Spit.Publishing.DialogPane, Object { |
1816 | +- private WebKit.WebView webview = null; |
1817 | +- private Gtk.Box pane_widget = null; |
1818 | +- private Gtk.ScrolledWindow webview_frame = null; |
1819 | +- private static bool cache_dirty = false; |
1820 | +- |
1821 | +- public signal void login_succeeded(string success_url); |
1822 | +- public signal void login_failed(); |
1823 | +- |
1824 | +- public WebAuthenticationPane() { |
1825 | +- pane_widget = new Gtk.Box(Gtk.Orientation.VERTICAL, 0); |
1826 | +- |
1827 | +- webview_frame = new Gtk.ScrolledWindow(null, null); |
1828 | +- webview_frame.set_shadow_type(Gtk.ShadowType.ETCHED_IN); |
1829 | +- webview_frame.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); |
1830 | +- |
1831 | +- webview = new WebKit.WebView(); |
1832 | +- webview.get_settings().enable_plugins = false; |
1833 | +- webview.get_settings().enable_default_context_menu = false; |
1834 | +- |
1835 | +- webview.load_finished.connect(on_page_load); |
1836 | +- webview.load_started.connect(on_load_started); |
1837 | +- |
1838 | +- webview_frame.add(webview); |
1839 | +- pane_widget.pack_start(webview_frame, true, true, 0); |
1840 | +- } |
1841 | +- |
1842 | +- private class LocaleLookup { |
1843 | +- public string prefix; |
1844 | +- public string translation; |
1845 | +- public string? exception_code; |
1846 | +- public string? exception_translation; |
1847 | +- public string? exception_code_2; |
1848 | +- public string? exception_translation_2; |
1849 | +- |
1850 | +- public LocaleLookup(string prefix, string translation, string? exception_code = null, |
1851 | +- string? exception_translation = null, string? exception_code_2 = null, |
1852 | +- string? exception_translation_2 = null) { |
1853 | +- this.prefix = prefix; |
1854 | +- this.translation = translation; |
1855 | +- this.exception_code = exception_code; |
1856 | +- this.exception_translation = exception_translation; |
1857 | +- this.exception_code_2 = exception_code_2; |
1858 | +- this.exception_translation_2 = exception_translation_2; |
1859 | +- } |
1860 | +- |
1861 | +- } |
1862 | +- |
1863 | +- private LocaleLookup[] locale_lookup_table = { |
1864 | +- new LocaleLookup( "es", "es-la", "ES", "es-es" ), |
1865 | +- new LocaleLookup( "en", "en-gb", "US", "en-us" ), |
1866 | +- new LocaleLookup( "fr", "fr-fr", "CA", "fr-ca" ), |
1867 | +- new LocaleLookup( "pt", "pt-br", "PT", "pt-pt" ), |
1868 | +- new LocaleLookup( "zh", "zh-cn", "HK", "zh-hk", "TW", "zh-tw" ), |
1869 | +- new LocaleLookup( "af", "af-za" ), |
1870 | +- new LocaleLookup( "ar", "ar-ar" ), |
1871 | +- new LocaleLookup( "nb", "nb-no" ), |
1872 | +- new LocaleLookup( "no", "nb-no" ), |
1873 | +- new LocaleLookup( "id", "id-id" ), |
1874 | +- new LocaleLookup( "ms", "ms-my" ), |
1875 | +- new LocaleLookup( "ca", "ca-es" ), |
1876 | +- new LocaleLookup( "cs", "cs-cz" ), |
1877 | +- new LocaleLookup( "cy", "cy-gb" ), |
1878 | +- new LocaleLookup( "da", "da-dk" ), |
1879 | +- new LocaleLookup( "de", "de-de" ), |
1880 | +- new LocaleLookup( "tl", "tl-ph" ), |
1881 | +- new LocaleLookup( "ko", "ko-kr" ), |
1882 | +- new LocaleLookup( "hr", "hr-hr" ), |
1883 | +- new LocaleLookup( "it", "it-it" ), |
1884 | +- new LocaleLookup( "lt", "lt-lt" ), |
1885 | +- new LocaleLookup( "hu", "hu-hu" ), |
1886 | +- new LocaleLookup( "nl", "nl-nl" ), |
1887 | +- new LocaleLookup( "ja", "ja-jp" ), |
1888 | +- new LocaleLookup( "nb", "nb-no" ), |
1889 | +- new LocaleLookup( "no", "nb-no" ), |
1890 | +- new LocaleLookup( "pl", "pl-pl" ), |
1891 | +- new LocaleLookup( "ro", "ro-ro" ), |
1892 | +- new LocaleLookup( "ru", "ru-ru" ), |
1893 | +- new LocaleLookup( "sk", "sk-sk" ), |
1894 | +- new LocaleLookup( "sl", "sl-si" ), |
1895 | +- new LocaleLookup( "sv", "sv-se" ), |
1896 | +- new LocaleLookup( "th", "th-th" ), |
1897 | +- new LocaleLookup( "vi", "vi-vn" ), |
1898 | +- new LocaleLookup( "tr", "tr-tr" ), |
1899 | +- new LocaleLookup( "el", "el-gr" ), |
1900 | +- new LocaleLookup( "bg", "bg-bg" ), |
1901 | +- new LocaleLookup( "sr", "sr-rs" ), |
1902 | +- new LocaleLookup( "he", "he-il" ), |
1903 | +- new LocaleLookup( "hi", "hi-in" ), |
1904 | +- new LocaleLookup( "bn", "bn-in" ), |
1905 | +- new LocaleLookup( "pa", "pa-in" ), |
1906 | +- new LocaleLookup( "ta", "ta-in" ), |
1907 | +- new LocaleLookup( "te", "te-in" ), |
1908 | +- new LocaleLookup( "ml", "ml-in" ) |
1909 | +- }; |
1910 | +- |
1911 | +- private string get_system_locale_as_facebook_locale() { |
1912 | +- unowned string? raw_system_locale = Intl.setlocale(LocaleCategory.ALL, ""); |
1913 | +- if (raw_system_locale == null || raw_system_locale == "") |
1914 | +- return "www"; |
1915 | +- |
1916 | +- string system_locale = raw_system_locale.split(".")[0]; |
1917 | +- |
1918 | +- foreach (LocaleLookup locale_lookup in locale_lookup_table) { |
1919 | +- if (!system_locale.has_prefix(locale_lookup.prefix)) |
1920 | +- continue; |
1921 | +- |
1922 | +- if (locale_lookup.exception_code != null) { |
1923 | +- assert(locale_lookup.exception_translation != null); |
1924 | +- |
1925 | +- if (system_locale.contains(locale_lookup.exception_code)) |
1926 | +- return locale_lookup.exception_translation; |
1927 | +- } |
1928 | +- |
1929 | +- if (locale_lookup.exception_code_2 != null) { |
1930 | +- assert(locale_lookup.exception_translation_2 != null); |
1931 | +- |
1932 | +- if (system_locale.contains(locale_lookup.exception_code_2)) |
1933 | +- return locale_lookup.exception_translation_2; |
1934 | +- } |
1935 | +- |
1936 | +- return locale_lookup.translation; |
1937 | +- } |
1938 | +- |
1939 | +- // default |
1940 | +- return "www"; |
1941 | +- } |
1942 | +- |
1943 | +- private string get_login_url() { |
1944 | +- string facebook_locale = get_system_locale_as_facebook_locale(); |
1945 | +- |
1946 | +- return "https://%s.facebook.com/dialog/oauth?client_id=%s&redirect_uri=https://www.facebook.com/connect/login_success.html&scope=offline_access,publish_stream,user_photos,user_videos&response_type=token".printf(facebook_locale, APPLICATION_ID); |
1947 | +- } |
1948 | +- |
1949 | +- private void on_page_load(WebKit.WebFrame origin_frame) { |
1950 | +- pane_widget.get_window().set_cursor(new Gdk.Cursor(Gdk.CursorType.LEFT_PTR)); |
1951 | +- |
1952 | +- string loaded_url = origin_frame.get_uri().dup(); |
1953 | +- |
1954 | +- // strip parameters from the loaded url |
1955 | +- if (loaded_url.contains("?")) { |
1956 | +- int index = loaded_url.index_of_char('?'); |
1957 | +- string params = loaded_url[index:loaded_url.length]; |
1958 | +- loaded_url = loaded_url.replace(params, ""); |
1959 | +- } |
1960 | +- |
1961 | +- // were we redirected to the facebook login success page? |
1962 | +- if (loaded_url.contains("login_success")) { |
1963 | +- cache_dirty = true; |
1964 | +- login_succeeded(origin_frame.get_uri()); |
1965 | +- return; |
1966 | +- } |
1967 | +- |
1968 | +- // were we redirected to the login total failure page? |
1969 | +- if (loaded_url.contains("login_failure")) { |
1970 | +- login_failed(); |
1971 | +- return; |
1972 | +- } |
1973 | +- } |
1974 | +- |
1975 | +- private void on_load_started(WebKit.WebFrame frame) { |
1976 | +- pane_widget.get_window().set_cursor(new Gdk.Cursor(Gdk.CursorType.WATCH)); |
1977 | +- } |
1978 | +- |
1979 | +- public static bool is_cache_dirty() { |
1980 | +- return cache_dirty; |
1981 | +- } |
1982 | +- |
1983 | +- public Gtk.Widget get_widget() { |
1984 | +- return pane_widget; |
1985 | +- } |
1986 | +- |
1987 | +- public Spit.Publishing.DialogPane.GeometryOptions get_preferred_geometry() { |
1988 | +- return Spit.Publishing.DialogPane.GeometryOptions.COLOSSAL_SIZE; |
1989 | +- } |
1990 | +- |
1991 | +- public void on_pane_installed() { |
1992 | +- webview.open(get_login_url()); |
1993 | +- } |
1994 | +- |
1995 | +- public void on_pane_uninstalled() { |
1996 | +- } |
1997 | +-} |
1998 | +- |
1999 | + internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
2000 | + private Gtk.Builder builder; |
2001 | + private Gtk.Box pane_widget = null; |
2002 | +@@ -1529,7 +1128,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
2003 | + private Gtk.Entry new_album_entry = null; |
2004 | + private Gtk.CheckButton strip_metadata_check = null; |
2005 | + private Gtk.Button publish_button = null; |
2006 | +- private Gtk.Button logout_button = null; |
2007 | + private Gtk.Label how_to_label = null; |
2008 | + private FacebookAlbum[] albums = null; |
2009 | + private FacebookPublisher publisher = null; |
2010 | +@@ -1546,7 +1144,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
2011 | + private const int CONTENT_GROUP_SPACING = 32; |
2012 | + private const int STANDARD_ACTION_BUTTON_WIDTH = 128; |
2013 | + |
2014 | +- public signal void logout(); |
2015 | + public signal void publish(string? target_album, string privacy_setting, Resolution target_resolution, bool strip_metadata); |
2016 | + |
2017 | + private class PrivacyDescription { |
2018 | +@@ -1586,7 +1183,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
2019 | + existing_albums_combo = (Gtk.ComboBoxText) this.builder.get_object("existing_albums_combo"); |
2020 | + visibility_combo = (Gtk.ComboBoxText) this.builder.get_object("visibility_combo"); |
2021 | + publish_button = (Gtk.Button) this.builder.get_object("publish_button"); |
2022 | +- logout_button = (Gtk.Button) this.builder.get_object("logout_button"); |
2023 | + new_album_entry = (Gtk.Entry) this.builder.get_object("new_album_entry"); |
2024 | + resolution_combo = (Gtk.ComboBoxText) this.builder.get_object("resolution_combo"); |
2025 | + how_to_label = (Gtk.Label) this.builder.get_object("how_to_label"); |
2026 | +@@ -1605,7 +1201,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
2027 | + visibility_combo.set_active(0); |
2028 | + |
2029 | + publish_button.clicked.connect(on_publish_button_clicked); |
2030 | +- logout_button.clicked.connect(on_logout_button_clicked); |
2031 | + |
2032 | + // Ticket #2916 - if the user is uploading photographs, allow |
2033 | + // them to choose what resolution they should be uploaded at. |
2034 | +@@ -1669,10 +1264,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
2035 | + publisher.set_persistent_default_size(resolution_combo.get_active()); |
2036 | + } |
2037 | + |
2038 | +- private void on_logout_button_clicked() { |
2039 | +- logout(); |
2040 | +- } |
2041 | +- |
2042 | + private void on_publish_button_clicked() { |
2043 | + string album_name; |
2044 | + string privacy_setting = privacy_descriptions[visibility_combo.get_active()].privacy_setting; |
2045 | +@@ -1747,10 +1338,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
2046 | + publish_button.grab_focus(); |
2047 | + } |
2048 | + |
2049 | +- private void notify_logout() { |
2050 | +- logout(); |
2051 | +- } |
2052 | +- |
2053 | + private void notify_publish(string? target_album, string privacy_setting, Resolution target_resolution) { |
2054 | + publish(target_album, privacy_setting, target_resolution, strip_metadata_check.get_active()); |
2055 | + } |
2056 | +@@ -1764,14 +1351,12 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
2057 | + } |
2058 | + |
2059 | + public void on_pane_installed() { |
2060 | +- logout.connect(notify_logout); |
2061 | + publish.connect(notify_publish); |
2062 | + |
2063 | + installed(); |
2064 | + } |
2065 | + |
2066 | + public void on_pane_uninstalled() { |
2067 | +- logout.disconnect(notify_logout); |
2068 | + publish.disconnect(notify_publish); |
2069 | + } |
2070 | + } |
2071 | +diff --git a/plugins/shotwell-publishing/FlickrPublishing.vala b/plugins/shotwell-publishing/FlickrPublishing.vala |
2072 | +index a6f8b45..abaf0b2 100644 |
2073 | +--- a/plugins/shotwell-publishing/FlickrPublishing.vala |
2074 | ++++ b/plugins/shotwell-publishing/FlickrPublishing.vala |
2075 | +@@ -4,32 +4,30 @@ |
2076 | + * (version 2.1 or later). See the COPYING file in this distribution. |
2077 | + */ |
2078 | + |
2079 | ++using Publishing.Accounts; |
2080 | ++ |
2081 | + extern string hmac_sha1(string key, string message); |
2082 | + |
2083 | +-public class FlickrService : Object, Spit.Pluggable, Spit.Publishing.Service { |
2084 | ++public class FlickrService : UOAPublishingService, Spit.Pluggable, Spit.Publishing.Service { |
2085 | + private const string ICON_FILENAME = "flickr.png"; |
2086 | + |
2087 | + private static Gdk.Pixbuf[] icon_pixbuf_set = null; |
2088 | + |
2089 | + public FlickrService(GLib.File resource_directory) { |
2090 | ++ base("flickr"); |
2091 | + if (icon_pixbuf_set == null) |
2092 | + icon_pixbuf_set = Resources.load_icon_set(resource_directory.get_child(ICON_FILENAME)); |
2093 | + } |
2094 | + |
2095 | +- public int get_pluggable_interface(int min_host_interface, int max_host_interface) { |
2096 | +- return Spit.negotiate_interfaces(min_host_interface, max_host_interface, |
2097 | +- Spit.Publishing.CURRENT_INTERFACE); |
2098 | +- } |
2099 | +- |
2100 | +- public unowned string get_id() { |
2101 | ++ public override unowned string get_id() { |
2102 | + return "org.yorba.shotwell.publishing.flickr"; |
2103 | + } |
2104 | + |
2105 | +- public unowned string get_pluggable_name() { |
2106 | ++ public override unowned string get_pluggable_name() { |
2107 | + return "Flickr"; |
2108 | + } |
2109 | + |
2110 | +- public void get_info(ref Spit.PluggableInfo info) { |
2111 | ++ public override void get_info(ref Spit.PluggableInfo info) { |
2112 | + info.authors = "Lucas Beeler"; |
2113 | + info.copyright = _("Copyright 2009-2012 Yorba Foundation"); |
2114 | + info.translators = Resources.TRANSLATORS; |
2115 | +@@ -41,14 +39,12 @@ public class FlickrService : Object, Spit.Pluggable, Spit.Publishing.Service { |
2116 | + info.icons = icon_pixbuf_set; |
2117 | + } |
2118 | + |
2119 | +- public void activation(bool enabled) { |
2120 | +- } |
2121 | +- |
2122 | +- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) { |
2123 | +- return new Publishing.Flickr.FlickrPublisher(this, host); |
2124 | ++ public override Spit.Publishing.Publisher create_publisher(string? account_name, Spit.Publishing.PluginHost host) { |
2125 | ++ SharingAccount account = find_account(account_name); |
2126 | ++ return new Publishing.Flickr.FlickrPublisher(this, account, host); |
2127 | + } |
2128 | + |
2129 | +- public Spit.Publishing.Publisher.MediaType get_supported_media() { |
2130 | ++ public override Spit.Publishing.Publisher.MediaType get_supported_media() { |
2131 | + return (Spit.Publishing.Publisher.MediaType.PHOTO | |
2132 | + Spit.Publishing.Publisher.MediaType.VIDEO); |
2133 | + } |
2134 | +@@ -105,60 +101,33 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object { |
2135 | + private bool was_started = false; |
2136 | + private Session session = null; |
2137 | + private PublishingOptionsPane publishing_options_pane = null; |
2138 | ++ private UOAPublisherAuthenticator authenticator = null; |
2139 | + |
2140 | + private PublishingParameters parameters = null; |
2141 | + |
2142 | + public FlickrPublisher(Spit.Publishing.Service service, |
2143 | ++ SharingAccount account, |
2144 | + Spit.Publishing.PluginHost host) { |
2145 | + debug("FlickrPublisher instantiated."); |
2146 | + this.service = service; |
2147 | + this.host = host; |
2148 | + this.session = new Session(); |
2149 | ++ authenticator = new UOAPublisherAuthenticator(account, host, |
2150 | ++ SERVICE_WELCOME_MESSAGE); |
2151 | + this.parameters = new PublishingParameters(); |
2152 | + |
2153 | + session.authenticated.connect(on_session_authenticated); |
2154 | ++ HashTable<string,Value?> data = |
2155 | ++ authenticator.get_authentication_data(); |
2156 | ++ session.set_api_credentials(data.lookup("ConsumerKey").get_string(), |
2157 | ++ data.lookup("ConsumerSecret").get_string()); |
2158 | ++ authenticator.authenticated.connect(on_authenticator_authenticated); |
2159 | + } |
2160 | + |
2161 | + ~FlickrPublisher() { |
2162 | + session.authenticated.disconnect(on_session_authenticated); |
2163 | + } |
2164 | + |
2165 | +- private void invalidate_persistent_session() { |
2166 | +- set_persistent_access_phase_token(""); |
2167 | +- set_persistent_access_phase_token_secret(""); |
2168 | +- set_persistent_access_phase_username(""); |
2169 | +- } |
2170 | +- |
2171 | +- private bool is_persistent_session_valid() { |
2172 | +- return (get_persistent_access_phase_username() != null && |
2173 | +- get_persistent_access_phase_token() != null && |
2174 | +- get_persistent_access_phase_token_secret() != null); |
2175 | +- } |
2176 | +- |
2177 | +- private string? get_persistent_access_phase_username() { |
2178 | +- return host.get_config_string("access_phase_username", null); |
2179 | +- } |
2180 | +- |
2181 | +- private void set_persistent_access_phase_username(string username) { |
2182 | +- host.set_config_string("access_phase_username", username); |
2183 | +- } |
2184 | +- |
2185 | +- private string? get_persistent_access_phase_token() { |
2186 | +- return host.get_config_string("access_phase_token", null); |
2187 | +- } |
2188 | +- |
2189 | +- private void set_persistent_access_phase_token(string token) { |
2190 | +- host.set_config_string("access_phase_token", token); |
2191 | +- } |
2192 | +- |
2193 | +- private string? get_persistent_access_phase_token_secret() { |
2194 | +- return host.get_config_string("access_phase_token_secret", null); |
2195 | +- } |
2196 | +- |
2197 | +- private void set_persistent_access_phase_token_secret(string secret) { |
2198 | +- host.set_config_string("access_phase_token_secret", secret); |
2199 | +- } |
2200 | +- |
2201 | + private bool get_persistent_strip_metadata() { |
2202 | + return host.get_config_bool("strip_metadata", false); |
2203 | + } |
2204 | +@@ -167,94 +136,17 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object { |
2205 | + host.set_config_bool("strip_metadata", strip_metadata); |
2206 | + } |
2207 | + |
2208 | +- private void on_welcome_pane_login_clicked() { |
2209 | +- if (!running) |
2210 | +- return; |
2211 | +- |
2212 | +- debug("EVENT: user clicked 'Login' button in the welcome pane"); |
2213 | +- |
2214 | +- do_run_authentication_request_transaction(); |
2215 | +- } |
2216 | +- |
2217 | +- private void on_auth_request_txn_completed(Publishing.RESTSupport.Transaction txn) { |
2218 | +- txn.completed.disconnect(on_auth_request_txn_completed); |
2219 | +- txn.network_error.disconnect(on_auth_request_txn_error); |
2220 | +- |
2221 | +- if (!is_running()) |
2222 | +- return; |
2223 | +- |
2224 | +- debug("EVENT: OAuth authentication request transaction completed; response = '%s'", |
2225 | +- txn.get_response()); |
2226 | +- |
2227 | +- do_parse_token_info_from_auth_request(txn.get_response()); |
2228 | +- } |
2229 | +- |
2230 | +- private void on_auth_request_txn_error(Publishing.RESTSupport.Transaction txn, |
2231 | +- Spit.Publishing.PublishingError err) { |
2232 | +- txn.completed.disconnect(on_auth_request_txn_completed); |
2233 | +- txn.network_error.disconnect(on_auth_request_txn_error); |
2234 | +- |
2235 | +- if (!is_running()) |
2236 | +- return; |
2237 | +- |
2238 | +- debug("EVENT: OAuth authentication request transaction caused a network error"); |
2239 | +- host.post_error(err); |
2240 | +- } |
2241 | +- |
2242 | +- private void on_authentication_token_available(string token, string token_secret) { |
2243 | +- debug("EVENT: OAuth authentication token (%s) and token secret (%s) available", |
2244 | +- token, token_secret); |
2245 | +- |
2246 | +- session.set_request_phase_credentials(token, token_secret); |
2247 | +- |
2248 | +- do_launch_system_browser(token); |
2249 | +- } |
2250 | +- |
2251 | +- private void on_system_browser_launched() { |
2252 | +- if (!is_running()) |
2253 | +- return; |
2254 | +- |
2255 | +- debug("EVENT: system browser launched."); |
2256 | +- |
2257 | +- do_show_pin_entry_pane(); |
2258 | +- } |
2259 | +- |
2260 | +- private void on_pin_entry_proceed(PinEntryPane sender, string pin) { |
2261 | +- sender.proceed.disconnect(on_pin_entry_proceed); |
2262 | +- |
2263 | +- if (!is_running()) |
2264 | +- return; |
2265 | +- |
2266 | +- debug("EVENT: user clicked 'Continue' in PIN entry pane."); |
2267 | +- |
2268 | +- do_verify_pin(pin); |
2269 | +- } |
2270 | ++ public void on_authenticator_authenticated(owned HashTable<string,Value?> session_data) { |
2271 | ++ host.set_service_locked(true); |
2272 | ++ host.install_account_fetch_wait_pane(); |
2273 | + |
2274 | +- private void on_access_token_fetch_txn_completed(Publishing.RESTSupport.Transaction txn) { |
2275 | +- txn.completed.disconnect(on_access_token_fetch_txn_completed); |
2276 | +- txn.network_error.disconnect(on_access_token_fetch_error); |
2277 | +- |
2278 | +- if (!is_running()) |
2279 | +- return; |
2280 | +- |
2281 | +- debug("EVENT: fetching OAuth access token over the network succeeded"); |
2282 | +- |
2283 | +- do_extract_access_phase_credentials_from_reponse(txn.get_response()); |
2284 | ++ string token = session_data.lookup("AccessToken").get_string(); |
2285 | ++ string token_secret = session_data.lookup("TokenSecret").get_string(); |
2286 | ++ string username = session_data.lookup("username").get_string(); |
2287 | ++ debug("Access Token: %s, %s, %s", token, token_secret, username); |
2288 | ++ session.set_access_phase_credentials(token, token_secret, username); |
2289 | + } |
2290 | + |
2291 | +- private void on_access_token_fetch_error(Publishing.RESTSupport.Transaction txn, |
2292 | +- Spit.Publishing.PublishingError err) { |
2293 | +- txn.completed.disconnect(on_access_token_fetch_txn_completed); |
2294 | +- txn.network_error.disconnect(on_access_token_fetch_error); |
2295 | +- |
2296 | +- if (!is_running()) |
2297 | +- return; |
2298 | +- |
2299 | +- debug("EVENT: fetching OAuth access token over the network caused an error."); |
2300 | +- |
2301 | +- host.post_error(err); |
2302 | +- } |
2303 | +- |
2304 | + private void on_session_authenticated() { |
2305 | + if (!is_running()) |
2306 | + return; |
2307 | +@@ -263,10 +155,6 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object { |
2308 | + |
2309 | + parameters.username = session.get_username(); |
2310 | + |
2311 | +- set_persistent_access_phase_token(session.get_access_phase_token()); |
2312 | +- set_persistent_access_phase_token_secret(session.get_access_phase_token_secret()); |
2313 | +- set_persistent_access_phase_username(session.get_username()); |
2314 | +- |
2315 | + do_fetch_account_info(); |
2316 | + } |
2317 | + |
2318 | +@@ -303,7 +191,6 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object { |
2319 | + |
2320 | + private void on_publishing_options_pane_publish(bool strip_metadata) { |
2321 | + publishing_options_pane.publish.disconnect(on_publishing_options_pane_publish); |
2322 | +- publishing_options_pane.logout.disconnect(on_publishing_options_pane_logout); |
2323 | + |
2324 | + if (!is_running()) |
2325 | + return; |
2326 | +@@ -312,18 +199,6 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object { |
2327 | + do_publish(strip_metadata); |
2328 | + } |
2329 | + |
2330 | +- private void on_publishing_options_pane_logout() { |
2331 | +- publishing_options_pane.publish.disconnect(on_publishing_options_pane_publish); |
2332 | +- publishing_options_pane.logout.disconnect(on_publishing_options_pane_logout); |
2333 | +- |
2334 | +- if (!is_running()) |
2335 | +- return; |
2336 | +- |
2337 | +- debug("EVENT: user clicked the 'Logout' button in the publishing options pane"); |
2338 | +- |
2339 | +- do_logout(); |
2340 | +- } |
2341 | +- |
2342 | + private void on_upload_status_updated(int file_number, double completed_fraction) { |
2343 | + if (!is_running()) |
2344 | + return; |
2345 | +@@ -361,148 +236,6 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object { |
2346 | + host.post_error(err); |
2347 | + } |
2348 | + |
2349 | +- private void do_show_login_welcome_pane() { |
2350 | +- debug("ACTION: installing login welcome pane"); |
2351 | +- |
2352 | +- host.set_service_locked(false); |
2353 | +- host.install_welcome_pane(SERVICE_WELCOME_MESSAGE, on_welcome_pane_login_clicked); |
2354 | +- } |
2355 | +- |
2356 | +- private void do_run_authentication_request_transaction() { |
2357 | +- debug("ACTION: running authentication request transaction"); |
2358 | +- |
2359 | +- host.set_service_locked(true); |
2360 | +- host.install_static_message_pane(_("Preparing for login...")); |
2361 | +- |
2362 | +- AuthenticationRequestTransaction txn = new AuthenticationRequestTransaction(session); |
2363 | +- txn.completed.connect(on_auth_request_txn_completed); |
2364 | +- txn.network_error.connect(on_auth_request_txn_error); |
2365 | +- |
2366 | +- try { |
2367 | +- txn.execute(); |
2368 | +- } catch (Spit.Publishing.PublishingError err) { |
2369 | +- host.post_error(err); |
2370 | +- } |
2371 | +- } |
2372 | +- |
2373 | +- private void do_parse_token_info_from_auth_request(string response) { |
2374 | +- debug("ACTION: parsing authorization request response '%s' into token and secret", response); |
2375 | +- |
2376 | +- string? oauth_token = null; |
2377 | +- string? oauth_token_secret = null; |
2378 | +- |
2379 | +- string[] key_value_pairs = response.split("&"); |
2380 | +- foreach (string pair in key_value_pairs) { |
2381 | +- string[] split_pair = pair.split("="); |
2382 | +- |
2383 | +- if (split_pair.length != 2) |
2384 | +- host.post_error(new Spit.Publishing.PublishingError.MALFORMED_RESPONSE( |
2385 | +- "'%s' isn't a valid response to an OAuth authentication request")); |
2386 | +- |
2387 | +- if (split_pair[0] == "oauth_token") |
2388 | +- oauth_token = split_pair[1]; |
2389 | +- else if (split_pair[0] == "oauth_token_secret") |
2390 | +- oauth_token_secret = split_pair[1]; |
2391 | +- } |
2392 | +- |
2393 | +- if (oauth_token == null || oauth_token_secret == null) |
2394 | +- host.post_error(new Spit.Publishing.PublishingError.MALFORMED_RESPONSE( |
2395 | +- "'%s' isn't a valid response to an OAuth authentication request")); |
2396 | +- |
2397 | +- |
2398 | +- on_authentication_token_available(oauth_token, oauth_token_secret); |
2399 | +- } |
2400 | +- |
2401 | +- private void do_launch_system_browser(string token) { |
2402 | +- string login_uri = "http://www.flickr.com/services/oauth/authorize?oauth_token=" + token + |
2403 | +- "&perms=write"; |
2404 | +- |
2405 | +- debug("ACTION: launching system browser with uri = '%s'", login_uri); |
2406 | +- |
2407 | +- try { |
2408 | +- Process.spawn_command_line_async("xdg-open " + login_uri); |
2409 | +- } catch (SpawnError e) { |
2410 | +- host.post_error(new Spit.Publishing.PublishingError.LOCAL_FILE_ERROR( |
2411 | +- "couldn't launch system web browser to complete Flickr login")); |
2412 | +- return; |
2413 | +- } |
2414 | +- |
2415 | +- on_system_browser_launched(); |
2416 | +- } |
2417 | +- |
2418 | +- private void do_show_pin_entry_pane() { |
2419 | +- debug("ACTION: showing PIN entry pane"); |
2420 | +- |
2421 | +- Gtk.Builder builder = new Gtk.Builder(); |
2422 | +- |
2423 | +- try { |
2424 | +- builder.add_from_file(host.get_module_file().get_parent().get_child("flickr_pin_entry_pane.glade").get_path()); |
2425 | +- } catch (Error e) { |
2426 | +- warning("Could not parse UI file! Error: %s.", e.message); |
2427 | +- host.post_error( |
2428 | +- new Spit.Publishing.PublishingError.LOCAL_FILE_ERROR( |
2429 | +- _("A file required for publishing is unavailable. Publishing to Flickr can't continue."))); |
2430 | +- return; |
2431 | +- } |
2432 | +- |
2433 | +- PinEntryPane pin_entry_pane = new PinEntryPane(builder); |
2434 | +- pin_entry_pane.proceed.connect(on_pin_entry_proceed); |
2435 | +- host.install_dialog_pane(pin_entry_pane); |
2436 | +- } |
2437 | +- |
2438 | +- private void do_verify_pin(string pin) { |
2439 | +- debug("ACTION: validating authorization PIN %s", pin); |
2440 | +- |
2441 | +- host.set_service_locked(true); |
2442 | +- host.install_static_message_pane(_("Verifying authorization...")); |
2443 | +- |
2444 | +- AccessTokenFetchTransaction txn = new AccessTokenFetchTransaction(session, pin); |
2445 | +- txn.completed.connect(on_access_token_fetch_txn_completed); |
2446 | +- txn.network_error.connect(on_access_token_fetch_error); |
2447 | +- |
2448 | +- try { |
2449 | +- txn.execute(); |
2450 | +- } catch (Spit.Publishing.PublishingError err) { |
2451 | +- host.post_error(err); |
2452 | +- } |
2453 | +- } |
2454 | +- |
2455 | +- private void do_extract_access_phase_credentials_from_reponse(string response) { |
2456 | +- debug("ACTION: extracting access phase credentials from '%s'", response); |
2457 | +- |
2458 | +- string[] key_value_pairs = response.split("&"); |
2459 | +- |
2460 | +- string? token = null; |
2461 | +- string? token_secret = null; |
2462 | +- string? username = null; |
2463 | +- foreach (string key_value_pair in key_value_pairs) { |
2464 | +- string[] split_pair = key_value_pair.split("="); |
2465 | +- |
2466 | +- if (split_pair.length != 2) |
2467 | +- continue; |
2468 | +- |
2469 | +- string key = split_pair[0]; |
2470 | +- string value = split_pair[1]; |
2471 | +- |
2472 | +- if (key == "oauth_token") |
2473 | +- token = value; |
2474 | +- else if (key == "oauth_token_secret") |
2475 | +- token_secret = value; |
2476 | +- else if (key == "username") |
2477 | +- username = value; |
2478 | +- } |
2479 | +- |
2480 | +- debug("access phase credentials: { token = '%s'; token_secret = '%s'; username = '%s' }", |
2481 | +- token, token_secret, username); |
2482 | +- |
2483 | +- if (token == null || token_secret == null || username == null) |
2484 | +- host.post_error(new Spit.Publishing.PublishingError.MALFORMED_RESPONSE("expected " + |
2485 | +- "access phase credentials to contain token, token secret, and username but at " + |
2486 | +- "least one of these is absent")); |
2487 | +- |
2488 | +- session.set_access_phase_credentials(token, token_secret, username); |
2489 | +- } |
2490 | +- |
2491 | + private void do_fetch_account_info() { |
2492 | + debug("ACTION: running network transaction to fetch account information"); |
2493 | + |
2494 | +@@ -568,7 +301,6 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object { |
2495 | + debug("ACTION: logging user out, deauthenticating session, and erasing stored credentials"); |
2496 | + |
2497 | + session.deauthenticate(); |
2498 | +- invalidate_persistent_session(); |
2499 | + |
2500 | + running = false; |
2501 | + |
2502 | +@@ -599,7 +331,6 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object { |
2503 | + publishing_options_pane = new PublishingOptionsPane(this, parameters, |
2504 | + host.get_publishable_media_type(), builder, get_persistent_strip_metadata()); |
2505 | + publishing_options_pane.publish.connect(on_publishing_options_pane_publish); |
2506 | +- publishing_options_pane.logout.connect(on_publishing_options_pane_logout); |
2507 | + host.install_dialog_pane(publishing_options_pane); |
2508 | + } |
2509 | + |
2510 | +@@ -674,16 +405,7 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object { |
2511 | + running = true; |
2512 | + was_started = true; |
2513 | + |
2514 | +- if (is_persistent_session_valid()) { |
2515 | +- debug("attempt start: a persistent session is available; using it"); |
2516 | +- |
2517 | +- session.authenticate_from_persistent_credentials(get_persistent_access_phase_token(), |
2518 | +- get_persistent_access_phase_token_secret(), get_persistent_access_phase_username()); |
2519 | +- } else { |
2520 | +- debug("attempt start: no persistent session available; showing login welcome pane"); |
2521 | +- |
2522 | +- do_show_login_welcome_pane(); |
2523 | +- } |
2524 | ++ authenticator.authenticate(); |
2525 | + } |
2526 | + |
2527 | + public void start() { |
2528 | +@@ -772,7 +494,7 @@ internal class Transaction : Publishing.RESTSupport.Transaction { |
2529 | + add_argument("oauth_version", "1.0"); |
2530 | + add_argument("oauth_callback", "oob"); |
2531 | + add_argument("oauth_timestamp", session.get_oauth_timestamp()); |
2532 | +- add_argument("oauth_consumer_key", API_KEY); |
2533 | ++ add_argument("oauth_consumer_key", session.get_api_key()); |
2534 | + } |
2535 | + |
2536 | + public Transaction.with_uri(Session session, string uri, |
2537 | +@@ -784,7 +506,7 @@ internal class Transaction : Publishing.RESTSupport.Transaction { |
2538 | + add_argument("oauth_version", "1.0"); |
2539 | + add_argument("oauth_callback", "oob"); |
2540 | + add_argument("oauth_timestamp", session.get_oauth_timestamp()); |
2541 | +- add_argument("oauth_consumer_key", API_KEY); |
2542 | ++ add_argument("oauth_consumer_key", session.get_api_key()); |
2543 | + } |
2544 | + |
2545 | + public override void execute() throws Spit.Publishing.PublishingError { |
2546 | +@@ -842,22 +564,6 @@ internal class Transaction : Publishing.RESTSupport.Transaction { |
2547 | + } |
2548 | + } |
2549 | + |
2550 | +-internal class AuthenticationRequestTransaction : Transaction { |
2551 | +- public AuthenticationRequestTransaction(Session session) { |
2552 | +- base.with_uri(session, "http://www.flickr.com/services/oauth/request_token", |
2553 | +- Publishing.RESTSupport.HttpMethod.GET); |
2554 | +- } |
2555 | +-} |
2556 | +- |
2557 | +-internal class AccessTokenFetchTransaction : Transaction { |
2558 | +- public AccessTokenFetchTransaction(Session session, string user_verifier) { |
2559 | +- base.with_uri(session, "http://www.flickr.com/services/oauth/access_token", |
2560 | +- Publishing.RESTSupport.HttpMethod.GET); |
2561 | +- add_argument("oauth_verifier", user_verifier); |
2562 | +- add_argument("oauth_token", session.get_request_phase_token()); |
2563 | +- } |
2564 | +-} |
2565 | +- |
2566 | + internal class AccountInfoFetchTransaction : Transaction { |
2567 | + public AccountInfoFetchTransaction(Session session) { |
2568 | + base(session, Publishing.RESTSupport.HttpMethod.GET); |
2569 | +@@ -884,7 +590,7 @@ private class UploadTransaction : Publishing.RESTSupport.UploadTransaction { |
2570 | + add_authorization_header_field("oauth_version", "1.0"); |
2571 | + add_authorization_header_field("oauth_callback", "oob"); |
2572 | + add_authorization_header_field("oauth_timestamp", session.get_oauth_timestamp()); |
2573 | +- add_authorization_header_field("oauth_consumer_key", API_KEY); |
2574 | ++ add_authorization_header_field("oauth_consumer_key", session.get_api_key()); |
2575 | + add_authorization_header_field("oauth_token", session.get_access_phase_token()); |
2576 | + |
2577 | + add_argument("is_public", ("%d".printf(parameters.visibility_specification.everyone_level))); |
2578 | +@@ -944,11 +650,11 @@ private class UploadTransaction : Publishing.RESTSupport.UploadTransaction { |
2579 | + } |
2580 | + |
2581 | + internal class Session : Publishing.RESTSupport.Session { |
2582 | +- private string? request_phase_token = null; |
2583 | +- private string? request_phase_token_secret = null; |
2584 | + private string? access_phase_token = null; |
2585 | + private string? access_phase_token_secret = null; |
2586 | + private string? username = null; |
2587 | ++ private string? api_key = API_KEY; |
2588 | ++ private string? api_secret = API_SECRET; |
2589 | + |
2590 | + public Session() { |
2591 | + base(ENDPOINT_URL); |
2592 | +@@ -959,15 +665,6 @@ internal class Session : Publishing.RESTSupport.Session { |
2593 | + username != null); |
2594 | + } |
2595 | + |
2596 | +- public void authenticate_from_persistent_credentials(string token, string secret, |
2597 | +- string username) { |
2598 | +- this.access_phase_token = token; |
2599 | +- this.access_phase_token_secret = secret; |
2600 | +- this.username = username; |
2601 | +- |
2602 | +- authenticated(); |
2603 | +- } |
2604 | +- |
2605 | + public void deauthenticate() { |
2606 | + access_phase_token = null; |
2607 | + access_phase_token_secret = null; |
2608 | +@@ -1008,16 +705,12 @@ internal class Session : Publishing.RESTSupport.Session { |
2609 | + if (access_phase_token_secret != null) { |
2610 | + debug("access phase token secret available; using it as signing key"); |
2611 | + |
2612 | +- signing_key = API_SECRET + "&" + access_phase_token_secret; |
2613 | +- } else if (request_phase_token_secret != null) { |
2614 | +- debug("request phase token secret available; using it as signing key"); |
2615 | +- |
2616 | +- signing_key = API_SECRET + "&" + request_phase_token_secret; |
2617 | ++ signing_key = api_secret + "&" + access_phase_token_secret; |
2618 | + } else { |
2619 | +- debug("neither access phase nor request phase token secrets available; using API " + |
2620 | ++ debug("access token secret not available; using API " + |
2621 | + "key as signing key"); |
2622 | + |
2623 | +- signing_key = API_SECRET + "&"; |
2624 | ++ signing_key = api_secret + "&"; |
2625 | + } |
2626 | + |
2627 | + string signature_base_string = http_method + "&" + Soup.URI.encode( |
2628 | +@@ -1040,11 +733,11 @@ internal class Session : Publishing.RESTSupport.Session { |
2629 | + txn.add_argument("oauth_signature", signature); |
2630 | + } |
2631 | + |
2632 | +- public void set_request_phase_credentials(string token, string secret) { |
2633 | +- this.request_phase_token = token; |
2634 | +- this.request_phase_token_secret = secret; |
2635 | ++ public void set_api_credentials(string api_key, string api_secret) { |
2636 | ++ this.api_key = api_key; |
2637 | ++ this.api_secret = api_secret; |
2638 | + } |
2639 | +- |
2640 | ++ |
2641 | + public void set_access_phase_credentials(string token, string secret, string username) { |
2642 | + this.access_phase_token = token; |
2643 | + this.access_phase_token_secret = secret; |
2644 | +@@ -1065,21 +758,16 @@ internal class Session : Publishing.RESTSupport.Session { |
2645 | + return GLib.get_real_time().to_string().substring(0, 10); |
2646 | + } |
2647 | + |
2648 | +- public string get_request_phase_token() { |
2649 | +- assert(request_phase_token != null); |
2650 | +- return request_phase_token; |
2651 | ++ public string get_api_key() { |
2652 | ++ assert(api_key != null); |
2653 | ++ return api_key; |
2654 | + } |
2655 | +- |
2656 | ++ |
2657 | + public string get_access_phase_token() { |
2658 | + assert(access_phase_token != null); |
2659 | + return access_phase_token; |
2660 | + } |
2661 | + |
2662 | +- public string get_access_phase_token_secret() { |
2663 | +- assert(access_phase_token_secret != null); |
2664 | +- return access_phase_token_secret; |
2665 | +- } |
2666 | +- |
2667 | + public string get_username() { |
2668 | + assert(is_authenticated()); |
2669 | + return username; |
2670 | +@@ -1112,7 +800,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
2671 | + private Gtk.Label visibility_label = null; |
2672 | + private Gtk.Label upload_info_label = null; |
2673 | + private Gtk.Label size_label = null; |
2674 | +- private Gtk.Button logout_button = null; |
2675 | + private Gtk.Button publish_button = null; |
2676 | + private Gtk.ComboBoxText visibility_combo = null; |
2677 | + private Gtk.ComboBoxText size_combo = null; |
2678 | +@@ -1124,7 +811,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
2679 | + private Spit.Publishing.Publisher.MediaType media_type; |
2680 | + |
2681 | + public signal void publish(bool strip_metadata); |
2682 | +- public signal void logout(); |
2683 | + |
2684 | + public PublishingOptionsPane(FlickrPublisher publisher, PublishingParameters parameters, |
2685 | + Spit.Publishing.Publisher.MediaType media_type, Gtk.Builder builder, bool strip_metadata) { |
2686 | +@@ -1136,7 +822,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
2687 | + pane_widget = (Gtk.Box) this.builder.get_object("flickr_pane"); |
2688 | + visibility_label = (Gtk.Label) this.builder.get_object("visibility_label"); |
2689 | + upload_info_label = (Gtk.Label) this.builder.get_object("upload_info_label"); |
2690 | +- logout_button = (Gtk.Button) this.builder.get_object("logout_button"); |
2691 | + publish_button = (Gtk.Button) this.builder.get_object("publish_button"); |
2692 | + visibility_combo = (Gtk.ComboBoxText) this.builder.get_object("visibility_combo"); |
2693 | + size_combo = (Gtk.ComboBoxText) this.builder.get_object("size_combo"); |
2694 | +@@ -1183,14 +868,9 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
2695 | + |
2696 | + strip_metadata_check.set_active(strip_metadata); |
2697 | + |
2698 | +- logout_button.clicked.connect(on_logout_clicked); |
2699 | + publish_button.clicked.connect(on_publish_clicked); |
2700 | + } |
2701 | + |
2702 | +- private void on_logout_clicked() { |
2703 | +- logout(); |
2704 | +- } |
2705 | +- |
2706 | + private void on_publish_clicked() { |
2707 | + parameters.visibility_specification = |
2708 | + visibilities[visibility_combo.get_active()].specification; |
2709 | +@@ -1257,10 +937,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
2710 | + publish(strip_metadata_check.get_active()); |
2711 | + } |
2712 | + |
2713 | +- protected void notify_logout() { |
2714 | +- logout(); |
2715 | +- } |
2716 | +- |
2717 | + public Gtk.Widget get_widget() { |
2718 | + return pane_widget; |
2719 | + } |
2720 | +@@ -1271,12 +947,10 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
2721 | + |
2722 | + public void on_pane_installed() { |
2723 | + publish.connect(notify_publish); |
2724 | +- logout.connect(notify_logout); |
2725 | + } |
2726 | + |
2727 | + public void on_pane_uninstalled() { |
2728 | + publish.disconnect(notify_publish); |
2729 | +- logout.disconnect(notify_logout); |
2730 | + } |
2731 | + } |
2732 | + |
2733 | +diff --git a/plugins/shotwell-publishing/Makefile b/plugins/shotwell-publishing/Makefile |
2734 | +index e939a77..bacfff4 100644 |
2735 | +--- a/plugins/shotwell-publishing/Makefile |
2736 | ++++ b/plugins/shotwell-publishing/Makefile |
2737 | +@@ -18,6 +18,7 @@ SRC_FILES := \ |
2738 | + FlickrPublishing.vala \ |
2739 | + YouTubePublishing.vala \ |
2740 | + PiwigoPublishing.vala \ |
2741 | ++ ../common/accounts.vala \ |
2742 | + ../../src/util/string.vala \ |
2743 | + ../common/RESTSupport.vala \ |
2744 | + ../common/ui.vala |
2745 | +diff --git a/plugins/shotwell-publishing/PicasaPublishing.vala b/plugins/shotwell-publishing/PicasaPublishing.vala |
2746 | +index 397503d..a428a30 100644 |
2747 | +--- a/plugins/shotwell-publishing/PicasaPublishing.vala |
2748 | ++++ b/plugins/shotwell-publishing/PicasaPublishing.vala |
2749 | +@@ -4,30 +4,28 @@ |
2750 | + * (version 2.1 or later). See the COPYING file in this distribution. |
2751 | + */ |
2752 | + |
2753 | +-public class PicasaService : Object, Spit.Pluggable, Spit.Publishing.Service { |
2754 | ++using Publishing.Accounts; |
2755 | ++ |
2756 | ++public class PicasaService : UOAPublishingService, Spit.Pluggable, Spit.Publishing.Service { |
2757 | + private const string ICON_FILENAME = "picasa.png"; |
2758 | + |
2759 | + private static Gdk.Pixbuf[] icon_pixbuf_set = null; |
2760 | + |
2761 | + public PicasaService(GLib.File resource_directory) { |
2762 | ++ base("google"); |
2763 | + if (icon_pixbuf_set == null) |
2764 | + icon_pixbuf_set = Resources.load_icon_set(resource_directory.get_child(ICON_FILENAME)); |
2765 | + } |
2766 | + |
2767 | +- public int get_pluggable_interface(int min_host_interface, int max_host_interface) { |
2768 | +- return Spit.negotiate_interfaces(min_host_interface, max_host_interface, |
2769 | +- Spit.Publishing.CURRENT_INTERFACE); |
2770 | +- } |
2771 | +- |
2772 | +- public unowned string get_id() { |
2773 | ++ public override unowned string get_id() { |
2774 | + return "org.yorba.shotwell.publishing.picasa"; |
2775 | + } |
2776 | + |
2777 | +- public unowned string get_pluggable_name() { |
2778 | ++ public override unowned string get_pluggable_name() { |
2779 | + return "Picasa Web Albums"; |
2780 | + } |
2781 | + |
2782 | +- public void get_info(ref Spit.PluggableInfo info) { |
2783 | ++ public override void get_info(ref Spit.PluggableInfo info) { |
2784 | + info.authors = "Lucas Beeler"; |
2785 | + info.copyright = _("Copyright 2009-2012 Yorba Foundation"); |
2786 | + info.translators = Resources.TRANSLATORS; |
2787 | +@@ -39,17 +37,15 @@ public class PicasaService : Object, Spit.Pluggable, Spit.Publishing.Service { |
2788 | + info.icons = icon_pixbuf_set; |
2789 | + } |
2790 | + |
2791 | +- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) { |
2792 | +- return new Publishing.Picasa.PicasaPublisher(this, host); |
2793 | ++ public override Spit.Publishing.Publisher create_publisher(string? account_name, Spit.Publishing.PluginHost host) { |
2794 | ++ SharingAccount account = find_account(account_name); |
2795 | ++ return new Publishing.Picasa.PicasaPublisher(this, account, host); |
2796 | + } |
2797 | + |
2798 | +- public Spit.Publishing.Publisher.MediaType get_supported_media() { |
2799 | ++ public override Spit.Publishing.Publisher.MediaType get_supported_media() { |
2800 | + return (Spit.Publishing.Publisher.MediaType.PHOTO | |
2801 | + Spit.Publishing.Publisher.MediaType.VIDEO); |
2802 | + } |
2803 | +- |
2804 | +- public void activation(bool enabled) { |
2805 | +- } |
2806 | + } |
2807 | + |
2808 | + namespace Publishing.Picasa { |
2809 | +@@ -72,29 +68,22 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object { |
2810 | + private PublishingParameters parameters = null; |
2811 | + private Spit.Publishing.Publisher.MediaType media_type = |
2812 | + Spit.Publishing.Publisher.MediaType.NONE; |
2813 | ++ private UOAPublisherAuthenticator authenticator = null; |
2814 | + |
2815 | + public PicasaPublisher(Spit.Publishing.Service service, |
2816 | ++ SharingAccount account, |
2817 | + Spit.Publishing.PluginHost host) { |
2818 | + this.service = service; |
2819 | + this.host = host; |
2820 | + this.session = new Session(); |
2821 | ++ authenticator = new UOAPublisherAuthenticator(account, host, |
2822 | ++ SERVICE_WELCOME_MESSAGE); |
2823 | ++ authenticator.authenticated.connect(on_authenticator_authenticated); |
2824 | + |
2825 | + foreach(Spit.Publishing.Publishable p in host.get_publishables()) |
2826 | + media_type |= p.get_media_type(); |
2827 | + } |
2828 | + |
2829 | +- private string get_user_authorization_url() { |
2830 | +- return "https://accounts.google.com/o/oauth2/auth?" + |
2831 | +- "response_type=code&" + |
2832 | +- "client_id=" + OAUTH_CLIENT_ID + "&" + |
2833 | +- "redirect_uri=" + Soup.URI.encode("urn:ietf:wg:oauth:2.0:oob", null) + "&" + |
2834 | +- "scope=" + Soup.URI.encode("http://picasaweb.google.com/data/", null) + "+" + |
2835 | +- Soup.URI.encode("https://www.googleapis.com/auth/userinfo.profile", null) + "&" + |
2836 | +- "state=connect&" + |
2837 | +- "access_type=offline&" + |
2838 | +- "approval_prompt=force"; |
2839 | +- } |
2840 | +- |
2841 | + private Album[] extract_albums(Xml.Node* document_root) throws Spit.Publishing.PublishingError { |
2842 | + Album[] result = new Album[0]; |
2843 | + |
2844 | +@@ -133,14 +122,6 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object { |
2845 | + return result; |
2846 | + } |
2847 | + |
2848 | +- internal string? get_persistent_refresh_token() { |
2849 | +- return host.get_config_string("refresh_token", null); |
2850 | +- } |
2851 | +- |
2852 | +- internal void set_persistent_refresh_token(string token) { |
2853 | +- host.set_config_string("refresh_token", token); |
2854 | +- } |
2855 | +- |
2856 | + internal bool get_persistent_strip_metadata() { |
2857 | + return host.get_config_bool("strip_metadata", false); |
2858 | + } |
2859 | +@@ -149,16 +130,6 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object { |
2860 | + host.set_config_bool("strip_metadata", strip_metadata); |
2861 | + } |
2862 | + |
2863 | +- internal void invalidate_persistent_session() { |
2864 | +- debug("invalidating persisted Picasa Web Albums session."); |
2865 | +- |
2866 | +- host.unset_config_key("refresh_token"); |
2867 | +- } |
2868 | +- |
2869 | +- internal bool is_persistent_session_available() { |
2870 | +- return get_persistent_refresh_token() != null; |
2871 | +- } |
2872 | +- |
2873 | + public bool is_running() { |
2874 | + return running; |
2875 | + } |
2876 | +@@ -167,98 +138,22 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object { |
2877 | + return service; |
2878 | + } |
2879 | + |
2880 | +- private void on_service_welcome_login() { |
2881 | +- if (!is_running()) |
2882 | +- return; |
2883 | +- |
2884 | +- debug("EVENT: user clicked 'Login' in welcome pane."); |
2885 | +- |
2886 | +- do_launch_browser_for_authorization(); |
2887 | +- } |
2888 | +- |
2889 | +- private void on_auth_code_entry_pane_proceed(AuthCodeEntryPane sender, string code) { |
2890 | +- debug("EVENT: user clicked 'Continue' in authorization code entry pane."); |
2891 | +- |
2892 | +- sender.proceed.disconnect(on_auth_code_entry_pane_proceed); |
2893 | +- |
2894 | +- do_get_access_tokens(code); |
2895 | +- } |
2896 | +- |
2897 | +- private void on_browser_launched() { |
2898 | +- debug("EVENT: system web browser launched to solicit user authorization."); |
2899 | +- |
2900 | +- do_show_auth_code_entry_pane(); |
2901 | +- } |
2902 | +- |
2903 | +- private void on_get_access_tokens_completed(Publishing.RESTSupport.Transaction txn) { |
2904 | +- txn.completed.disconnect(on_get_access_tokens_completed); |
2905 | +- txn.network_error.disconnect(on_get_access_tokens_error); |
2906 | +- |
2907 | +- debug("EVENT: network transaction to exchange authorization code for access tokens " + |
2908 | +- "completed successfully."); |
2909 | +- |
2910 | +- do_extract_tokens(txn.get_response()); |
2911 | +- } |
2912 | +- |
2913 | +- private void on_get_access_tokens_error(Publishing.RESTSupport.Transaction txn, |
2914 | +- Spit.Publishing.PublishingError err) { |
2915 | +- txn.completed.disconnect(on_get_access_tokens_completed); |
2916 | +- txn.network_error.disconnect(on_get_access_tokens_error); |
2917 | +- |
2918 | +- debug("EVENT: network transaction to exchange authorization code for access tokens " + |
2919 | +- "failed; response = '%s'", txn.get_response()); |
2920 | +- } |
2921 | +- |
2922 | +- private void on_refresh_token_available(string token) { |
2923 | +- debug("EVENT: an OAuth refresh token has become available."); |
2924 | +- |
2925 | +- do_save_refresh_token_to_configuration_system(token); |
2926 | +- } |
2927 | +- |
2928 | +- private void on_access_token_available(string token) { |
2929 | +- debug("EVENT: an OAuth access token has become available."); |
2930 | +- |
2931 | +- do_authenticate_session(token); |
2932 | +- } |
2933 | +- |
2934 | +- private void on_not_set_up_pane_proceed(NotSetUpMessagePane sender) { |
2935 | +- debug("EVENT: user clicked 'Continue' in Account Not Set Up Message Pane."); |
2936 | +- |
2937 | +- sender.proceed.disconnect(on_not_set_up_pane_proceed); |
2938 | +- |
2939 | +- do_launch_browser_for_authorization(); |
2940 | +- } |
2941 | +- |
2942 | +- private void on_refresh_access_token_transaction_completed(Publishing.RESTSupport.Transaction |
2943 | +- txn) { |
2944 | +- txn.completed.disconnect(on_refresh_access_token_transaction_completed); |
2945 | +- txn.network_error.disconnect(on_refresh_access_token_transaction_error); |
2946 | +- |
2947 | +- if (!is_running()) |
2948 | +- return; |
2949 | +- |
2950 | +- if (session.is_authenticated()) // ignore these events if the session is already auth'd |
2951 | +- return; |
2952 | +- |
2953 | +- debug("EVENT: refresh access token transaction completed successfully."); |
2954 | +- |
2955 | +- do_extract_tokens(txn.get_response()); |
2956 | +- } |
2957 | +- |
2958 | +- private void on_refresh_access_token_transaction_error(Publishing.RESTSupport.Transaction txn, |
2959 | +- Spit.Publishing.PublishingError err) { |
2960 | +- txn.completed.disconnect(on_refresh_access_token_transaction_completed); |
2961 | +- txn.network_error.disconnect(on_refresh_access_token_transaction_error); |
2962 | +- |
2963 | +- if (!is_running()) |
2964 | +- return; |
2965 | ++ public void on_authenticator_authenticated(owned HashTable<string,Value?> session_data) { |
2966 | ++ host.install_account_fetch_wait_pane(); |
2967 | + |
2968 | +- if (session.is_authenticated()) // ignore these events if the session is already auth'd |
2969 | +- return; |
2970 | ++ session.authenticated.connect(on_session_authenticated); |
2971 | + |
2972 | +- debug("EVENT: refresh access token transaction caused a network error."); |
2973 | +- |
2974 | +- host.post_error(err); |
2975 | ++ if (session_data.lookup("AccessToken") != null) { |
2976 | ++ string token = session_data.lookup("AccessToken").get_string(); |
2977 | ++ debug("OAuth Access Token: %s", token); |
2978 | ++ session.authenticate(token, "OAuth2"); |
2979 | ++ } else if (session_data.lookup("AuthToken") != null) { |
2980 | ++ string token = session_data.lookup("AuthToken").get_string(); |
2981 | ++ debug("ClientLogin Access Token: %s", token); |
2982 | ++ session.authenticate(token, "ClientLogin"); |
2983 | ++ } else { |
2984 | ++ debug("Access token not present!"); |
2985 | ++ } |
2986 | + } |
2987 | + |
2988 | + private void on_session_authenticated() { |
2989 | +@@ -313,31 +208,7 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object { |
2990 | + debug("EVENT: fetching account and album information failed; response = '%s'.", |
2991 | + bad_txn.get_response()); |
2992 | + |
2993 | +- if (bad_txn.get_status_code() == 404) { |
2994 | +- // if we get a 404 error (resource not found) on the initial album fetch, then the |
2995 | +- // user's album feed doesn't exist -- this occurs when the user has a valid Google |
2996 | +- // account but it hasn't yet been set up for use with Picasa. In this case, we |
2997 | +- // display an informational pane with an "account not set up" message. In addition, we |
2998 | +- // deauthenticate the session. Deauth is neccessary because must've previously auth'd |
2999 | +- // the user's account to even be able to query the album feed. |
3000 | +- session.deauthenticate(); |
3001 | +- do_show_not_set_up_pane(); |
3002 | +- } else { |
3003 | +- // If we get any other kind of error, we can't recover, so just post it to the user |
3004 | +- host.post_error(err); |
3005 | +- } |
3006 | +- } |
3007 | +- |
3008 | +- private void on_publishing_options_logout() { |
3009 | +- if (!is_running()) |
3010 | +- return; |
3011 | +- |
3012 | +- debug("EVENT: user clicked 'Logout' in the publishing options pane."); |
3013 | +- |
3014 | +- session.deauthenticate(); |
3015 | +- invalidate_persistent_session(); |
3016 | +- |
3017 | +- do_show_service_welcome_pane(); |
3018 | ++ host.post_error(err); |
3019 | + } |
3020 | + |
3021 | + private void on_publishing_options_publish(PublishingParameters parameters, |
3022 | +@@ -447,100 +318,6 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object { |
3023 | + host.post_error(err); |
3024 | + } |
3025 | + |
3026 | +- private void do_show_service_welcome_pane() { |
3027 | +- debug("ACTION: showing service welcome pane."); |
3028 | +- |
3029 | +- host.install_welcome_pane(SERVICE_WELCOME_MESSAGE, on_service_welcome_login); |
3030 | +- } |
3031 | +- |
3032 | +- private void do_launch_browser_for_authorization() { |
3033 | +- string auth_url = get_user_authorization_url(); |
3034 | +- |
3035 | +- debug("ACTION: launching external web browser to get user authorization; " + |
3036 | +- "authorization URL = '%s'", auth_url); |
3037 | +- |
3038 | +- try { |
3039 | +- Process.spawn_command_line_async("xdg-open " + auth_url); |
3040 | +- } catch (SpawnError e) { |
3041 | +- host.post_error(new Spit.Publishing.PublishingError.LOCAL_FILE_ERROR( |
3042 | +- _("couldn't launch system web browser to complete Picasa Web Albums login"))); |
3043 | +- return; |
3044 | +- } |
3045 | +- |
3046 | +- on_browser_launched(); |
3047 | +- } |
3048 | +- |
3049 | +- private void do_show_auth_code_entry_pane() { |
3050 | +- debug("ACTION: showing OAuth authorization code entry pane."); |
3051 | +- |
3052 | +- Gtk.Builder builder = new Gtk.Builder(); |
3053 | +- |
3054 | +- try { |
3055 | +- builder.add_from_file(host.get_module_file().get_parent().get_child( |
3056 | +- "picasa_auth_code_entry_pane.glade").get_path()); |
3057 | +- } catch (Error e) { |
3058 | +- warning("Could not parse UI file! Error: %s.", e.message); |
3059 | +- host.post_error( |
3060 | +- new Spit.Publishing.PublishingError.LOCAL_FILE_ERROR( |
3061 | +- _("A file required for publishing is unavailable. Publishing to Picasa Web Albums can't continue."))); |
3062 | +- return; |
3063 | +- } |
3064 | +- |
3065 | +- AuthCodeEntryPane pane = new AuthCodeEntryPane(builder); |
3066 | +- pane.proceed.connect(on_auth_code_entry_pane_proceed); |
3067 | +- host.install_dialog_pane(pane); |
3068 | +- } |
3069 | +- |
3070 | +- private void do_get_access_tokens(string code) { |
3071 | +- debug("ACTION: exchanging OAuth authorization code '%s' for access token.", code); |
3072 | +- |
3073 | +- GetAccessTokensTransaction txn = new GetAccessTokensTransaction(session, code); |
3074 | +- txn.completed.connect(on_get_access_tokens_completed); |
3075 | +- txn.network_error.connect(on_get_access_tokens_error); |
3076 | +- |
3077 | +- try { |
3078 | +- txn.execute(); |
3079 | +- } catch (Spit.Publishing.PublishingError err) { |
3080 | +- host.post_error(err); |
3081 | +- } |
3082 | +- } |
3083 | +- |
3084 | +- private void do_extract_tokens(string response_body) { |
3085 | +- debug("ACTION: extracting OAuth tokens from body of server response"); |
3086 | +- |
3087 | +- Json.Parser parser = new Json.Parser(); |
3088 | +- |
3089 | +- try { |
3090 | +- parser.load_from_data(response_body); |
3091 | +- } catch (Error err) { |
3092 | +- host.post_error(new Spit.Publishing.PublishingError.MALFORMED_RESPONSE( |
3093 | +- "Couldn't parse JSON response: " + err.message)); |
3094 | +- return; |
3095 | +- } |
3096 | +- |
3097 | +- Json.Object response_obj = parser.get_root().get_object(); |
3098 | +- |
3099 | +- if ((!response_obj.has_member("access_token")) && (!response_obj.has_member("refresh_token"))) { |
3100 | +- host.post_error(new Spit.Publishing.PublishingError.MALFORMED_RESPONSE( |
3101 | +- "neither access_token nor refresh_token not present in server response")); |
3102 | +- return; |
3103 | +- } |
3104 | +- |
3105 | +- if (response_obj.has_member("refresh_token")) { |
3106 | +- string refresh_token = response_obj.get_string_member("refresh_token"); |
3107 | +- |
3108 | +- if (refresh_token != "") |
3109 | +- on_refresh_token_available(refresh_token); |
3110 | +- } |
3111 | +- |
3112 | +- if (response_obj.has_member("access_token")) { |
3113 | +- string access_token = response_obj.get_string_member("access_token"); |
3114 | +- |
3115 | +- if (access_token != "") |
3116 | +- on_access_token_available(access_token); |
3117 | +- } |
3118 | +- } |
3119 | +- |
3120 | + private void do_extract_username(string response_body) { |
3121 | + debug("ACTION: extracting username from body of server response"); |
3122 | + |
3123 | +@@ -562,66 +339,8 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object { |
3124 | + if (username != "") |
3125 | + this.username = username; |
3126 | + } |
3127 | +- |
3128 | +- if (response_obj.has_member("access_token")) { |
3129 | +- string access_token = response_obj.get_string_member("access_token"); |
3130 | +- |
3131 | +- if (access_token != "") |
3132 | +- on_access_token_available(access_token); |
3133 | +- } |
3134 | + } |
3135 | + |
3136 | +- private void do_save_refresh_token_to_configuration_system(string token) { |
3137 | +- debug("ACTION: saving OAuth refresh token to configuration system"); |
3138 | +- |
3139 | +- set_persistent_refresh_token(token); |
3140 | +- } |
3141 | +- |
3142 | +- private void do_refresh_session(string refresh_token) { |
3143 | +- debug("ACTION: using OAuth refresh token to refresh session."); |
3144 | +- |
3145 | +- host.install_login_wait_pane(); |
3146 | +- |
3147 | +- RefreshAccessTokenTransaction txn = new RefreshAccessTokenTransaction(session, refresh_token); |
3148 | +- |
3149 | +- txn.completed.connect(on_refresh_access_token_transaction_completed); |
3150 | +- txn.network_error.connect(on_refresh_access_token_transaction_error); |
3151 | +- |
3152 | +- try { |
3153 | +- txn.execute(); |
3154 | +- } catch (Spit.Publishing.PublishingError err) { |
3155 | +- host.post_error(err); |
3156 | +- } |
3157 | +- } |
3158 | +- |
3159 | +- private void do_authenticate_session(string token) { |
3160 | +- debug("ACTION: authenticating session."); |
3161 | +- |
3162 | +- session.authenticated.connect(on_session_authenticated); |
3163 | +- session.authenticate(token); |
3164 | +- } |
3165 | +- |
3166 | +- private void do_show_not_set_up_pane() { |
3167 | +- debug("ACTION: showing account not set up message pane"); |
3168 | +- |
3169 | +- Gtk.Builder builder = new Gtk.Builder(); |
3170 | +- |
3171 | +- try { |
3172 | +- builder.add_from_file(host.get_module_file().get_parent().get_child( |
3173 | +- "picasa_not_set_up_pane.glade").get_path()); |
3174 | +- } catch (Error e) { |
3175 | +- warning("Could not parse UI file! Error: %s.", e.message); |
3176 | +- host.post_error( |
3177 | +- new Spit.Publishing.PublishingError.LOCAL_FILE_ERROR( |
3178 | +- _("A file required for publishing is unavailable. Publishing to Picasa Web Albums can't continue."))); |
3179 | +- return; |
3180 | +- } |
3181 | +- |
3182 | +- NotSetUpMessagePane pane = new NotSetUpMessagePane(builder); |
3183 | +- pane.proceed.connect(on_not_set_up_pane_proceed); |
3184 | +- host.install_dialog_pane(pane); |
3185 | +- } |
3186 | +- |
3187 | + private void do_fetch_username() { |
3188 | + debug("ACTION: running network transaction to fetch username."); |
3189 | + |
3190 | +@@ -701,7 +420,6 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object { |
3191 | + PublishingOptionsPane opts_pane = new PublishingOptionsPane(host, username, albums, media_type, builder, |
3192 | + get_persistent_strip_metadata()); |
3193 | + opts_pane.publish.connect(on_publishing_options_publish); |
3194 | +- opts_pane.logout.connect(on_publishing_options_logout); |
3195 | + host.install_dialog_pane(opts_pane); |
3196 | + |
3197 | + host.set_service_locked(false); |
3198 | +@@ -770,12 +488,7 @@ public class PicasaPublisher : Spit.Publishing.Publisher, GLib.Object { |
3199 | + debug("PicasaPublisher: starting interaction."); |
3200 | + |
3201 | + running = true; |
3202 | +- |
3203 | +- if (is_persistent_session_available()) { |
3204 | +- do_refresh_session(get_persistent_refresh_token()); |
3205 | +- } else { |
3206 | +- do_show_service_welcome_pane(); |
3207 | +- } |
3208 | ++ authenticator.authenticate(); |
3209 | + } |
3210 | + |
3211 | + public void stop() { |
3212 | +@@ -801,6 +514,7 @@ internal class Album { |
3213 | + |
3214 | + internal class Session : Publishing.RESTSupport.Session { |
3215 | + private string? auth_token = null; |
3216 | ++ private string? auth_method = null; |
3217 | + |
3218 | + public Session() { |
3219 | + } |
3220 | +@@ -809,45 +523,19 @@ internal class Session : Publishing.RESTSupport.Session { |
3221 | + return (auth_token != null); |
3222 | + } |
3223 | + |
3224 | +- public void authenticate(string auth_token) { |
3225 | ++ public void authenticate(string auth_token, string auth_method) { |
3226 | + this.auth_token = auth_token; |
3227 | ++ this.auth_method = auth_method; |
3228 | + |
3229 | + notify_authenticated(); |
3230 | + } |
3231 | + |
3232 | +- public void deauthenticate() { |
3233 | +- auth_token = null; |
3234 | +- } |
3235 | +- |
3236 | + public string? get_auth_token() { |
3237 | + return auth_token; |
3238 | + } |
3239 | +-} |
3240 | + |
3241 | +-internal class GetAccessTokensTransaction : Publishing.RESTSupport.Transaction { |
3242 | +- private const string ENDPOINT_URL = "https://accounts.google.com/o/oauth2/token"; |
3243 | +- |
3244 | +- public GetAccessTokensTransaction(Session session, string auth_code) { |
3245 | +- base.with_endpoint_url(session, ENDPOINT_URL); |
3246 | +- |
3247 | +- add_argument("code", auth_code); |
3248 | +- add_argument("client_id", OAUTH_CLIENT_ID); |
3249 | +- add_argument("client_secret", OAUTH_CLIENT_SECRET); |
3250 | +- add_argument("redirect_uri", "urn:ietf:wg:oauth:2.0:oob"); |
3251 | +- add_argument("grant_type", "authorization_code"); |
3252 | +- } |
3253 | +-} |
3254 | +- |
3255 | +-internal class RefreshAccessTokenTransaction : Publishing.RESTSupport.Transaction { |
3256 | +- private const string ENDPOINT_URL = "https://accounts.google.com/o/oauth2/token"; |
3257 | +- |
3258 | +- public RefreshAccessTokenTransaction(Session session, string refresh_token) { |
3259 | +- base.with_endpoint_url(session, ENDPOINT_URL); |
3260 | +- |
3261 | +- add_argument("client_id", OAUTH_CLIENT_ID); |
3262 | +- add_argument("client_secret", OAUTH_CLIENT_SECRET); |
3263 | +- add_argument("refresh_token", refresh_token); |
3264 | +- add_argument("grant_type", "refresh_token"); |
3265 | ++ public string? get_auth_method() { |
3266 | ++ return auth_method; |
3267 | + } |
3268 | + } |
3269 | + |
3270 | +@@ -862,7 +550,13 @@ internal class AuthenticatedTransaction : Publishing.RESTSupport.Transaction { |
3271 | + base.with_endpoint_url(session, endpoint_url, method); |
3272 | + assert(session.is_authenticated()); |
3273 | + |
3274 | +- add_header("Authorization", "Bearer " + session.get_auth_token()); |
3275 | ++ if (session.get_auth_method() == "ClientLogin") { |
3276 | ++ add_header("Authorization", |
3277 | ++ "GoogleLogin auth=" + session.get_auth_token()); |
3278 | ++ } else { |
3279 | ++ add_header("Authorization", |
3280 | ++ "Bearer " + session.get_auth_token()); |
3281 | ++ } |
3282 | + } |
3283 | + } |
3284 | + |
3285 | +@@ -875,7 +569,7 @@ internal class UsernameFetchTransaction : AuthenticatedTransaction { |
3286 | + } |
3287 | + |
3288 | + internal class AlbumDirectoryTransaction : AuthenticatedTransaction { |
3289 | +- private const string ENDPOINT_URL = "http://picasaweb.google.com/data/feed/api/user/" + |
3290 | ++ private const string ENDPOINT_URL = "https://picasaweb.google.com/data/feed/api/user/" + |
3291 | + "default"; |
3292 | + |
3293 | + public AlbumDirectoryTransaction(Session session) { |
3294 | +@@ -892,7 +586,7 @@ internal class AlbumDirectoryTransaction : AuthenticatedTransaction { |
3295 | + } |
3296 | + |
3297 | + private class AlbumCreationTransaction : AuthenticatedTransaction { |
3298 | +- private const string ENDPOINT_URL = "http://picasaweb.google.com/data/feed/api/user/" + |
3299 | ++ private const string ENDPOINT_URL = "https://picasaweb.google.com/data/feed/api/user/" + |
3300 | + "default"; |
3301 | + private const string ALBUM_ENTRY_TEMPLATE = "<?xml version='1.0' encoding='utf-8'?><entry xmlns='http://www.w3.org/2005/Atom' xmlns:gphoto='http://schemas.google.com/photos/2007'><title type='text'>%s</title><gphoto:access>%s</gphoto:access><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/photos/2007#album'></category></entry>"; |
3302 | + |
3303 | +@@ -971,9 +665,14 @@ internal class UploadTransaction : AuthenticatedTransaction { |
3304 | + // that we've been building up |
3305 | + Soup.Message outbound_message = |
3306 | + soup_form_request_new_from_multipart(get_endpoint_url(), message_parts); |
3307 | +- outbound_message.request_headers.append("Authorization", "Bearer " + |
3308 | +- session.get_auth_token()); |
3309 | + set_message(outbound_message); |
3310 | ++ if (session.get_auth_method() == "ClientLogin") { |
3311 | ++ add_header("Authorization", |
3312 | ++ "GoogleLogin auth=" + session.get_auth_token()); |
3313 | ++ } else { |
3314 | ++ add_header("Authorization", |
3315 | ++ "Bearer " + session.get_auth_token()); |
3316 | ++ } |
3317 | + |
3318 | + // send the message and get its response |
3319 | + set_is_executed(true); |
3320 | +@@ -981,95 +680,6 @@ internal class UploadTransaction : AuthenticatedTransaction { |
3321 | + } |
3322 | + } |
3323 | + |
3324 | +-internal class AuthCodeEntryPane : Spit.Publishing.DialogPane, GLib.Object { |
3325 | +- private Gtk.Box pane_widget = null; |
3326 | +- private Gtk.Button continue_button = null; |
3327 | +- private Gtk.Entry entry = null; |
3328 | +- private Gtk.Label entry_caption = null; |
3329 | +- private Gtk.Label explanatory_text = null; |
3330 | +- |
3331 | +- public signal void proceed(AuthCodeEntryPane sender, string authorization_code); |
3332 | +- |
3333 | +- public AuthCodeEntryPane(Gtk.Builder builder) { |
3334 | +- assert(builder != null); |
3335 | +- assert(builder.get_objects().length() > 0); |
3336 | +- |
3337 | +- explanatory_text = builder.get_object("explanatory_text") as Gtk.Label; |
3338 | +- entry_caption = builder.get_object("entry_caption") as Gtk.Label; |
3339 | +- entry = builder.get_object("entry") as Gtk.Entry; |
3340 | +- continue_button = builder.get_object("continue_button") as Gtk.Button; |
3341 | +- |
3342 | +- pane_widget = builder.get_object("pane_widget") as Gtk.Box; |
3343 | +- |
3344 | +- pane_widget.show_all(); |
3345 | +- |
3346 | +- on_entry_contents_changed(); |
3347 | +- } |
3348 | +- |
3349 | +- private void on_continue_clicked() { |
3350 | +- proceed(this, entry.get_text()); |
3351 | +- } |
3352 | +- |
3353 | +- private void on_entry_contents_changed() { |
3354 | +- continue_button.set_sensitive(entry.text_length > 0); |
3355 | +- } |
3356 | +- |
3357 | +- public Gtk.Widget get_widget() { |
3358 | +- return pane_widget; |
3359 | +- } |
3360 | +- |
3361 | +- public Spit.Publishing.DialogPane.GeometryOptions get_preferred_geometry() { |
3362 | +- return Spit.Publishing.DialogPane.GeometryOptions.NONE; |
3363 | +- } |
3364 | +- |
3365 | +- public void on_pane_installed() { |
3366 | +- continue_button.clicked.connect(on_continue_clicked); |
3367 | +- entry.changed.connect(on_entry_contents_changed); |
3368 | +- } |
3369 | +- |
3370 | +- public void on_pane_uninstalled() { |
3371 | +- continue_button.clicked.disconnect(on_continue_clicked); |
3372 | +- entry.changed.disconnect(on_entry_contents_changed); |
3373 | +- } |
3374 | +-} |
3375 | +- |
3376 | +-internal class NotSetUpMessagePane : Spit.Publishing.DialogPane, GLib.Object { |
3377 | +- private Gtk.Box pane_widget = null; |
3378 | +- private Gtk.Button continue_button = null; |
3379 | +- |
3380 | +- public signal void proceed(NotSetUpMessagePane sender); |
3381 | +- |
3382 | +- public NotSetUpMessagePane(Gtk.Builder builder) { |
3383 | +- assert(builder != null); |
3384 | +- assert(builder.get_objects().length() > 0); |
3385 | +- |
3386 | +- continue_button = builder.get_object("continue_button") as Gtk.Button; |
3387 | +- pane_widget = builder.get_object("pane_widget") as Gtk.Box; |
3388 | +- |
3389 | +- pane_widget.show_all(); |
3390 | +- } |
3391 | +- |
3392 | +- private void on_continue_clicked() { |
3393 | +- proceed(this); |
3394 | +- } |
3395 | +- |
3396 | +- public Gtk.Widget get_widget() { |
3397 | +- return pane_widget; |
3398 | +- } |
3399 | +- |
3400 | +- public Spit.Publishing.DialogPane.GeometryOptions get_preferred_geometry() { |
3401 | +- return Spit.Publishing.DialogPane.GeometryOptions.NONE; |
3402 | +- } |
3403 | +- |
3404 | +- public void on_pane_installed() { |
3405 | +- continue_button.clicked.connect(on_continue_clicked); |
3406 | +- } |
3407 | +- |
3408 | +- public void on_pane_uninstalled() { |
3409 | +- continue_button.clicked.disconnect(on_continue_clicked); |
3410 | +- } |
3411 | +-} |
3412 | +- |
3413 | + internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
3414 | + private class SizeDescription { |
3415 | + public string name; |
3416 | +@@ -1097,7 +707,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
3417 | + private Gtk.ComboBoxText size_combo = null; |
3418 | + private Gtk.CheckButton strip_metadata_check = null; |
3419 | + private Gtk.Button publish_button = null; |
3420 | +- private Gtk.Button logout_button = null; |
3421 | + |
3422 | + private Album[] albums; |
3423 | + private SizeDescription[] size_descriptions; |
3424 | +@@ -1105,7 +714,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
3425 | + private weak Spit.Publishing.PluginHost host; |
3426 | + |
3427 | + public signal void publish(PublishingParameters parameters, bool strip_metadata); |
3428 | +- public signal void logout(); |
3429 | + |
3430 | + public PublishingOptionsPane(Spit.Publishing.PluginHost host, string username, |
3431 | + Album[] albums, Spit.Publishing.Publisher.MediaType media_type, Gtk.Builder builder, |
3432 | +@@ -1131,7 +739,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
3433 | + size_combo = (Gtk.ComboBoxText) builder.get_object("size_combo"); |
3434 | + strip_metadata_check = (Gtk.CheckButton) this.builder.get_object("strip_metadata_check"); |
3435 | + publish_button = (Gtk.Button) builder.get_object("publish_button"); |
3436 | +- logout_button = (Gtk.Button) builder.get_object("logout_button"); |
3437 | + |
3438 | + // populate any widgets whose contents are programmatically-generated. |
3439 | + login_identity_label.set_label(_("You are logged into Picasa Web Albums as %s.").printf(username)); |
3440 | +@@ -1157,7 +764,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
3441 | + use_existing_radio.clicked.connect(on_use_existing_radio_clicked); |
3442 | + create_new_radio.clicked.connect(on_create_new_radio_clicked); |
3443 | + new_album_entry.changed.connect(on_new_album_entry_changed); |
3444 | +- logout_button.clicked.connect(on_logout_clicked); |
3445 | + publish_button.clicked.connect(on_publish_clicked); |
3446 | + } |
3447 | + |
3448 | +@@ -1200,10 +806,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
3449 | + public_check.set_sensitive(true); |
3450 | + } |
3451 | + |
3452 | +- private void on_logout_clicked() { |
3453 | +- logout(); |
3454 | +- } |
3455 | +- |
3456 | + private void update_publish_button_sensitivity() { |
3457 | + string album_name = new_album_entry.get_text(); |
3458 | + publish_button.set_sensitive(!(album_name.strip() == "" && |
3459 | +@@ -1263,10 +865,6 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
3460 | + publish(parameters, strip_metadata_check.get_active()); |
3461 | + } |
3462 | + |
3463 | +- protected void notify_logout() { |
3464 | +- logout(); |
3465 | +- } |
3466 | +- |
3467 | + public Gtk.Widget get_widget() { |
3468 | + return pane_widget; |
3469 | + } |
3470 | +@@ -1279,12 +877,10 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object { |
3471 | + installed(); |
3472 | + |
3473 | + publish.connect(notify_publish); |
3474 | +- logout.connect(notify_logout); |
3475 | + } |
3476 | + |
3477 | + public void on_pane_uninstalled() { |
3478 | + publish.disconnect(notify_publish); |
3479 | +- logout.disconnect(notify_logout); |
3480 | + } |
3481 | + } |
3482 | + |
3483 | +diff --git a/plugins/shotwell-publishing/PiwigoPublishing.vala b/plugins/shotwell-publishing/PiwigoPublishing.vala |
3484 | +index 772536c..0c96d84 100644 |
3485 | +--- a/plugins/shotwell-publishing/PiwigoPublishing.vala |
3486 | ++++ b/plugins/shotwell-publishing/PiwigoPublishing.vala |
3487 | +@@ -42,7 +42,7 @@ public class PiwigoService : Object, Spit.Pluggable, Spit.Publishing.Service { |
3488 | + public void activation(bool enabled) { |
3489 | + } |
3490 | + |
3491 | +- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) { |
3492 | ++ public Spit.Publishing.Publisher create_publisher(string? account, Spit.Publishing.PluginHost host) { |
3493 | + return new Publishing.Piwigo.PiwigoPublisher(this, host); |
3494 | + } |
3495 | + |
3496 | +diff --git a/plugins/shotwell-publishing/YouTubePublishing.vala b/plugins/shotwell-publishing/YouTubePublishing.vala |
3497 | +index 9319eb9..fc03fe7 100644 |
3498 | +--- a/plugins/shotwell-publishing/YouTubePublishing.vala |
3499 | ++++ b/plugins/shotwell-publishing/YouTubePublishing.vala |
3500 | +@@ -39,7 +39,7 @@ public class YouTubeService : Object, Spit.Pluggable, Spit.Publishing.Service { |
3501 | + info.icons = icon_pixbuf_set; |
3502 | + } |
3503 | + |
3504 | +- public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) { |
3505 | ++ public Spit.Publishing.Publisher create_publisher(string? account, Spit.Publishing.PluginHost host) { |
3506 | + return new Publishing.YouTube.YouTubePublisher(this, host); |
3507 | + } |
3508 | + |
3509 | +diff --git a/plugins/shotwell-publishing/facebook_publishing_options_pane.glade b/plugins/shotwell-publishing/facebook_publishing_options_pane.glade |
3510 | +index 0ba57ad..567b8c8 100644 |
3511 | +--- a/plugins/shotwell-publishing/facebook_publishing_options_pane.glade |
3512 | ++++ b/plugins/shotwell-publishing/facebook_publishing_options_pane.glade |
3513 | +@@ -196,29 +196,14 @@ anything put into this field won't display)</property> |
3514 | + <object class="GtkBox" id="box2"> |
3515 | + <property name="visible">True</property> |
3516 | + <property name="can_focus">False</property> |
3517 | ++ <property name="halign">center</property> |
3518 | + <property name="spacing">32</property> |
3519 | + <property name="homogeneous">True</property> |
3520 | + <child> |
3521 | +- <object class="GtkButton" id="logout_button"> |
3522 | +- <property name="label" translatable="yes">_Logout</property> |
3523 | +- <property name="use_action_appearance">False</property> |
3524 | +- <property name="visible">True</property> |
3525 | +- <property name="can_focus">True</property> |
3526 | +- <property name="receives_default">True</property> |
3527 | +- <property name="use_action_appearance">False</property> |
3528 | +- <property name="use_underline">True</property> |
3529 | +- </object> |
3530 | +- <packing> |
3531 | +- <property name="expand">False</property> |
3532 | +- <property name="fill">True</property> |
3533 | +- <property name="padding">80</property> |
3534 | +- <property name="position">0</property> |
3535 | +- </packing> |
3536 | +- </child> |
3537 | +- <child> |
3538 | + <object class="GtkButton" id="publish_button"> |
3539 | + <property name="label" translatable="yes">_Publish</property> |
3540 | + <property name="use_action_appearance">False</property> |
3541 | ++ <property name="width_request">96</property> |
3542 | + <property name="visible">True</property> |
3543 | + <property name="can_focus">True</property> |
3544 | + <property name="receives_default">True</property> |
3545 | +@@ -229,13 +214,13 @@ anything put into this field won't display)</property> |
3546 | + <property name="expand">False</property> |
3547 | + <property name="fill">True</property> |
3548 | + <property name="padding">80</property> |
3549 | +- <property name="position">1</property> |
3550 | ++ <property name="position">0</property> |
3551 | + </packing> |
3552 | + </child> |
3553 | + </object> |
3554 | + <packing> |
3555 | + <property name="expand">False</property> |
3556 | +- <property name="fill">True</property> |
3557 | ++ <property name="fill">False</property> |
3558 | + <property name="padding">2</property> |
3559 | + <property name="position">3</property> |
3560 | + </packing> |
3561 | +diff --git a/plugins/shotwell-publishing/flickr_publishing_options_pane.glade b/plugins/shotwell-publishing/flickr_publishing_options_pane.glade |
3562 | +index e39a52e..b9edd04 100644 |
3563 | +--- a/plugins/shotwell-publishing/flickr_publishing_options_pane.glade |
3564 | ++++ b/plugins/shotwell-publishing/flickr_publishing_options_pane.glade |
3565 | +@@ -135,24 +135,6 @@ so changes made here will not display)</property> |
3566 | + <property name="spacing">64</property> |
3567 | + <property name="homogeneous">True</property> |
3568 | + <child> |
3569 | +- <object class="GtkButton" id="logout_button"> |
3570 | +- <property name="label" translatable="yes">_Logout</property> |
3571 | +- <property name="use_action_appearance">False</property> |
3572 | +- <property name="width_request">96</property> |
3573 | +- <property name="visible">True</property> |
3574 | +- <property name="can_focus">True</property> |
3575 | +- <property name="receives_default">True</property> |
3576 | +- <property name="use_action_appearance">False</property> |
3577 | +- <property name="use_underline">True</property> |
3578 | +- </object> |
3579 | +- <packing> |
3580 | +- <property name="expand">False</property> |
3581 | +- <property name="fill">True</property> |
3582 | +- <property name="padding">24</property> |
3583 | +- <property name="position">0</property> |
3584 | +- </packing> |
3585 | +- </child> |
3586 | +- <child> |
3587 | + <object class="GtkButton" id="publish_button"> |
3588 | + <property name="label" translatable="yes">_Publish</property> |
3589 | + <property name="use_action_appearance">False</property> |
3590 | +@@ -167,7 +149,7 @@ so changes made here will not display)</property> |
3591 | + <property name="expand">False</property> |
3592 | + <property name="fill">True</property> |
3593 | + <property name="padding">24</property> |
3594 | +- <property name="position">1</property> |
3595 | ++ <property name="position">0</property> |
3596 | + </packing> |
3597 | + </child> |
3598 | + </object> |
3599 | +diff --git a/plugins/shotwell-publishing/picasa_publishing_options_pane.glade b/plugins/shotwell-publishing/picasa_publishing_options_pane.glade |
3600 | +index 07af67d..4d2cfb4 100644 |
3601 | +--- a/plugins/shotwell-publishing/picasa_publishing_options_pane.glade |
3602 | ++++ b/plugins/shotwell-publishing/picasa_publishing_options_pane.glade |
3603 | +@@ -226,32 +226,16 @@ |
3604 | + <object class="GtkBox" id="button_area_box"> |
3605 | + <property name="visible">True</property> |
3606 | + <property name="can_focus">False</property> |
3607 | +- <property name="margin_left">112</property> |
3608 | +- <property name="margin_right">112</property> |
3609 | ++ <property name="halign">center</property> |
3610 | + <property name="margin_top">48</property> |
3611 | + <property name="margin_bottom">24</property> |
3612 | + <property name="spacing">128</property> |
3613 | + <property name="homogeneous">True</property> |
3614 | + <child> |
3615 | +- <object class="GtkButton" id="logout_button"> |
3616 | +- <property name="label" translatable="yes">_Logout</property> |
3617 | +- <property name="use_action_appearance">False</property> |
3618 | +- <property name="visible">True</property> |
3619 | +- <property name="can_focus">True</property> |
3620 | +- <property name="receives_default">True</property> |
3621 | +- <property name="use_action_appearance">False</property> |
3622 | +- <property name="use_underline">True</property> |
3623 | +- </object> |
3624 | +- <packing> |
3625 | +- <property name="expand">False</property> |
3626 | +- <property name="fill">True</property> |
3627 | +- <property name="position">0</property> |
3628 | +- </packing> |
3629 | +- </child> |
3630 | +- <child> |
3631 | + <object class="GtkButton" id="publish_button"> |
3632 | + <property name="label" translatable="yes">_Publish</property> |
3633 | + <property name="use_action_appearance">False</property> |
3634 | ++ <property name="width_request">96</property> |
3635 | + <property name="visible">True</property> |
3636 | + <property name="can_focus">True</property> |
3637 | + <property name="receives_default">True</property> |
3638 | +@@ -261,13 +245,13 @@ |
3639 | + <packing> |
3640 | + <property name="expand">False</property> |
3641 | + <property name="fill">True</property> |
3642 | +- <property name="position">1</property> |
3643 | ++ <property name="position">0</property> |
3644 | + </packing> |
3645 | + </child> |
3646 | + </object> |
3647 | + <packing> |
3648 | + <property name="expand">False</property> |
3649 | +- <property name="fill">True</property> |
3650 | ++ <property name="fill">False</property> |
3651 | + <property name="position">4</property> |
3652 | + </packing> |
3653 | + </child> |
3654 | +diff --git a/src/plugins/PublishingInterfaces.vala b/src/plugins/PublishingInterfaces.vala |
3655 | +index 339cc9d..4ed2bec 100644 |
3656 | +--- a/src/plugins/PublishingInterfaces.vala |
3657 | ++++ b/src/plugins/PublishingInterfaces.vala |
3658 | +@@ -494,6 +494,7 @@ public interface PluginHost : GLib.Object, Spit.HostInterface { |
3659 | + */ |
3660 | + public abstract Spit.Publishing.Publisher.MediaType get_publishable_media_type(); |
3661 | + |
3662 | ++ public abstract ulong get_dialog_xid(); |
3663 | + // |
3664 | + // For future expansion. |
3665 | + // |
3666 | +@@ -579,18 +580,26 @@ public interface Service : Object, Spit.Pluggable { |
3667 | + * A factory method that instantiates and returns a new {@link Publisher} object that |
3668 | + * encapsulates a connection to the remote publishing service that this Service describes. |
3669 | + */ |
3670 | +- public abstract Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host); |
3671 | ++ public abstract Spit.Publishing.Publisher create_publisher(string? account, Spit.Publishing.PluginHost host); |
3672 | + |
3673 | + /** |
3674 | + * Returns the kinds of media that this service can work with. |
3675 | + */ |
3676 | + public abstract Spit.Publishing.Publisher.MediaType get_supported_media(); |
3677 | + |
3678 | ++ /** |
3679 | ++ * Checks whether the service is enabled. |
3680 | ++ */ |
3681 | ++ public virtual bool is_enabled() { return true; } |
3682 | ++ |
3683 | ++ /** |
3684 | ++ * List the accounts available for this service. |
3685 | ++ */ |
3686 | ++ public virtual string[] list_account_names() { return {}; } |
3687 | ++ |
3688 | + // |
3689 | + // For future expansion. |
3690 | + // |
3691 | +- protected virtual void reserved0() {} |
3692 | +- protected virtual void reserved1() {} |
3693 | + protected virtual void reserved2() {} |
3694 | + protected virtual void reserved3() {} |
3695 | + protected virtual void reserved4() {} |
3696 | +diff --git a/src/publishing/PublishingPluginHost.vala b/src/publishing/PublishingPluginHost.vala |
3697 | +index 7be7bed..c0417f8 100644 |
3698 | +--- a/src/publishing/PublishingPluginHost.vala |
3699 | ++++ b/src/publishing/PublishingPluginHost.vala |
3700 | +@@ -21,7 +21,8 @@ public class ConcretePublishingHost : Plugins.StandardHostInterface, |
3701 | + private Spit.Publishing.Publisher.MediaType media_type = |
3702 | + Spit.Publishing.Publisher.MediaType.NONE; |
3703 | + |
3704 | +- public ConcretePublishingHost(Service service, PublishingUI.PublishingDialog dialog, |
3705 | ++ public ConcretePublishingHost(Service service, string? account, |
3706 | ++ PublishingUI.PublishingDialog dialog, |
3707 | + Publishable[] publishables) { |
3708 | + base(service, "sharing"); |
3709 | + this.dialog = dialog; |
3710 | +@@ -30,7 +31,7 @@ public class ConcretePublishingHost : Plugins.StandardHostInterface, |
3711 | + foreach (Publishable curr_publishable in publishables) |
3712 | + this.media_type |= curr_publishable.get_media_type(); |
3713 | + |
3714 | +- this.active_publisher = service.create_publisher(this); |
3715 | ++ this.active_publisher = service.create_publisher(account, this); |
3716 | + } |
3717 | + |
3718 | + private void on_login_clicked() { |
3719 | +@@ -232,6 +233,13 @@ public class ConcretePublishingHost : Plugins.StandardHostInterface, |
3720 | + |
3721 | + return report_plugin_upload_progress; |
3722 | + } |
3723 | ++ |
3724 | ++ public ulong get_dialog_xid() { |
3725 | ++ if (dialog == null) return 0; |
3726 | ++ |
3727 | ++ Gdk.Window window = dialog.get_window(); |
3728 | ++ return Gdk.X11Window.get_xid(window); |
3729 | ++ } |
3730 | + } |
3731 | + |
3732 | + } |
3733 | +diff --git a/src/publishing/PublishingUI.vala b/src/publishing/PublishingUI.vala |
3734 | +index b7f7f75..37f2713 100644 |
3735 | +--- a/src/publishing/PublishingUI.vala |
3736 | ++++ b/src/publishing/PublishingUI.vala |
3737 | +@@ -130,6 +130,11 @@ public class LoginWaitPane : StaticMessagePane { |
3738 | + } |
3739 | + |
3740 | + public class PublishingDialog : Gtk.Dialog { |
3741 | ++ private struct AccountService { |
3742 | ++ Spit.Publishing.Service service; |
3743 | ++ string? account; |
3744 | ++ } |
3745 | ++ |
3746 | + private const int LARGE_WINDOW_WIDTH = 860; |
3747 | + private const int LARGE_WINDOW_HEIGHT = 688; |
3748 | + private const int COLOSSAL_WINDOW_WIDTH = 1024; |
3749 | +@@ -151,6 +156,8 @@ public class PublishingDialog : Gtk.Dialog { |
3750 | + private Spit.Publishing.DialogPane active_pane; |
3751 | + private Spit.Publishing.Publishable[] publishables; |
3752 | + private Spit.Publishing.ConcretePublishingHost host; |
3753 | ++ private Gee.HashMap<string,AccountService?> services; |
3754 | ++ private int service_selector_add_accounts_index; |
3755 | + |
3756 | + protected PublishingDialog(Gee.Collection<MediaSource> to_publish) { |
3757 | + assert(to_publish.size > 0); |
3758 | +@@ -158,6 +165,8 @@ public class PublishingDialog : Gtk.Dialog { |
3759 | + resizable = false; |
3760 | + delete_event.connect(on_window_close); |
3761 | + |
3762 | ++ services = new Gee.HashMap<string,AccountService?>(); |
3763 | ++ |
3764 | + publishables = new Spit.Publishing.Publishable[0]; |
3765 | + bool has_photos = false; |
3766 | + bool has_videos = false; |
3767 | +@@ -206,9 +215,28 @@ public class PublishingDialog : Gtk.Dialog { |
3768 | + if (last_used_service != null && last_used_service == curr_service_id) |
3769 | + last_used_index = ticker; |
3770 | + |
3771 | +- service_selector_box.append_text(service.get_pluggable_name()); |
3772 | +- ticker++; |
3773 | ++ var account_names = service.list_account_names(); |
3774 | ++ if (account_names.length == 0) { |
3775 | ++ account_names += null; |
3776 | ++ } |
3777 | ++ |
3778 | ++ foreach (string? account_name in account_names) { |
3779 | ++ string service_name = service.get_pluggable_name(); |
3780 | ++ if (account_name != null) { |
3781 | ++ service_name += " (%s)".printf(account_name); |
3782 | ++ } |
3783 | ++ |
3784 | ++ AccountService account_service = { |
3785 | ++ service: service, |
3786 | ++ account: account_name |
3787 | ++ }; |
3788 | ++ services.set(service_name, account_service); |
3789 | ++ service_selector_box.append_text(service_name); |
3790 | ++ ticker++; |
3791 | ++ } |
3792 | + } |
3793 | ++ service_selector_box.append_text(_("Add more accounts…")); |
3794 | ++ service_selector_add_accounts_index = ticker; |
3795 | + if (last_used_index >= 0) |
3796 | + service_selector_box.set_active(last_used_index); |
3797 | + else |
3798 | +@@ -296,6 +324,7 @@ public class PublishingDialog : Gtk.Dialog { |
3799 | + Spit.Publishing.Service[] all_services = load_all_services(); |
3800 | + |
3801 | + foreach (Spit.Publishing.Service service in all_services) { |
3802 | ++ if (!service.is_enabled()) continue; |
3803 | + |
3804 | + if (has_photos && !has_videos) { |
3805 | + if ((service.get_supported_media() & Spit.Publishing.Publisher.MediaType.PHOTO) != 0) |
3806 | +@@ -384,21 +413,34 @@ public class PublishingDialog : Gtk.Dialog { |
3807 | + } |
3808 | + |
3809 | + private void on_service_changed() { |
3810 | +- string service_name = service_selector_box.get_active_text(); |
3811 | +- |
3812 | +- Spit.Publishing.Service? selected_service = null; |
3813 | +- Spit.Publishing.Service[] services = load_all_services(); |
3814 | +- foreach (Spit.Publishing.Service service in services) { |
3815 | +- if (service.get_pluggable_name() == service_name) { |
3816 | +- selected_service = service; |
3817 | +- break; |
3818 | ++ if (service_selector_box.get_active() == |
3819 | ++ service_selector_add_accounts_index) { |
3820 | ++ debug("Starting Online Accounts..."); |
3821 | ++ try |
3822 | ++ { |
3823 | ++ DesktopAppInfo app_info = |
3824 | ++ new DesktopAppInfo ("gnome-credentials-panel.desktop"); |
3825 | ++ GLib.Process.spawn_command_line_async(app_info.get_commandline() + " application=shotwell"); |
3826 | ++ } |
3827 | ++ catch (Error e) |
3828 | ++ { |
3829 | ++ warning ("Error launching Online Accounts: %s", e.message); |
3830 | + } |
3831 | ++ |
3832 | ++ on_close_cancel_clicked(); |
3833 | ++ return; |
3834 | + } |
3835 | +- assert(selected_service != null); |
3836 | ++ |
3837 | ++ string service_name = service_selector_box.get_active_text(); |
3838 | ++ |
3839 | ++ AccountService account_service = services.get(service_name); |
3840 | ++ Spit.Publishing.Service? selected_service = account_service.service; |
3841 | + |
3842 | + Config.Facade.get_instance().set_last_used_service(selected_service.get_id()); |
3843 | + |
3844 | +- host = new Spit.Publishing.ConcretePublishingHost(selected_service, this, publishables); |
3845 | ++ host = new Spit.Publishing.ConcretePublishingHost(selected_service, |
3846 | ++ account_service.account, |
3847 | ++ this, publishables); |
3848 | + host.start_publishing(); |
3849 | + } |
3850 | + |
3851 | |
3852 | === added file 'debian/patches/series' |
3853 | --- debian/patches/series 1970-01-01 00:00:00 +0000 |
3854 | +++ debian/patches/series 2012-09-17 10:22:22 +0000 |
3855 | @@ -0,0 +1,6 @@ |
3856 | +02_desktop_translations.patch |
3857 | +03_appmenu_no_stubs.patch |
3858 | +04_no_resize_grip.patch |
3859 | +05-gomp-linking.patch |
3860 | + |
3861 | +06_uoa.patch |
3862 | |
3863 | === added file 'debian/rules' |
3864 | --- debian/rules 1970-01-01 00:00:00 +0000 |
3865 | +++ debian/rules 2012-09-17 10:22:22 +0000 |
3866 | @@ -0,0 +1,10 @@ |
3867 | +#!/usr/bin/make -f |
3868 | + |
3869 | +%: |
3870 | + dh $@ --with-scour |
3871 | + |
3872 | +override_dh_auto_configure: |
3873 | + dh_auto_configure -- --disable-schemas-compile --disable-icon-update --unity-support |
3874 | + |
3875 | +override_dh_installchangelogs: |
3876 | + dh_installchangelogs NEWS |
3877 | |
3878 | === added file 'debian/shotwell-video-thumbnailer.1' |
3879 | --- debian/shotwell-video-thumbnailer.1 1970-01-01 00:00:00 +0000 |
3880 | +++ debian/shotwell-video-thumbnailer.1 2012-09-17 10:22:22 +0000 |
3881 | @@ -0,0 +1,13 @@ |
3882 | +.TH shotwell-video-thumbnailer 1 "August 21, 2011" |
3883 | +.SH NAME |
3884 | +shotwell-video-thumbnailer \- writes video thumbnail to stdout |
3885 | +.SH DESCRIPTION |
3886 | +Writes video thumbnail to stdout. |
3887 | +.PP |
3888 | +This program is designed to be called by shotwell directly, normally it is not |
3889 | +of any use for shotwell users. |
3890 | +.SH COPYRIGHT |
3891 | +This manual page is Copyright 2011 Luca Falavigna <dktrkranz@debian.org>. |
3892 | +Permission is granted to copy, distribute and/or modify this document |
3893 | +under the terms of the GNU Lesser General Public License, Version 2.1 or any |
3894 | +later version published by the Free Software Foundation. |
3895 | |
3896 | === added file 'debian/shotwell.1' |
3897 | --- debian/shotwell.1 1970-01-01 00:00:00 +0000 |
3898 | +++ debian/shotwell.1 2012-09-17 10:22:22 +0000 |
3899 | @@ -0,0 +1,14 @@ |
3900 | +.TH shotwell 1 "December 30, 2009" |
3901 | +.SH NAME |
3902 | +shotwell \- a digital photo organizer |
3903 | +.SH DESCRIPTION |
3904 | +.B shotwell |
3905 | +is a digital photo organizer designed for the GNOME desktop environment. It |
3906 | +allows you to import photos from disk or camera, organize them in various ways, |
3907 | +view them in full-window or fullscreen mode, and export them to share with |
3908 | +others. |
3909 | +.SH AUTHOR |
3910 | +shotwell was written by Jim Nelson, Lucas Beeler and Allison Barlow. |
3911 | +.PP |
3912 | +This manual page was written by Devid Antonio Filoni <d.filoni@ubuntu.com>, |
3913 | +for the Debian project (and may be used by others). |
3914 | |
3915 | === added file 'debian/shotwell.lintian-overrides' |
3916 | --- debian/shotwell.lintian-overrides 1970-01-01 00:00:00 +0000 |
3917 | +++ debian/shotwell.lintian-overrides 2012-09-17 10:22:22 +0000 |
3918 | @@ -0,0 +1,2 @@ |
3919 | +library-not-linked-against-libc |
3920 | +image-file-in-usr-lib |
3921 | |
3922 | === added directory 'debian/source' |
3923 | === added file 'debian/source/format' |
3924 | --- debian/source/format 1970-01-01 00:00:00 +0000 |
3925 | +++ debian/source/format 2012-09-17 10:22:22 +0000 |
3926 | @@ -0,0 +1,1 @@ |
3927 | +3.0 (quilt) |
3928 | |
3929 | === added file 'debian/watch' |
3930 | --- debian/watch 1970-01-01 00:00:00 +0000 |
3931 | +++ debian/watch 2012-09-17 10:22:22 +0000 |
3932 | @@ -0,0 +1,3 @@ |
3933 | +version=3 |
3934 | +opts=dversionmangle=s/\+dfsg// \ |
3935 | + http://yorba.org/download/shotwell/([\d\.]+)/unstable/shotwell-(.*)\.tar\.xz |