[gnome-documents/f19] Backport support for previewing password protected PDFs (GNOME #700716)
Debarshi Ray
rishi at fedoraproject.org
Thu Jul 11 13:05:40 UTC 2013
commit c67ead5e5d25f16b17f926241518fbe6ce06c2bb
Author: Debarshi Ray <debarshir at gnome.org>
Date: Thu Jul 11 15:05:16 2013 +0200
Backport support for previewing password protected PDFs (GNOME #700716)
...ort-previewing-of-password-protected-PDFs.patch | 484 ++++++++++++++++++++
gnome-documents.spec | 13 +-
2 files changed, 496 insertions(+), 1 deletions(-)
---
diff --git a/0001-Support-previewing-of-password-protected-PDFs.patch b/0001-Support-previewing-of-password-protected-PDFs.patch
new file mode 100644
index 0000000..47c49bb
--- /dev/null
+++ b/0001-Support-previewing-of-password-protected-PDFs.patch
@@ -0,0 +1,484 @@
+From 2781cd44e764b89f0342f5efc2afc5ca35e54efc Mon Sep 17 00:00:00 2001
+From: Debarshi Ray <debarshir at gnome.org>
+Date: Mon, 27 May 2013 16:48:49 +0200
+Subject: [PATCH] Support previewing of password protected PDFs
+
+Delay changing the window mode when loading a document, so that we are
+still in the overview when presenting the dialog to enter the password.
+We switch the mode to preview when load-finished or load-error has
+been received.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=700716
+---
+ src/Makefile-js.am | 1 +
+ src/documents.js | 24 ++++++-----
+ src/embed.js | 28 ++++++++++---
+ src/lib/gd-pdf-loader.c | 40 +++++++++++++++---
+ src/lib/gd-pdf-loader.h | 1 +
+ src/mainToolbar.js | 3 +-
+ src/password.js | 105 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 7 files changed, 181 insertions(+), 21 deletions(-)
+ create mode 100644 src/password.js
+
+diff --git a/src/Makefile-js.am b/src/Makefile-js.am
+index 9387e0f..764981e 100644
+--- a/src/Makefile-js.am
++++ b/src/Makefile-js.am
+@@ -11,6 +11,7 @@ dist_js_DATA = \
+ manager.js \
+ miners.js \
+ notifications.js \
++ password.js \
+ places.js \
+ presentation.js \
+ preview.js \
+diff --git a/src/documents.js b/src/documents.js
+index ed5fa92..c412b27 100644
+--- a/src/documents.js
++++ b/src/documents.js
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2011, 2012 Red Hat, Inc.
++ * Copyright (c) 2011, 2012, 2013 Red Hat, Inc.
+ *
+ * Gnome Documents is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+@@ -19,6 +19,7 @@
+ *
+ */
+
++const EvDocument = imports.gi.EvinceDocument;
+ const EvView = imports.gi.EvinceView;
+ const GdkPixbuf = imports.gi.GdkPixbuf;
+ const Gio = imports.gi.Gio;
+@@ -548,7 +549,7 @@ const DocCommon = new Lang.Class({
+ },
+
+ print: function(toplevel) {
+- this.load(null, Lang.bind(this,
++ this.load(null, null, Lang.bind(this,
+ function(doc, docModel, error) {
+ if (error) {
+ log('Unable to print document ' + this.uri + ': ' + error);
+@@ -621,8 +622,8 @@ const LocalDocument = new Lang.Class({
+ this.typeDescription = Gio.content_type_get_description(this.mimeType);
+ },
+
+- load: function(cancellable, callback) {
+- GdPrivate.pdf_loader_load_uri_async(this.uri, cancellable, Lang.bind(this,
++ load: function(passwd, cancellable, callback) {
++ GdPrivate.pdf_loader_load_uri_async(this.uri, passwd, cancellable, Lang.bind(this,
+ function(source, res) {
+ try {
+ let docModel = GdPrivate.pdf_loader_load_uri_finish(res);
+@@ -687,7 +688,7 @@ const GoogleDocument = new Lang.Class({
+ }));
+ },
+
+- load: function(cancellable, callback) {
++ load: function(passwd, cancellable, callback) {
+ this._createGDataEntry(cancellable, Lang.bind(this,
+ function(entry, service, exception) {
+ if (exception) {
+@@ -839,7 +840,7 @@ const SkydriveDocument = new Lang.Class({
+ }));
+ },
+
+- load: function(cancellable, callback) {
++ load: function(passwd, cancellable, callback) {
+ this._createZpjEntry(cancellable, Lang.bind(this,
+ function(entry, service, exception) {
+ if (exception) {
+@@ -1018,6 +1019,11 @@ const DocumentManager = new Lang.Class({
+ if (error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
+ return;
+
++ if (error.matches(EvDocument.DocumentError, EvDocument.DocumentError.ENCRYPTED)) {
++ this.emit('password-needed', doc);
++ return;
++ }
++
+ // Translators: %s is the title of a document
+ let message = _("Oops! Unable to load ā%sā").format(doc.name);
+ let exception = this._humanizeError(error);
+@@ -1042,7 +1048,7 @@ const DocumentManager = new Lang.Class({
+ this.emit('load-finished', doc, docModel);
+ },
+
+- reloadActiveItem: function() {
++ reloadActiveItem: function(passwd) {
+ let doc = this.getActiveItem();
+
+ if (!doc)
+@@ -1055,7 +1061,7 @@ const DocumentManager = new Lang.Class({
+ this._clearActiveDocModel();
+
+ this._loaderCancellable = new Gio.Cancellable();
+- doc.load(this._loaderCancellable, Lang.bind(this, this._onDocumentLoaded));
++ doc.load(passwd, this._loaderCancellable, Lang.bind(this, this._onDocumentLoaded));
+ this.emit('load-started', doc);
+ },
+
+@@ -1079,7 +1085,7 @@ const DocumentManager = new Lang.Class({
+ recentManager.add_item(doc.uri);
+
+ this._loaderCancellable = new Gio.Cancellable();
+- doc.load(this._loaderCancellable, Lang.bind(this, this._onDocumentLoaded));
++ doc.load(null, this._loaderCancellable, Lang.bind(this, this._onDocumentLoaded));
+ this.emit('load-started', doc);
+ },
+
+diff --git a/src/embed.js b/src/embed.js
+index 1d1744a..13b7e66 100644
+--- a/src/embed.js
++++ b/src/embed.js
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2011 Red Hat, Inc.
++ * Copyright (c) 2011, 2013 Red Hat, Inc.
+ *
+ * Gnome Documents is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+@@ -25,6 +25,7 @@ const Mainloop = imports.mainloop;
+ const Application = imports.application;
+ const MainToolbar = imports.mainToolbar;
+ const Notifications = imports.notifications;
++const Password = imports.password;
+ const Preview = imports.preview;
+ const Edit = imports.edit;
+ const Selections = imports.selections;
+@@ -269,6 +270,8 @@ const Embed = new Lang.Class({
+ Lang.bind(this, this._onLoadFinished));
+ Application.documentManager.connect('load-error',
+ Lang.bind(this, this._onLoadError));
++ Application.documentManager.connect('password-needed',
++ Lang.bind(this, this._onPasswordNeeded));
+
+ this._onQueryStatusChanged();
+
+@@ -354,15 +357,13 @@ const Embed = new Lang.Class({
+ },
+
+ _onActiveItemChanged: function(manager, doc) {
+- let newMode = WindowMode.WindowMode.OVERVIEW;
+-
+ if (doc) {
+ let collection = Application.collectionManager.getItemById(doc.id);
+ if (!collection)
+- newMode = WindowMode.WindowMode.PREVIEW;
++ return;
+ }
+
+- Application.modeController.setWindowMode(newMode);
++ Application.modeController.setWindowMode(WindowMode.WindowMode.OVERVIEW);
+ },
+
+ _clearLoadTimer: function() {
+@@ -385,6 +386,8 @@ const Embed = new Lang.Class({
+ },
+
+ _onLoadFinished: function(manager, doc, docModel) {
++ Application.modeController.setWindowMode(WindowMode.WindowMode.PREVIEW);
++
+ docModel.set_sizing_mode(EvView.SizingMode.AUTOMATIC);
+ docModel.set_page_layout(EvView.PageLayout.AUTOMATIC);
+ this._toolbar.setModel(docModel);
+@@ -397,11 +400,26 @@ const Embed = new Lang.Class({
+ },
+
+ _onLoadError: function(manager, doc, message, exception) {
++ Application.modeController.setWindowMode(WindowMode.WindowMode.PREVIEW);
++
+ this._clearLoadTimer();
+ this._spinnerBox.stop();
+ this._setError(message, exception.message);
+ },
+
++ _onPasswordNeeded: function(manager, doc) {
++ this._clearLoadTimer();
++ this._spinnerBox.stop();
++
++ let dialog = new Password.PasswordDialog(doc);
++ dialog.widget.connect('response', Lang.bind(this,
++ function(widget, response) {
++ dialog.widget.destroy();
++ if (response == Gtk.ResponseType.CANCEL)
++ Application.documentManager.setActiveItem(null);
++ }));
++ },
++
+ _prepareForOverview: function() {
+ if (this._preview)
+ this._preview.setModel(null);
+diff --git a/src/lib/gd-pdf-loader.c b/src/lib/gd-pdf-loader.c
+index 6b1aed2..f835f80 100644
+--- a/src/lib/gd-pdf-loader.c
++++ b/src/lib/gd-pdf-loader.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2011, 2012 Red Hat, Inc.
++ * Copyright (c) 2011, 2012, 2013 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+@@ -41,6 +41,9 @@ typedef struct {
+ gchar *pdf_path;
+ GPid unoconv_pid;
+
++ gchar *passwd;
++ gboolean passwd_tried;
++
+ GFile *download_file;
+ GInputStream *stream;
+
+@@ -135,6 +138,7 @@ pdf_load_job_free (PdfLoadJob *job)
+ g_clear_object (&job->zpj_entry);
+
+ g_free (job->uri);
++ g_free (job->passwd);
+ g_free (job->resource_id);
+
+ if (job->pdf_path != NULL) {
+@@ -157,6 +161,7 @@ pdf_load_job_new (GSimpleAsyncResult *result,
+ const gchar *uri,
+ GDataEntry *gdata_entry,
+ ZpjSkydriveEntry *zpj_entry,
++ const gchar *passwd,
+ GCancellable *cancellable)
+ {
+ PdfLoadJob *retval;
+@@ -169,6 +174,8 @@ pdf_load_job_new (GSimpleAsyncResult *result,
+
+ if (uri != NULL)
+ retval->uri = g_strdup (uri);
++ if (passwd != NULL)
++ retval->passwd = g_strdup (passwd);
+ if (gdata_entry != NULL)
+ retval->gdata_entry = g_object_ref (gdata_entry);
+ if (zpj_entry != NULL)
+@@ -222,14 +229,23 @@ ev_load_job_done (EvJob *ev_job,
+ PdfLoadJob *job = user_data;
+
+ if (ev_job_is_failed (ev_job) || (ev_job->document == NULL)) {
+- if (job->from_old_cache)
++ if (job->from_old_cache) {
+ pdf_load_job_force_refresh_cache (job);
+- else
++ } else if (g_error_matches (ev_job->error, EV_DOCUMENT_ERROR, EV_DOCUMENT_ERROR_ENCRYPTED)
++ && job->passwd != NULL
++ && !job->passwd_tried) {
++ /* EvJobLoad tries using the password only after the job has
++ * failed once.
++ */
++ ev_job_scheduler_push_job (ev_job, EV_JOB_PRIORITY_NONE);
++ job->passwd_tried = TRUE;
++ } else {
+ pdf_load_job_complete_error (job, (ev_job->error != NULL) ?
+ g_error_copy (ev_job->error) :
+ g_error_new_literal (G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Unable to load the document")));
++ }
+
+ g_clear_object (&ev_job);
+ return;
+@@ -255,6 +271,9 @@ pdf_load_job_from_pdf (PdfLoadJob *job)
+ }
+
+ ev_job = ev_job_load_new ((uri != NULL) ? (uri) : (job->uri));
++ if (job->passwd != NULL)
++ ev_job_load_set_password (EV_JOB_LOAD (ev_job), job->passwd);
++
+ g_signal_connect (ev_job, "finished",
+ G_CALLBACK (ev_load_job_done), job);
+
+@@ -1015,8 +1034,17 @@ pdf_load_job_start (PdfLoadJob *job)
+ pdf_load_job_from_regular_file (job);
+ }
+
++/**
++ * gd_pdf_loader_load_uri_async:
++ * @uri:
++ * @passwd: (allow-none):
++ * @cancellable: (allow-none):
++ * @callback:
++ * @user_data:
++ */
+ void
+ gd_pdf_loader_load_uri_async (const gchar *uri,
++ const gchar *passwd,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+@@ -1027,7 +1055,7 @@ gd_pdf_loader_load_uri_async (const gchar *uri,
+ result = g_simple_async_result_new (NULL, callback, user_data,
+ gd_pdf_loader_load_uri_async);
+
+- job = pdf_load_job_new (result, uri, NULL, NULL, cancellable);
++ job = pdf_load_job_new (result, uri, NULL, NULL, passwd, cancellable);
+
+ pdf_load_job_start (job);
+
+@@ -1068,7 +1096,7 @@ gd_pdf_loader_load_gdata_entry_async (GDataEntry *entry,
+ result = g_simple_async_result_new (NULL, callback, user_data,
+ gd_pdf_loader_load_gdata_entry_async);
+
+- job = pdf_load_job_new (result, NULL, entry, NULL, cancellable);
++ job = pdf_load_job_new (result, NULL, entry, NULL, NULL, cancellable);
+ job->gdata_service = g_object_ref (service);
+
+ pdf_load_job_start (job);
+@@ -1110,7 +1138,7 @@ gd_pdf_loader_load_zpj_entry_async (ZpjSkydriveEntry *entry,
+ result = g_simple_async_result_new (NULL, callback, user_data,
+ gd_pdf_loader_load_zpj_entry_async);
+
+- job = pdf_load_job_new (result, NULL, NULL, entry, cancellable);
++ job = pdf_load_job_new (result, NULL, NULL, entry, NULL, cancellable);
+ job->zpj_service = g_object_ref (service);
+
+ pdf_load_job_start (job);
+diff --git a/src/lib/gd-pdf-loader.h b/src/lib/gd-pdf-loader.h
+index 22b05b4..9e5ffb7 100644
+--- a/src/lib/gd-pdf-loader.h
++++ b/src/lib/gd-pdf-loader.h
+@@ -33,6 +33,7 @@
+ G_BEGIN_DECLS
+
+ void gd_pdf_loader_load_uri_async (const gchar *uri,
++ const gchar *passwd,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+diff --git a/src/mainToolbar.js b/src/mainToolbar.js
+index 25e6b94..a1b1c52 100644
+--- a/src/mainToolbar.js
++++ b/src/mainToolbar.js
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2011 Red Hat, Inc.
++ * Copyright (c) 2011, 2013 Red Hat, Inc.
+ *
+ * Gnome Documents is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+@@ -58,6 +58,7 @@ const MainToolbar = new Lang.Class({
+ }));
+
+ Application.documentManager.connect('load-error', Lang.bind(this, this._onLoadErrorOrPassword));
++ Application.documentManager.connect('password-needed', Lang.bind(this, this._onLoadErrorOrPassword));
+ },
+
+ _onLoadErrorOrPassword: function() {
+diff --git a/src/password.js b/src/password.js
+new file mode 100644
+index 0000000..3a09b10
+--- /dev/null
++++ b/src/password.js
+@@ -0,0 +1,105 @@
++/*
++ * Copyright (c) 2013 Red Hat, Inc.
++ *
++ * Gnome Documents is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * Gnome Documents is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with Gnome Documents; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ * Author: Debarshi Ray <debarshir at gnome.org>
++ *
++ */
++
++const Gio = imports.gi.Gio;
++const GLib = imports.gi.GLib;
++const Gtk = imports.gi.Gtk;
++const _ = imports.gettext.gettext;
++const C_ = imports.gettext.pgettext;
++
++const Application = imports.application;
++const Documents = imports.documents;
++const Mainloop = imports.mainloop;
++
++const Lang = imports.lang;
++
++const PasswordDialog = new Lang.Class({
++ Name: 'PasswordDialog',
++
++ _init: function(doc) {
++ let toplevel = Application.application.get_windows()[0];
++ this.widget = new Gtk.Dialog({ resizable: false,
++ transient_for: toplevel,
++ modal: true,
++ destroy_with_parent: true,
++ default_width: 400,
++ border_width: 6,
++ title: _("Password Required"),
++ hexpand: true });
++ this.widget.add_button('gtk-cancel', Gtk.ResponseType.CANCEL);
++ this.widget.add_button(_("_Unlock"), Gtk.ResponseType.OK);
++ this.widget.set_default_response(Gtk.ResponseType.OK);
++ this.widget.set_response_sensitive(Gtk.ResponseType.OK, false);
++
++ let grid = new Gtk.Grid({ column_spacing: 12,
++ row_spacing: 18,
++ border_width: 5,
++ margin_bottom: 6,
++ hexpand: true,
++ vexpand: true });
++
++ let contentArea = this.widget.get_content_area();
++ contentArea.pack_start(grid, true, true, 2);
++
++ let label;
++
++ let msg = _("Document %s is locked and requires a password to be opened."
++ ).format(doc.name);
++ // Doesn't respect halign and hexpand.
++ label = new Gtk.Label({ label: msg,
++ max_width_chars: 56,
++ use_markup: true,
++ wrap: true });
++ label.set_alignment(0.0, 0.5);
++ grid.attach(label, 0, 0, 2, 1);
++
++ let entry = new Gtk.Entry({ activates_default: true,
++ can_focus: true,
++ visibility: false,
++ hexpand: true });
++ label = new Gtk.Label({ label: _("_Password"),
++ mnemonic_widget: entry,
++ use_underline: true });
++ label.get_style_context().add_class('dim-label');
++ grid.attach(label, 0, 1, 1, 1);
++ grid.attach(entry, 1, 1, 1, 1);
++
++ entry.connect('realize', Lang.bind(this,
++ function() {
++ entry.grab_focus();
++ }));
++ entry.connect('changed', Lang.bind(this,
++ function() {
++ let length = entry.get_text_length();
++ this.widget.set_response_sensitive(Gtk.ResponseType.OK, (length != 0));
++ }));
++
++ this.widget.connect('response', Lang.bind(this,
++ function(widget, response) {
++ if (response != Gtk.ResponseType.OK)
++ return;
++ let passwd = entry.get_text();
++ Application.documentManager.reloadActiveItem(passwd);
++ }));
++
++ this.widget.show_all();
++ }
++});
+--
+1.8.3.1
+
diff --git a/gnome-documents.spec b/gnome-documents.spec
index d736973..6333216 100644
--- a/gnome-documents.spec
+++ b/gnome-documents.spec
@@ -2,13 +2,17 @@
Name: gnome-documents
Version: 3.8.3.1
-Release: 1%{?dist}
+Release: 2%{?dist}
Summary: A document manager application for GNOME
License: GPLv2+
URL: https://live.gnome.org/Design/Apps/Documents
Source0: http://ftp.acc.umu.se/pub/GNOME/sources/%{name}/3.8/%{name}-%{version}.tar.xz
+# https://bugzilla.gnome.org/show_bug.cgi?id=700716
+Patch0: 0001-Support-previewing-of-password-protected-PDFs.patch
+
+BuildRequires: autoconf
BuildRequires: intltool
BuildRequires: libgdata-devel
BuildRequires: gnome-desktop3-devel
@@ -32,8 +36,12 @@ the Documents directory.
%prep
%setup -q
+%patch0 -p1
%build
+autoreconf -fi
+intltoolize --automake -f
+
%configure --disable-static --enable-getting-started
make %{?_smp_mflags}
@@ -78,6 +86,9 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor >&/dev/null || :
%{_mandir}/man1/gnome-documents.1.gz
%changelog
+* Thu Jul 11 2013 Debarshi Ray <rishi at fedoraproject.org> - 3.8.3.1-2
+- Backport support for previewing password protected PDFs (GNOME #700716)
+
* Fri Jun 14 2013 Debarshi Ray <rishi at fedoraproject.org> - 3.8.3.1-1
- Update to 3.8.3.1
More information about the scm-commits
mailing list