[evince/open_pdf: 4/4] pdf: let launch action to open pdfs from click event




commit e5594f96468bf737bb90fee92a26f20837b614d5
Author: Nelson Benítez León <nbenitezl gmail com>
Date:   Sun Jan 30 21:37:07 2022 -0400

    pdf: let launch action to open pdfs from click event
    
    Issue #1333 removed Evince ability to run any command
    from pdf 'launch action', while the security concerns
    brought up in #1333 were valid, the measure implemented
    was maybe too drastic, as there are valid use cases
    where launching a pdf is needed.
    
    For instance, the cases described in issue #48, one of
    them is the document 'Nissan Patrol Maintenance Manual'
    which is comprised of several pdf files, where there is
    one acting as index for the others, this index pdf file
    uses the launch action to open the other pdf's.
    
    So this commit allows to launch a file from a link
    action only when:
    
    - that file is a pdf file.
    - the launch action originates from click event,
      to be sure the user requested the action.
    
    Besides, we don't just let the system execute the
    file, but because it's a pdf we do it ourselves by
    launching a new evince instance (or if that file was
    already opened then presenting its window).
    
    Fixes issue #48

 libview/ev-view.c | 29 +++++++++++--------
 libview/ev-view.h |  3 ++
 shell/ev-window.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 101 insertions(+), 15 deletions(-)
---
diff --git a/libview/ev-view.c b/libview/ev-view.c
index 358eb5e0c..18f10052c 100644
--- a/libview/ev-view.c
+++ b/libview/ev-view.c
@@ -2183,6 +2183,23 @@ tip_from_link (EvView *view, EvLink *link)
        return msg;
 }
 
+gboolean
+ev_view_current_event_is_type (EvView *view, GdkEventType type)
+{
+       GdkEvent *event;
+       gboolean ret = FALSE;
+
+       event = gtk_get_current_event ();
+       if (event) {
+               if (event->type == type &&
+                   gdk_event_get_window (event) == gtk_widget_get_window (GTK_WIDGET (view))) {
+                       ret = TRUE;
+               }
+               gdk_event_free (event);
+       }
+       return ret;
+}
+
 static void
 ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
 {
@@ -2222,13 +2239,11 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
                EvLinkDest      *dest;
                EvLinkDestType   type;
                GtkWidget       *popover, *spinner;
-               GdkEvent        *event;
                cairo_surface_t *page_surface = NULL;
                guint            link_dest_page;
                EvPoint          link_dest_doc;
                GdkPoint         link_dest_view;
                gint             device_scale = 1;
-               gboolean         from_motion = FALSE;
 
                ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
 
@@ -2244,16 +2259,8 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
                if (!dest)
                        return;
 
-               event = gtk_get_current_event ();
-               if (event) {
-                       if (event->type == GDK_MOTION_NOTIFY &&
-                           gdk_event_get_window (event) == gtk_widget_get_window (GTK_WIDGET (view))) {
-                               from_motion = TRUE;
-                       }
-                       gdk_event_free (event);
-               }
                /* Show preview popups only for motion events - Issue #1666 */
-               if (!from_motion)
+               if (!ev_view_current_event_is_type (view, GDK_MOTION_NOTIFY))
                        return;
 
                type = ev_link_dest_get_dest_type (dest);
diff --git a/libview/ev-view.h b/libview/ev-view.h
index 1ade3b731..74959c90d 100644
--- a/libview/ev-view.h
+++ b/libview/ev-view.h
@@ -191,4 +191,7 @@ EV_PUBLIC
 void           ev_view_set_caret_cursor_position    (EvView  *view,
                                                      guint    page,
                                                      guint    offset);
+EV_PUBLIC
+gboolean       ev_view_current_event_is_type        (EvView *view,
+                                                    GdkEventType type);
 G_END_DECLS
diff --git a/shell/ev-window.c b/shell/ev-window.c
index 921be7de6..88d770e85 100644
--- a/shell/ev-window.c
+++ b/shell/ev-window.c
@@ -6636,12 +6636,88 @@ window_configure_event_cb (EvWindow *window, GdkEventConfigure *event, gpointer
        return FALSE;
 }
 
+static gchar *
+get_uri (const char *filename, EvWindow *window)
+{
+       EvWindowPrivate *priv = GET_PRIVATE (window);
+       gchar *ret;
+
+       if (g_path_is_absolute (filename)) {
+               ret =  g_strdup (filename);
+       } else {
+               GFile *base_file, *file;
+               gchar *dir;
+
+               dir = g_path_get_dirname (priv->uri);
+               base_file = g_file_new_for_uri (dir);
+               file = g_file_resolve_relative_path (base_file, filename);
+               ret = g_file_get_uri (file);
+
+               g_free (dir);
+               g_object_unref (base_file);
+               g_object_unref (file);
+       }
+
+       return ret;
+}
+
+static gboolean
+file_is_pdf (const char *uri)
+{
+       GFile *file;
+       GFileInfo *file_info;
+       gboolean ret = FALSE;
+
+       file = g_file_new_for_uri (uri);
+       file_info = g_file_query_info (file,
+                                      G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+                                      G_FILE_QUERY_INFO_NONE, NULL, NULL);
+       if (file_info != NULL) {
+               const gchar *content_type;
+               content_type = g_file_info_get_content_type (file_info);
+               if (content_type) {
+                       gchar *mime_type;
+                       mime_type = g_content_type_get_mime_type (content_type);
+                       if (g_ascii_strcasecmp (mime_type, "application/pdf") == 0)
+                               ret = TRUE;
+                       g_free (mime_type);
+               }
+               g_object_unref (file_info);
+       }
+       g_object_unref (file);
+
+       return ret;
+}
+
 static void
-launch_action (EvWindow *window, EvLinkAction *action)
+launch_action (EvWindow *ev_window, EvLinkAction *action)
 {
-       ev_window_warning_message (window,
-                                   _("Security alert: this document has been prevented from opening the file 
“%s”"),
-                                  ev_link_action_get_filename (action));
+       EvView *view;
+       EvWindowPrivate *priv = GET_PRIVATE (ev_window);
+       const char *filename = ev_link_action_get_filename (action);
+       gchar *uri;
+
+       if (filename == NULL)
+               return;
+
+       uri = get_uri (filename, ev_window);
+       view = EV_VIEW (priv->view);
+
+       if (!file_is_pdf (uri) || !ev_view_current_event_is_type (view, GDK_BUTTON_RELEASE)) {
+               ev_window_warning_message (ev_window,
+                       _("Security alert: this document has been prevented from opening the file “%s”"),
+                       filename);
+               return;
+       }
+       /* We are asked to open a PDF file, from a click event, proceed with that - Issue #48
+        * This spawns new Evince process or if already opened presents its window */
+       ev_application_open_uri_at_dest (EV_APP, uri,
+                                        gtk_window_get_screen (GTK_WINDOW (ev_window)),
+                                        ev_link_action_get_dest (action),
+                                        priv->window_mode, NULL,
+                                        gtk_get_current_event_time ());
+       g_free (uri);
+
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]