1 /* nautilus-mime-actions.c - uri-specific versions of mime action functions
2  *
3  *  Copyright (C) 2000, 2001 Eazel, Inc.
4  *
5  *  The Gnome Library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Library General Public License as
7  *  published by the Free Software Foundation; either version 2 of the
8  *  License, or (at your option) any later version.
9  *
10  *  The Gnome Library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Library General Public
16  *  License along with the Gnome Library; see the file COPYING.LIB.  If not,
17  *  see <http://www.gnu.org/licenses/>.
18  *
19  *  Authors: Maciej Stachowiak <mjs@eazel.com>
20  */
21 
22 #include "nautilus-mime-actions.h"
23 
24 #include <eel/eel-stock-dialogs.h>
25 #include <eel/eel-string.h>
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <glib/gstdio.h>
29 #include <string.h>
30 
31 #define DEBUG_FLAG NAUTILUS_DEBUG_MIME
32 #include "nautilus-debug.h"
33 
34 #include "nautilus-application.h"
35 #include "nautilus-enums.h"
36 #include "nautilus-file.h"
37 #include "nautilus-file-utilities.h"
38 #include "nautilus-file-operations.h"
39 #include "nautilus-global-preferences.h"
40 #include "nautilus-metadata.h"
41 #include "nautilus-program-choosing.h"
42 #include "nautilus-signaller.h"
43 #include "nautilus-ui-utilities.h"
44 #include "nautilus-window.h"
45 #include "nautilus-window-slot.h"
46 
47 typedef enum
48 {
49     ACTIVATION_ACTION_LAUNCH,
50     ACTIVATION_ACTION_LAUNCH_IN_TERMINAL,
51     ACTIVATION_ACTION_OPEN_IN_VIEW,
52     ACTIVATION_ACTION_OPEN_IN_APPLICATION,
53     ACTIVATION_ACTION_EXTRACT,
54     ACTIVATION_ACTION_DO_NOTHING,
55 } ActivationAction;
56 
57 typedef struct
58 {
59     NautilusFile *file;
60     char *uri;
61 } LaunchLocation;
62 
63 typedef struct
64 {
65     GAppInfo *application;
66     GList *uris;
67 } ApplicationLaunchParameters;
68 
69 typedef struct
70 {
71     NautilusWindowSlot *slot;
72     gpointer window;
73     GtkWindow *parent_window;
74     GCancellable *cancellable;
75     GList *locations;
76     GList *mountables;
77     GList *start_mountables;
78     GList *not_mounted;
79     NautilusWindowOpenFlags flags;
80     char *timed_wait_prompt;
81     gboolean timed_wait_active;
82     NautilusFileListHandle *files_handle;
83     gboolean tried_mounting;
84     char *activation_directory;
85     gboolean user_confirmation;
86 } ActivateParameters;
87 
88 typedef struct
89 {
90     ActivateParameters *activation_params;
91     GQueue *uris;
92 } ApplicationLaunchAsyncParameters;
93 
94 /* Microsoft mime types at https://blogs.msdn.microsoft.com/vsofficedeveloper/2008/05/08/office-2007-file-format-mime-types-for-http-content-streaming-2/ */
95 struct
96 {
97     char *name;
98     char *mimetypes[20];
99 } mimetype_groups[] =
100 {
101     {
102         N_("Anything"),
103         { NULL }
104     },
105     {
106         N_("Files"),
107         { "application/octet-stream",
108           "text/plain",
109           NULL}
110     },
111     {
112         N_("Folders"),
113         { "inode/directory",
114           NULL}
115     },
116     { N_("Documents"),
117       { "application/rtf",
118         "application/msword",
119         "application/vnd.sun.xml.writer",
120         "application/vnd.sun.xml.writer.global",
121         "application/vnd.sun.xml.writer.template",
122         "application/vnd.oasis.opendocument.text",
123         "application/vnd.oasis.opendocument.text-template",
124         "application/x-abiword",
125         "application/x-applix-word",
126         "application/x-mswrite",
127         "application/docbook+xml",
128         "application/x-kword",
129         "application/x-kword-crypt",
130         "application/x-lyx",
131         "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
132         NULL}},
133     { N_("Illustration"),
134       { "application/illustrator",
135         "application/vnd.corel-draw",
136         "application/vnd.stardivision.draw",
137         "application/vnd.oasis.opendocument.graphics",
138         "application/x-dia-diagram",
139         "application/x-karbon",
140         "application/x-killustrator",
141         "application/x-kivio",
142         "application/x-kontour",
143         "application/x-wpg",
144         NULL}},
145     { N_("Music"),
146       { "application/ogg",
147         "audio/x-vorbis+ogg",
148         "audio/ac3",
149         "audio/basic",
150         "audio/midi",
151         "audio/x-flac",
152         "audio/mp4",
153         "audio/mpeg",
154         "audio/x-mpeg",
155         "audio/x-ms-asx",
156         "audio/x-pn-realaudio",
157         NULL}},
158     { N_("PDF / PostScript"),
159       { "application/pdf",
160         "application/postscript",
161         "application/x-dvi",
162         "image/x-eps",
163         "image/vnd.djvu+multipage",
164         NULL}},
165     { N_("Picture"),
166       { "application/vnd.oasis.opendocument.image",
167         "application/x-krita",
168         "image/bmp",
169         "image/cgm",
170         "image/gif",
171         "image/jpeg",
172         "image/jpeg2000",
173         "image/png",
174         "image/svg+xml",
175         "image/tiff",
176         "image/x-compressed-xcf",
177         "image/x-pcx",
178         "image/x-photo-cd",
179         "image/x-psd",
180         "image/x-tga",
181         "image/x-xcf",
182         NULL}},
183     { N_("Presentation"),
184       { "application/vnd.ms-powerpoint",
185         "application/vnd.sun.xml.impress",
186         "application/vnd.oasis.opendocument.presentation",
187         "application/x-magicpoint",
188         "application/x-kpresenter",
189         "application/vnd.openxmlformats-officedocument.presentationml.presentation",
190         NULL}},
191     { N_("Spreadsheet"),
192       { "application/vnd.lotus-1-2-3",
193         "application/vnd.ms-excel",
194         "application/vnd.stardivision.calc",
195         "application/vnd.sun.xml.calc",
196         "application/vnd.oasis.opendocument.spreadsheet",
197         "application/x-applix-spreadsheet",
198         "application/x-gnumeric",
199         "application/x-kspread",
200         "application/x-kspread-crypt",
201         "application/x-quattropro",
202         "application/x-sc",
203         "application/x-siag",
204         "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
205         NULL}},
206     { N_("Text File"),
207       { "text/plain",
208         NULL}},
209     { N_("Video"),
210       { "video/mp4",
211         "video/3gpp",
212         "video/mpeg",
213         "video/quicktime",
214         "video/vivo",
215         "video/x-avi",
216         "video/x-mng",
217         "video/x-ms-asf",
218         "video/x-ms-wmv",
219         "video/x-msvideo",
220         "video/x-nsv",
221         "video/x-real-video",
222         NULL}}
223 };
224 
225 /* Number of seconds until cancel dialog shows up */
226 #define DELAY_UNTIL_CANCEL_MSECS 5000
227 
228 #define SILENT_WINDOW_OPEN_LIMIT 5
229 #define SILENT_OPEN_LIMIT 5
230 
231 /* This number controls a maximum character count for a URL that is
232  * displayed as part of a dialog. It's fairly arbitrary -- big enough
233  * to allow most "normal" URIs to display in full, but small enough to
234  * prevent the dialog from getting insanely wide.
235  */
236 #define MAX_URI_IN_DIALOG_LENGTH 60
237 
238 static void cancel_activate_callback (gpointer callback_data);
239 static void activate_activation_uris_ready_callback (GList   *files,
240                                                      gpointer callback_data);
241 static void activation_mount_mountables (ActivateParameters *parameters);
242 static void activation_start_mountables (ActivateParameters *parameters);
243 static void activate_callback (GList   *files,
244                                gpointer callback_data);
245 static void activation_mount_not_mounted (ActivateParameters *parameters);
246 
247 static gboolean
is_sandboxed(void)248 is_sandboxed (void)
249 {
250     static gboolean ret;
251 
252     static gsize init = 0;
253     if (g_once_init_enter (&init))
254     {
255         ret = g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS);
256         g_once_init_leave (&init, 1);
257     }
258 
259     return ret;
260 }
261 
262 static void
launch_location_free(LaunchLocation * location)263 launch_location_free (LaunchLocation *location)
264 {
265     nautilus_file_unref (location->file);
266     g_free (location->uri);
267     g_free (location);
268 }
269 
270 static void
launch_location_list_free(GList * list)271 launch_location_list_free (GList *list)
272 {
273     g_list_foreach (list, (GFunc) launch_location_free, NULL);
274     g_list_free (list);
275 }
276 
277 static GList *
get_file_list_for_launch_locations(GList * locations)278 get_file_list_for_launch_locations (GList *locations)
279 {
280     GList *files, *l;
281     LaunchLocation *location;
282 
283     files = NULL;
284     for (l = locations; l != NULL; l = l->next)
285     {
286         location = l->data;
287 
288         files = g_list_prepend (files,
289                                 nautilus_file_ref (location->file));
290     }
291     return g_list_reverse (files);
292 }
293 
294 
295 static LaunchLocation *
launch_location_from_file(NautilusFile * file)296 launch_location_from_file (NautilusFile *file)
297 {
298     LaunchLocation *location;
299     location = g_new (LaunchLocation, 1);
300     location->file = nautilus_file_ref (file);
301     location->uri = nautilus_file_get_uri (file);
302 
303     return location;
304 }
305 
306 static void
launch_location_update_from_file(LaunchLocation * location,NautilusFile * file)307 launch_location_update_from_file (LaunchLocation *location,
308                                   NautilusFile   *file)
309 {
310     nautilus_file_unref (location->file);
311     g_free (location->uri);
312     location->file = nautilus_file_ref (file);
313     location->uri = nautilus_file_get_uri (file);
314 }
315 
316 static void
launch_location_update_from_uri(LaunchLocation * location,const char * uri)317 launch_location_update_from_uri (LaunchLocation *location,
318                                  const char     *uri)
319 {
320     nautilus_file_unref (location->file);
321     g_free (location->uri);
322     location->file = nautilus_file_get_by_uri (uri);
323     location->uri = g_strdup (uri);
324 }
325 
326 static LaunchLocation *
find_launch_location_for_file(GList * list,NautilusFile * file)327 find_launch_location_for_file (GList        *list,
328                                NautilusFile *file)
329 {
330     LaunchLocation *location;
331     GList *l;
332 
333     for (l = list; l != NULL; l = l->next)
334     {
335         location = l->data;
336 
337         if (location->file == file)
338         {
339             return location;
340         }
341     }
342     return NULL;
343 }
344 
345 static GList *
launch_locations_from_file_list(GList * list)346 launch_locations_from_file_list (GList *list)
347 {
348     GList *new;
349 
350     new = NULL;
351     while (list)
352     {
353         new = g_list_prepend (new,
354                               launch_location_from_file (list->data));
355         list = list->next;
356     }
357     new = g_list_reverse (new);
358     return new;
359 }
360 
361 static ApplicationLaunchParameters *
application_launch_parameters_new(GAppInfo * application,GList * uris)362 application_launch_parameters_new (GAppInfo *application,
363                                    GList    *uris)
364 {
365     ApplicationLaunchParameters *result;
366 
367     result = g_new0 (ApplicationLaunchParameters, 1);
368     result->application = g_object_ref (application);
369     result->uris = g_list_copy_deep (uris, (GCopyFunc) g_strdup, NULL);
370 
371     return result;
372 }
373 
374 static void
application_launch_parameters_free(ApplicationLaunchParameters * parameters)375 application_launch_parameters_free (ApplicationLaunchParameters *parameters)
376 {
377     g_object_unref (parameters->application);
378     g_list_free_full (parameters->uris, g_free);
379 
380     g_free (parameters);
381 }
382 
383 static gboolean
nautilus_mime_actions_check_if_required_attributes_ready(NautilusFile * file)384 nautilus_mime_actions_check_if_required_attributes_ready (NautilusFile *file)
385 {
386     NautilusFileAttributes attributes;
387     gboolean ready;
388 
389     attributes = nautilus_mime_actions_get_required_file_attributes ();
390     ready = nautilus_file_check_if_ready (file, attributes);
391 
392     return ready;
393 }
394 
395 NautilusFileAttributes
nautilus_mime_actions_get_required_file_attributes(void)396 nautilus_mime_actions_get_required_file_attributes (void)
397 {
398     return NAUTILUS_FILE_ATTRIBUTE_INFO;
399 }
400 
401 GAppInfo *
nautilus_mime_get_default_application_for_file(NautilusFile * file)402 nautilus_mime_get_default_application_for_file (NautilusFile *file)
403 {
404     GAppInfo *app;
405     char *mime_type;
406     char *uri_scheme;
407 
408     if (!nautilus_mime_actions_check_if_required_attributes_ready (file))
409     {
410         return NULL;
411     }
412 
413     mime_type = nautilus_file_get_mime_type (file);
414     app = g_app_info_get_default_for_type (mime_type,
415                                            !nautilus_file_has_local_path (file));
416     g_free (mime_type);
417 
418     if (app == NULL)
419     {
420         uri_scheme = nautilus_file_get_uri_scheme (file);
421         if (uri_scheme != NULL)
422         {
423             app = g_app_info_get_default_for_uri_scheme (uri_scheme);
424             g_free (uri_scheme);
425         }
426     }
427 
428     return app;
429 }
430 
431 static int
file_compare_by_mime_type(NautilusFile * file_a,NautilusFile * file_b)432 file_compare_by_mime_type (NautilusFile *file_a,
433                            NautilusFile *file_b)
434 {
435     char *mime_type_a, *mime_type_b;
436     int ret;
437 
438     mime_type_a = nautilus_file_get_mime_type (file_a);
439     mime_type_b = nautilus_file_get_mime_type (file_b);
440 
441     ret = strcmp (mime_type_a, mime_type_b);
442 
443     g_free (mime_type_a);
444     g_free (mime_type_b);
445 
446     return ret;
447 }
448 
449 static int
file_compare_by_parent_uri(NautilusFile * file_a,NautilusFile * file_b)450 file_compare_by_parent_uri (NautilusFile *file_a,
451                             NautilusFile *file_b)
452 {
453     char *parent_uri_a, *parent_uri_b;
454     int ret;
455 
456     parent_uri_a = nautilus_file_get_parent_uri (file_a);
457     parent_uri_b = nautilus_file_get_parent_uri (file_b);
458 
459     ret = strcmp (parent_uri_a, parent_uri_b);
460 
461     g_free (parent_uri_a);
462     g_free (parent_uri_b);
463 
464     return ret;
465 }
466 
467 GAppInfo *
nautilus_mime_get_default_application_for_files(GList * files)468 nautilus_mime_get_default_application_for_files (GList *files)
469 {
470     GList *l, *sorted_files;
471     NautilusFile *file;
472     GAppInfo *app, *one_app;
473 
474     g_assert (files != NULL);
475 
476     sorted_files = g_list_sort (g_list_copy (files), (GCompareFunc) file_compare_by_mime_type);
477 
478     app = NULL;
479     for (l = sorted_files; l != NULL; l = l->next)
480     {
481         file = l->data;
482 
483         if (l->prev &&
484             file_compare_by_mime_type (file, l->prev->data) == 0 &&
485             file_compare_by_parent_uri (file, l->prev->data) == 0)
486         {
487             continue;
488         }
489 
490         one_app = nautilus_mime_get_default_application_for_file (file);
491         if (one_app == NULL || (app != NULL && !g_app_info_equal (app, one_app)))
492         {
493             if (app)
494             {
495                 g_object_unref (app);
496             }
497             if (one_app)
498             {
499                 g_object_unref (one_app);
500             }
501             app = NULL;
502             break;
503         }
504 
505         if (app == NULL)
506         {
507             app = one_app;
508         }
509         else
510         {
511             g_object_unref (one_app);
512         }
513     }
514 
515     g_list_free (sorted_files);
516 
517     return app;
518 }
519 
520 static void
trash_or_delete_files(GtkWindow * parent_window,const GList * files,gboolean delete_if_all_already_in_trash)521 trash_or_delete_files (GtkWindow   *parent_window,
522                        const GList *files,
523                        gboolean     delete_if_all_already_in_trash)
524 {
525     GList *locations;
526     const GList *node;
527 
528     locations = NULL;
529     for (node = files; node != NULL; node = node->next)
530     {
531         locations = g_list_prepend (locations,
532                                     nautilus_file_get_location ((NautilusFile *) node->data));
533     }
534 
535     locations = g_list_reverse (locations);
536 
537     nautilus_file_operations_trash_or_delete_async (locations,
538                                                     parent_window,
539                                                     NULL,
540                                                     NULL, NULL);
541     g_list_free_full (locations, g_object_unref);
542 }
543 
544 static void
report_broken_symbolic_link(GtkWindow * parent_window,NautilusFile * file)545 report_broken_symbolic_link (GtkWindow    *parent_window,
546                              NautilusFile *file)
547 {
548     char *target_path;
549     char *display_name;
550     char *prompt;
551     char *detail;
552     GtkDialog *dialog;
553     GList file_as_list;
554     int response;
555     gboolean can_trash;
556 
557     g_assert (nautilus_file_is_broken_symbolic_link (file));
558 
559     display_name = nautilus_file_get_display_name (file);
560     can_trash = nautilus_file_can_trash (file) && !nautilus_file_is_in_trash (file);
561 
562     if (can_trash)
563     {
564         prompt = g_strdup_printf (_("The link “%s” is broken. Move it to Trash?"), display_name);
565     }
566     else
567     {
568         prompt = g_strdup_printf (_("The link “%s” is broken."), display_name);
569     }
570     g_free (display_name);
571 
572     target_path = nautilus_file_get_symbolic_link_target_path (file);
573     if (target_path == NULL)
574     {
575         detail = g_strdup (_("This link cannot be used because it has no target."));
576     }
577     else
578     {
579         detail = g_strdup_printf (_("This link cannot be used because its target "
580                                     "“%s” doesn’t exist."), target_path);
581     }
582 
583     if (!can_trash)
584     {
585         eel_run_simple_dialog (GTK_WIDGET (parent_window), FALSE, GTK_MESSAGE_WARNING,
586                                prompt, detail, _("_Cancel"), NULL);
587         goto out;
588     }
589 
590     dialog = eel_show_yes_no_dialog (prompt, detail, _("Mo_ve to Trash"), _("_Cancel"),
591                                      parent_window);
592 
593     gtk_dialog_set_default_response (dialog, GTK_RESPONSE_CANCEL);
594 
595     /* Make this modal to avoid problems with reffing the view & file
596      * to keep them around in case the view changes, which would then
597      * cause the old view not to be destroyed, which would cause its
598      * merged Bonobo items not to be un-merged. Maybe we need to unmerge
599      * explicitly when disconnecting views instead of relying on the
600      * unmerge in Destroy. But since BonoboUIHandler is probably going
601      * to change wildly, I don't want to mess with this now.
602      */
603 
604     response = gtk_dialog_run (dialog);
605     gtk_widget_destroy (GTK_WIDGET (dialog));
606 
607     if (response == GTK_RESPONSE_YES)
608     {
609         file_as_list.data = file;
610         file_as_list.next = NULL;
611         file_as_list.prev = NULL;
612         trash_or_delete_files (parent_window, &file_as_list, TRUE);
613     }
614 
615 out:
616     g_free (prompt);
617     g_free (target_path);
618     g_free (detail);
619 }
620 
621 static ActivationAction
get_default_executable_text_file_action(void)622 get_default_executable_text_file_action (void)
623 {
624     return ACTIVATION_ACTION_OPEN_IN_APPLICATION;
625 }
626 
627 static ActivationAction
get_activation_action(NautilusFile * file)628 get_activation_action (NautilusFile *file)
629 {
630     ActivationAction action;
631     char *activation_uri;
632     gboolean handles_extract = FALSE;
633     g_autoptr (GAppInfo) app_info = NULL;
634     const gchar *app_id;
635 
636     app_info = nautilus_mime_get_default_application_for_file (file);
637     if (app_info != NULL)
638     {
639         app_id = g_app_info_get_id (app_info);
640         handles_extract = g_strcmp0 (app_id, NAUTILUS_DESKTOP_ID) == 0;
641     }
642     if (handles_extract && nautilus_file_is_archive (file))
643     {
644         return ACTIVATION_ACTION_EXTRACT;
645     }
646 
647     activation_uri = nautilus_file_get_activation_uri (file);
648     if (activation_uri == NULL)
649     {
650         activation_uri = nautilus_file_get_uri (file);
651     }
652 
653     action = ACTIVATION_ACTION_DO_NOTHING;
654     if (nautilus_file_is_launchable (file))
655     {
656         char *executable_path;
657 
658         action = ACTIVATION_ACTION_LAUNCH;
659 
660         executable_path = g_filename_from_uri (activation_uri, NULL, NULL);
661         if (!executable_path)
662         {
663             action = ACTIVATION_ACTION_DO_NOTHING;
664         }
665         else if (nautilus_file_contains_text (file))
666         {
667             action = get_default_executable_text_file_action ();
668         }
669         g_free (executable_path);
670     }
671 
672     if (action == ACTIVATION_ACTION_DO_NOTHING)
673     {
674         if (nautilus_file_opens_in_view (file))
675         {
676             action = ACTIVATION_ACTION_OPEN_IN_VIEW;
677         }
678         else
679         {
680             action = ACTIVATION_ACTION_OPEN_IN_APPLICATION;
681         }
682     }
683     g_free (activation_uri);
684 
685     return action;
686 }
687 
688 gboolean
nautilus_mime_file_extracts(NautilusFile * file)689 nautilus_mime_file_extracts (NautilusFile *file)
690 {
691     return get_activation_action (file) == ACTIVATION_ACTION_EXTRACT;
692 }
693 
694 gboolean
nautilus_mime_file_launches(NautilusFile * file)695 nautilus_mime_file_launches (NautilusFile *file)
696 {
697     ActivationAction activation_action;
698 
699     activation_action = get_activation_action (file);
700 
701     return (activation_action == ACTIVATION_ACTION_LAUNCH);
702 }
703 
704 gboolean
nautilus_mime_file_opens_in_external_app(NautilusFile * file)705 nautilus_mime_file_opens_in_external_app (NautilusFile *file)
706 {
707     ActivationAction activation_action;
708 
709     activation_action = get_activation_action (file);
710 
711     return (activation_action == ACTIVATION_ACTION_OPEN_IN_APPLICATION);
712 }
713 
714 
715 static unsigned int
mime_application_hash(GAppInfo * app)716 mime_application_hash (GAppInfo *app)
717 {
718     const char *id;
719 
720     id = g_app_info_get_id (app);
721 
722     if (id == NULL)
723     {
724         return GPOINTER_TO_UINT (app);
725     }
726 
727     return g_str_hash (id);
728 }
729 
730 static void
list_to_parameters_foreach(GAppInfo * application,GList * uris,GList ** ret)731 list_to_parameters_foreach (GAppInfo  *application,
732                             GList     *uris,
733                             GList    **ret)
734 {
735     ApplicationLaunchParameters *parameters;
736 
737     uris = g_list_reverse (uris);
738 
739     parameters = application_launch_parameters_new
740                      (application, uris);
741     *ret = g_list_prepend (*ret, parameters);
742 }
743 
744 
745 /**
746  * make_activation_parameters
747  *
748  * Construct a list of ApplicationLaunchParameters from a list of NautilusFiles,
749  * where files that have the same default application are put into the same
750  * launch parameter, and others are put into the unhandled_files list.
751  *
752  * @files: Files to use for construction.
753  * @unhandled_files: Files without any default application will be put here.
754  *
755  * Return value: Newly allocated list of ApplicationLaunchParameters.
756  **/
757 static GList *
make_activation_parameters(GList * uris,GList ** unhandled_uris)758 make_activation_parameters (GList  *uris,
759                             GList **unhandled_uris)
760 {
761     GList *ret, *l, *app_uris;
762     NautilusFile *file;
763     GAppInfo *app, *old_app;
764     GHashTable *app_table;
765     char *uri;
766 
767     ret = NULL;
768     *unhandled_uris = NULL;
769 
770     app_table = g_hash_table_new_full
771                     ((GHashFunc) mime_application_hash,
772                     (GEqualFunc) g_app_info_equal,
773                     (GDestroyNotify) g_object_unref,
774                     (GDestroyNotify) g_list_free);
775 
776     for (l = uris; l != NULL; l = l->next)
777     {
778         uri = l->data;
779         file = nautilus_file_get_by_uri (uri);
780 
781         app = nautilus_mime_get_default_application_for_file (file);
782         if (app != NULL)
783         {
784             app_uris = NULL;
785 
786             if (g_hash_table_lookup_extended (app_table, app,
787                                               (gpointer *) &old_app,
788                                               (gpointer *) &app_uris))
789             {
790                 g_hash_table_steal (app_table, old_app);
791 
792                 app_uris = g_list_prepend (app_uris, uri);
793 
794                 g_object_unref (app);
795                 app = old_app;
796             }
797             else
798             {
799                 app_uris = g_list_prepend (NULL, uri);
800             }
801 
802             g_hash_table_insert (app_table, app, app_uris);
803         }
804         else
805         {
806             *unhandled_uris = g_list_prepend (*unhandled_uris, uri);
807         }
808         nautilus_file_unref (file);
809     }
810 
811     g_hash_table_foreach (app_table,
812                           (GHFunc) list_to_parameters_foreach,
813                           &ret);
814 
815     g_hash_table_destroy (app_table);
816 
817     *unhandled_uris = g_list_reverse (*unhandled_uris);
818 
819     return g_list_reverse (ret);
820 }
821 
822 static gboolean
file_was_cancelled(NautilusFile * file)823 file_was_cancelled (NautilusFile *file)
824 {
825     GError *error;
826 
827     error = nautilus_file_get_file_info_error (file);
828     return
829         error != NULL &&
830         error->domain == G_IO_ERROR &&
831         error->code == G_IO_ERROR_CANCELLED;
832 }
833 
834 static gboolean
file_was_not_mounted(NautilusFile * file)835 file_was_not_mounted (NautilusFile *file)
836 {
837     GError *error;
838 
839     error = nautilus_file_get_file_info_error (file);
840     return
841         error != NULL &&
842         error->domain == G_IO_ERROR &&
843         error->code == G_IO_ERROR_NOT_MOUNTED;
844 }
845 
846 static void
activation_parameters_free(ActivateParameters * parameters)847 activation_parameters_free (ActivateParameters *parameters)
848 {
849     if (parameters->timed_wait_active)
850     {
851         eel_timed_wait_stop (cancel_activate_callback, parameters);
852     }
853 
854     if (parameters->slot)
855     {
856         g_object_remove_weak_pointer (G_OBJECT (parameters->slot), (gpointer *) &parameters->slot);
857     }
858     if (parameters->parent_window)
859     {
860         g_object_remove_weak_pointer (G_OBJECT (parameters->parent_window), (gpointer *) &parameters->parent_window);
861     }
862     g_object_unref (parameters->cancellable);
863     launch_location_list_free (parameters->locations);
864     nautilus_file_list_free (parameters->mountables);
865     nautilus_file_list_free (parameters->start_mountables);
866     nautilus_file_list_free (parameters->not_mounted);
867     g_free (parameters->activation_directory);
868     g_free (parameters->timed_wait_prompt);
869     g_assert (parameters->files_handle == NULL);
870     g_free (parameters);
871 }
872 
873 static void
application_launch_async_parameters_free(ApplicationLaunchAsyncParameters * parameters)874 application_launch_async_parameters_free (ApplicationLaunchAsyncParameters *parameters)
875 {
876     g_queue_free (parameters->uris);
877     activation_parameters_free (parameters->activation_params);
878 
879     g_free (parameters);
880 }
881 
882 static void
cancel_activate_callback(gpointer callback_data)883 cancel_activate_callback (gpointer callback_data)
884 {
885     ActivateParameters *parameters = callback_data;
886 
887     parameters->timed_wait_active = FALSE;
888 
889     g_cancellable_cancel (parameters->cancellable);
890 
891     if (parameters->files_handle)
892     {
893         nautilus_file_list_cancel_call_when_ready (parameters->files_handle);
894         parameters->files_handle = NULL;
895         activation_parameters_free (parameters);
896     }
897 }
898 
899 static void
activation_start_timed_cancel(ActivateParameters * parameters)900 activation_start_timed_cancel (ActivateParameters *parameters)
901 {
902     parameters->timed_wait_active = TRUE;
903     eel_timed_wait_start_with_duration
904         (DELAY_UNTIL_CANCEL_MSECS,
905         cancel_activate_callback,
906         parameters,
907         parameters->timed_wait_prompt,
908         parameters->parent_window);
909 }
910 
911 static void
pause_activation_timed_cancel(ActivateParameters * parameters)912 pause_activation_timed_cancel (ActivateParameters *parameters)
913 {
914     if (parameters->timed_wait_active)
915     {
916         eel_timed_wait_stop (cancel_activate_callback, parameters);
917         parameters->timed_wait_active = FALSE;
918     }
919 }
920 
921 static void
unpause_activation_timed_cancel(ActivateParameters * parameters)922 unpause_activation_timed_cancel (ActivateParameters *parameters)
923 {
924     if (!parameters->timed_wait_active)
925     {
926         activation_start_timed_cancel (parameters);
927     }
928 }
929 
930 
931 static void
activate_mount_op_active(GtkMountOperation * operation,GParamSpec * pspec,ActivateParameters * parameters)932 activate_mount_op_active (GtkMountOperation  *operation,
933                           GParamSpec         *pspec,
934                           ActivateParameters *parameters)
935 {
936     gboolean is_active;
937 
938     g_object_get (operation, "is-showing", &is_active, NULL);
939 
940     if (is_active)
941     {
942         pause_activation_timed_cancel (parameters);
943     }
944     else
945     {
946         unpause_activation_timed_cancel (parameters);
947     }
948 }
949 
950 static gboolean
confirm_multiple_windows(GtkWindow * parent_window,int count,gboolean use_tabs)951 confirm_multiple_windows (GtkWindow *parent_window,
952                           int        count,
953                           gboolean   use_tabs)
954 {
955     GtkDialog *dialog;
956     char *prompt;
957     char *detail;
958     int response;
959 
960     if (count <= SILENT_WINDOW_OPEN_LIMIT)
961     {
962         return TRUE;
963     }
964 
965     prompt = _("Are you sure you want to open all files?");
966     if (use_tabs)
967     {
968         detail = g_strdup_printf (ngettext ("This will open %d separate tab.",
969                                             "This will open %d separate tabs.", count), count);
970     }
971     else
972     {
973         detail = g_strdup_printf (ngettext ("This will open %d separate window.",
974                                             "This will open %d separate windows.", count), count);
975     }
976     dialog = eel_show_yes_no_dialog (prompt, detail,
977                                      _("_OK"), _("_Cancel"),
978                                      parent_window);
979     g_free (detail);
980 
981     response = gtk_dialog_run (dialog);
982     gtk_widget_destroy (GTK_WIDGET (dialog));
983 
984     return response == GTK_RESPONSE_YES;
985 }
986 
987 typedef struct
988 {
989     NautilusWindowSlot *slot;
990     GtkWindow *parent_window;
991     NautilusFile *file;
992     GList *files;
993     NautilusWindowOpenFlags flags;
994     char *activation_directory;
995     gboolean user_confirmation;
996     char *uri;
997     GDBusProxy *proxy;
998     GtkWidget *dialog;
999 } ActivateParametersInstall;
1000 
1001 static void
activate_parameters_install_free(ActivateParametersInstall * parameters_install)1002 activate_parameters_install_free (ActivateParametersInstall *parameters_install)
1003 {
1004     if (parameters_install->slot)
1005     {
1006         g_object_remove_weak_pointer (G_OBJECT (parameters_install->slot), (gpointer *) &parameters_install->slot);
1007     }
1008     if (parameters_install->parent_window)
1009     {
1010         g_object_remove_weak_pointer (G_OBJECT (parameters_install->parent_window), (gpointer *) &parameters_install->parent_window);
1011     }
1012 
1013     if (parameters_install->proxy != NULL)
1014     {
1015         g_object_unref (parameters_install->proxy);
1016     }
1017 
1018     nautilus_file_unref (parameters_install->file);
1019     nautilus_file_list_free (parameters_install->files);
1020     g_free (parameters_install->activation_directory);
1021     g_free (parameters_install->uri);
1022     g_free (parameters_install);
1023 }
1024 
1025 static char *
get_application_no_mime_type_handler_message(NautilusFile * file,char * uri)1026 get_application_no_mime_type_handler_message (NautilusFile *file,
1027                                               char         *uri)
1028 {
1029     char *uri_for_display;
1030     char *name;
1031     char *error_message;
1032 
1033     name = nautilus_file_get_display_name (file);
1034 
1035     /* Truncate the URI so it doesn't get insanely wide. Note that even
1036      * though the dialog uses wrapped text, if the URI doesn't contain
1037      * white space then the text-wrapping code is too stupid to wrap it.
1038      */
1039     uri_for_display = eel_str_middle_truncate (name, MAX_URI_IN_DIALOG_LENGTH);
1040     error_message = g_strdup_printf (_("Could Not Display “%s”"), uri_for_display);
1041     g_free (uri_for_display);
1042     g_free (name);
1043 
1044     return error_message;
1045 }
1046 
1047 static void
open_with_response_cb(GtkDialog * dialog,gint response_id,gpointer user_data)1048 open_with_response_cb (GtkDialog *dialog,
1049                        gint       response_id,
1050                        gpointer   user_data)
1051 {
1052     GtkWindow *parent_window;
1053     NautilusFile *file;
1054     GList files;
1055     GAppInfo *info;
1056     ActivateParametersInstall *parameters = user_data;
1057 
1058     if (response_id != GTK_RESPONSE_OK)
1059     {
1060         gtk_widget_destroy (GTK_WIDGET (dialog));
1061         return;
1062     }
1063 
1064     parent_window = parameters->parent_window;
1065     file = g_object_get_data (G_OBJECT (dialog), "mime-action:file");
1066     info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (dialog));
1067 
1068     gtk_widget_destroy (GTK_WIDGET (dialog));
1069 
1070     g_signal_emit_by_name (nautilus_signaller_get_current (), "mime-data-changed");
1071 
1072     files.next = NULL;
1073     files.prev = NULL;
1074     files.data = file;
1075     nautilus_launch_application (info, &files, parent_window);
1076 
1077     g_object_unref (info);
1078 
1079     activate_parameters_install_free (parameters);
1080 }
1081 
1082 static void
choose_program(GtkDialog * message_dialog,int response,gpointer callback_data)1083 choose_program (GtkDialog *message_dialog,
1084                 int        response,
1085                 gpointer   callback_data)
1086 {
1087     GtkWidget *dialog;
1088     NautilusFile *file;
1089     GFile *location;
1090     ActivateParametersInstall *parameters = callback_data;
1091 
1092     if (response != GTK_RESPONSE_ACCEPT)
1093     {
1094         gtk_widget_destroy (GTK_WIDGET (message_dialog));
1095         activate_parameters_install_free (parameters);
1096         return;
1097     }
1098 
1099     file = g_object_get_data (G_OBJECT (message_dialog), "mime-action:file");
1100 
1101     g_assert (NAUTILUS_IS_FILE (file));
1102 
1103     location = nautilus_file_get_location (file);
1104     nautilus_file_ref (file);
1105 
1106     /* Destroy the message dialog after ref:ing the file */
1107     gtk_widget_destroy (GTK_WIDGET (message_dialog));
1108 
1109     dialog = gtk_app_chooser_dialog_new (parameters->parent_window,
1110                                          GTK_DIALOG_MODAL,
1111                                          location);
1112     g_object_set_data_full (G_OBJECT (dialog),
1113                             "mime-action:file",
1114                             nautilus_file_ref (file),
1115                             (GDestroyNotify) nautilus_file_unref);
1116 
1117     gtk_widget_show (dialog);
1118 
1119     g_signal_connect (dialog,
1120                       "response",
1121                       G_CALLBACK (open_with_response_cb),
1122                       parameters);
1123 
1124     g_object_unref (location);
1125     nautilus_file_unref (file);
1126 }
1127 
1128 static void
show_unhandled_type_error(ActivateParametersInstall * parameters)1129 show_unhandled_type_error (ActivateParametersInstall *parameters)
1130 {
1131     GtkWidget *dialog;
1132 
1133     char *mime_type = nautilus_file_get_mime_type (parameters->file);
1134     char *error_message = get_application_no_mime_type_handler_message (parameters->file, parameters->uri);
1135     if (g_content_type_is_unknown (mime_type))
1136     {
1137         dialog = gtk_message_dialog_new (parameters->parent_window,
1138                                          GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
1139                                          GTK_MESSAGE_ERROR,
1140                                          0,
1141                                          "%s", error_message);
1142         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1143                                                   _("The file is of an unknown type"));
1144     }
1145     else
1146     {
1147         char *text;
1148         text = g_strdup_printf (_("There is no application installed for “%s” files"), g_content_type_get_description (mime_type));
1149 
1150         dialog = gtk_message_dialog_new (parameters->parent_window,
1151                                          GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
1152                                          GTK_MESSAGE_ERROR,
1153                                          0,
1154                                          "%s", error_message);
1155         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1156                                                   "%s", text);
1157 
1158         g_free (text);
1159     }
1160 
1161     gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Select Application"), GTK_RESPONSE_ACCEPT);
1162 
1163     gtk_dialog_add_button (GTK_DIALOG (dialog), _("_OK"), GTK_RESPONSE_OK);
1164 
1165     gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
1166 
1167     g_object_set_data_full (G_OBJECT (dialog),
1168                             "mime-action:file",
1169                             nautilus_file_ref (parameters->file),
1170                             (GDestroyNotify) nautilus_file_unref);
1171 
1172     gtk_widget_show (GTK_WIDGET (dialog));
1173 
1174     g_signal_connect (dialog, "response",
1175                       G_CALLBACK (choose_program), parameters);
1176 
1177     g_free (error_message);
1178     g_free (mime_type);
1179 }
1180 
1181 static void
search_for_application_dbus_call_notify_cb(GDBusProxy * proxy,GAsyncResult * result,gpointer user_data)1182 search_for_application_dbus_call_notify_cb (GDBusProxy   *proxy,
1183                                             GAsyncResult *result,
1184                                             gpointer      user_data)
1185 {
1186     ActivateParametersInstall *parameters_install = user_data;
1187     GVariant *variant;
1188     GError *error = NULL;
1189 
1190     variant = g_dbus_proxy_call_finish (proxy, result, &error);
1191     if (variant == NULL)
1192     {
1193         if (!g_dbus_error_is_remote_error (error) ||
1194             g_strcmp0 (g_dbus_error_get_remote_error (error), "org.freedesktop.PackageKit.Modify.Failed") == 0)
1195         {
1196             char *message;
1197 
1198             message = g_strdup_printf ("%s\n%s",
1199                                        _("There was an internal error trying to search for applications:"),
1200                                        error->message);
1201             show_dialog (_("Unable to search for application"),
1202                          message,
1203                          parameters_install->parent_window,
1204                          GTK_MESSAGE_ERROR);
1205             g_free (message);
1206         }
1207         else
1208         {
1209             g_warning ("Error while trying to search for applications: %s",
1210                        error->message);
1211         }
1212 
1213         g_error_free (error);
1214         activate_parameters_install_free (parameters_install);
1215         return;
1216     }
1217 
1218     g_variant_unref (variant);
1219 
1220     activate_parameters_install_free (parameters_install);
1221 }
1222 
1223 static void
search_for_application_mime_type(ActivateParametersInstall * parameters_install,const gchar * mime_type)1224 search_for_application_mime_type (ActivateParametersInstall *parameters_install,
1225                                   const gchar               *mime_type)
1226 {
1227     gchar *desktop_startup_id;
1228 
1229     g_assert (parameters_install->proxy != NULL);
1230 
1231     desktop_startup_id = g_strdup_printf ("_TIME%i", gtk_get_current_event_time ());
1232 
1233     g_dbus_proxy_call (parameters_install->proxy,
1234                        "InstallMimeTypes",
1235                        g_variant_new_parsed ("([%s], %s, %s, [{%s, %v}])",
1236                                              mime_type,
1237                                              "hide-confirm-search",
1238                                              APPLICATION_ID,
1239                                              "desktop-startup-id",
1240                                              g_variant_new_take_string (desktop_startup_id)),
1241                        G_DBUS_CALL_FLAGS_NONE,
1242                        G_MAXINT /* no timeout */,
1243                        NULL /* cancellable */,
1244                        (GAsyncReadyCallback) search_for_application_dbus_call_notify_cb,
1245                        parameters_install);
1246 
1247     DEBUG ("InstallMimeType method invoked for %s", mime_type);
1248 }
1249 
1250 static void
application_unhandled_file_install(GtkDialog * dialog,gint response_id,ActivateParametersInstall * parameters_install)1251 application_unhandled_file_install (GtkDialog                 *dialog,
1252                                     gint                       response_id,
1253                                     ActivateParametersInstall *parameters_install)
1254 {
1255     char *mime_type;
1256 
1257     gtk_widget_destroy (GTK_WIDGET (dialog));
1258     parameters_install->dialog = NULL;
1259 
1260     if (response_id == GTK_RESPONSE_YES)
1261     {
1262         mime_type = nautilus_file_get_mime_type (parameters_install->file);
1263         search_for_application_mime_type (parameters_install, mime_type);
1264         g_free (mime_type);
1265     }
1266     else
1267     {
1268         /* free as we're not going to get the async dbus callback */
1269         activate_parameters_install_free (parameters_install);
1270     }
1271 }
1272 
1273 static void
pk_proxy_appeared_cb(GObject * source,GAsyncResult * res,gpointer user_data)1274 pk_proxy_appeared_cb (GObject      *source,
1275                       GAsyncResult *res,
1276                       gpointer      user_data)
1277 {
1278     ActivateParametersInstall *parameters_install = user_data;
1279     char *mime_type, *name_owner;
1280     char *error_message;
1281     GtkWidget *dialog;
1282     GDBusProxy *proxy;
1283     GError *error = NULL;
1284 
1285     proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
1286     name_owner = g_dbus_proxy_get_name_owner (proxy);
1287 
1288     if (error != NULL || name_owner == NULL)
1289     {
1290         g_warning ("Couldn't call Modify on the PackageKit interface: %s",
1291                    error != NULL ? error->message : "no owner for PackageKit");
1292         g_clear_error (&error);
1293 
1294         /* show an unhelpful dialog */
1295         show_unhandled_type_error (parameters_install);
1296 
1297         return;
1298     }
1299 
1300     g_free (name_owner);
1301 
1302     mime_type = nautilus_file_get_mime_type (parameters_install->file);
1303     error_message = get_application_no_mime_type_handler_message (parameters_install->file,
1304                                                                   parameters_install->uri);
1305     /* use a custom dialog to prompt the user to install new software */
1306     dialog = gtk_message_dialog_new (parameters_install->parent_window,
1307                                      GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
1308                                      GTK_MESSAGE_ERROR,
1309                                      GTK_BUTTONS_NONE,
1310                                      "%s", error_message);
1311     gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1312                                               _("There is no application installed for “%s” files. "
1313                                                 "Do you want to search for an application to open this file?"),
1314                                               g_content_type_get_description (mime_type));
1315     gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
1316 
1317     gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL);
1318     gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Search in Software"), GTK_RESPONSE_YES);
1319 
1320     gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
1321 
1322     parameters_install->dialog = dialog;
1323     parameters_install->proxy = proxy;
1324 
1325     g_signal_connect (dialog, "response",
1326                       G_CALLBACK (application_unhandled_file_install),
1327                       parameters_install);
1328     gtk_widget_show_all (dialog);
1329     g_free (mime_type);
1330 }
1331 
1332 static void
application_unhandled_uri(ActivateParameters * parameters,char * uri)1333 application_unhandled_uri (ActivateParameters *parameters,
1334                            char               *uri)
1335 {
1336     gboolean show_install_mime;
1337     char *mime_type;
1338     NautilusFile *file;
1339     ActivateParametersInstall *parameters_install;
1340 
1341     file = nautilus_file_get_by_uri (uri);
1342 
1343     mime_type = nautilus_file_get_mime_type (file);
1344 
1345     /* copy the parts of parameters we are interested in as the orignal will be unref'd */
1346     parameters_install = g_new0 (ActivateParametersInstall, 1);
1347     parameters_install->slot = parameters->slot;
1348     g_object_add_weak_pointer (G_OBJECT (parameters_install->slot), (gpointer *) &parameters_install->slot);
1349     if (parameters->parent_window)
1350     {
1351         parameters_install->parent_window = parameters->parent_window;
1352         g_object_add_weak_pointer (G_OBJECT (parameters_install->parent_window), (gpointer *) &parameters_install->parent_window);
1353     }
1354     parameters_install->activation_directory = g_strdup (parameters->activation_directory);
1355     parameters_install->file = file;
1356     parameters_install->files = get_file_list_for_launch_locations (parameters->locations);
1357     parameters_install->flags = parameters->flags;
1358     parameters_install->user_confirmation = parameters->user_confirmation;
1359     parameters_install->uri = g_strdup (uri);
1360 
1361 #ifdef ENABLE_PACKAGEKIT
1362     /* allow an admin to disable the PackageKit search functionality */
1363     show_install_mime = g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_INSTALL_MIME_ACTIVATION);
1364 #else
1365     /* we have no install functionality */
1366     show_install_mime = FALSE;
1367 #endif
1368     /* There is no use trying to look for handlers of application/octet-stream */
1369     if (g_content_type_is_unknown (mime_type))
1370     {
1371         show_install_mime = FALSE;
1372     }
1373 
1374     g_free (mime_type);
1375 
1376     if (!show_install_mime)
1377     {
1378         goto out;
1379     }
1380 
1381     g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
1382                               G_DBUS_PROXY_FLAGS_NONE,
1383                               NULL,
1384                               "org.freedesktop.PackageKit",
1385                               "/org/freedesktop/PackageKit",
1386                               "org.freedesktop.PackageKit.Modify2",
1387                               NULL,
1388                               pk_proxy_appeared_cb,
1389                               parameters_install);
1390 
1391     return;
1392 
1393 out:
1394     /* show an unhelpful dialog */
1395     show_unhandled_type_error (parameters_install);
1396 }
1397 
1398 static void
launch_default_for_uris_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)1399 launch_default_for_uris_callback (GObject      *source_object,
1400                                   GAsyncResult *res,
1401                                   gpointer      user_data)
1402 {
1403     ApplicationLaunchAsyncParameters *params;
1404     ActivateParameters *activation_params;
1405     char *uri;
1406     g_autoptr (GError) error = NULL;
1407 
1408     params = user_data;
1409     activation_params = params->activation_params;
1410     uri = g_queue_pop_head (params->uris);
1411 
1412     nautilus_launch_default_for_uri_finish (res, &error);
1413     if (error == NULL)
1414     {
1415         gtk_recent_manager_add_item (gtk_recent_manager_get_default (), uri);
1416     }
1417 
1418     if (!g_queue_is_empty (params->uris))
1419     {
1420         nautilus_launch_default_for_uri_async (g_queue_peek_head (params->uris),
1421                                                activation_params->parent_window,
1422                                                activation_params->cancellable,
1423                                                launch_default_for_uris_callback,
1424                                                params);
1425     }
1426     else
1427     {
1428         application_launch_async_parameters_free (params);
1429     }
1430 }
1431 
1432 static void
activate_files(ActivateParameters * parameters)1433 activate_files (ActivateParameters *parameters)
1434 {
1435     NautilusFile *file;
1436     NautilusWindowOpenFlags flags;
1437     g_autoptr (GList) open_in_app_parameters = NULL;
1438     g_autoptr (GList) unhandled_open_in_app_uris = NULL;
1439     ApplicationLaunchParameters *one_parameters;
1440     int count;
1441     g_autofree char *old_working_dir = NULL;
1442     GdkScreen *screen;
1443     gint num_apps;
1444     gint num_unhandled;
1445     gint num_files;
1446     gboolean open_files;
1447     g_autoptr (GQueue) launch_files = NULL;
1448     g_autoptr (GQueue) launch_in_terminal_files = NULL;
1449     g_autoptr (GQueue) open_in_app_uris = NULL;
1450     g_autoptr (GQueue) open_in_view_files = NULL;
1451     GList *l;
1452     ActivationAction action;
1453 
1454     launch_files = g_queue_new ();
1455     launch_in_terminal_files = g_queue_new ();
1456     open_in_view_files = g_queue_new ();
1457     open_in_app_uris = g_queue_new ();
1458 
1459     for (l = parameters->locations; l != NULL; l = l->next)
1460     {
1461         LaunchLocation *location;
1462 
1463         location = l->data;
1464         file = location->file;
1465 
1466         if (file_was_cancelled (file))
1467         {
1468             continue;
1469         }
1470 
1471         action = get_activation_action (file);
1472 
1473         switch (action)
1474         {
1475             case ACTIVATION_ACTION_LAUNCH:
1476             {
1477                 g_queue_push_tail (launch_files, file);
1478             }
1479             break;
1480 
1481             case ACTIVATION_ACTION_LAUNCH_IN_TERMINAL:
1482             {
1483                 g_queue_push_tail (launch_in_terminal_files, file);
1484             }
1485             break;
1486 
1487             case ACTIVATION_ACTION_OPEN_IN_VIEW:
1488             {
1489                 g_queue_push_tail (open_in_view_files, file);
1490             }
1491             break;
1492 
1493             case ACTIVATION_ACTION_OPEN_IN_APPLICATION:
1494             {
1495                 g_queue_push_tail (open_in_app_uris, location->uri);
1496             }
1497             break;
1498 
1499             case ACTIVATION_ACTION_DO_NOTHING:
1500             {
1501             }
1502             break;
1503 
1504             case ACTIVATION_ACTION_EXTRACT:
1505             {
1506                 /* Extraction of files should be handled in the view */
1507                 g_assert_not_reached ();
1508             }
1509             break;
1510         }
1511     }
1512 
1513     if (parameters->activation_directory &&
1514         (!g_queue_is_empty (launch_files) ||
1515          !g_queue_is_empty (launch_in_terminal_files)))
1516     {
1517         old_working_dir = g_get_current_dir ();
1518         g_chdir (parameters->activation_directory);
1519     }
1520 
1521     screen = gtk_widget_get_screen (GTK_WIDGET (parameters->parent_window));
1522     for (l = g_queue_peek_head_link (launch_files); l != NULL; l = l->next)
1523     {
1524         g_autofree char *uri = NULL;
1525         g_autofree char *executable_path = NULL;
1526         g_autofree char *quoted_path = NULL;
1527 
1528         file = NAUTILUS_FILE (l->data);
1529 
1530         uri = nautilus_file_get_activation_uri (file);
1531         executable_path = g_filename_from_uri (uri, NULL, NULL);
1532         quoted_path = g_shell_quote (executable_path);
1533 
1534         DEBUG ("Launching file path %s", quoted_path);
1535 
1536         nautilus_launch_application_from_command (screen, quoted_path, FALSE, NULL);
1537     }
1538 
1539     for (l = g_queue_peek_head_link (launch_in_terminal_files); l != NULL; l = l->next)
1540     {
1541         g_autofree char *uri = NULL;
1542         g_autofree char *executable_path = NULL;
1543         g_autofree char *quoted_path = NULL;
1544 
1545         file = NAUTILUS_FILE (l->data);
1546 
1547         uri = nautilus_file_get_activation_uri (file);
1548         executable_path = g_filename_from_uri (uri, NULL, NULL);
1549         quoted_path = g_shell_quote (executable_path);
1550 
1551         DEBUG ("Launching in terminal file quoted path %s", quoted_path);
1552 
1553         nautilus_launch_application_from_command (screen, quoted_path, TRUE, NULL);
1554     }
1555 
1556     if (old_working_dir != NULL)
1557     {
1558         g_chdir (old_working_dir);
1559     }
1560 
1561     count = g_queue_get_length (open_in_view_files);
1562 
1563     flags = parameters->flags;
1564     if (count > 1)
1565     {
1566         if ((parameters->flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW) == 0)
1567         {
1568             flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB;
1569         }
1570         else
1571         {
1572             flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW;
1573         }
1574     }
1575 
1576     if (parameters->slot != NULL &&
1577         (!parameters->user_confirmation ||
1578          confirm_multiple_windows (parameters->parent_window, count,
1579                                    (flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB) != 0)))
1580     {
1581         if ((flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB) != 0 &&
1582             g_settings_get_enum (nautilus_preferences, NAUTILUS_PREFERENCES_NEW_TAB_POSITION) ==
1583             NAUTILUS_NEW_TAB_POSITION_AFTER_CURRENT_TAB)
1584         {
1585             /* When inserting N tabs after the current one,
1586              * we first open tab N, then tab N-1, ..., then tab 0.
1587              * Each of them is appended to the current tab, i.e.
1588              * prepended to the list of tabs to open.
1589              */
1590             g_queue_reverse (open_in_view_files);
1591         }
1592 
1593         for (l = g_queue_peek_head_link (open_in_view_files); l != NULL; l = l->next)
1594         {
1595             g_autofree char *uri = NULL;
1596             g_autoptr (GFile) location = NULL;
1597             g_autoptr (GFile) location_with_permissions = NULL;
1598             /* The ui should ask for navigation or object windows
1599              * depending on what the current one is */
1600             file = NAUTILUS_FILE (l->data);
1601             uri = nautilus_file_get_activation_uri (file);
1602             location = g_file_new_for_uri (uri);
1603             if (g_file_is_native (location) &&
1604                 (nautilus_file_is_in_admin (file) ||
1605                  !nautilus_file_can_read (file) ||
1606                  !nautilus_file_can_execute (file)))
1607             {
1608                 g_autofree gchar *file_path = NULL;
1609 
1610                 g_free (uri);
1611 
1612                 file_path = g_file_get_path (location);
1613                 uri = g_strconcat ("admin://", file_path, NULL);
1614             }
1615 
1616             location_with_permissions = g_file_new_for_uri (uri);
1617             /* FIXME: we need to pass the parent_window, but we only use it for the current active window,
1618              * which nautilus-application should take care of. However is not working and creating regressions
1619              * in some cases. Until we figure out what's going on, continue to use the parameters->slot
1620              * to make splicit the window we want to use for activating the files */
1621             nautilus_application_open_location_full (NAUTILUS_APPLICATION (g_application_get_default ()),
1622                                                      location_with_permissions, flags, NULL, NULL, parameters->slot);
1623         }
1624     }
1625 
1626     if (!g_queue_is_empty (open_in_app_uris) && is_sandboxed ())
1627     {
1628         const char *uri;
1629         ApplicationLaunchAsyncParameters *async_params;
1630 
1631         uri = g_queue_peek_head (open_in_app_uris);
1632 
1633         async_params = g_new0 (ApplicationLaunchAsyncParameters, 1);
1634         async_params->activation_params = parameters;
1635         async_params->uris = g_steal_pointer (&open_in_app_uris);
1636 
1637         nautilus_launch_default_for_uri_async (uri,
1638                                                parameters->parent_window,
1639                                                parameters->cancellable,
1640                                                launch_default_for_uris_callback,
1641                                                async_params);
1642         return;
1643     }
1644 
1645     if (open_in_app_uris != NULL)
1646     {
1647         open_in_app_parameters = make_activation_parameters (g_queue_peek_head_link (open_in_app_uris),
1648                                                              &unhandled_open_in_app_uris);
1649     }
1650 
1651     num_apps = g_list_length (open_in_app_parameters);
1652     num_unhandled = g_list_length (unhandled_open_in_app_uris);
1653     num_files = g_queue_get_length (open_in_app_uris);
1654     open_files = TRUE;
1655 
1656     if (!g_queue_is_empty (open_in_app_uris) &&
1657         (!parameters->user_confirmation ||
1658          num_files + num_unhandled > SILENT_OPEN_LIMIT) &&
1659         num_apps > 1)
1660     {
1661         GtkDialog *dialog;
1662         char *prompt;
1663         g_autofree char *detail = NULL;
1664         int response;
1665 
1666         pause_activation_timed_cancel (parameters);
1667 
1668         prompt = _("Are you sure you want to open all files?");
1669         /* TODO: Replace 'window' with 'application' after string freeze. */
1670         detail = g_strdup_printf (ngettext ("This will open %d separate window.",
1671                                             "This will open %d separate windows.", num_apps), num_apps);
1672         dialog = eel_show_yes_no_dialog (prompt, detail,
1673                                          _("_OK"), _("_Cancel"),
1674                                          parameters->parent_window);
1675         response = gtk_dialog_run (dialog);
1676         gtk_widget_destroy (GTK_WIDGET (dialog));
1677 
1678         unpause_activation_timed_cancel (parameters);
1679 
1680         if (response != GTK_RESPONSE_YES)
1681         {
1682             open_files = FALSE;
1683         }
1684     }
1685 
1686     if (open_files)
1687     {
1688         for (l = open_in_app_parameters; l != NULL; l = l->next)
1689         {
1690             one_parameters = l->data;
1691 
1692             nautilus_launch_application_by_uri (one_parameters->application,
1693                                                 one_parameters->uris,
1694                                                 parameters->parent_window);
1695             application_launch_parameters_free (one_parameters);
1696         }
1697 
1698         for (l = unhandled_open_in_app_uris; l != NULL; l = l->next)
1699         {
1700             char *uri = l->data;
1701 
1702             /* this does not block */
1703             application_unhandled_uri (parameters, uri);
1704         }
1705     }
1706 
1707     activation_parameters_free (parameters);
1708 }
1709 
1710 static void
activation_mount_not_mounted_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)1711 activation_mount_not_mounted_callback (GObject      *source_object,
1712                                        GAsyncResult *res,
1713                                        gpointer      user_data)
1714 {
1715     ActivateParameters *parameters = user_data;
1716     GError *error;
1717     NautilusFile *file;
1718     LaunchLocation *loc;
1719 
1720     file = parameters->not_mounted->data;
1721 
1722     error = NULL;
1723     if (!g_file_mount_enclosing_volume_finish (G_FILE (source_object), res, &error))
1724     {
1725         if (error->domain != G_IO_ERROR ||
1726             (error->code != G_IO_ERROR_CANCELLED &&
1727              error->code != G_IO_ERROR_FAILED_HANDLED &&
1728              error->code != G_IO_ERROR_ALREADY_MOUNTED))
1729         {
1730             show_dialog (_("Unable to access location"),
1731                          error->message,
1732                          parameters->parent_window,
1733                          GTK_MESSAGE_ERROR);
1734         }
1735 
1736         if (error->domain != G_IO_ERROR ||
1737             error->code != G_IO_ERROR_ALREADY_MOUNTED)
1738         {
1739             loc = find_launch_location_for_file (parameters->locations,
1740                                                  file);
1741             if (loc)
1742             {
1743                 parameters->locations =
1744                     g_list_remove (parameters->locations, loc);
1745                 launch_location_free (loc);
1746             }
1747         }
1748 
1749         g_error_free (error);
1750     }
1751 
1752     parameters->not_mounted = g_list_delete_link (parameters->not_mounted,
1753                                                   parameters->not_mounted);
1754     nautilus_file_unref (file);
1755 
1756     activation_mount_not_mounted (parameters);
1757 }
1758 
1759 static void
activation_mount_not_mounted(ActivateParameters * parameters)1760 activation_mount_not_mounted (ActivateParameters *parameters)
1761 {
1762     NautilusFile *file;
1763     GFile *location;
1764     LaunchLocation *loc;
1765     GMountOperation *mount_op;
1766     GList *l, *next, *files;
1767 
1768     if (parameters->not_mounted != NULL)
1769     {
1770         file = parameters->not_mounted->data;
1771         mount_op = gtk_mount_operation_new (parameters->parent_window);
1772         g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
1773         g_signal_connect (mount_op, "notify::is-showing",
1774                           G_CALLBACK (activate_mount_op_active), parameters);
1775         location = nautilus_file_get_location (file);
1776         g_file_mount_enclosing_volume (location, 0, mount_op, parameters->cancellable,
1777                                        activation_mount_not_mounted_callback, parameters);
1778         g_object_unref (location);
1779         /* unref mount_op here - g_file_mount_enclosing_volume() does ref for itself */
1780         g_object_unref (mount_op);
1781         return;
1782     }
1783 
1784     parameters->tried_mounting = TRUE;
1785 
1786     if (parameters->locations == NULL)
1787     {
1788         activation_parameters_free (parameters);
1789         return;
1790     }
1791 
1792     /*  once the mount is finished, refresh all attributes
1793      *  - fixes new windows not appearing after successful mount
1794      */
1795     for (l = parameters->locations; l != NULL; l = next)
1796     {
1797         loc = l->data;
1798         next = l->next;
1799         nautilus_file_invalidate_all_attributes (loc->file);
1800     }
1801 
1802     files = get_file_list_for_launch_locations (parameters->locations);
1803     nautilus_file_list_call_when_ready
1804         (files,
1805         nautilus_mime_actions_get_required_file_attributes (),
1806         &parameters->files_handle,
1807         activate_callback, parameters);
1808     nautilus_file_list_free (files);
1809 }
1810 
1811 
1812 static void
activate_callback(GList * files,gpointer callback_data)1813 activate_callback (GList    *files,
1814                    gpointer  callback_data)
1815 {
1816     ActivateParameters *parameters = callback_data;
1817     GList *l, *next;
1818     NautilusFile *file;
1819     LaunchLocation *location;
1820 
1821     parameters->files_handle = NULL;
1822 
1823     for (l = parameters->locations; l != NULL; l = next)
1824     {
1825         location = l->data;
1826         file = location->file;
1827         next = l->next;
1828 
1829         if (file_was_cancelled (file))
1830         {
1831             launch_location_free (location);
1832             parameters->locations = g_list_delete_link (parameters->locations, l);
1833             continue;
1834         }
1835 
1836         if (file_was_not_mounted (file))
1837         {
1838             if (parameters->tried_mounting)
1839             {
1840                 launch_location_free (location);
1841                 parameters->locations = g_list_delete_link (parameters->locations, l);
1842             }
1843             else
1844             {
1845                 parameters->not_mounted = g_list_prepend (parameters->not_mounted,
1846                                                           nautilus_file_ref (file));
1847             }
1848             continue;
1849         }
1850     }
1851 
1852 
1853     if (parameters->not_mounted != NULL)
1854     {
1855         activation_mount_not_mounted (parameters);
1856     }
1857     else
1858     {
1859         activate_files (parameters);
1860     }
1861 }
1862 
1863 static void
activate_activation_uris_ready_callback(GList * files_ignore,gpointer callback_data)1864 activate_activation_uris_ready_callback (GList    *files_ignore,
1865                                          gpointer  callback_data)
1866 {
1867     ActivateParameters *parameters = callback_data;
1868     GList *l, *next, *files;
1869     NautilusFile *file;
1870     LaunchLocation *location;
1871 
1872     parameters->files_handle = NULL;
1873 
1874     for (l = parameters->locations; l != NULL; l = next)
1875     {
1876         location = l->data;
1877         file = location->file;
1878         next = l->next;
1879 
1880         if (file_was_cancelled (file))
1881         {
1882             launch_location_free (location);
1883             parameters->locations = g_list_delete_link (parameters->locations, l);
1884             continue;
1885         }
1886 
1887         if (nautilus_file_is_broken_symbolic_link (file))
1888         {
1889             launch_location_free (location);
1890             parameters->locations = g_list_delete_link (parameters->locations, l);
1891             pause_activation_timed_cancel (parameters);
1892             report_broken_symbolic_link (parameters->parent_window, file);
1893             unpause_activation_timed_cancel (parameters);
1894             continue;
1895         }
1896 
1897         if (nautilus_file_get_file_type (file) == G_FILE_TYPE_MOUNTABLE &&
1898             !nautilus_file_has_activation_uri (file))
1899         {
1900             /* Don't launch these... There is nothing we
1901              *  can do */
1902             launch_location_free (location);
1903             parameters->locations = g_list_delete_link (parameters->locations, l);
1904             continue;
1905         }
1906     }
1907 
1908     if (parameters->locations == NULL)
1909     {
1910         activation_parameters_free (parameters);
1911         return;
1912     }
1913 
1914     /* Convert the files to the actual activation uri files */
1915     for (l = parameters->locations; l != NULL; l = l->next)
1916     {
1917         char *uri;
1918         location = l->data;
1919 
1920         /* We want the file for the activation URI since we care
1921          * about the attributes for that, not for the original file.
1922          */
1923         uri = nautilus_file_get_activation_uri (location->file);
1924         if (uri != NULL)
1925         {
1926             launch_location_update_from_uri (location, uri);
1927         }
1928         g_free (uri);
1929     }
1930 
1931 
1932     /* get the parameters for the actual files */
1933     files = get_file_list_for_launch_locations (parameters->locations);
1934     nautilus_file_list_call_when_ready
1935         (files,
1936         nautilus_mime_actions_get_required_file_attributes (),
1937         &parameters->files_handle,
1938         activate_callback, parameters);
1939     nautilus_file_list_free (files);
1940 }
1941 
1942 static void
activate_regular_files(ActivateParameters * parameters)1943 activate_regular_files (ActivateParameters *parameters)
1944 {
1945     GList *l, *files;
1946     NautilusFile *file;
1947     LaunchLocation *location;
1948 
1949     /* link target info might be stale, re-read it */
1950     for (l = parameters->locations; l != NULL; l = l->next)
1951     {
1952         location = l->data;
1953         file = location->file;
1954 
1955         if (file_was_cancelled (file))
1956         {
1957             launch_location_free (location);
1958             parameters->locations = g_list_delete_link (parameters->locations, l);
1959             continue;
1960         }
1961     }
1962 
1963     if (parameters->locations == NULL)
1964     {
1965         activation_parameters_free (parameters);
1966         return;
1967     }
1968 
1969     files = get_file_list_for_launch_locations (parameters->locations);
1970     nautilus_file_list_call_when_ready
1971         (files, nautilus_mime_actions_get_required_file_attributes (),
1972         &parameters->files_handle,
1973         activate_activation_uris_ready_callback, parameters);
1974     nautilus_file_list_free (files);
1975 }
1976 
1977 static void
activation_mountable_mounted(NautilusFile * file,GFile * result_location,GError * error,gpointer callback_data)1978 activation_mountable_mounted (NautilusFile *file,
1979                               GFile        *result_location,
1980                               GError       *error,
1981                               gpointer      callback_data)
1982 {
1983     ActivateParameters *parameters = callback_data;
1984     NautilusFile *target_file;
1985     LaunchLocation *location;
1986 
1987     /* Remove from list of files that have to be mounted */
1988     parameters->mountables = g_list_remove (parameters->mountables, file);
1989     nautilus_file_unref (file);
1990 
1991 
1992     if (error == NULL)
1993     {
1994         /* Replace file with the result of the mount */
1995         target_file = nautilus_file_get (result_location);
1996 
1997         location = find_launch_location_for_file (parameters->locations,
1998                                                   file);
1999         if (location)
2000         {
2001             launch_location_update_from_file (location, target_file);
2002         }
2003         nautilus_file_unref (target_file);
2004     }
2005     else
2006     {
2007         /* Remove failed file */
2008 
2009         if (error->domain != G_IO_ERROR ||
2010             (error->code != G_IO_ERROR_FAILED_HANDLED &&
2011              error->code != G_IO_ERROR_ALREADY_MOUNTED))
2012         {
2013             location = find_launch_location_for_file (parameters->locations,
2014                                                       file);
2015             if (location)
2016             {
2017                 parameters->locations =
2018                     g_list_remove (parameters->locations,
2019                                    location);
2020                 launch_location_free (location);
2021             }
2022         }
2023 
2024         if (error->domain != G_IO_ERROR ||
2025             (error->code != G_IO_ERROR_CANCELLED &&
2026              error->code != G_IO_ERROR_FAILED_HANDLED &&
2027              error->code != G_IO_ERROR_ALREADY_MOUNTED))
2028         {
2029             show_dialog (_("Unable to access location"),
2030                          error->message,
2031                          parameters->parent_window,
2032                          GTK_MESSAGE_ERROR);
2033         }
2034 
2035         if (error->code == G_IO_ERROR_CANCELLED)
2036         {
2037             activation_parameters_free (parameters);
2038             return;
2039         }
2040     }
2041 
2042     /* Mount more mountables */
2043     activation_mount_mountables (parameters);
2044 }
2045 
2046 
2047 static void
activation_mount_mountables(ActivateParameters * parameters)2048 activation_mount_mountables (ActivateParameters *parameters)
2049 {
2050     NautilusFile *file;
2051     GMountOperation *mount_op;
2052 
2053     if (parameters->mountables != NULL)
2054     {
2055         file = parameters->mountables->data;
2056         mount_op = gtk_mount_operation_new (parameters->parent_window);
2057         g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
2058         g_signal_connect (mount_op, "notify::is-showing",
2059                           G_CALLBACK (activate_mount_op_active), parameters);
2060         nautilus_file_mount (file,
2061                              mount_op,
2062                              parameters->cancellable,
2063                              activation_mountable_mounted,
2064                              parameters);
2065         g_object_unref (mount_op);
2066         return;
2067     }
2068 
2069     if (parameters->mountables == NULL && parameters->start_mountables == NULL)
2070     {
2071         activate_regular_files (parameters);
2072     }
2073 }
2074 
2075 
2076 static void
activation_mountable_started(NautilusFile * file,GFile * gfile_of_file,GError * error,gpointer callback_data)2077 activation_mountable_started (NautilusFile *file,
2078                               GFile        *gfile_of_file,
2079                               GError       *error,
2080                               gpointer      callback_data)
2081 {
2082     ActivateParameters *parameters = callback_data;
2083     LaunchLocation *location;
2084 
2085     /* Remove from list of files that have to be mounted */
2086     parameters->start_mountables = g_list_remove (parameters->start_mountables, file);
2087     nautilus_file_unref (file);
2088 
2089     if (error == NULL)
2090     {
2091         /* Remove file */
2092         location = find_launch_location_for_file (parameters->locations, file);
2093         if (location != NULL)
2094         {
2095             parameters->locations = g_list_remove (parameters->locations, location);
2096             launch_location_free (location);
2097         }
2098     }
2099     else
2100     {
2101         /* Remove failed file */
2102         if (error->domain != G_IO_ERROR ||
2103             (error->code != G_IO_ERROR_FAILED_HANDLED))
2104         {
2105             location = find_launch_location_for_file (parameters->locations,
2106                                                       file);
2107             if (location)
2108             {
2109                 parameters->locations =
2110                     g_list_remove (parameters->locations,
2111                                    location);
2112                 launch_location_free (location);
2113             }
2114         }
2115 
2116         if (error->domain != G_IO_ERROR ||
2117             (error->code != G_IO_ERROR_CANCELLED &&
2118              error->code != G_IO_ERROR_FAILED_HANDLED))
2119         {
2120             show_dialog (_("Unable to start location"),
2121                          error->message,
2122                          parameters->parent_window,
2123                          GTK_MESSAGE_ERROR);
2124         }
2125 
2126         if (error->code == G_IO_ERROR_CANCELLED)
2127         {
2128             activation_parameters_free (parameters);
2129             return;
2130         }
2131     }
2132 
2133     /* Start more mountables */
2134     activation_start_mountables (parameters);
2135 }
2136 
2137 static void
activation_start_mountables(ActivateParameters * parameters)2138 activation_start_mountables (ActivateParameters *parameters)
2139 {
2140     NautilusFile *file;
2141     GMountOperation *start_op;
2142 
2143     if (parameters->start_mountables != NULL)
2144     {
2145         file = parameters->start_mountables->data;
2146         start_op = gtk_mount_operation_new (parameters->parent_window);
2147         g_signal_connect (start_op, "notify::is-showing",
2148                           G_CALLBACK (activate_mount_op_active), parameters);
2149         nautilus_file_start (file,
2150                              start_op,
2151                              parameters->cancellable,
2152                              activation_mountable_started,
2153                              parameters);
2154         g_object_unref (start_op);
2155         return;
2156     }
2157 
2158     if (parameters->mountables == NULL && parameters->start_mountables == NULL)
2159     {
2160         activate_regular_files (parameters);
2161     }
2162 }
2163 
2164 /**
2165  * nautilus_mime_activate_files:
2166  *
2167  * Activate a list of files. Each one might launch with an application or
2168  * with a component. This is normally called only by subclasses.
2169  * @view: FMDirectoryView in question.
2170  * @files: A GList of NautilusFiles to activate.
2171  *
2172  **/
2173 void
nautilus_mime_activate_files(GtkWindow * parent_window,NautilusWindowSlot * slot,GList * files,const char * launch_directory,NautilusWindowOpenFlags flags,gboolean user_confirmation)2174 nautilus_mime_activate_files (GtkWindow               *parent_window,
2175                               NautilusWindowSlot      *slot,
2176                               GList                   *files,
2177                               const char              *launch_directory,
2178                               NautilusWindowOpenFlags  flags,
2179                               gboolean                 user_confirmation)
2180 {
2181     ActivateParameters *parameters;
2182     char *file_name;
2183     int file_count;
2184     GList *l, *next;
2185     NautilusFile *file;
2186     LaunchLocation *location;
2187 
2188     if (files == NULL)
2189     {
2190         return;
2191     }
2192 
2193     DEBUG_FILES (files, "Calling activate_files() with files:");
2194 
2195     parameters = g_new0 (ActivateParameters, 1);
2196     parameters->slot = slot;
2197     g_object_add_weak_pointer (G_OBJECT (parameters->slot), (gpointer *) &parameters->slot);
2198     if (parent_window)
2199     {
2200         parameters->parent_window = parent_window;
2201         g_object_add_weak_pointer (G_OBJECT (parameters->parent_window), (gpointer *) &parameters->parent_window);
2202     }
2203     parameters->cancellable = g_cancellable_new ();
2204     parameters->activation_directory = g_strdup (launch_directory);
2205     parameters->locations = launch_locations_from_file_list (files);
2206     parameters->flags = flags;
2207     parameters->user_confirmation = user_confirmation;
2208 
2209     file_count = g_list_length (files);
2210     if (file_count == 1)
2211     {
2212         file_name = nautilus_file_get_display_name (files->data);
2213         parameters->timed_wait_prompt = g_strdup_printf (_("Opening “%s”."), file_name);
2214         g_free (file_name);
2215     }
2216     else
2217     {
2218         parameters->timed_wait_prompt = g_strdup_printf (ngettext ("Opening %d item.",
2219                                                                    "Opening %d items.",
2220                                                                    file_count),
2221                                                          file_count);
2222     }
2223 
2224 
2225     for (l = parameters->locations; l != NULL; l = next)
2226     {
2227         location = l->data;
2228         file = location->file;
2229         next = l->next;
2230 
2231         if (nautilus_file_can_mount (file))
2232         {
2233             parameters->mountables = g_list_prepend (parameters->mountables,
2234                                                      nautilus_file_ref (file));
2235         }
2236 
2237         if (nautilus_file_can_start (file))
2238         {
2239             parameters->start_mountables = g_list_prepend (parameters->start_mountables,
2240                                                            nautilus_file_ref (file));
2241         }
2242     }
2243 
2244     activation_start_timed_cancel (parameters);
2245     if (parameters->mountables != NULL)
2246     {
2247         activation_mount_mountables (parameters);
2248     }
2249     if (parameters->start_mountables != NULL)
2250     {
2251         activation_start_mountables (parameters);
2252     }
2253     if (parameters->mountables == NULL && parameters->start_mountables == NULL)
2254     {
2255         activate_regular_files (parameters);
2256     }
2257 }
2258 
2259 /**
2260  * nautilus_mime_activate_file:
2261  *
2262  * Activate a file in this view. This might involve switching the displayed
2263  * location for the current window, or launching an application.
2264  * @view: FMDirectoryView in question.
2265  * @file: A NautilusFile representing the file in this view to activate.
2266  * @use_new_window: Should this item be opened in a new window?
2267  *
2268  **/
2269 
2270 void
nautilus_mime_activate_file(GtkWindow * parent_window,NautilusWindowSlot * slot,NautilusFile * file,const char * launch_directory,NautilusWindowOpenFlags flags)2271 nautilus_mime_activate_file (GtkWindow               *parent_window,
2272                              NautilusWindowSlot      *slot,
2273                              NautilusFile            *file,
2274                              const char              *launch_directory,
2275                              NautilusWindowOpenFlags  flags)
2276 {
2277     GList *files;
2278 
2279     g_return_if_fail (NAUTILUS_IS_FILE (file));
2280 
2281     files = g_list_prepend (NULL, file);
2282     nautilus_mime_activate_files (parent_window, slot, files, launch_directory, flags, FALSE);
2283     g_list_free (files);
2284 }
2285 
2286 gint
nautilus_mime_types_get_number_of_groups(void)2287 nautilus_mime_types_get_number_of_groups (void)
2288 {
2289     return G_N_ELEMENTS (mimetype_groups);
2290 }
2291 
2292 const gchar *
nautilus_mime_types_group_get_name(gint group_index)2293 nautilus_mime_types_group_get_name (gint group_index)
2294 {
2295     g_return_val_if_fail (group_index < G_N_ELEMENTS (mimetype_groups), NULL);
2296 
2297     return gettext (mimetype_groups[group_index].name);
2298 }
2299 
2300 GPtrArray *
nautilus_mime_types_group_get_mimetypes(gint group_index)2301 nautilus_mime_types_group_get_mimetypes (gint group_index)
2302 {
2303     GStrv group;
2304     GPtrArray *mimetypes;
2305 
2306     g_return_val_if_fail (group_index < G_N_ELEMENTS (mimetype_groups), NULL);
2307 
2308     group = mimetype_groups[group_index].mimetypes;
2309     mimetypes = g_ptr_array_new_full (g_strv_length (group), g_free);
2310 
2311     /* Setup the new mimetypes set */
2312     for (gint i = 0; group[i] != NULL; i++)
2313     {
2314         g_ptr_array_add (mimetypes, g_strdup (group[i]));
2315     }
2316 
2317     return mimetypes;
2318 }
2319